网格交易的风控困局与复合风控引擎的解法
做量化交易做久了,你会发现一个规律:真正让你亏大钱的,往往不是某一个明确的坏信号,而是好几个"看起来还行"的信号同时出了问题。
这就好比开车。下雨天你会减速,转弯时你会减速,路面有坑你也会减速——每种情况单独处理都没问题。但如果下雨、转弯、路面有坑同时发生呢?三个"减速"叠在一起,可能就得停车了。你的大脑很自然地做了这种复合判断,但交易系统的风控模块并不一定能做到。
这篇文章聊聊我们在 QuantMesh 网格交易系统里遇到的风控困局,以及最终怎么用一套复合风控引擎(Composite Risk Controller)来解决它。
老系统的风控长什么样
先说现状。QuantMesh 的风控一直都有,而且看起来还挺全面——K线异常检测、市场深度监控、资金费率监控、AI 新闻分析、均线趋势过滤,该有的都有。
问题是它们各干各的。
具体来说:
-
K线异常检测(RiskMonitor) 和 深度监控(DepthMonitor) 在
symbol_manager.go里做一个 OR 判断——只要有一个触发就拉响警报。 -
资金费率监控(FundingRateMonitor) 在
super_position_manager.go里独立调整买入偏置系数buyBias。 -
趋势检测(TrendDetector) 也在
super_position_manager.go里独立决定是否过滤买入。 -
AI 新闻分析(NewsMonitor) 在
risk_monitor.go里做二元触发——要么触发要么不触发,非黑即白。
每个模块都在自己的世界里运转,彼此不知道对方在想什么。
这带来一个非常现实的问题:没法表达"多个因子同时偏空但都没达到单独触发阈值"的复合风险。
举个例子。某天晚上,AI 新闻模块检测到几条偏负面的消息,评分 55 分(触发线是 70),没触发。同一时间,均线出现死叉迹象,趋势检测的信号还不够强。资金费率连续两期为负,但还没到"连续三期"的阈值。市场深度比平时薄了一些,但没薄到触发线。
每个模块都觉得"嗯,还行,继续"。系统继续正常买入。然后价格一个小时跌了 8%。
这不是假设,这类场景在运行过程中出现过不止一次。
核心问题:独立判断 vs 联合判断
把上面的问题抽象一下,本质上就是"OR 判断"和"加权判断"的区别。
老系统用的是 OR 判断——每个模块独立看自己的数据,达到阈值就触发,没达到就放行。模块之间没有信息交换。
但风险这个东西不是这么运作的。一个 55 分的新闻风险加上一个 40 分的趋势风险加上一个 35 分的资金费率风险,三者叠加起来,整体风险远比任何单一因子看起来都高。可在老架构下,这三个信号加起来约等于零——因为没有一个达到各自的触发线。
这就是为什么需要一个能做"联合判断"的东西。
复合风控引擎的设计
解法其实不复杂。思路是这样的:把所有风控因子的输出统一归一化到 0-100 的分数,然后加权求和得到一个复合分数,再根据这个复合分数映射到不同的风控级别,执行不同的动作。
三层结构:
风控因子层 → 复合风控引擎 → 风控动作层
风控因子层:每个因子独立评估当前市场状况,输出一个 0-100 的风险分数。0 表示安全,100 表示极度危险。
复合风控引擎:收集所有因子的分数,按权重加权求和,得到一个 compositeScore。
风控动作层:根据 compositeScore 的区间,映射到五个风控级别,执行对应的动作。
风控级别
| compositeScore 区间 | 风控级别 | 对应动作 |
|---|---|---|
| < 25 | Normal | 正常交易 |
| 25 - 45 | Caution | 减少买入量 20% |
| 45 - 65 | ReducePosition | 减少买入量 50% |
| 65 - 80 | PauseBuying | 暂停开新仓 |
| > 80 | StopTrading | 停止交易并撤销所有挂单 |
这里有个设计上的考量:阈值不是线性分布的。低风险区间(Normal)给了 25 分的宽度,而高风险区间(StopTrading)只需要超过 80 就触发。这是因为在低风险区间容忍度应该高一些,避免频繁切换状态;而高风险时,宁可过度反应也不能反应不足。
核心数据结构
每个风控因子都实现同一个接口:
type RiskFactor interface {
Name() string
Evaluate(ctx context.Context) FactorResult
Weight() float64
}
因子评估的结果除了分数之外,还带着一个置信度(Confidence)字段:
type FactorResult struct {
Score float64 // 0-100, 0=安全, 100=极度危险
Confidence float64 // 0-1, 数据可信度
Reason string // 人类可读的原因
Details map[string]interface{}
}
为什么要有置信度?因为不是所有因子在所有时候都同样可靠。比如 AI 新闻分析在突发事件时很有用,但在没有新闻的时候它的输出意义不大。资金费率在某些交易所数据缺失的时候是不可用的。置信度低的因子在加权时影响会被削弱,避免"垃圾数据进、垃圾决策出"。
加权聚合的实际公式:
compositeScore = Σ(wi × si × ci) / Σ(wi × ci)
其中 wi 是权重,si 是分数,ci 是置信度。分母做了归一化,确保最终分数仍然在 0-100 范围内。
五个风控因子
1. AI 新闻因子(NewsRiskFactor)
权重:0.30(默认最高)
这个因子权重最大,因为新闻对加密货币短期价格的冲击最直接。一条监管利空、一个交易所暴雷,价格反应比任何技术指标都快。
数据来源是已有的 NewsMonitor 模块,它会调用大语言模型对最新新闻做风险评估,输出一个 OverallRiskScore。新闻因子直接复用这个分数,再叠加一层逻辑:如果 CrashProbability(崩盘概率)超过 0.5,额外加分。
说实话,AI 分析新闻这件事准确率没法做到 100%,但它的价值在于提供了一个"技术指标看不到"的维度。K线还没反应的时候,新闻可能已经出来了。
2. 均线趋势因子(TrendRiskFactor)
权重:0.25
这个因子负责看"大方向"。它综合了好几个经典技术指标:
- 均线偏离度:短期均线相对长期均线的位置。死叉程度越深,分数越高。
- RSI:超买超卖区间。RSI 低于 30 进入超卖区,说明市场恐慌情绪浓厚。
- MACD:柱状图的方向和强度。MACD 持续向下发散,趋势恶化的信号。
- 价格与均线的关系:当前价格跌破了几根均线。跌破一根扣分不多,跌破三根以上就值得警觉了。
这些指标单独看都有噪音,但综合在一起能给出一个比较稳定的趋势判断。趋势因子的特点是反应偏慢(均线天然滞后),但一旦给出信号,通常持续时间较长。它和新闻因子的快反应形成互补。
3. 资金费率因子(FundingRateFactor)
权重:0.20
资金费率是永续合约市场独有的指标,反映多空力量对比。这个因子的评分规则:
- 单次负费率:中等风险,30 分。说明空头力量暂时占优。
- 连续 N 期负费率:每多一期加 10 分,上限 80 分。连续负费率是比较明确的空头信号。
- 极端负费率(< -0.1%):直接 70 分。这种级别的负费率通常意味着市场正在剧烈下跌。
- 正费率过高(> 0.15%):同样高风险,70 分。这意味着多头过度拥挤,随时可能出现多杀多的踩踏。
配置里有个 consecutive_negative_periods 参数,默认是 3,意思是连续 3 期负费率就开始升级风险等级。这个参数可以根据不同交易对的特性调整。
4. 市场深度因子(DepthRiskFactor)
权重:0.10
市场深度指的是挂单簿上买卖双方的挂单量。深度突然变薄,意味着大资金在撤单观望,市场可能即将出现大幅波动。
这个因子直接复用了现有的 DepthMonitor,把深度下降的百分比映射到 0-100 分。实现简单,但在极端行情前往往能提供有价值的预警。
权重设为 0.10,是因为深度数据波动比较大,单独看容易产生误判。但作为复合判断中的一个维度,它的边际贡献是正的。
5. K线异常因子(KlineAnomalyFactor)
权重:0.15
K线异常检测关注的是短期内的价格行为异常——比如突然出现的巨幅波动、成交量异常放大、连续的长上影线或长下影线等。
这个因子复用现有的 RiskMonitor,把它的异常检测结果映射到 0-100。它和深度因子类似,单独作为触发条件不够稳定,但在复合评分里提供了额外的信息量。
为什么是这个权重分配
权重分配不是拍脑袋的结果。背后的逻辑是:
- 新闻因子 0.30:唯一能提供"场外信息"的因子,在黑天鹅事件中几乎是唯一的预警源。
- 趋势因子 0.25:技术面的"骨干",稳定性最好,但有滞后性。
- 资金费率 0.20:衍生品市场的情绪指标,有独立的信息价值。
- K线异常 0.15:短期波动检测,对闪崩等事件有快速反应。
- 市场深度 0.10:辅助指标,波动大但边际信息有用。
当然,这些权重是可配置的。不同的交易对、不同的市场环境,最优权重可能不同。配置文件里可以灵活调整。
集成方式:覆盖而非叠加
复合风控引擎的输出是覆盖原有的独立判断,而不是在原有判断的基础上再加一层。
这是一个很重要的设计决策。如果是叠加模式,原来的独立风控判断可能把买入量砍了 30%,复合风控又砍了 50%,加起来实际买入量只剩 35%——这就过度风控了。
覆盖模式下,当复合风控引擎启用后,它的 CompositeRiskResult 直接决定 buyBias(买入偏置系数)和是否暂停交易。原来分散在各处的独立判断逻辑不再生效。
在 SuperPositionManager.AdjustOrders() 方法中,复合风控检查被插入到网格风控逻辑之后:
if spm.compositeRisk != nil {
result := spm.compositeRisk.GetCurrentResult()
switch result.Level {
case safety.RiskStopTrading:
spm.CancelAllBuyOrders()
return nil
case safety.RiskPauseBuying:
skipBuying = true
case safety.RiskReducePosition:
buyBias *= 0.5
case safety.RiskCaution:
buyBias *= 0.8
}
}
干净利落。没有冗余,没有"先判断一次再判断一次"的浪费。
评估频率和性能
复合风控引擎的评估默认每 30 秒执行一次,不是每笔交易都跑一遍。
为什么?因为多数因子的数据源本身更新就没那么快。新闻不会每秒都来,均线的计算至少要有 K线级别的时间粒度,资金费率通常每 8 小时结算一次。每 30 秒评估一次已经足够覆盖大部分场景了。
每次评估的计算量也很小——五个因子各算一个分数,加权求和,查表映射。整个过程在毫秒级完成。不会对交易引擎的主循环造成任何可感知的延迟。
评估结果通过 GetCurrentResult() 方法缓存,交易引擎读取的是最近一次评估的快照,而不是实时计算。这保证了交易路径上没有额外的计算开销。
一个完整的场景推演
假设现在是凌晨 3 点,BTC 报价 98,000 USDT。各因子的状态:
- AI 新闻因子:检测到某大型交易所传出"暂停提币"的消息,评分 62 分,置信度 0.8。
- 均线趋势因子:4 小时级别 MA7 刚刚下穿 MA25,RSI 在 38,MACD 柱状图开始向下。评分 48 分,置信度 0.9。
- 资金费率因子:连续两期负费率,分别是 -0.03% 和 -0.05%。评分 40 分,置信度 1.0。
- 市场深度因子:买盘深度比 24 小时平均薄了 22%。评分 35 分,置信度 0.7。
- K线异常因子:最近一根 15 分钟 K线出现了 2.3% 的长上影线。评分 30 分,置信度 0.85。
在老系统下,没有一个因子达到各自的触发线。系统会继续正常买入。
复合风控引擎的计算:
加权分数 = (0.30×62×0.8 + 0.25×48×0.9 + 0.20×40×1.0 + 0.15×30×0.85 + 0.10×35×0.7)
/ (0.30×0.8 + 0.25×0.9 + 0.20×1.0 + 0.15×0.85 + 0.10×0.7)
= (14.88 + 10.8 + 8.0 + 3.825 + 2.45) / (0.24 + 0.225 + 0.20 + 0.1275 + 0.07)
= 39.955 / 0.8625
≈ 46.3
compositeScore 46.3,落在 45-65 的区间,对应 ReducePosition 级别。系统将买入量减半。
如果之后新闻进一步恶化,或者资金费率第三期仍为负,compositeScore 会继续上升,可能触发 PauseBuying 甚至 StopTrading。
这就是复合判断的价值——任何单个因子都没有说"危险",但综合起来,系统已经开始自我保护了。
配置示例
composite_risk:
enabled: true
evaluate_interval: 30 # 评估间隔,秒
thresholds:
caution: 25
reduce_position: 45
pause_buying: 65
stop_trading: 80
factors:
news:
enabled: true
weight: 0.30
trend:
enabled: true
weight: 0.25
use_rsi: true
use_macd: true
funding_rate:
enabled: true
weight: 0.20
consecutive_negative_periods: 3
depth:
enabled: true
weight: 0.10
kline:
enabled: true
weight: 0.15
每个因子都可以单独启用或禁用。权重在禁用某个因子后会自动重新归一化——你不需要手动调整其他因子的权重来凑 1.0。
阈值也是可配置的。如果你的交易策略比较激进,可以把 caution 调高一些,让系统在更高的风险水平下才开始减仓。反过来,保守型策略可以把阈值调低。
API 暴露
系统提供了一个 /api/composite-risk 端点,返回当前的复合风控状态:
{
"composite_score": 46.3,
"level": "reduce_position",
"buy_bias": 0.5,
"timestamp": "2026-02-06T03:00:30Z",
"factors": {
"news": { "score": 62, "confidence": 0.8, "reason": "交易所暂停提币传闻" },
"trend": { "score": 48, "confidence": 0.9, "reason": "MA7 下穿 MA25, RSI 38" },
"funding_rate": { "score": 40, "confidence": 1.0, "reason": "连续 2 期负费率" },
"depth": { "score": 35, "confidence": 0.7, "reason": "买盘深度下降 22%" },
"kline": { "score": 30, "confidence": 0.85, "reason": "15m K线 2.3% 长上影线" }
},
"reasons": [
"AI 新闻因子评分较高 (62)",
"趋势因子出现死叉信号 (48)",
"资金费率连续负值 (40)"
]
}
这个接口在 WebUI 仪表盘上也有对应的可视化展示。你可以随时看到每个因子的评分和整体风控状态,不用去翻日志。
写在最后
复合风控引擎不是什么花哨的概念,核心就一句话:把分散的信号聚合起来做联合判断。
回到开头的开车比喻——下雨 + 转弯 + 路面有坑,你的大脑会综合评估然后决定是减速、刹车还是停车,而不是分三个独立的"如果下雨就减速 10%"、"如果转弯就减速 10%"、"如果有坑就减速 10%"叠在一起。复合风控引擎做的事情本质上就是这个。
对于网格交易来说,这类引擎特别有意义。网格策略的核心逻辑是在区间内反复买卖赚取波动差价,天然就需要一个可靠的"什么时候该收手"的判断机制。独立的风控模块在信号明确时能工作,但在"阴天"——多个信号都有点不对但又不够明确时——就力不从心了。复合引擎填补的正是这个盲区。
Top comments (0)