套利策略系统设计
做市商视角的完整套利系统:三角套利、期现套利、期权期货套利、交易所做市返佣、割头皮统计套利策略,以及配套的风控、延迟优化与盈亏监控体系。
1. 套利系统总览
套利系统以做市商 (Market Maker) 角色运行,同时覆盖多种套利策略,通过高频交易赚取价差、交易所返佣和统计回归收益。所有策略共享统一的信号采集、订单执行和风控模块。
核心设计原则
微秒级延迟
Co-location + Kernel Bypass + 共享内存订单簿,端到端延迟 < 100μs
多策略并行
三角套利、期现套利、做市、统计套利并行运行,共享行情与执行通道
统一风控
所有策略共享持仓限制、净敞口控制、最大亏损熔断,避免策略间相互冲突
原子执行
多腿套利使用原子下单或对冲延迟 < 5ms,防止单腿风险
自适应参数
根据波动率、流动性自动调整价差、仓位和阈值
全链路监控
每笔交易归因到具体策略,实时 PnL、Sharpe、最大回撤仪表盘
2. 三角套利
三角套利利用同一交易所内三个交易对之间的价格不一致,在极短时间内完成三步交易,锁定无风险利润。做市商由于 Maker 负手续费(返佣),在三角套利中具有天然成本优势。
核心算法
// === 三角套利检测 ===
function detectTriangularArb(bookA, bookB, bookC):
// 路径 1: USDT → BTC → ETH → USDT
// 步骤: 买BTC/USDT(ask) → 卖ETH/BTC(bid) → 卖ETH/USDT(bid)
rate1 = (1 / bookA.bestAsk) * bookC.bestBid * bookB.bestBid
// 路径 2: USDT → ETH → BTC → USDT
// 步骤: 买ETH/USDT(ask) → 买ETH/BTC(ask, 即卖BTC) → 卖BTC/USDT(bid)
rate2 = (1 / bookB.bestAsk) * (1 / bookC.bestAsk) * bookA.bestBid
// 扣除手续费 (3次交易)
feeMultiplier = (1 - makerFee) ** 3 // 做市商用 maker fee (可能为负 = 返佣)
netRate1 = rate1 * feeMultiplier
netRate2 = rate2 * feeMultiplier
if netRate1 > 1.0:
return { path: "USDT→BTC→ETH→USDT", profit: (netRate1 - 1) * capital }
if netRate2 > 1.0:
return { path: "USDT→ETH→BTC→USDT", profit: (netRate2 - 1) * capital }
return null
// === 执行策略 ===
function executeTriangularArb(signal):
// 关键: 三腿必须在极短时间内完成
// 方案 A: 并行下单 (风险: 部分成交)
// 方案 B: 顺序下单 + 对冲 (更安全)
orders = buildOrderLegs(signal)
// 使用 IOC (Immediate or Cancel) 避免挂单
for order in orders:
order.timeInForce = "IOC"
order.type = "LIMIT" // 用限价+IOC, 而非市价, 避免滑点
// 并行提交 (通过多路复用连接)
results = await Promise.all(orders.map(submitOrder))
// 检查是否全部成交
if any(r.status != "FILLED" for r in results):
hedgeRemainingLegs(results) // 对冲未成交腿每次 OrderBook 更新触发重算(tick-by-tick),延迟 < 1ms。扫描所有三角组合。
净利润 > 最小阈值(通常 > 3倍手续费)才触发。做市商返佣可大幅降低阈值。
不仅看最优价,还检查可用深度。只在深度足够覆盖下单量时触发。
使用 IOC 订单 + 毫秒级超时。任何一腿未成交立即对冲其他腿。
三角套利模拟器
调整三个交易对的价格,观察均衡偏离和套利利润。点击「制造套利机会」快速体验:
3. 期现套利 (Basis Trade)
期现套利利用期货与现货之间的价差(基差 Basis)来获利。当期货溢价(正基差)超过持有成本时,买入现货 + 卖出期货,锁定年化收益。对于永续合约,利用资金费率进行类似套利。
期现套利算法
// === 期现套利 (交割合约) ===
function basisArbitrage(spot, futures, daysToExpiry):
basis = futures - spot
basisRate = basis / spot
annualized = basisRate * (365 / daysToExpiry)
// 成本计算
tradingFee = (spot + futures) * quantity * feeRate * 2 // 开平各一次
borrowCost = spot * quantity * (borrowRate / 365) * daysToExpiry
totalCost = tradingFee + borrowCost
netProfit = abs(basis) * quantity - totalCost
if basis > 0 and netProfit > minProfit:
// 正向套利: 买现货 + 卖期货
execute("BUY", "SPOT", spot, quantity)
execute("SELL", "FUTURES", futures, quantity)
return { annualized, netProfit, action: "CASH_AND_CARRY" }
if basis < 0 and netProfit > minProfit:
// 反向套利: 卖现货 + 买期货
execute("SELL", "SPOT", spot, quantity)
execute("BUY", "FUTURES", futures, quantity)
return { annualized, netProfit, action: "REVERSE_CASH_AND_CARRY" }
// === 永续合约资金费率套利 ===
function fundingRateArbitrage(fundingRate, spot, perpPrice):
// 资金费率 > 0: 多头付空头 → 做空永续 + 买入现货
// 资金费率 < 0: 空头付多头 → 做多永续 + 卖出现货
annualizedFunding = fundingRate * 3 * 365 // 每8小时一次
if abs(annualizedFunding) > minYield:
if fundingRate > 0:
execute("BUY", "SPOT", spot, qty)
execute("SELL", "PERP", perpPrice, qty)
// 持续收取资金费率直到不划算
else:
execute("SELL", "SPOT", spot, qty)
execute("BUY", "PERP", perpPrice, qty)期货溢价时买现货卖期货。到期自动收敛,风险极低。年化收益率 = 基差率 * 365 / 剩余天数。
期货折价时卖现货买期货。需要融币或已持有现货。通常在市场恐慌时出现机会。
永续合约 funding rate 持续为正时,做空永续 + 买入现货。每 8 小时收取一次资金费率。
交割合约到期需要展期。展期时基差可能变化,需重新评估。永续合约无此问题。
4. 期权期货套利
基于 Put-Call Parity(看跌看涨平价关系),通过期权构建合成期货,与实际期货价格对比。当两者出现偏差时,通过买低卖高锁定无风险利润。
期权期货套利算法
// === Put-Call Parity 套利 ===
// 理论: C - P = F * e^(-rT) - K * e^(-rT)
// 变形: F_synthetic = K + (C - P) / e^(-rT)
function optionFuturesArbitrage(call, put, strike, futuresPrice, T, r):
discount = exp(-r * T)
syntheticFuture = strike + (call - put) / discount
diff = futuresPrice - syntheticFuture
if abs(diff) < minSpread:
return null // 价差太小,无机会
if diff > 0:
// 实际期货 > 合成期货
// 策略: 卖出实际期货 + 做多合成期货 (买Call + 卖Put)
return {
legs: [
{ action: "SELL", instrument: "FUTURES", price: futuresPrice },
{ action: "BUY", instrument: "CALL", price: call, strike },
{ action: "SELL", instrument: "PUT", price: put, strike },
],
profit: diff,
type: "CONVERSION" // 转换套利
}
else:
// 实际期货 < 合成期货
// 策略: 买入实际期货 + 做空合成期货 (卖Call + 买Put)
return {
legs: [
{ action: "BUY", instrument: "FUTURES", price: futuresPrice },
{ action: "SELL", instrument: "CALL", price: call, strike },
{ action: "BUY", instrument: "PUT", price: put, strike },
],
profit: -diff,
type: "REVERSAL" // 反转套利
}
// === Box Spread 套利 (进阶) ===
// 同时做 Bull Call Spread + Bear Put Spread
function boxSpreadArbitrage(K1, K2, calls, puts, T, r):
// Bull Call: 买 Call(K1) + 卖 Call(K2)
bullCallCost = calls[K1].ask - calls[K2].bid
// Bear Put: 买 Put(K2) + 卖 Put(K1)
bearPutCost = puts[K2].ask - puts[K1].bid
totalCost = bullCallCost + bearPutCost
boxValue = (K2 - K1) * exp(-r * T) // 理论价值
if boxValue - totalCost > minProfit:
// 买入 Box (期望到期获得 K2-K1)
return { profit: boxValue - totalCost, type: "LONG_BOX" }实际期货高于合成期货时,卖期货+买Call+卖Put。到期无论涨跌均获得固定利润。
实际期货低于合成期货时,买期货+卖Call+买Put。与 Conversion 方向相反。
使用两个行权价构建盒式价差。收益固定,等价于买入零息债券,用于套利定价偏差。
期权流动性通常低于期货。需要同时在 3 个市场建仓,腿间延迟是核心风险。
期现 / 期权套利模拟器
切换 Tab 体验期现基差套利和期权期货 Put-Call Parity 套利:
5. 做市商 & 交易所返佣
做市商通过在买卖两侧持续挂单提供流动性,赚取买卖价差 (Spread)。交易所为激励做市商提供负手续费(Maker Rebate),即每笔 Maker 成交不仅不收手续费,还反向支付返佣给做市商。顶级做市商月交易量超过 20 亿 USDT,单月返佣可达数十万美元。
做市策略核心
// === Avellaneda-Stoikov 做市模型 ===
// 最优报价 = 中间价 ± 调整后价差
function calculateQuotes(midPrice, inventory, volatility, T):
// 保留价格 (考虑库存风险的理论中间价)
gamma = riskAversion // 风险厌恶系数, 通常 0.01 - 0.1
reservationPrice = midPrice - inventory * gamma * volatility^2 * T
// 最优价差
optimalSpread = gamma * volatility^2 * T + (2/gamma) * ln(1 + gamma/kappa)
// kappa = 订单到达率参数
bidPrice = reservationPrice - optimalSpread / 2
askPrice = reservationPrice + optimalSpread / 2
return { bidPrice, askPrice }
// === 库存管理 ===
function adjustForInventory(quotes, inventory, maxInventory):
// 库存偏移: 持仓偏多时降低 ask 吸引卖单
skew = (inventory / maxInventory) * maxSkewBps
quotes.bidPrice -= skew * midPrice / 10000
quotes.askPrice -= skew * midPrice / 10000
// 库存超限时只挂减仓方向
if inventory >= maxInventory:
quotes.bidQty = 0 // 不再买入
if inventory <= -maxInventory:
quotes.askQty = 0 // 不再卖出
return quotes
// === 交易所返佣计算 ===
function calculateRebate(volume, tier):
// 各交易所返佣结构 (示例)
// Tier 0: Maker -0.010%, Taker 0.030%
// Tier 1: Maker -0.015%, Taker 0.025% (月交易量 > 1亿)
// Tier 2: Maker -0.020%, Taker 0.020% (月交易量 > 5亿)
// Tier 3: Maker -0.025%, Taker 0.015% (月交易量 > 20亿)
rebateRate = REBATE_TIERS[tier].makerRebate
monthlyRebate = volume * abs(rebateRate)
return {
dailyRebate: monthlyRebate / 30,
monthlyRebate,
annualRebate: monthlyRebate * 12
}同时在买卖两侧挂限价单。Bid 和 Ask 价格围绕中间价对称分布,价差 = 利润来源之一。
核心风险。做市商需要在做市和持仓风险间取得平衡。使用偏移 (Skew) 鼓励减少库存方向。
交易所对 Maker 订单返还手续费(负费率)。交易量越大,返佣比例越高。顶级做市商返佣 -0.025%。
低波动率时收窄价差抢成交量;高波动率时放宽价差保护库存。使用 Avellaneda-Stoikov 模型。
做市商模拟器
设置中间价、价差和做市等级,点击开始模拟做市过程,实时查看成交、返佣和 PnL:
| 等级 | 月交易量 | Maker 返佣 | Taker 费率 | 1亿月交易额返佣 |
|---|---|---|---|---|
| 普通做市 | < 1亿 | -0.010% (返) | 0.030% | +10,000 U |
| 专业做市 T1 | 1-5亿 | -0.015% (返) | 0.025% | +15,000 U |
| 专业做市 T2 | 5-20亿 | -0.020% (返) | 0.020% | +20,000 U |
| 顶级做市 T3 | 20亿+ | -0.025% (返) | 0.015% | +25,000 U |
6. 割头皮统计套利
割头皮(Scalping)统计套利结合配对交易 (Pairs Trading) 和高频割头皮策略。选取具有协整关系的两个资产,当价差偏离均值超过 Z-Score 阈值时建仓,等待均值回归获利。持仓时间极短(秒级到分钟级),单次利润微小但频率极高。
统计套利核心算法
// === 配对交易 - 协整检验 ===
function findCointegrationPairs(assets, window):
pairs = []
for i in range(len(assets)):
for j in range(i+1, len(assets)):
// Engle-Granger 两步法
// 1. 回归: priceA = α + β * priceB + ε
beta = OLS(assets[i].prices, assets[j].prices).slope
residuals = assets[i].prices - beta * assets[j].prices
// 2. ADF 检验残差平稳性
adfStat = augmentedDickeyFuller(residuals)
if adfStat.pValue < 0.05:
halfLife = calcHalfLife(residuals)
pairs.append({ assetA: i, assetB: j, beta, halfLife })
return pairs.sortBy(halfLife) // 半衰期越短,回归越快
// === Z-Score 信号生成 ===
function generateSignal(priceA, priceB, beta, lookback):
spread = priceA - beta * priceB
rollingMean = mean(spreads[-lookback:])
rollingStd = std(spreads[-lookback:])
zscore = (spread - rollingMean) / rollingStd
return zscore
// === 割头皮执行 ===
function scalpingExecution(zscore, position, params):
{ entryZ, exitZ, stopZ, size } = params
if position == NONE:
if zscore > entryZ:
// 价差过高 → 做空价差 (卖A买B)
shortA(size)
longB(size * beta)
return SHORT_SPREAD
if zscore < -entryZ:
// 价差过低 → 做多价差 (买A卖B)
longA(size)
shortB(size * beta)
return LONG_SPREAD
if position == SHORT_SPREAD:
if zscore < exitZ: closeAll(); return NONE // 止盈
if zscore > stopZ: closeAll(); return NONE // 止损
if position == LONG_SPREAD:
if zscore > -exitZ: closeAll(); return NONE // 止盈
if zscore < -stopZ: closeAll(); return NONE // 止损
// === 动态参数调整 ===
function adaptiveParams(volatility, recentPnL):
// 高波动率 → 放宽入场阈值,缩小仓位
entryZ = baseEntryZ * (1 + volatility / baseVolatility * 0.5)
size = baseSize * (baseVolatility / volatility)
// 连续亏损 → 缩减仓位 (Kelly 准则)
if recentPnL < 0:
size *= max(0.25, 1 + recentPnL / maxDrawdown)
return { entryZ, size }不同于相关性,协整意味着价差是平稳的、会回归均值。使用 ADF 检验确认。同币种跨所最强。
价差标准化后的 Z-Score 指示偏离程度。|Z| > 2 入场,|Z| < 0.5 平仓。简单高效。
均值回归的速度。半衰期越短(< 50 个 tick),策略换手越快,适合割头皮。
止损阈值 (|Z| > 4) 防止价差发散。仓位按波动率动态调整。连续亏损自动缩仓。
统计套利模拟器
模拟两个协整资产的价差变化,实时观察 Z-Score 信号触发交易。调整入场/出场阈值体验不同策略效果:
7. 套利风控系统
所有策略合并计算净多/空仓位。净敞口不能超过限额。三角套利本身无敞口,但单腿失败会产生临时敞口。
单笔亏损、日内亏损、累计亏损三级熔断。触发后暂停对应策略,不影响其他策略运行。严重时全量撤单。
多腿套利中,任何一腿成交后,其余腿必须在 100ms 内完成。超时立即用市价对冲,将风险转化为已知亏损。
波动率飙升或连续亏损时,自动缩减所有策略仓位到 25%-50%。使用改进版 Kelly 准则动态计算最优仓位。
8. 基础设施与延迟优化
┌──────────────────────────────────────────────────────────────┐ │ 延迟优化技术栈 │ ├──────────────┬───────────────────┬───────────────────────────┤ │ 层级 │ 技术 │ 延迟目标 │ ├──────────────┼───────────────────┼───────────────────────────┤ │ 网络层 │ Co-location │ 物理距离 < 1km │ │ │ FPGA NIC │ 网络延迟 < 5μs │ │ │ Kernel Bypass │ 避免系统调用开销 │ ├──────────────┼───────────────────┼───────────────────────────┤ │ 数据处理 │ Lock-free Queue │ 行情解析 < 1μs │ │ │ 共享内存 OrderBook │ 簿更新 < 2μs │ │ │ SIMD 指令集 │ 批量价格计算 < 0.5μs │ ├──────────────┼───────────────────┼───────────────────────────┤ │ 策略层 │ 预编译决策树 │ 信号生成 < 1μs │ │ │ 缓存行友好布局 │ L1 Cache 命中率 > 95% │ │ │ 分支预测优化 │ 减少 CPU stall │ ├──────────────┼───────────────────┼───────────────────────────┤ │ 执行层 │ 预构建报文模板 │ 序列化 < 0.5μs │ │ │ 多路复用连接 │ 同时多腿下单 │ │ │ 零拷贝发送 │ 数据直接从用户态到网卡 │ ├──────────────┼───────────────────┼───────────────────────────┤ │ 端到端 │ 行情 → 信号 → 下单 │ < 50-100μs (目标) │ └──────────────┴───────────────────┴───────────────────────────┘
Co-location
服务器部署在交易所机房或同城数据中心。物理距离 < 1km。网络往返 < 100μs。
Kernel Bypass
使用 DPDK/io_uring 绕过内核网络栈。减少上下文切换和拷贝开销。
共享内存
多策略共享同一份 OrderBook 数据。使用 mmap + lock-free 结构避免锁竞争。
预热优化
JIT 预热、内存预分配、CPU 亲和性绑定。减少运行时不确定性。
9. 盈亏归因与监控
// === PnL 归因 ===
function dailyPnLAttribution(trades, positions):
attribution = {
triangularArb: { pnl: 0, trades: 0, volume: 0 },
basisTrade: { pnl: 0, trades: 0, volume: 0 },
optionArb: { pnl: 0, trades: 0, volume: 0 },
marketMaking: { pnl: 0, trades: 0, volume: 0 },
statArb: { pnl: 0, trades: 0, volume: 0 },
}
for trade in trades:
strategy = trade.strategyTag
attribution[strategy].pnl += trade.realizedPnl
attribution[strategy].trades += 1
attribution[strategy].volume += trade.notional
// 加入返佣
for rebate in rebates:
attribution[rebate.strategy].pnl += rebate.amount
// 计算各策略 Sharpe
for strat in attribution:
returns = getDailyReturns(strat, last30Days)
strat.sharpe = mean(returns) / std(returns) * sqrt(365)
strat.maxDrawdown = calcMaxDrawdown(returns)
return attribution
// === 监控指标 ===
// Sharpe Ratio > 2.0: 优秀
// Sharpe Ratio 1.0-2.0: 良好
// Sharpe Ratio < 1.0: 需要优化
// 最大回撤 < 3%: 目标
// 胜率 > 55%: 做市/统计套利
// 日换手率: 衡量资金利用效率策略归因
每笔成交标记 strategyTag。PnL 精确归属到三角/期现/做市/统计套利各策略。
交易所归因
跨所套利需按交易所分别计算 PnL。含手续费差异、返佣差异和出入金成本。
Sharpe Ratio
风险调整后收益指标。目标 > 2.0。低于 1.0 的策略需要优化或暂停。
实时仪表盘
Grafana + Prometheus 实时展示各策略 PnL、仓位、延迟百分位。异常自动触发 Slack 告警。