25. 基差交易的算法执行:TWAP/VWAP算法、冰山订单、拆单策略、冲击成本控制

基差交易的核心,说白了就是「吃价差」。但当你拿着几百万甚至几千万的资金进场时,你会发现一个残酷的现实:你还没吃完价差,市场已经被你推走了。这就是冲击成本——你每下一笔单,都在跟市场博弈。

我早年做股指期货期现套利时,吃过一次大亏。当时基差到了5个点,我信心满满地一把梭进去,结果现货端还没买完,期货价格已经往回跑了3个点。嗯,那次之后我才真正明白:策略再好,执行不到位,一切都是白搭。

为什么需要算法执行?

基差交易通常涉及双边操作——一边买现货,一边卖期货(或者反过来)。你想想看,如果两边的订单同时砸进去,市场会怎么反应?

  • 流动性冲击:大单瞬间吃掉盘口,价格剧烈波动
  • 信号暴露:别人一看你的挂单,就知道有人在套利,马上跟风或反向操作
  • 滑点放大:基差本来只有2个点,结果执行完变成了4个点,套利变亏损

所以,我们需要一套「隐形」的执行方案。把大单拆成小单,分散到时间或成交量中,让市场感觉不到你的存在。

核心目标:在基差窗口关闭之前,以最小的冲击成本完成双边建仓或平仓。

TWAP算法:时间加权平均价格

TWAP(Time-Weighted Average Price)是最基础的算法。它的逻辑很简单:把总订单量均匀地分配到每个时间切片里。

比如你要买1000手,交易时间还剩100分钟。那就每分钟下10手,雷打不动。

def twap_executor(total_qty, total_seconds, interval=60):
    """
    TWAP算法执行器
    :param total_qty: 总下单量
    :param total_seconds: 总执行时间(秒)
    :param interval: 每次下单间隔(秒)
    """
    slices = total_seconds // interval
    qty_per_slice = total_qty // slices
    
    orders = []
    for i in range(slices):
        # 模拟下单逻辑
        order = {
            'time': i * interval,
            'qty': qty_per_slice,
            'price': 'market'  # 通常用市价单
        }
        orders.append(order)
        print(f"第{i+1}次下单: 时间={order['time']}s, 数量={order['qty']}")
    
    return orders

# 示例:1000手,10分钟执行完,每30秒下一单
twap_executor(1000, 600, 30)

TWAP的优点是什么?简单、透明、容易预测。但缺点也很明显——它完全无视市场成交量。如果某个时间段市场很冷清,你硬塞进去10手,照样会造成冲击。

我的经验:TWAP适合流动性较好的品种,比如股指期货主力合约。对于流动性差的品种,我建议把间隔拉长,或者配合限价单使用。

VWAP算法:成交量加权平均价格

VWAP(Volume-Weighted Average Price)比TWAP聪明一点。它不按时间均匀分配,而是按历史成交量分布来分配。

举个例子:根据历史数据,上午9:30-10:00的成交量占全天的20%,那这段时间你就下20%的单子。10:00-10:30占15%,那就下15%。

def vwap_executor(total_qty, volume_profile):
    """
    VWAP算法执行器
    :param total_qty: 总下单量
    :param volume_profile: 成交量分布字典 {时间段: 成交量占比}
    """
    orders = []
    for period, ratio in volume_profile.items():
        qty = int(total_qty * ratio)
        order = {
            'period': period,
            'qty': qty,
            'ratio': ratio
        }
        orders.append(order)
        print(f"时段{period}: 下单{qty}手, 占比{ratio*100:.1f}%")
    
    return orders

# 示例:根据历史成交量分布下单
volume_profile = {
    '09:30-10:00': 0.20,
    '10:00-10:30': 0.15,
    '10:30-11:00': 0.12,
    '11:00-11:30': 0.10,
    '13:00-13:30': 0.18,
    '13:30-14:00': 0.15,
    '14:00-14:30': 0.10
}
vwap_executor(1000, volume_profile)

VWAP的好处是:你在成交量大的时候多下,成交量小的时候少下,冲击成本自然降低。但这里有个坑——历史分布不代表未来分布。万一今天突然放量或者缩量,你的计划就乱了。

我曾经踩过的坑:有一次做国债期货基差交易,我用了VWAP算法,但那天正好有宏观数据发布,成交量分布完全变了。结果我在低流动性时段下了大量单子,冲击成本比TWAP还高。后来我加了一个「实时成交量修正」模块,每5分钟重新计算一次分布。

冰山订单:隐藏你的真实意图

冰山订单(Iceberg Order)是一种特殊的订单类型。你只暴露一小部分订单在盘口上,大部分订单藏在「水下」。当暴露的部分成交后,系统自动再挂出一部分。

比如你想买1000手,设置显示量为100手。那么盘口上只看到100手买单,成交后自动再挂100手,直到全部成交。

class IcebergOrder:
    """
    冰山订单模拟器
    """
    def __init__(self, total_qty, display_qty, price):
        self.total_qty = total_qty
        self.display_qty = display_qty
        self.price = price
        self.remaining = total_qty
        self.current_display = min(display_qty, total_qty)
    
    def execute(self, market_qty):
        """
        模拟冰山订单执行
        :param market_qty: 市场吃单量
        """
        if market_qty >= self.current_display:
            # 全部成交,重新挂单
            self.remaining -= self.current_display
            self.current_display = min(self.display_qty, self.remaining)
            print(f"冰山订单全部成交,剩余{self.remaining}手,重新挂{self.current_display}手")
        else:
            # 部分成交
            self.current_display -= market_qty
            self.remaining -= market_qty
            print(f"冰山订单部分成交,剩余显示{self.current_display}手,总剩余{self.remaining}手")
        
        return self.remaining == 0

# 示例:总1000手,每次显示100手
iceberg = IcebergOrder(1000, 100, 3500)
iceberg.execute(100)  # 第一次被吃100手
iceberg.execute(50)   # 第二次被吃50手

冰山订单的核心价值在于「隐藏意图」。别人看到盘口只有100手,以为压力不大,但实际上你还有900手在排队。这样就不会吓跑对手盘。

我建议:冰山订单的显示量不要设得太小。如果总1000手你只显示10手,那成交速度太慢,基差窗口可能就关闭了。一般设总量的5%-10%比较合适。

拆单策略:把大象装进冰箱

拆单策略是算法执行的核心。说白了就是把一个大订单拆成多个小订单,分散到不同时间、不同价格、不同交易对手。

常见的拆单策略有几种:

策略名称 核心逻辑 适用场景
时间切片 按固定时间间隔拆单 流动性好、波动小的品种
成交量跟随 按市场成交量比例拆单 流动性变化大的品种
价格触发 价格有利时多下,不利时少下 基差快速收窄时
自适应拆单 根据实时冲击成本动态调整 高波动、低流动性品种

我个人比较喜欢「成交量跟随+价格触发」的组合。先按市场成交量分布拆单,然后根据基差变化动态调整。比如基差从5个点缩到3个点,我就加快下单速度;如果基差反而扩大了,我就放慢甚至暂停。

def adaptive_slicing(total_qty, base_price, spread, volume_ratio):
    """
    自适应拆单策略
    :param total_qty: 总下单量
    :param base_price: 基准价格
    :param spread: 当前基差
    :param volume_ratio: 当前成交量占比
    """
    # 基差越有利,下单比例越高
    spread_factor = max(0.5, min(2.0, spread / 3.0))
    
    # 成交量占比越高,下单比例越高
    volume_factor = max(0.3, min(1.5, volume_ratio * 5))
    
    # 综合因子
    factor = spread_factor * volume_factor
    
    qty = int(total_qty * factor * 0.1)  # 每次下总量的10%
    qty = min(qty, total_qty)  # 不超过剩余量
    
    print(f"基差={spread}点, 成交量占比={volume_ratio:.2f}, 下单因子={factor:.2f}, 本次下单={qty}手")
    return qty

# 模拟执行
remaining = 1000
while remaining > 0:
    qty = adaptive_slicing(remaining, 3500, 4.5, 0.15)
    remaining -= qty
    if qty == 0:
        break

冲击成本控制:算法执行的终极目标

冲击成本控制不是单一策略,而是一套组合拳。我把它总结为三个层次:

  1. 事前控制:根据历史数据预估冲击成本,设定最大容忍度
  2. 事中控制:实时监控盘口变化,动态调整下单节奏
  3. 事后控制:分析执行结果,优化算法参数

这里有一个关键指标——实现差价(Implementation Shortfall)。它衡量的是「理论成交价」和「实际成交价」之间的差距。

def calculate_shortfall(theoretical_price, actual_avg_price, qty):
    """
    计算实现差价
    :param theoretical_price: 理论价格(决策时的价格)
    :param actual_avg_price: 实际成交均价
    :param qty: 成交量
    """
    shortfall = (actual_avg_price - theoretical_price) * qty
    shortfall_bps = (actual_avg_price - theoretical_price) / theoretical_price * 10000
    
    print(f"实现差价: {shortfall:.2f}元")
    print(f"实现差价: {shortfall_bps:.2f}个基点")
    return shortfall, shortfall_bps

# 示例
calculate_shortfall(3500, 3502.5, 1000)

注意:基差交易的冲击成本控制比单边交易更难。因为你要同时控制两边的冲击,而且两边的流动性可能不一样。我一般会先做流动性好的一边,再做流动性差的一边。或者用「配对下单」的方式,两边同时下,但每边都拆得很碎。

实战中的算法选择

说了这么多,到底该用哪个算法?我根据经验给个参考:

基差交易类型 推荐算法 理由
股指期货期现套利 VWAP + 冰山订单 流动性好,但信号敏感,需要隐藏意图
商品期货跨期套利 TWAP + 自适应拆单 流动性差异大,需要动态调整
ETF与期货套利 成交量跟随 + 价格触发 ETF申赎有延迟,需要灵活应对
国债期货基差交易 冰山订单 + 时间切片 流动性集中,需要耐心等待

最后说一句:算法执行不是万能的。如果你的基差策略本身有问题,再好的算法也救不了。但反过来,一个好的策略配上糟糕的执行,同样会亏钱。两者缺一不可。

核心总结:TWAP求稳,VWAP求准,冰山求隐,拆单求活。冲击成本控制是贯穿始终的底线。记住,在基差交易里,你不是在跟市场对赌,而是在跟市场「躲猫猫」。

基差交易算法执行体系 目标:最小化冲击成本,完成基差套利 TWAP算法 时间加权平均 VWAP算法 成交量加权平均 冰山订单 隐藏真实意图 拆单策略 分散执行风险 时间切片 固定间隔下单 成交量跟随 按比例分配 隐藏显示 冰山一角 自适应拆单 动态调整 冲击成本控制(事前 → 事中 → 事后) 关键指标:实现差价(Implementation Shortfall)

公众号:蓝海资料掘金营,微信deep3321