第三章 暗池交易策略基础:流动性探测、信息防护与算法执行
各位同学,今天我们来聊聊暗池交易里最核心的几个基础策略。说实话,这些策略听起来名字挺唬人——流动性探测、信息泄露防范、TWAP、VWAP。但拆开来看,每个都是解决一个具体问题的工具。
我个人习惯把暗池策略分成两类:一类是探测型,用来摸清对手的底牌;另一类是执行型,用来把自己的单子悄无声息地塞进市场。今天这四种策略,正好覆盖了这两个维度。
3.1 流动性探测策略
流动性探测,说白了就是「先派个小兵去探路」。你想想看,暗池里你看不到订单簿,不知道对面是鲸鱼还是小鱼。直接扔个大单进去,等于告诉所有人「我来了」。
我在项目中遇到过最典型的场景:某机构想在暗池里吃进50万股,结果第一笔试探单刚进去,价格就跳了三个tick。嗯,这说明池子里有「鲨鱼」在蹲守。
3.1.1 探测的基本逻辑
流动性探测的核心思路很简单:
- 小单试探:先发一笔远低于目标量的订单(比如目标量的1%-5%)
- 观察反馈:看价格是否异常波动、成交速度是否突然加快
- 判断深度:如果小单成交后价格纹丝不动,说明流动性不错;如果价格跳了,说明对面有「聪明钱」
关键指标:
- 成交时间:正常暗池里小单应该在毫秒级成交
- 价格滑点:超过0.5个tick就要警惕
- 订单簿失衡:如果探测单成交后,反向挂单突然增多,说明有人盯上你了
3.1.2 我常用的探测算法
这里给一个我实际用过的Python伪代码框架。注意,这不是完整的生产代码,但核心逻辑都在里面了。
class LiquidityProbe:
def __init__(self, target_qty, probe_ratio=0.02):
self.target = target_qty
self.probe_size = target_qty * probe_ratio
self.threshold = 0.5 # tick
def send_probe(self, pool):
# 发送探测单
probe_order = pool.send_limit_order(
side='BUY',
qty=self.probe_size,
price='midpoint'
)
# 等待反馈
time.sleep(0.1) # 100ms窗口
price_change = probe_order.get_price_change()
if price_change < self.threshold:
return 'LIQUID' # 流动性充足
else:
return 'THIN' # 流动性不足,需要调整策略
避坑指南:我曾经犯过一个错误——探测单的size设得太大了。结果探测单本身就成了一个信号,被对手捕捉到。后来我改成随机化探测单的size和时机,效果好了很多。
3.2 信息泄露防范
信息泄露,是暗池交易里最要命的事。你想想,暗池之所以叫暗池,就是因为不想让别人知道你在交易。一旦你的意图暴露了,对手就能提前布局,把你的利润吃干抹净。
为什么会泄露?其实就两个渠道:
- 订单本身:你的订单大小、方向、价格,都是信息
- 行为模式:你下单的时间、频率、撤单习惯,都能被分析出来
3.2.1 防范策略一:订单拆分与随机化
我建议把大单拆成小单,而且每个小单的size和间隔都要随机化。别用固定模式,比如每次1000股、间隔5秒——这种模式太容易被机器学习模型识别了。
| 策略 | 说明 | 我踩过的坑 |
|---|---|---|
| 随机化size | 在目标量的±30%范围内随机 | 曾经用固定比例拆分,被对手的统计模型抓到了规律 |
| 随机化间隔 | 使用泊松分布或指数分布生成间隔 | 均匀间隔太容易被预测,改成泊松分布后好多了 |
| 虚假订单 | 偶尔发一些不会成交的试探单 | 注意别发太多,否则会被暗池标记为「垃圾流量」 |
3.2.2 防范策略二:冰山订单
冰山订单是暗池里最经典的防泄露工具。你只显示一小部分数量,剩下的藏在「水下」。比如你想买10万股,只显示2000股,成交后自动补上。
嗯,这里要注意:冰山订单也不是万能的。有些暗池的匹配引擎会检测到冰山模式,反向推断你的真实意图。所以我的做法是——冰山订单配合随机化使用,效果更好。
警告:千万别在同一个暗池里长期使用相同的冰山参数。我见过有人因为冰山订单的「露出量」一直固定,被对手用逆向工程算出了总订单量。后来我改成每次交易都随机调整露出比例。
3.3 时间加权平均价格策略(TWAP)
TWAP,全称Time-Weighted Average Price。说白了就是「把时间切成片,每片里均匀地扔一点单子」。这个策略适合那些不着急、只想按时间段平均价格成交的场景。
我个人习惯把TWAP叫做「懒人策略」——因为它不需要预测市场走势,只需要机械地执行。但懒人策略也有讲究。
3.3.1 TWAP的核心逻辑
假设你要在1小时内买入10万股,TWAP的做法是:
- 把1小时切成60个1分钟的切片
- 每个切片里买入约1667股(10万/60)
- 在每个切片内,再进一步拆分到秒级执行
代码实现其实很简单:
class TWAP:
def __init__(self, total_qty, duration_minutes, slices=60):
self.qty_per_slice = total_qty / slices
self.interval = (duration_minutes * 60) / slices
def execute(self, pool):
for i in range(slices):
# 每个切片内再随机拆分
sub_qty = self.qty_per_slice * random.uniform(0.8, 1.2)
pool.send_market_order(qty=sub_qty)
time.sleep(self.interval)
实战要点:
- 切片数量不是越多越好——切片太多会导致每笔单子太小,增加交易成本
- 我一般把切片数控制在20-60之间,具体看市场波动率
- 如果市场突然剧烈波动,我会暂停TWAP,等稳定了再继续
3.4 成交量加权平均价格策略(VWAP)
VWAP和TWAP的区别在哪?TWAP只看时间,VWAP还要看成交量。VWAP的目标是让你的成交价格尽量接近市场当天的平均成交价。
你想想看,如果某个时间段成交量特别大,VWAP就会在那个时间段多分配一些订单。这样你的成交价就更接近市场的「真实价格」。
3.4.1 VWAP的分配逻辑
VWAP需要预测未来每个时间段的成交量。常用的方法有两种:
- 历史数据法:用过去N天的成交量分布来预测今天
- 实时调整法:根据已经发生的成交量动态调整后续分配
我比较推荐第二种。因为历史数据法有个问题——如果今天出了个突发新闻,成交量分布会完全偏离历史模式。
class VWAP:
def __init__(self, total_qty, historical_volume_profile):
self.remaining_qty = total_qty
self.volume_profile = historical_volume_profile
def update_allocation(self, current_time, actual_volume):
# 根据实际成交量调整后续分配
expected_volume = self.volume_profile[current_time]
adjustment = actual_volume / expected_volume
# 如果实际成交量比预期高,就多分配一些
next_slice_qty = self.remaining_qty * adjustment * 0.1
return next_slice_qty
我的经验:VWAP在暗池里执行时,要注意一个问题——暗池的成交量可能和公开市场不一样。我曾经在某个暗池里用公开市场的成交量分布来跑VWAP,结果偏差很大。后来我改成用该暗池自己的历史成交量数据,效果才正常。
3.5 四种策略的对比与选择
最后,我用一张表格来总结这四种策略的适用场景:
| 策略 | 适用场景 | 风险点 | 我的推荐指数 |
|---|---|---|---|
| 流动性探测 | 进入陌生暗池前、大单执行前 | 探测单本身可能泄露意图 | ★★★★★ |
| 信息泄露防范 | 所有暗池交易 | 过度防范会增加交易成本 | ★★★★★ |
| TWAP | 市场平稳、不急于成交 | 无法应对突发波动 | ★★★★ |
| VWAP | 需要跟踪市场平均价 | 依赖成交量预测的准确性 | ★★★★ |
下面这张SVG图,展示了这四种策略在暗池交易中的整体关系:
好了,这一章的内容就到这里。四种策略各有各的脾气,关键是要根据市场环境和你的目标来选。下一章我们会深入讲如何把这些策略组合起来,形成一套完整的暗池交易系统。
公众号:蓝海资料掘金营,微信deep3321