第二十九讲:订单流与组合策略——多策略组合中的订单流权重分配
说实话,做量化交易这些年,我见过太多人把鸡蛋放在一个篮子里。单一策略再牛,也有失效的时候。我自己就吃过这个亏——2018年那会儿,我重仓了一个纯趋势跟踪策略,结果市场一震荡,回撤直接打穿了我的心理防线。
从那以后,我开始认真研究多策略组合。而订单流数据,恰恰是连接不同策略的那根线。今天我们就聊聊,怎么用订单流来分配多策略的权重。
为什么需要多策略组合?
单一策略的痛点很明显:
- 趋势策略:震荡市里反复打脸
- 反转策略:单边行情中死扛
- 套利策略:流动性枯竭时无法执行
但多策略组合不是简单地把几个策略拼在一起。你想想看,如果两个策略都在同一时间开多单,那跟一个策略有什么区别?
真正的组合,需要策略之间低相关,甚至负相关。而订单流数据,能帮我们判断当前市场环境更适合哪种策略。
订单流权重的核心逻辑
我个人的习惯是,把订单流数据抽象成三个维度:
- 主动性:买卖双方谁更积极
- 失衡度:大单与小单的比例
- 速度:订单到达的频率
这三个维度组合起来,就能刻画市场状态。比如:
| 市场状态 | 主动性 | 失衡度 | 速度 | 适合策略 |
|---|---|---|---|---|
| 强趋势 | 单边主动 | 高失衡 | 快 | 趋势跟踪 |
| 震荡吸筹 | 双向交替 | 低失衡 | 中速 | 均值回归 |
| 恐慌抛售 | 卖方主导 | 极高失衡 | 极快 | 反转抄底 |
| 流动性枯竭 | 无主动 | 极低 | 慢 | 暂停交易 |
权重分配的具体方法
嗯,这里要注意,权重分配不是拍脑袋定的。我一般用两种方法:
方法一:基于信号强度的动态权重
每个策略都会输出一个信号强度,比如0到1之间的值。订单流数据可以修正这个强度。
def adjust_weight_by_orderflow(strategy_signal, orderflow_metrics):
"""
根据订单流调整策略权重
strategy_signal: 原始策略信号 [0,1]
orderflow_metrics: 订单流指标字典
"""
# 基础权重
base_weight = strategy_signal
# 主动性修正
if orderflow_metrics['aggression'] > 0.7:
# 主动性很强,趋势策略加分
if strategy_name == 'trend':
base_weight *= 1.2
else:
base_weight *= 0.8
# 失衡度修正
if orderflow_metrics['imbalance'] > 0.8:
# 极度失衡,反转策略减分
if strategy_name == 'reversal':
base_weight *= 0.5
# 速度修正
if orderflow_metrics['speed'] < 0.2:
# 速度太慢,所有策略减半
base_weight *= 0.5
return min(base_weight, 1.0) # 限制在0-1之间
方法二:基于市场状态的切换权重
这个方法更直接。我先把市场分成几个状态,然后给每个状态预设一个权重模板。
# 市场状态到策略权重的映射
state_weights = {
'strong_trend': {
'trend_follow': 0.7,
'mean_reversion': 0.1,
'arbitrage': 0.2
},
'oscillation': {
'trend_follow': 0.2,
'mean_reversion': 0.6,
'arbitrage': 0.2
},
'panic_sell': {
'trend_follow': 0.1,
'mean_reversion': 0.3,
'arbitrage': 0.6 # 套利机会出现
}
}
def get_current_state(orderflow_data):
"""根据订单流判断当前市场状态"""
# 这里用简单的规则判断
if orderflow_data['buy_volume'] / orderflow_data['sell_volume'] > 1.5:
return 'strong_trend'
elif orderflow_data['imbalance_ratio'] < 0.3:
return 'oscillation'
elif orderflow_data['delta'] < -1000 and orderflow_data['volume'] > 5000:
return 'panic_sell'
else:
return 'oscillation' # 默认震荡
核心要点:权重分配不是静态的,而是随着订单流数据动态调整。我建议每5-10分钟重新计算一次权重,太频繁会增加交易成本,太慢又跟不上市场变化。
实战中的避坑指南
我曾经犯过一个错误:把权重调得太敏感。有一次,订单流数据突然显示主动性飙升,我立刻把趋势策略权重加到80%。结果那只是一个大户在分批建仓,市场并没有真正启动趋势。嗯,那次回撤让我记忆犹新。
所以我现在加了两个保护机制:
- 平滑处理:用EMA对权重做平滑,避免突变
- 最小权重限制:每个策略至少保留10%的权重,防止完全踏空
代码实现示例
下面是一个完整的权重分配类,我把它封装成了可复用的模块:
class OrderFlowWeightAllocator:
def __init__(self, strategies, smooth_factor=0.3):
self.strategies = strategies # 策略列表
self.smooth_factor = smooth_factor
self.current_weights = {s: 1/len(strategies) for s in strategies}
def update_weights(self, orderflow_snapshot):
# 1. 计算原始权重
raw_weights = self._calculate_raw_weights(orderflow_snapshot)
# 2. 平滑处理
for strategy in self.strategies:
self.current_weights[strategy] = (
self.smooth_factor * raw_weights[strategy] +
(1 - self.smooth_factor) * self.current_weights[strategy]
)
# 3. 归一化
total = sum(self.current_weights.values())
for strategy in self.strategies:
self.current_weights[strategy] /= total
# 4. 最小权重保护
min_weight = 0.1
for strategy in self.strategies:
if self.current_weights[strategy] < min_weight:
self.current_weights[strategy] = min_weight
# 重新归一化
total = sum(self.current_weights.values())
for strategy in self.strategies:
self.current_weights[strategy] /= total
return self.current_weights
def _calculate_raw_weights(self, snapshot):
# 这里实现具体的权重计算逻辑
# 省略具体实现...
pass
可视化:订单流权重分配流程
下面这张图,是我自己画的一个流程图,能帮你理清整个逻辑:
个人小技巧:我习惯在权重分配中加入一个「冷却期」。如果某个策略连续亏损3次,我会暂时降低它的权重,等它重新盈利后再恢复。这个机制帮我躲过了好几次策略失效的坑。
回测中的注意事项
回测时,很多人会忽略一个细节:订单流数据是高频的,但策略信号可能是低频的。你想想看,如果订单流每秒都在变,而你的策略每5分钟才出一个信号,那中间的数据怎么处理?
我的做法是:
- 对订单流数据做聚合,比如每1分钟计算一次平均值
- 用聚合后的数据来调整权重
- 避免用单笔订单流数据做决策,那太容易受噪声干扰
警告:千万不要在回测中使用未来数据!比如用当前时刻的订单流数据去调整当前时刻的权重,这在实盘中是做不到的。正确的做法是:用t-1时刻的订单流数据,去调整t时刻的权重。
好了,关于订单流在多策略组合中的权重分配,核心思路就是这些。说白了,就是让数据说话,让市场状态决定谁该多出力。你可以在自己的策略组合里试试看,先从两个策略开始,慢慢加。记住,少即是多,组合不是越多越好,而是越互补越好。