第十四章:高频做市中的曲面:Tick级曲面更新、延迟优化、订单流与曲面互动
做市这行,说到底就是跟时间赛跑。
你手里的曲面,每秒钟都在变。别人比你快1毫秒,你的报价就成了别人的流动性。我做了这么多年,最深的体会就是:曲面不是静态的风景画,它是动态的战场地图。今天我们就聊聊,怎么让这张地图在高频环境下真正活起来。
一、Tick级曲面更新:别等K线,要等每一笔
很多新手做市商喜欢用1秒或者100毫秒的快照来更新曲面。说实话,这在高频领域根本不够用。
为什么?因为一个tick过来,可能只有0.1秒,但隐含波动率已经跳了0.5个vol。你还在用上一秒的曲面报价,那不是做市,是送钱。
我个人的习惯是,把曲面拆成两部分:
- 全局基准曲面:每100ms或200ms重建一次,用于长期定价参考
- 局部tick级修正:每笔tick到来,只更新受影响的行权价和期限附近
举个例子,如果某只股票在3.0秒时有一笔大单在ATM行权价成交,我不会去重建整个曲面。我只会更新那个行权价附近3-5个点的skew参数,以及对应的期限结构。这样计算量小,速度快。
二、延迟优化:每一微秒都要抠
高频做市,延迟就是生命线。曲面更新的延迟,直接影响你的报价能否抢到对手盘。
我总结了几条实战中验证过的优化策略:
- 预计算与缓存:把常用的希腊值、波动率插值系数提前算好。别等到tick来了再算,那太慢了。
- 内存对齐与数据结构:用数组代替链表,用连续内存块存储曲面网格。CPU缓存命中率能提升30%以上。
- 避免锁竞争:曲面更新和报价线程之间,用无锁队列或者双缓冲。我见过太多团队因为加锁导致延迟抖动。
- 硬件加速:如果条件允许,把曲面插值放到FPGA或者GPU上。我们团队在FPGA上实现了SVI参数化曲面,延迟只有50纳秒。
三、订单流与曲面互动:曲面会“说话”
曲面不是单向的输入。订单流本身,会反过来影响曲面。
你想想看,如果某只期权突然出现大量买单,隐含波动率会怎么走?大概率是上升。这时候你的曲面如果还按历史数据算,那就落后了。
我常用的方法是:
- 订单流冲击模型:根据订单的规模、方向、速度,实时调整局部波动率。比如,一笔1000手的ATM call买单,我会把该行权价的vol临时上调0.2个点。
- 曲面反馈循环:曲面更新后,报价会变,报价变又会影响订单流。这个循环要控制在毫秒级。
说白了,曲面和订单流是互相喂养的。你越早感知到这种互动,你的报价就越有优势。
四、实战架构:一张图看懂
下面这张图,是我个人在高频做市系统中使用的曲面更新流程。你可以看到,从tick输入到报价输出,每一步都有明确的延迟目标。
嗯,这张图里最关键的就是那个反馈循环。订单流影响曲面,曲面影响报价,报价又影响订单流。如果你能把这个循环控制在350微秒以内,你的做市策略就已经跑赢了90%的对手。
五、代码示例:局部曲面更新核心逻辑
下面是一个简化版的局部曲面更新代码。实际生产环境会更复杂,但核心思路是一样的。
// 伪代码:局部曲面更新
void updateLocalSurface(Tick& tick, Surface& surface) {
// 1. 找到受影响的行权价范围
int strikeIdx = findNearestStrike(tick.strike);
int startIdx = max(0, strikeIdx - 3);
int endIdx = min(surface.numStrikes - 1, strikeIdx + 3);
// 2. 只更新局部网格
for (int i = startIdx; i <= endIdx; i++) {
for (int j = 0; j < surface.numTenors; j++) {
// 用SVI参数化模型快速插值
double newVol = sviInterpolate(
surface.params[i][j],
tick.spot,
tick.timeToExpiry
);
// 应用订单流冲击修正
newVol += orderFlowImpact(tick, i, j);
surface.volGrid[i][j] = newVol;
}
}
// 3. 更新希腊值缓存
updateGreeksCache(surface, startIdx, endIdx);
}
六、订单流与曲面互动的实战案例
我记得有一次,某只科技股在盘后突然出现大量异动期权成交。普通做市商还在用收盘前的曲面报价,结果全部被吃掉。
我们团队因为实现了订单流冲击模型,在tick到达后的50微秒内就上调了对应行权价的vol。等对手反应过来时,我们已经调整了3轮报价。那晚我们赚了大概20个bp的额外利润。
说白了,曲面不是死的。它应该像活水一样,随着订单流不断流动。你越早感知到这种流动,你的优势就越大。