从回测到实盘的鸿沟#
量化策略开发中,研究者常陷入一个致命陷阱:忽视实盘交易中的执行成本。一个在回测中表现优异的策略,可能因为滑点和交易成本而在实盘中亏损。
什么是滑点?#
滑点(Slippage) 是指预期交易价格与实际成交价格之间的差额。在理想情况下,我们希望以特定价格成交,但真实市场中:
- 正向滑点:实际成交价格比预期更好(如预期买入价10元,实际9.98元成交)
- 负向滑点:实际成交价格比预期更差(如预期买入价10元,实际10.02元成交)
滑点产生的原因#
1. 市场微观结构#
- 买卖价差(Bid-Ask Spread):流动性提供商的利润来源
- 订单簿深度:不同价位的挂单量影响大单成交价格
- 市场冲击:大额订单会消耗订单簿流动性,推动价格向不利方向移动
2. 时间延迟#
- 信号生成到订单发送延迟:价格可能已经变动
- 交易所处理延迟:从订单发送到成交的时间差
- 网络延迟:特别是跨地域交易
3. 市场波动性#
- 高波动时段:价格快速变动,预期价格与实际成交价偏差更大
- 开盘/收盘:流动性变化剧烈,滑点通常更大
滑点的量化测量#
1. 实现短缺(Implementation Shortfall)#
最常用的滑点衡量指标,由Andre Perold提出:
其中:
- 基准成本 = 决策时的中间价 × 交易数量
- 实际总成本 = 实际成交价格 × 交易数量 + 交易成本
2. Python实现滑点分析#
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
class SlippageAnalyzer:
"""滑点分析器"""
def __init__(self, benchmark_price_col='mid_price',
execution_price_col='execution_price',
volume_col='volume', side_col='side'):
self.benchmark_price_col = benchmark_price_col
self.execution_price_col = execution_price_col
self.volume_col = volume_col
self.side_col = side_col
def calculate_slippage(self, df):
"""计算每笔交易的滑点"""
# 复制数据避免修改原始数据
data = df.copy()
# 计算绝对滑点
if self.side_col in data.columns:
# 考虑买卖方向
data['slippage_abs'] = np.where(
data[self.side_col] == 'buy',
data[self.execution_price_col] - data[self.benchmark_price_col],
data[self.benchmark_price_col] - data[self.execution_price_col]
)
else:
# 不区分方向,取绝对值
data['slippage_abs'] = np.abs(
data[self.execution_price_col] - data[self.benchmark_price_col]
)
# 计算相对滑点(基点)
data['slippage_bps'] = (data['slippage_abs'] /
data[self.benchmark_price_col]) * 10000
return data
def calculate_implementation_shortfall(self, df, price_col='execution_price',
benchmark_col='decision_price',
volume_col='volume', side_col='side'):
"""计算实现短缺"""
data = df.copy()
# 总成本
data['total_cost'] = data[price_col] * data[volume_col]
# 基准成本
data['benchmark_cost'] = data[benchmark_col] * data[volume_col]
# 实现短缺
data['implementation_shortfall'] = (data['total_cost'] -
data['benchmark_cost']) / data['benchmark_cost']
# 区分买卖方向
if side_col in data.columns:
data['is_buy'] = data[side_col] == 'buy'
data.loc[~data['is_buy'], 'implementation_shortfall'] = \
-data.loc[~data['is_buy'], 'implementation_shortfall']
return data
def slippage_statistics(self, df):
"""滑点统计分析"""
stats = {}
stats['mean_slippage_abs'] = df['slippage_abs'].mean()
stats['median_slippage_abs'] = df['slippage_abs'].median()
stats['std_slippage_abs'] = df['slippage_abs'].std()
stats['max_slippage_abs'] = df['slippage_abs'].max()
stats['min_slippage_abs'] = df['slippage_abs'].min()
stats['mean_slippage_bps'] = df['slippage_bps'].mean()
stats['median_slippage_bps'] = df['slippage_bps'].median()
stats['std_slippage_bps'] = df['slippage_bps'].std()
# 分位数
stats['percentile_95'] = np.percentile(df['slippage_bps'], 95)
stats['percentile_99'] = np.percentile(df['slippage_bps'], 99)
return stats
# 示例使用
# 生成模拟交易数据
np.random.seed(42)
n_trades = 1000
mock_data = pd.DataFrame({
'timestamp': pd.date_range('2026-01-01', periods=n_trades, freq='min'),
'decision_price': np.random.uniform(9.5, 10.5, n_trades),
'mid_price': np.random.uniform(9.5, 10.5, n_trades),
'execution_price': np.random.uniform(9.5, 10.5, n_trades),
'volume': np.random.randint(100, 10000, n_trades),
'side': np.random.choice(['buy', 'sell'], n_trades)
})
# 添加一些滑点(偏向负向滑点)
mock_data['execution_price'] = np.where(
mock_data['side'] == 'buy',
mock_data['execution_price'] + np.random.exponential(0.01, n_trades),
mock_data['execution_price'] - np.random.exponential(0.01, n_trades)
)
# 分析滑点
analyzer = SlippageAnalyzer()
result_data = analyzer.calculate_slippage(mock_data)
result_data = analyzer.calculate_implementation_shortfall(result_data)
# 统计结果
stats = analyzer.slippage_statistics(result_data)
print("=== 滑点统计分析 ===")
for key, value in stats.items():
if 'bps' in key:
print(f"{key}: {value:.2f} bps")
else:
print(f"{key}: {value:.4f}")python降低滑点的实战策略#
1. 订单拆分与执行算法#
大额订单不应一次性提交,而应使用执行算法拆分为多个小单。
(1) VWAP(成交量加权平均价格)#
class VWAPExecutor:
"""VWAP执行算法"""
def __init__(self, total_volume, time_horizon_minutes=60,
num_slices=10, randomize=True):
self.total_volume = total_volume
self.time_horizon = time_horizon_minutes
self.num_slices = num_slices
self.randomize = randomize
def generate_schedule(self, historical_volume_profile=None):
"""生成执行时间表"""
if historical_volume_profile is not None:
# 基于历史成交量分布
volume_weights = historical_volume_profile / historical_volume_profile.sum()
else:
# 默认均匀分配
volume_weights = np.ones(self.num_slices) / self.num_slices
# 添加随机化(实际交易中常用)
if self.randomize:
volume_weights = volume_weights * np.random.uniform(0.8, 1.2, self.num_slices)
volume_weights = volume_weights / volume_weights.sum()
# 计算每段时间应执行的成交量
slice_volumes = volume_weights * self.total_volume
# 计算执行时间间隔
time_interval = self.time_horizon / self.num_slices
schedule = []
for i in range(self.num_slices):
schedule.append({
'slice_id': i + 1,
'start_time': i * time_interval,
'end_time': (i + 1) * time_interval,
'target_volume': slice_volumes[i],
'participation_rate': volume_weights[i] * self.num_slices # 占该时段预期成交量的比例
})
return pd.DataFrame(schedule)
def execute(self, order_book, current_time, remaining_volume):
"""执行一个时间段的订单"""
# 获取当前订单簿状态
bid_price = order_book['bid'][0]['price']
ask_price = order_book['ask'][0]['price']
mid_price = (bid_price + ask_price) / 2
# 根据VWAP进度计算应执行量
# 简化:这里假设我们已经知道应该执行多少
target_volume = min(remaining_volume, self.total_volume / self.num_slices)
# 智能下单:使用限价单避免滑点
order = {
'price': mid_price, # 中间价挂单
'volume': target_volume,
'side': 'buy', # 或'sell'
'order_type': 'limit',
'time_in_force': 'IOC' # Immediate-or-Cancel
}
return order
# 示例使用
executor = VWAPExecutor(total_volume=10000, time_horizon_minutes=60, num_slices=12)
schedule = executor.generate_schedule()
print("VWAP执行计划:")
print(schedule.head())python(2) TWAP(时间加权平均价格)#
class TWAPExecutor:
"""TWAP执行算法"""
def __init__(self, total_volume, time_horizon_minutes=60, num_slices=10):
self.total_volume = total_volume
self.time_horizon = time_horizon_minutes
self.num_slices = num_slices
def generate_schedule(self):
"""生成均匀执行时间表"""
slice_volumes = self.total_volume / self.num_slices
time_interval = self.time_horizon / self.num_slices
schedule = []
for i in range(self.num_slices):
schedule.append({
'slice_id': i + 1,
'start_time': i * time_interval,
'end_time': (i + 1) * time_interval,
'target_volume': slice_volumes,
'execution_rate': slice_volumes / time_interval # 每分钟执行量
})
return pd.DataFrame(schedule)
# 示例使用
twap_executor = TWAPExecutor(total_volume=10000, time_horizon_minutes=60, num_slices=6)
twap_schedule = twap_executor.generate_schedule()
print("\nTWAP执行计划:")
print(twap_schedule)python(3) POV(参与率算法)#
class POVExecutor:
"""参与率执行算法"""
def __init__(self, total_volume, target_participation_rate=0.1,
max_participation_rate=0.2, min_participation_rate=0.05):
self.total_volume = total_volume
self.target_rate = target_participation_rate
self.max_rate = max_participation_rate
self.min_rate = min_participation_rate
def calculate_order_size(self, market_volume_last_n_minutes, lookback=5):
"""根据市场成交量动态调整订单大小"""
# 计算市场平均成交量
avg_market_volume = np.mean(market_volume_last_n_minutes[-lookback:])
# 目标成交量
target_volume = avg_market_volume * self.target_rate
# 限制在上下限内
max_volume = avg_market_volume * self.max_rate
min_volume = avg_market_volume * self.min_rate
order_volume = np.clip(target_volume, min_volume, max_volume)
return order_volume, avg_market_volume
def adaptive_execution(self, market_data):
"""自适应执行"""
results = []
for i, row in market_data.iterrows():
market_volume = row['market_volume']
current_price = row['mid_price']
# 计算订单大小
order_volume, avg_market_vol = self.calculate_order_size([market_volume])
# 判断市场冲击
market_impact = self.estimate_market_impact(order_volume, avg_market_vol)
# 如果市场冲击太大,降低参与率
if market_impact > 0.001: # 超过10个基点
adjusted_volume = order_volume * 0.5
else:
adjusted_volume = order_volume
results.append({
'timestamp': row['timestamp'],
'order_volume': adjusted_volume,
'participation_rate': adjusted_volume / market_volume,
'estimated_impact': market_impact
})
return pd.DataFrame(results)
def estimate_market_impact(self, order_volume, market_volume):
"""估计市场冲击"""
# 简化模型:使用平方根法则
participation_rate = order_volume / market_volume
impact = 0.1 * np.sqrt(participation_rate) # 临时模型
return impact
# 示例使用
pov_executor = POVExecutor(total_volume=10000, target_participation_rate=0.1)
mock_market_data = pd.DataFrame({
'timestamp': pd.date_range('2026-01-01', periods=100, freq='min'),
'market_volume': np.random.randint(1000, 5000, 100),
'mid_price': np.random.uniform(9.8, 10.2, 100)
})
pov_results = pov_executor.adaptive_execution(mock_market_data)
print("\nPOV执行结果示例:")
print(pov_results.head())python2. 限价单与市价单的智能选择#
class OrderTypeOptimizer:
"""订单类型优化器"""
def __init__(self, max_wait_time=300, urgency_threshold=0.8):
self.max_wait_time = max_wait_time # 最大等待时间(秒)
self.urgency_threshold = urgency_threshold # 紧急程度阈值
def decide_order_type(self, order_size, order_book, urgency=0.5,
volatility=0.01, time_horizon=None):
"""
决策使用限价单还是市价单
参数:
- order_size: 订单大小
- order_book: 订单簿快照
- urgency: 紧急程度 (0-1)
- volatility: 市场波动率
- time_horizon: 允许的最长执行时间
"""
# 分析订单簿深度
bid_depth = sum([level['volume'] for level in order_book['bid'][:5]])
ask_depth = sum([level['volume'] for level in order_book['ask'][:5]])
# 计算订单对市场的影响
if order_size > bid_depth * 0.1: # 订单大小超过买一档深度的10%
market_impact_high = True
else:
market_impact_high = False
# 决策逻辑
if urgency > self.urgency_threshold:
# 高紧急程度:使用市价单
return 'market', {'reason': 'high_urgency', 'expected_slippage': volatility * 2}
elif market_impact_high:
# 市场冲击大:使用限价单,分批执行
return 'limit', {'reason': 'high_market_impact', 'recommended_price': order_book['bid'][0]['price']}
elif volatility > 0.02: # 高波动
# 高波动:使用限价单,避免滑点
return 'limit', {'reason': 'high_volatility', 'recommended_price': (order_book['bid'][0]['price'] + order_book['ask'][0]['price']) / 2}
else:
# 正常情况:根据时间允许度决策
if time_horizon and time_horizon > self.max_wait_time:
# 时间充裕:使用限价单
return 'limit', {'reason': 'sufficient_time', 'recommended_price': order_book['bid'][0]['price']}
else:
# 时间紧张:使用市价单
return 'market', {'reason': 'time_constraint', 'expected_slippage': volatility}
def optimal_limit_price(self, order_book, side='buy', order_size=None):
"""计算最优限价单价格"""
if side == 'buy':
# 买订单:希望以较低价格成交
price_levels = [(level['price'], level['volume']) for level in order_book['ask']]
else:
# 卖订单:希望以较高价格成交
price_levels = [(level['price'], level['volume']) for level in order_book['bid']]
# 如果指定了订单大小,找到能全部成交的价格
if order_size:
cumulative_volume = 0
for price, volume in price_levels:
cumulative_volume += volume
if cumulative_volume >= order_size:
return price
# 如果深度不够,返回最后一个价格
return price_levels[-1][0]
# 如果没有指定大小,返回最有竞争力的价格(买一/卖一)
return price_levels[0][0]
# 示例使用
optimizer = OrderTypeOptimizer()
# 模拟订单簿
mock_order_book = {
'bid': [
{'price': 10.00, 'volume': 500},
{'price': 9.99, 'volume': 800},
{'price': 9.98, 'volume': 1200},
{'price': 9.97, 'volume': 600},
{'price': 9.96, 'volume': 900}
],
'ask': [
{'price': 10.01, 'volume': 400},
{'price': 10.02, 'volume': 700},
{'price': 10.03, 'volume': 1000},
{'price': 10.04, 'volume': 500},
{'price': 10.05, 'volume': 800}
]
}
# 决策示例
order_type, params = optimizer.decide_order_type(
order_size=2000,
order_book=mock_order_book,
urgency=0.9, # 高紧急
volatility=0.015
)
print(f"推荐订单类型: {order_type}")
print(f"参数: {params}")
# 计算最优限价
optimal_price = optimizer.optimal_limit_price(mock_order_book, side='buy', order_size=1000)
print(f"买入订单最优限价: {optimal_price}")python3. 订单路由与智能订单#
现代交易系统使用智能订单路由(Smart Order Router, SOR)在多个交易所寻找最佳流动性。
class SmartOrderRouter:
"""智能订单路由器"""
def __init__(self, exchanges=['SSE', 'SZSE', 'HKEX']):
self.exchanges = exchanges
self.exchange_fees = {
'SSE': {'maker': 0.0001, 'taker': 0.0002},
'SZSE': {'maker': 0.0001, 'taker': 0.0002},
'HKEX': {'maker': 0.00015, 'taker': 0.00025}
}
def find_best_exchange(self, order, order_book_snapshots):
"""
寻找最佳交易所
参数:
- order: 订单信息 {'side': 'buy'/'sell', 'volume': 1000, 'price': 10.00}
- order_book_snapshots: 各交易所订单簿快照
"""
best_exchange = None
best_cost = float('inf')
best_execution_prob = 0
for exchange in self.exchanges:
if exchange not in order_book_snapshots:
continue
ob = order_book_snapshots[exchange]
# 计算在该交易所的成交概率
if order['side'] == 'buy':
# 买订单:检查卖单深度
available_volume = sum([level['volume'] for level in ob['ask'][:5]])
execution_prob = min(1.0, available_volume / order['volume'])
# 计算预期成交价格
if execution_prob > 0:
expected_price = self.estimate_execution_price(order, ob, order['side'])
else:
expected_price = order['price']
else:
# 卖订单:检查买单深度
available_volume = sum([level['volume'] for level in ob['bid'][:5]])
execution_prob = min(1.0, available_volume / order['volume'])
if execution_prob > 0:
expected_price = self.estimate_execution_price(order, ob, order['side'])
else:
expected_price = order['price']
# 计算总成本(含手续费)
if order['type'] == 'limit':
fee_rate = self.exchange_fees[exchange]['maker']
else:
fee_rate = self.exchange_fees[exchange]['taker']
total_cost = expected_price * order['volume'] * (1 + fee_rate)
# 综合评分:成本越低越好,成交概率越高越好
score = total_cost / (execution_prob + 0.01) # 避免除零
if score < best_cost:
best_cost = score
best_exchange = exchange
best_execution_prob = execution_prob
return {
'exchange': best_exchange,
'expected_cost': best_cost,
'execution_probability': best_execution_prob,
'fee_rate': self.exchange_fees[best_exchange][order['type']]
}
def estimate_execution_price(self, order, order_book, side):
"""估计执行价格"""
if side == 'buy':
# 买订单:会消耗卖单
remaining = order['volume']
total_cost = 0
for level in order_book['ask']:
price = level['price']
volume = level['volume']
if remaining <= 0:
break
fill_volume = min(remaining, volume)
total_cost += fill_volume * price
remaining -= fill_volume
if order['volume'] > 0:
return total_cost / order['volume']
else:
return order['price']
else: # sell
# 卖订单:会消耗买单
remaining = order['volume']
total_cost = 0
for level in order_book['bid']:
price = level['price']
volume = level['volume']
if remaining <= 0:
break
fill_volume = min(remaining, volume)
total_cost += fill_volume * price
remaining -= fill_volume
if order['volume'] > 0:
return total_cost / order['volume']
else:
return order['price']
def split_order_across_exchanges(self, order, order_book_snapshots,
max_slippage=0.001):
"""跨交易所拆分订单"""
splits = []
remaining_volume = order['volume']
# 按流动性排序交易所
exchanges_by_liquidity = []
for exchange in self.exchanges:
if exchange in order_book_snapshots:
ob = order_book_snapshots[exchange]
if order['side'] == 'buy':
liquidity = sum([level['volume'] for level in ob['ask'][:5]])
else:
liquidity = sum([level['volume'] for level in ob['bid'][:5]])
exchanges_by_liquidity.append((exchange, liquidity))
exchanges_by_liquidity.sort(key=lambda x: x[1], reverse=True)
# 分配订单
for exchange, liquidity in exchanges_by_liquidity:
if remaining_volume <= 0:
break
# 根据流动性比例分配
allocation = min(remaining_volume, order['volume'] * (liquidity / sum([x[1] for x in exchanges_by_liquidity])))
if allocation > 0:
splits.append({
'exchange': exchange,
'volume': allocation,
'expected_price': self.estimate_execution_price(
{'volume': allocation, 'side': order['side'], 'type': order['type']},
order_book_snapshots[exchange],
order['side']
)
})
remaining_volume -= allocation
return splits
# 示例使用
router = SmartOrderRouter()
# 模拟各交易所订单簿
order_book_snapshots = {
'SSE': {
'bid': [{'price': 10.00, 'volume': 5000}, {'price': 9.99, 'volume': 8000}],
'ask': [{'price': 10.01, 'volume': 4000}, {'price': 10.02, 'volume': 7000}]
},
'SZSE': {
'bid': [{'price': 10.00, 'volume': 3000}, {'price': 9.99, 'volume': 6000}],
'ask': [{'price': 10.01, 'volume': 2500}, {'price': 10.02, 'volume': 5500}]
},
'HKEX': {
'bid': [{'price': 10.00, 'volume': 2000}, {'price': 9.99, 'volume': 4000}],
'ask': [{'price': 10.01, 'volume': 1500}, {'price': 10.02, 'volume': 3000}]
}
}
# 寻找最佳交易所
order = {'side': 'buy', 'volume': 5000, 'price': 10.01, 'type': 'limit'}
best_exchange_info = router.find_best_exchange(order, order_book_snapshots)
print("最佳交易所:")
print(best_exchange_info)
# 跨交易所拆分订单
split_plan = router.split_order_across_exchanges(order, order_book_snapshots)
print("\n跨交易所订单拆分计划:")
for split in split_plan:
print(f"交易所: {split['exchange']}, 数量: {split['volume']}, 预期价格: {split['expected_price']:.4f}")python订单管理系统架构#
一个完整的实盘交易系统需要强大的订单管理模块。
import uuid
from enum import Enum
from datetime import datetime
from typing import List, Dict, Optional
class OrderStatus(Enum):
CREATED = "created"
SENT = "sent"
PARTIALLY_FILLED = "partially_filled"
FILLED = "filled"
CANCELLED = "cancelled"
REJECTED = "rejected"
class OrderType(Enum):
MARKET = "market"
LIMIT = "limit"
STOP = "stop"
STOP_LIMIT = "stop_limit"
class TimeInForce(Enum):
DAY = "day" # 当日有效
GTC = "gtc" # Good Till Cancelled
IOC = "ioc" # Immediate-or-Cancel
FOK = "fok" # Fill-or-Kill
class Order:
"""订单类"""
def __init__(self, symbol: str, side: str, volume: float,
order_type: OrderType = OrderType.LIMIT,
price: Optional[float] = None,
stop_price: Optional[float] = None,
time_in_force: TimeInForce = TimeInForce.DAY):
self.order_id = str(uuid.uuid4())
self.symbol = symbol
self.side = side # 'buy' or 'sell'
self.volume = volume
self.order_type = order_type
self.price = price
self.stop_price = stop_price
self.time_in_force = time_in_force
self.status = OrderStatus.CREATED
self.filled_volume = 0
self.remaining_volume = volume
self.avg_fill_price = 0
self.commission = 0
self.created_time = datetime.now()
self.sent_time = None
self.filled_time = None
self.exchange = None
self.client_order_id = None
def update_fill(self, fill_volume: float, fill_price: float, commission: float = 0):
"""更新成交信息"""
if self.status == OrderStatus.CANCELLED or self.status == OrderStatus.REJECTED:
raise ValueError(f"Cannot fill order in status {self.status}")
self.filled_volume += fill_volume
self.remaining_volume -= fill_volume
# 计算平均成交价
total_cost = (self.avg_fill_price * (self.filled_volume - fill_volume) +
fill_price * fill_volume)
self.avg_fill_price = total_cost / self.filled_volume
self.commission += commission
# 更新状态
if self.remaining_volume <= 0:
self.status = OrderStatus.FILLED
self.filled_time = datetime.now()
else:
self.status = OrderStatus.PARTIALLY_FILLED
def cancel(self):
"""取消订单"""
if self.status in [OrderStatus.FILLED, OrderStatus.CANCELLED, OrderStatus.REJECTED]:
raise ValueError(f"Cannot cancel order in status {self.status}")
self.status = OrderStatus.CANCELLED
def to_dict(self):
"""转换为字典"""
return {
'order_id': self.order_id,
'symbol': self.symbol,
'side': self.side,
'volume': self.volume,
'order_type': self.order_type.value,
'price': self.price,
'status': self.status.value,
'filled_volume': self.filled_volume,
'remaining_volume': self.remaining_volume,
'avg_fill_price': self.avg_fill_price,
'commission': self.commission,
'created_time': self.created_time.isoformat(),
'filled_time': self.filled_time.isoformat() if self.filled_time else None
}
class OrderManager:
"""订单管理器"""
def __init__(self, max_orders=1000):
self.orders = {} # order_id -> Order
self.active_orders = [] # 活跃订单ID列表
self.max_orders = max_orders
def create_order(self, symbol: str, side: str, volume: float, **kwargs) -> Order:
"""创建订单"""
if len(self.orders) >= self.max_orders:
raise ValueError(f"Maximum number of orders ({self.max_orders}) reached")
order = Order(symbol, side, volume, **kwargs)
self.orders[order.order_id] = order
if order.status == OrderStatus.CREATED:
self.active_orders.append(order.order_id)
return order
def send_order(self, order_id: str, exchange: str):
"""发送订单到交易所"""
if order_id not in self.orders:
raise ValueError(f"Order {order_id} not found")
order = self.orders[order_id]
if order.status != OrderStatus.CREATED:
raise ValueError(f"Order {order_id} cannot be sent in status {order.status}")
# 更新订单状态
order.status = OrderStatus.SENT
order.sent_time = datetime.now()
order.exchange = exchange
# 这里应该调用交易所API发送订单
print(f"订单 {order_id} 已发送到 {exchange}")
return order
def process_fill(self, order_id: str, fill_volume: float,
fill_price: float, commission: float = 0):
"""处理成交回报"""
if order_id not in self.orders:
raise ValueError(f"Order {order_id} not found")
order = self.orders[order_id]
order.update_fill(fill_volume, fill_price, commission)
# 如果订单完成,从活跃列表移除
if order.status == OrderStatus.FILLED:
if order_id in self.active_orders:
self.active_orders.remove(order_id)
return order
def cancel_order(self, order_id: str):
"""取消订单"""
if order_id not in self.orders:
raise ValueError(f"Order {order_id} not found")
order = self.orders[order_id]
order.cancel()
# 从活跃列表移除
if order_id in self.active_orders:
self.active_orders.remove(order_id)
# 这里应该调用交易所API取消订单
print(f"订单 {order_id} 已取消")
return order
def get_order(self, order_id: str) -> Optional[Order]:
"""获取订单"""
return self.orders.get(order_id)
def get_active_orders(self) -> List[Order]:
"""获取所有活跃订单"""
return [self.orders[oid] for oid in self.active_orders if oid in self.orders]
def get_orders_by_symbol(self, symbol: str) -> List[Order]:
"""按标的查询订单"""
return [order for order in self.orders.values() if order.symbol == symbol]
# 示例使用
order_manager = OrderManager()
# 创建订单
order1 = order_manager.create_order(
symbol='600519.SS',
side='buy',
volume=1000,
order_type=OrderType.LIMIT,
price=10.00
)
print(f"创建订单: {order1.order_id}")
print(f"订单状态: {order1.status}")
# 发送订单
order_manager.send_order(order1.order_id, 'SSE')
# 模拟部分成交
order_manager.process_fill(order1.order_id, 500, 10.00, commission=5.0)
print(f"部分成交后状态: {order1.status}")
print(f"已成交: {order1.filled_volume}, 剩余: {order1.remaining_volume}")
# 模拟剩余成交
order_manager.process_fill(order1.order_id, 500, 10.01, commission=5.0)
print(f"全部成交后状态: {order1.status}")
print(f"平均成交价: {order1.avg_fill_price:.4f}")
print(f"总手续费: {order1.commission:.2f}")python绩效评估与持续优化#
1. 执行质量分析#
class ExecutionQualityAnalyzer:
"""执行质量分析器"""
def __init__(self):
self.metrics = {}
def calculate_metrics(self, orders: List[Order], benchmark_prices: Dict[str, float]):
"""计算执行质量指标"""
if not orders:
return {}
# 计算各项指标
total_volume = sum([order.volume for order in orders])
total_filled = sum([order.filled_volume for order in orders])
if total_filled == 0:
return {'error': 'No fills to analyze'}
# 平均滑点
slippages = []
for order in orders:
if order.filled_volume > 0 and order.symbol in benchmark_prices:
benchmark = benchmark_prices[order.symbol]
if order.side == 'buy':
slippage = order.avg_fill_price - benchmark
else:
slippage = benchmark - order.avg_fill_price
slippages.append(slippage)
avg_slippage = np.mean(slippages) if slippages else 0
# 实现短缺
implementation_shortfalls = []
for order in orders:
if (order.filled_volume > 0 and order.symbol in benchmark_prices and
hasattr(order, 'decision_price') and order.decision_price):
decision_price = order.decision_price
actual_cost = order.avg_fill_price * order.filled_volume + order.commission
benchmark_cost = decision_price * order.filled_volume
is_shortfall = (actual_cost - benchmark_cost) / benchmark_cost
implementation_shortfalls.append(is_shortfall)
avg_is = np.mean(implementation_shortfalls) if implementation_shortfalls else 0
# 成交率
fill_rate = total_filled / total_volume if total_volume > 0 else 0
# 平均执行时间
execution_times = []
for order in orders:
if order.filled_time and order.sent_time:
exec_time = (order.filled_time - order.sent_time).total_seconds()
execution_times.append(exec_time)
avg_exec_time = np.mean(execution_times) if execution_times else 0
# 市场冲击成本(简化计算)
market_impact = avg_slippage * 2 # 简化模型
self.metrics = {
'total_orders': len(orders),
'total_volume': total_volume,
'total_filled': total_filled,
'fill_rate': fill_rate,
'avg_slippage': avg_slippage,
'avg_slippage_bps': avg_slippage * 10000,
'avg_implementation_shortfall': avg_is,
'avg_implementation_shortfall_bps': avg_is * 10000,
'avg_execution_time': avg_exec_time,
'market_impact_cost': market_impact,
'total_commission': sum([order.commission for order in orders])
}
return self.metrics
def plot_execution_analysis(self, orders: List[Order]):
"""绘制执行质量分析图"""
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. 滑点分布
slippages = []
for order in orders:
if order.filled_volume > 0 and hasattr(order, 'decision_price') and order.decision_price:
benchmark = order.decision_price
if order.side == 'buy':
slippage = order.avg_fill_price - benchmark
else:
slippage = benchmark - order.avg_fill_price
slippages.append(slippage * 10000) # 转换为基点
if slippages:
axes[0, 0].hist(slippages, bins=30, edgecolor='black', alpha=0.7)
axes[0, 0].axvline(np.mean(slippages), color='red', linestyle='--',
label=f'平均: {np.mean(slippages):.2f} bps')
axes[0, 0].set_xlabel('滑点 (基点)')
axes[0, 0].set_ylabel('频率')
axes[0, 0].set_title('滑点分布')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 2. 订单状态分布
status_counts = {}
for order in orders:
status = order.status.value
status_counts[status] = status_counts.get(status, 0) + 1
if status_counts:
axes[0, 1].pie(status_counts.values(), labels=status_counts.keys(),
autopct='%1.1f%%', startangle=90)
axes[0, 1].set_title('订单状态分布')
# 3. 执行时间分析
exec_times = []
for order in orders:
if order.filled_time and order.sent_time:
exec_time = (order.filled_time - order.sent_time).total_seconds()
exec_times.append(exec_time)
if exec_times:
axes[1, 0].hist(exec_times, bins=30, edgecolor='black', alpha=0.7)
axes[1, 0].axvline(np.mean(exec_times), color='red', linestyle='--',
label=f'平均: {np.mean(exec_times):.2f}秒')
axes[1, 0].set_xlabel('执行时间 (秒)')
axes[1, 0].set_ylabel('频率')
axes[1, 0].set_title('订单执行时间分布')
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)
# 4. 成交量与滑点关系
volumes = []
slippages_by_volume = []
for order in orders:
if (order.filled_volume > 0 and hasattr(order, 'decision_price') and
order.decision_price):
benchmark = order.decision_price
if order.side == 'buy':
slippage = order.avg_fill_price - benchmark
else:
slippage = benchmark - order.avg_fill_price
volumes.append(order.filled_volume)
slippages_by_volume.append(slippage * 10000)
if volumes and slippages_by_volume:
axes[1, 1].scatter(volumes, slippages_by_volume, alpha=0.6)
axes[1, 1].set_xlabel('订单大小')
axes[1, 1].set_ylabel('滑点 (基点)')
axes[1, 1].set_title('订单大小 vs 滑点')
axes[1, 1].grid(True, alpha=0.3)
# 添加趋势线
z = np.polyfit(volumes, slippages_by_volume, 1)
p = np.poly1d(z)
axes[1, 1].plot(volumes, p(volumes), "r--", label='趋势线')
axes[1, 1].legend()
plt.tight_layout()
plt.savefig('/Users/halo/workspace/astro-blog/public/images/execution-slippage-control/execution_quality_analysis.svg',
format='svg', bbox_inches='tight')
plt.show()
return fig
# 示例使用
# 假设我们有一系列订单
analyzer = ExecutionQualityAnalyzer()
# 模拟一些订单数据(实际中应从订单管理器获取)
mock_orders = []
for i in range(50):
order = Order(
symbol='600519.SS',
side=np.random.choice(['buy', 'sell']),
volume=np.random.randint(100, 5000),
order_type=OrderType.LIMIT,
price=10.00 + np.random.uniform(-0.05, 0.05)
)
order.status = OrderStatus.FILLED
order.filled_volume = order.volume
order.avg_fill_price = order.price + np.random.uniform(-0.02, 0.02)
order.commission = order.volume * 0.0001
order.decision_price = 10.00
mock_orders.append(order)
# 计算指标
benchmark_prices = {'600519.SS': 10.00}
metrics = analyzer.calculate_metrics(mock_orders, benchmark_prices)
print("=== 执行质量分析 ===")
for key, value in metrics.items():
if 'bps' in key or 'slippage' in key or 'shortfall' in key:
print(f"{key}: {value:.2f}")
else:
print(f"{key}: {value}")
# 绘制分析图
analyzer.plot_execution_analysis(mock_orders)python2. 持续优化建议#
基于执行质量分析,提出以下优化建议:
- 参数调优:根据历史滑点数据调整执行算法参数
- 订单类型优化:针对不同市场环境选择最优订单类型
- 交易所选择:动态选择流动性最好的交易所
- 时间优化:避开高波动和低流动性时段
- 算法混合:根据订单特征动态切换VWAP/TWAP/POV
结论#
实盘交易中的滑点控制和订单管理是量化策略成功的关键因素。本文系统介绍了:
- 滑点测量:使用实现短缺等指标量化执行成本
- 执行算法:VWAP、TWAP、POV等算法的Python实现
- 订单优化:智能选择限价单/市价单,动态计算最优价格
- 订单路由:跨交易所智能分配订单,降低市场冲击
- 系统设计:完整的订单管理系统架构
- 绩效评估:执行质量分析和持续优化
关键要点:
- 滑点是隐蔽但致命的成本,必须系统测量和管理
- 没有万能的执行算法,需要根据市场环境和订单特征动态调整
- 订单管理不仅是技术问题,更是风险管理和成本控制的核心
- 持续的绩效评估和优化是降低执行成本的关键
通过科学系统的滑点控制和订单管理,量化策略才能真正实现从回测到实盘的平稳过渡,将理论收益转化为实际利润。
参考文献:
- Perold, A. F. (1988). The implementation shortfall: Paper versus reality. Journal of Portfolio Management, 14(3), 4-9.
- Almgren, R., & Chriss, N. (2000). Optimal execution of portfolio transactions. Journal of Risk, 3(2), 5-39.
- Kissell, R., & Glantz, M. (2003). Optimal Trading Strategies: Quantitative Approaches for Managing Market Impact and Trading Risk. AMACOM.
- Gatheral, J., & Schied, A. (2013). Optimal trade execution under geometric rough volatility. Risk, 26(5), 82-86.