从回测到实盘:残酷的现实#
许多量化策略在回测中表现优异,但实盘运行时却遭遇”实盘衰减(Live Trading Decay)“。造成这一现象的核心原因之一是 执行缺口(Implementation Shortfall) —— 从产生交易信号到实际成交之间的价格偏离。
执行缺口主要由以下因素构成:
- 滑点(Slippage):预期价格与实际成交价格的差异
- 市场冲击(Market Impact):大单执行改变市场价格
- 机会成本(Opportunity Cost):延迟执行导致的价格变动
- 交易成本(Transaction Cost):佣金、印花税、买卖价差
其中,滑点 是散户和中小型机构最容易忽视、但影响最显著的执行成本。
滑点的成因与测量#
滑点的定义#
滑点 = 订单申报价格 - 实际成交价格(对买单而言)
- 正滑点(有利):实际成交价优于申报价(如买单以更低价格成交)
- 负滑点(不利):实际成交价劣于申报价(如买单以更高价格成交)
在实盘中,负滑点 是常态,因为:
- 做市商(Market Maker)需要赚取买卖价差(Bid-Ask Spread)
- 你的订单可能”跳过”中间价位(尤其是市价单)
- 高频交易者(HFT)可能抢在你前面成交
滑点的测量指标#
import pandas as pd
import numpy as np
def calculate_slippage(df_orders, df_trades):
"""
计算滑点
df_orders: 订单表 (timestamp, symbol, side, order_price, quantity)
df_trades: 成交表 (timestamp, symbol, side, fill_price, quantity)
"""
merged = pd.merge(df_orders, df_trades, on=['timestamp', 'symbol', 'side'])
# 计算滑点(对买单,滑点 = order_price - fill_price)
merged['slippage'] = np.where(
merged['side'] == 'BUY',
merged['order_price'] - merged['fill_price'],
merged['fill_price'] - merged['order_price']
)
# 统计指标
avg_slippage = merged['slippage'].mean()
slippage_bps = avg_slippage / merged['order_price'].mean() * 10000 # 转换为基点
return {
'avg_slippage': avg_slippage,
'slippage_bps': slippage_bps,
'slippage_std': merged['slippage'].std(),
'positive_rate': (merged['slippage'] > 0).mean() # 正滑点占比
}
# 示例输出
# {'avg_slippage': 0.0032, 'slippage_bps': 1.8, 'slippage_std': 0.0051, 'positive_rate': 0.12}python影响滑点的因素#
| 因素 | 影响方向 | 说明 |
|---|---|---|
| 订单规模 | + | 订单越大,滑点越严重 |
| 市场波动率 | + | 高波动时买卖价差扩大 |
| 流动性 | - | 流动性好的股票滑点更小 |
| 订单类型 | 不定 | 限价单降低滑点但可能不成交 |
| 交易时段 | 不定 | 开盘/收盘滑点更大 |
执行算法:降低滑点的核心武器#
执行算法(Execution Algorithms)的目标是:在指定时间内,以尽可能低的市场冲击完成订单。
1. VWAP(成交量加权平均价格)#
VWAP 策略试图使订单的成交价格接近当日的成交量加权平均价。
核心思想:按照历史成交量分布,将大单拆分成小单,在成交量大的时段多交易,成交量小的时段少交易。
def vwap_schedule(total_shares, volume_profile, horizon_minutes=60):
"""
VWAP 执行计划
total_shares: 总股数
volume_profile: 历史成交量分布 (每分钟)
horizon_minutes: 执行时间窗口(分钟)
"""
# 归一化成交量分布
volume_profile = volume_profile[:horizon_minutes]
volume_profile = volume_profile / volume_profile.sum()
# 计算每分钟应执行的股数
schedule = total_shares * volume_profile
return schedule.cumsum() # 累计执行计划
# 示例:3600 股分 60 分钟执行
# 如果前 10 分钟成交量占全天的 5%,则前 10 分钟执行 180 股python优点:
- 易于理解和实现
- 适合流动性好的大盘股
缺点:
- 被动跟踪市场,无法应对价格趋势
- 如果价格上涨,VWAP 会导致”越买越贵”
2. TWAP(时间加权平均价格)#
TWAP 策略将订单均匀分布在执行时间窗口内。
def twap_schedule(total_shares, horizon_minutes=60, interval_minutes=5):
"""
TWAP 执行计划
每 interval_minutes 执行一次
"""
n_intervals = horizon_minutes // interval_minutes
shares_per_interval = total_shares // n_intervals
schedule = np.ones(n_intervals) * shares_per_interval
schedule[-1] += total_shares - schedule.sum() # 处理余数
return schedule.cumsum()
# 示例:3600 股分 12 个区间执行(每 5 分钟一次),每次执行 300 股python优点:
- 简单稳定,市场冲击小
- 不依赖成交量预测
缺点:
- 忽略流动性变化,可能在流动性差时执行
- 容易被其他交易者识别并”front-run”
3. POV(Percentage of Volume)#
POV 策略以固定比例参与市场成交,例如”以 10% 的参与度执行订单”。
def pov_schedule(total_shares, current_volume, participation_rate=0.1):
"""
POV 执行计划
participation_rate: 参与度(0-1)
"""
# 根据当前成交量计算本轮应执行的股数
shares_to_trade = current_volume * participation_rate
# 限制最大/最小执行量
shares_to_trade = np.clip(shares_to_trade, 100, 10000)
return min(shares_to_trade, total_shares)python优点:
- 自动适应市场流动性
- 市场冲击可控
缺点:
- 如果成交量突然放大,可能执行过快
- 如果成交量萎缩,可能执行过慢
4. IS(Implementation Shortfall)算法#
IS 算法(又称”冰山订单”)由 Robert Almgren 和 Neil Chriss 提出,是业界最先进的执行算法之一。
核心思想:在 市场冲击成本 和 机会成本 之间寻找最优平衡。
def is_optimal_schedule(total_shares, volatility, risk_aversion=1e-6):
"""
Almgren-Chriss IS 模型
volatility: 波动率
risk_aversion: 风险厌恶系数(越大越保守)
"""
# 模型参数
eta = 0.05 # 临时市场冲击系数
gamma = 0.1 # 永久市场冲击系数
tau = 1.0 # 执行时间(归一化)
# 最优执行轨迹(解析解)
k = np.sqrt(gamma / (eta * risk_aversion * volatility**2))
t = np.linspace(0, tau, 100)
# 持仓变化
x_t = total_shares * (np.cosh(k * (tau - t)) / np.cosh(k * tau))
# 执行速率
v_t = -np.gradient(x_t, t)
return x_t, v_t
# 可视化最优执行轨迹
import matplotlib.pyplot as plt
x_t, v_t = is_optimal_schedule(10000, volatility=0.02)
plt.plot(x_t, label='持仓')
plt.plot(v_t, label='执行速率')
plt.legend()
plt.show()python优点:
- 理论上最优(最小化执行成本)
- 可根据风险偏好调整
缺点:
- 参数估计困难(需要准确的冲击成本模型)
- 对波动率预测敏感
滑点控制实战技巧#
1. 限价单 vs 市价单#
| 订单类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 限价单(Limit Order) | 控制价格,避免不利滑点 | 可能不成交 | 流动性好、不紧急的订单 |
| 市价单(Market Order) | 保证成交 | 滑点不可控 | 紧急平仓、流动性极好的股票 |
实战建议:
- 单笔订单 < 日均成交量(ADV)的 1%,使用市价单
- 单笔订单 > ADV 的 5%,必须使用限价单 + 拆单算法
2. 隐藏订单(Iceberg Order)#
隐藏订单只允许部分订单显示在订单簿上(如显示 100 股,实际想买 1000 股)。
# Interactive Brokers API 示例
from ib_insync import *
ib = IB()
ib.connect('127.0.0.1', 7497, clientId=1)
contract = Stock('AAPL', 'SMART', 'USD')
order = LimitOrder('BUY', 1000, 150.0, hidden=True) # 隐藏订单
ib.placeOrder(contract, order)python3. 盘前盘后交易#
盘中执行滑点更大(因为 HFT 活跃),可以考虑在盘前(Pre-Market)或盘后(After-Hours)交易。
注意:盘前盘后流动性差,买卖价差大,适合小单。
4. 智能订单路由(SOR)#
如果股票在多个交易所上市(如 AAPL 在 NASDAQ、NYSE、BATS 等),使用 SOR 自动寻找最优价格。
# 使用 IB 的智能路由
order = LimitOrder('BUY', 100, 150.0, smartComboRoutingParams=[])
# IB 会自动在多个交易所寻找最优价格python实盘系统架构#
一个完整的实盘交易系统应包含以下模块:
┌─────────────────────────────────────────┐
│ 策略层 (Strategy Layer) │
│ - 产生交易信号 │
│ - 计算目标持仓 │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 执行层 (Execution Layer) │
│ - 订单拆分(VWAP/TWAP/IS) │
│ - 滑点控制(限价单/隐藏订单) │
│ - 智能路由(SOR) │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 风控层 (Risk Layer) │
│ - 仓位限制 │
│ - 止损/止盈 │
│ - 异常监控(熔断机制) │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ 交易接口 (Broker API) │
│ - IB / Alpaca / TDAmeritrade │
│ - 订单状态管理 │
└─────────────────────────────────────────┘plaintextPython 实盘框架推荐#
- Backtrader + IBridgePy:适合 IB 用户
- QuantConnect / Lean:云端回测 + 实盘(支持多券商)
- Alpaca Trade API:零佣金,适合散户
- ccxt:加密货币专用
性能评估:实盘 vs 回测#
定期对比实盘收益与回测收益,计算 执行缺口:
def calculate_implementation_shortfall(df_backtest, df_live):
"""
计算执行缺口
"""
# 回测收益(假设无滑点)
bt_return = df_backtest['equity'].pct_change().sum()
# 实盘收益(含滑点)
live_return = df_live['equity'].pct_change().sum()
# 执行缺口
is_cost = bt_return - live_return
return {
'backtest_return': bt_return,
'live_return': live_return,
'implementation_shortfall': is_cost,
'is_bps': is_cost * 10000 # 转换为基点
}
# 示例输出
# {'backtest_return': 0.15, 'live_return': 0.12, 'implementation_shortfall': 0.03, 'is_bps': 300}python经验法则:
- IS < 50 bps:执行优秀
- IS 50-100 bps:可接受
- IS > 100 bps:需要优化执行算法
总结#
从回测到实盘,执行系统是量化策略成功的关键一环。核心要点:
- 滑点 是实盘衰减的主要原因,必须测量和控制
- 执行算法(VWAP/TWAP/POV/IS)可降低市场冲击
- 订单类型选择(限价单 vs 市价单)取决于流动性和紧急性
- 实盘系统架构需要策略层、执行层、风控层、交易接口四层分离
- 定期评估 执行缺口,持续优化执行算法
实盘建议:先用小资金测试执行算法,测量滑点后再逐步加大仓位。记住:活得久比跑得快更重要!
参考资料:
- Almgren, R., & Chriss, N. (2000). Optimal execution of portfolio transactions
- Kissell, R. (2013). The Science of Algorithmic Trading and Portfolio Management
- Chan, E. (2013). Algorithmic Trading: Winning Strategies and Their Rationale