第三章:信号生成基础
做市策略的核心,说白了就是「信号驱动」。你想想看,没有信号,你的订单就像无头苍蝇。今天这一章,我带你从零搭建信号生成体系。我个人习惯把信号分成四类:价差、成交量、订单簿不平衡,再加上归一化处理。嗯,咱们一个一个来。
3.1 价差信号的定义
价差信号是最直观的。它衡量的是买卖价差(spread)的实时变化。我在项目中遇到过,很多人直接拿「当前卖一价 - 当前买一价」当信号,其实这不够。
真正的价差信号,要关注「相对价差」和「价差变化率」。
- 绝对价差:ask_price[0] - bid_price[0]
- 相对价差:绝对价差 / 中间价
- 价差变化率:(当前价差 - 前N笔价差均值) / 前N笔价差标准差
为什么要用相对价差?举个例子,BTC价格5万美金时,价差10美金很正常。但ETH价格2000美金时,价差10美金就太大了。相对价差能消除价格尺度的影响。
核心公式:
mid_price = (ask_price[0] + bid_price[0]) / 2
relative_spread = (ask_price[0] - bid_price[0]) / mid_price
spread_zscore = (relative_spread - rolling_mean) / rolling_std
价差Z-score是我最常用的信号。当Z-score > 2时,说明价差异常扩大,这时候做市商可以收窄自己的报价,赚取超额利润。反之,Z-score < -2时,价差异常缩小,要小心流动性陷阱。
我的经验:滚动窗口长度我一般取50-100笔。太短了噪声大,太长了反应迟钝。你可以根据交易对流动性调整。
3.2 成交量信号的定义
成交量信号反映的是「资金在动」。光看价格不看量,很容易被假突破骗进去。我曾经吃过这个亏——价格突然拉升,我追进去做市,结果发现是空头陷阱,成交量根本没跟上。
成交量信号我常用三个维度:
- 成交量变化率:当前成交量 / 过去N笔平均成交量
- 成交量加权价格(VWAP)偏离:当前价格 / VWAP - 1
- 大单检测:单笔成交量超过均值3倍标准差的,标记为异常单
代码示例:
def volume_signal(trades, window=20):
# trades: list of (price, volume, timestamp)
volumes = [t[1] for t in trades[-window:]]
avg_vol = np.mean(volumes)
std_vol = np.std(volumes)
current_vol = trades[-1][1]
vol_ratio = current_vol / avg_vol if avg_vol > 0 else 1.0
# 大单检测
is_large_order = current_vol > (avg_vol + 3 * std_vol)
return vol_ratio, is_large_order
成交量信号怎么用?当vol_ratio > 3且is_large_order为True时,说明有大资金进场。这时候做市策略要调整:如果是买单大单,说明买方强势,你可以把卖单挂高一点,买单挂低一点,赚取更大价差。
注意:成交量信号有滞后性。大单已经成交了,你才看到。所以它更适合做「确认信号」,而不是「预测信号」。我一般把它和订单簿信号配合使用。
3.3 订单簿不平衡信号
订单簿不平衡(Order Book Imbalance)是我个人最喜欢的信号。它直接反映了买卖双方的「力量对比」。你想想看,如果买单深度远大于卖单深度,价格大概率要涨。
定义很简单:
imbalance = (bid_volume - ask_volume) / (bid_volume + ask_volume)
其中bid_volume是买一到买五的总挂单量,ask_volume同理。imbalance的取值范围是[-1, 1]。正值表示买方强势,负值表示卖方强势。
但这里有个坑。我曾经在ETH-USDT上直接用这个公式,结果发现信号噪声特别大。为什么?因为有些做市商挂单很深但很虚,比如在买五位置挂1000个ETH,但价格跌到那里之前早就撤单了。
所以,我建议用「加权不平衡」:
def weighted_imbalance(order_book, levels=5):
bid_vol = 0
ask_vol = 0
for i in range(levels):
# 越靠近中间价,权重越大
weight = 1 / (i + 1)
bid_vol += order_book['bids'][i][1] * weight
ask_vol += order_book['asks'][i][1] * weight
return (bid_vol - ask_vol) / (bid_vol + ask_vol)
小技巧:我一般取前5档,权重按1/distance递减。这样既考虑了深度,又避免了远端虚挂单的干扰。
3.4 信号归一化与阈值设定
信号归一化,说白了就是把不同量纲的信号拉到同一个尺度上。价差信号可能是0.001,成交量信号可能是5.0,不平衡信号可能是0.3。你没法直接比较它们。
归一化方法我常用两种:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score归一化 | (x - μ) / σ | 信号分布近似正态时 |
| Min-Max归一化 | (x - min) / (max - min) | 信号有明确上下界时 |
我个人习惯用Z-score。因为它保留了信号的「异常程度」信息。比如Z-score=2.5,说明这个信号比均值高2.5个标准差,属于比较强的信号。
阈值设定呢?我一般遵循「二八原则」:
- 弱信号:|Z-score| > 1.0(约30%的时间触发)
- 中信号:|Z-score| > 1.5(约13%的时间触发)
- 强信号:|Z-score| > 2.0(约5%的时间触发)
避坑指南:我曾经在回测中把阈值设成1.0,结果信号太频繁,手续费把利润全吃掉了。后来改成1.5,效果好了很多。阈值要根据交易对流动性和手续费动态调整,别死板。
3.5 信号融合框架
单个信号往往不够稳定。我习惯把三个信号融合成一个综合信号:
composite_signal = w1 * spread_zscore + w2 * vol_zscore + w3 * imbalance_zscore
权重w1、w2、w3怎么定?我建议用回测优化。比如在BTC-USDT上,价差信号权重0.4,成交量0.3,不平衡0.3。但在ETH-USDT上,可能不平衡信号更重要,权重调到0.5。
下面这张图展示了信号生成的整体流程:
总结一下:信号生成不是越复杂越好。我见过有人用20个信号做融合,结果过拟合得一塌糊涂。三个核心信号,加上合理的归一化和阈值,足够覆盖大部分做市场景。记住,信号是工具,不是目的。最终目的是让订单簿更健康、利润更稳定。
公众号:蓝海资料掘金营,微信deep3321