第四章:时间加权平均价格算法(TWAP)

TWAP,全称 Time-Weighted Average Price。说白了,就是把一个大订单,拆成很多小单,然后均匀地扔到市场里去。目标是让最终的成交均价,尽量贴近这段时间的市场平均价。

我刚开始做量化交易那会儿,觉得这玩意儿太简单了。不就是定时定量发单吗?后来在实盘中被市场狠狠教育了几次,才发现事情没那么简单。嗯,咱们今天就把 TWAP 彻底聊透。

4.1 核心原理:时间切片

TWAP 的核心思想,我总结成一句话:把时间切成片,每片吃一口

假设你要在 10 分钟内买入 100 万股。TWAP 的做法是:

  • 把 10 分钟切成 10 个 1 分钟的切片
  • 每个切片只发 10 万股的订单
  • 每个切片内,再随机或均匀地发单

你想想看,这样做的好处是什么?

你的交易行为不会在某个时间点集中爆发。市场不会因为你的一笔大单而剧烈波动。说白了,就是「化整为零,暗度陈仓」。

核心公式:

TWAP 目标价 = (P₁ + P₂ + ... + Pₙ) / N

其中 Pᵢ 是每个时间点的市场价格,N 是时间点总数。

我们的目标,就是让实际成交均价 ≈ 这个理论值。

4.2 数学模型:从理论到代码

TWAP 的数学模型其实不复杂。我习惯把它拆成两层:

第一层:时间分配模型

总时间 T,分成 N 个等长切片。每个切片分配的交易量是 Q/N。

这里有个坑:如果市场在某个切片内流动性极差,你硬发 Q/N 的量,可能会把价格打飞。我在项目中遇到过这种情况,后来加了个「流动性自适应」的模块。

第二层:切片内执行模型

每个切片内,再拆成 M 个子单。子单的发送时机可以随机化,避免被对手盘识别。

// 一个简单的 TWAP 拆单逻辑(伪代码)
function twapSlicer(totalQty, totalTime, sliceCount) {
    let sliceQty = totalQty / sliceCount;
    let sliceInterval = totalTime / sliceCount;
    let orders = [];
    
    for (let i = 0; i < sliceCount; i++) {
        // 每个切片内,再随机拆成 3-5 个子单
        let subCount = 3 + Math.floor(Math.random() * 3);
        let subQty = sliceQty / subCount;
        
        for (let j = 0; j < subCount; j++) {
            // 子单发送时间:在切片内随机偏移
            let offset = (Math.random() * 0.8 + 0.1) * sliceInterval;
            let sendTime = i * sliceInterval + offset;
            
            orders.push({
                time: sendTime,
                qty: subQty,
                price: 'market'  // 或者用限价单
            });
        }
    }
    
    // 按时间排序
    return orders.sort((a, b) => a.time - b.time);
}

我的经验:切片数量 N 不是越大越好。N 太大,每单量太小,手续费占比会飙升。我一般建议 N 取 10-20 之间,具体看总交易时长。

4.3 适用场景:什么时候用 TWAP?

TWAP 不是万能的。我把它适用的场景总结成三个:

  1. 大单拆小单:单笔订单超过市场日均成交量的 1% 时,必须拆。TWAP 是最基础的拆法。
  2. 低波动市场:如果市场波动剧烈,TWAP 的效果会打折扣。因为价格在切片之间可能已经大幅变动了。
  3. 被动执行:你不急于成交,愿意花时间慢慢吃单。比如做市商的库存调整,或者 ETF 申赎的底仓构建。

我记得有一次帮一个私募做 ETF 套利策略。他们每天收盘前要调整 5000 万的底仓。用 TWAP 在最后 30 分钟慢慢吃,冲击成本从原来的 0.3% 降到了 0.05%。这就是典型的适用场景。

4.4 优缺点分析:别被表面迷惑

优点 缺点
实现简单,逻辑清晰 对市场波动不敏感
冲击成本可控 无法利用价格优势
容易被风控接受 在趋势行情中表现差
适合低流动性品种 执行时间较长

这里我要重点说一下缺点。TWAP 最大的问题是什么?是它「无脑」。它不管市场是涨是跌,只管按时间发单。

我曾经在 2020 年 3 月那波暴跌中,用 TWAP 执行一个卖出订单。结果呢?市场在 10 分钟内跌了 3%,我的 TWAP 还在傻傻地卖。最后成交均价比开盘价低了 1.5%。

避坑指南:如果你发现市场正在朝不利方向快速运动,立刻暂停 TWAP。我曾经吃过这个亏,后来在系统里加了个「紧急暂停」按钮——当价格偏离超过 0.5% 时,自动停止发单。

4.5 核心逻辑流程图

下面这张图,是我自己画的一个 TWAP 执行流程。你看完应该能对整个逻辑有个直观认识。

TWAP 拆单执行流程图 接收大订单 步骤1:计算总时间 T 和切片数 N 步骤2:每切片分配 Q/N 的量 步骤3:切片内随机拆分子单 步骤4:按时间顺序发送子单 订单执行完毕

4.6 实战中的几个关键点

最后,我分享几个实战中总结出来的要点:

  • 时间区间选择:尽量避开开盘和收盘的「竞价时段」。那个时间段波动大,TWAP 容易跑偏。
  • 随机化是必须的:如果你每次都在整点发单,对手盘一眼就能看穿你的策略。加个随机偏移,成本几乎为零,收益却很大。
  • 监控偏差率:实时计算「实际成交均价 - 理论 TWAP 价」。如果偏差超过 0.1%,就要检查是不是市场出了问题。
  • 结合限价单:纯市价单的 TWAP 冲击成本高。我习惯用「限价单 + 小幅追单」的方式,既能控制价格,又能保证成交。

TWAP 是所有拆单算法的基础。你把它吃透了,后面学 VWAP、POV、Implementation Shortfall 都会轻松很多。说白了,TWAP 就是那个「笨但可靠」的老实人——虽然不够聪明,但永远不会给你捅大篓子。