曲面交易系统设计:数据源接入、实时曲面更新、交易信号生成、订单执行与风控
做 Vega 交易这么多年,我最大的体会是:曲面交易系统不是写出来的,是磨出来的。你想想看,一个曲面有几十个节点,每个节点都在跳动,数据源稍微慢个 100 毫秒,信号就完全变味了。今天我就把整套系统的设计思路掰开揉碎讲给你听。
一、数据源接入:别让脏数据毁了你的曲面
数据源是曲面交易的地基。我见过太多团队,花大把精力搞模型,结果数据源没处理好,曲面天天出妖蛾子。
我个人习惯把数据源分成三层:
- 第一层:交易所直连。比如 CME、Eurex 的行情源,延迟最低,但成本高。适合做高频 Vega 交易的场景。
- 第二层:第三方聚合。像 Bloomberg、Refinitiv,数据全但慢。适合做日频或小时频的策略。
- 第三层:OTC 报价。来自做市商或经纪商,需要做清洗和插值。这块水最深。
数据接入的代码框架,我一般这样写:
class DataFeed:
def __init__(self, sources):
self.sources = sources # 数据源列表
self.cleaner = DataCleaner()
self.curves = {}
def start(self):
# 启动多线程接收数据
for src in self.sources:
thread = Thread(target=self._listen, args=(src,))
thread.start()
def _listen(self, source):
while True:
raw = source.get_quote()
cleaned = self.cleaner.run(raw)
if cleaned:
self.curves[source.name] = cleaned
self._notify_curve_update()
二、实时曲面更新:从报价到曲面的 100 毫秒
数据进来了,接下来就是曲面构建。这里有个关键问题:你是用全部数据重建曲面,还是增量更新?
我建议用增量更新。原因很简单——全量重建太慢了。一个 50 个节点的曲面,全量重建要算 50 次插值,每次插值还要解一个优化问题。增量更新只改受影响的节点,速度快一个数量级。
具体做法是这样的:
- 维护一个基准曲面,比如昨天收盘时的曲面。
- 新报价进来后,只更新对应期限和行权价的节点。
- 用局部插值(比如三次样条)更新相邻节点。
- 检查曲面是否满足无套利条件。
曲面更新的核心逻辑:
def update_surface(self, new_quote):
# 找到受影响的节点
node = self._find_node(new_quote.tenor, new_quote.strike)
# 更新该节点
node.iv = new_quote.iv
# 局部插值更新相邻节点
neighbors = self._get_neighbors(node)
for n in neighbors:
n.iv = self._local_interpolate(n, node)
# 无套利检查
if not self._check_arbitrage():
self._rollback() # 回滚到上一个有效状态
三、交易信号生成:曲面形态才是王道
曲面更新好了,信号怎么来?很多人盯着单个节点的 Vega 变化,其实这是片面的。真正有价值的信号,藏在曲面的形态变化里。
我常用的信号有三类:
| 信号类型 | 描述 | 典型场景 |
|---|---|---|
| 斜率信号 | 曲面在某个期限上的倾斜度变化 | 短期波动率预期变化 |
| 曲率信号 | 曲面在某个行权价附近的弯曲程度 | 尾部风险定价偏差 |
| 相对价值信号 | 不同期限/行权价之间的价差 | 曲面套利机会 |
举个例子。我记得有一次,标普 500 的曲面在 1 个月期限上突然变得很陡峭。斜率从 0.3 飙到 0.8。这说明市场在短期内的波动率预期发生了剧烈变化。我当时的策略是:做多短期 Vega,做空长期 Vega,形成一个斜率回归的 Vega 组合。
信号生成的伪代码:
def generate_signals(surface):
signals = []
# 计算斜率
slope = surface.calc_slope(tenor='1M')
if abs(slope - slope_ma) > threshold:
signals.append({
'type': 'slope',
'direction': 'long' if slope > slope_ma else 'short',
'tenor': '1M',
'confidence': abs(slope - slope_ma) / threshold
})
# 计算曲率
curvature = surface.calc_curvature(strike='ATM')
# ... 类似逻辑
return signals
四、订单执行:Vega 交易的特殊性
信号出来了,怎么执行?Vega 交易和 Delta 交易不一样。Delta 交易可以拆成小单慢慢吃,Vega 交易不行——因为 Vega 是二阶风险,流动性差很多。
我个人的执行原则是:
- 大单用算法交易。比如 TWAP 或 VWAP,把 Vega 拆成多个小单,分散到不同时段执行。
- 小单直接吃盘口。如果 Vega 敞口不大,直接挂单成交,省得暴露意图。
- 跨品种 Vega 用组合单。比如同时买卖不同期限的期权,用组合单降低滑点。
订单执行的核心逻辑:
def execute_vega(signal, portfolio):
# 计算目标 Vega 敞口
target_vega = signal.vega * signal.confidence
# 选择执行策略
if abs(target_vega) > 100000: # 大单
strategy = TWAPStrategy(duration=30, slices=10)
else:
strategy = DirectMarketStrategy()
# 执行
order = strategy.execute(target_vega, portfolio)
# 监控执行质量
monitor.slippage(order)
五、风控:曲面交易的最后一道防线
风控这块,我吃过不少亏。曲面交易的风险点太多了:数据源断连、曲面变形、流动性枯竭、模型失效……任何一个环节出问题,都可能造成巨大损失。
我的风控体系分三层:
- 事前风控:设置 Vega 敞口上限、曲面偏离度阈值、最大订单规模。
- 事中风控:实时监控曲面状态、订单执行进度、组合风险指标。
- 事后风控:每日复盘、压力测试、模型回测。
风控的代码实现:
class RiskManager:
def __init__(self, limits):
self.vega_limit = limits['vega']
self.surface_deviation = limits['deviation']
self.order_size = limits['order_size']
def check(self, signal, portfolio):
# 检查 Vega 敞口
if abs(portfolio.vega + signal.vega) > self.vega_limit:
return False, "Vega 敞口超限"
# 检查曲面偏离度
if signal.surface_deviation > self.surface_deviation:
return False, "曲面偏离度过大"
# 检查订单规模
if abs(signal.vega) > self.order_size:
return False, "订单规模超限"
return True, "通过"
六、系统架构总览
说了这么多,最后用一张图把整个系统串起来。这是我在实际项目中用的架构:
这套架构我用了三年,迭代了十几个版本。说实话,没有完美的系统,只有不断进化的系统。每次遇到新的市场环境,我都会回头看看曲面构建的逻辑是不是需要调整,风控阈值是不是需要重新校准。
嗯,今天就先聊到这儿。曲面交易系统设计,说白了就是把数据变成信号,把信号变成订单,把订单变成利润。每一步都有坑,但每一步也都有机会。希望这些经验能帮你少走一些弯路。