3、回测系统搭建:回测框架选型、数据准备、模拟撮合引擎设计
好,咱们进入第三章。回测系统,说白了就是你的策略实验室。没有它,你所有的参数调优都是闭着眼睛开车。我个人习惯把回测系统拆成三块:框架选型、数据准备、撮合引擎。一块一块来聊。
3.1 回测框架选型:别盲目追新,合适最重要
市面上回测框架不少,我这些年用过不下七八个。踩过坑,也捡过宝。选框架这事,没有银弹。
主流框架对比
| 框架 | 语言 | 适合场景 | 我的评价 |
|---|---|---|---|
| Backtrader | Python | 股票、期货、简单策略 | 入门快,文档全,但性能一般 |
| Zipline | Python | A股、美股、学术研究 | Quantopian遗产,生态好但维护慢 |
| vn.py | Python | 期货、CTA、实盘对接 | 国内最强,但学习曲线陡 |
| 自研框架 | 任意 | 高频、复杂撮合逻辑 | 灵活但开发成本高 |
我个人建议:做市商策略,优先考虑自研或基于vn.py二次开发。为什么?因为市商策略对撮合逻辑的精度要求极高,通用框架往往简化了订单簿和成交细节。
3.2 数据准备:垃圾进,垃圾出
回测的命根子就是数据。数据不对,后面全是白费功夫。我见过太多人花三个月调参数,最后发现数据里有个跳空缺口没处理。
数据源选择
- 交易所官方数据:最可靠,但获取门槛高,通常需要付费或API权限
- 第三方数据商:如Wind、聚宽、Tushare,覆盖全但可能有延迟
- 自建爬虫:灵活但维护成本高,容易被封
数据清洗要点
嗯,这里要注意几个坑:
- 缺失值处理:不要简单填充。我曾经用前值填充,结果把一次熔断行情给填平了,回测结果虚高。
- 复权处理:做市商策略建议用后复权,因为前复权会扭曲历史价格。
- 时间对齐:不同交易所的撮合时间不同,比如币圈是7x24,A股有午休。对齐不好,你的买卖信号会错位。
3.3 模拟撮合引擎设计:核心中的核心
撮合引擎,说白了就是模拟「你的订单怎么被市场吃掉」。市商策略的成败,很大程度上取决于撮合引擎的逼真程度。
三种撮合模式
| 模式 | 原理 | 适用场景 | 缺点 |
|---|---|---|---|
| Tick级撮合 | 逐笔成交,完全复刻订单簿 | 高频、做市商策略 | 数据量大,回测慢 |
| K线级撮合 | 用OHLCV模拟成交 | 中低频、趋势策略 | 精度低,忽略滑点 |
| 事件驱动撮合 | 按订单簿快照模拟 | 中高频、兼顾精度和速度 | 实现复杂 |
我个人强烈建议:做市商策略至少用事件驱动撮合。Tick级虽然最准,但数据量太大,回测一次可能要跑几个小时。事件驱动能在精度和速度之间取得平衡。
核心代码示例:一个简化的订单簿撮合
class OrderBook:
def __init__(self):
self.bids = [] # 买单队列,按价格降序
self.asks = [] # 卖单队列,按价格升序
def match_order(self, order):
"""模拟订单簿撮合"""
if order.side == 'buy':
# 吃卖单
while order.remaining > 0 and self.asks:
best_ask = self.asks[0]
if order.price < best_ask.price:
break # 价格不够,吃不动了
trade_qty = min(order.remaining, best_ask.quantity)
trade_price = best_ask.price
# 记录成交
self.record_trade(order, best_ask, trade_qty, trade_price)
order.remaining -= trade_qty
best_ask.quantity -= trade_qty
if best_ask.quantity == 0:
self.asks.pop(0)
else:
# 吃买单,逻辑对称
pass
滑点模型
做市商策略最怕的就是滑点。你想想看,你挂单在买一,结果一个大单砸下来,你的单子被吃掉了,但成交价可能比预期差了好几个tick。
我常用的滑点模型有两种:
- 固定滑点:每笔成交加固定tick数,简单粗暴
- 流动性滑点:根据订单簿深度动态计算,更真实
举个例子:如果订单簿买一有100个币,卖一有50个币。你下了一个80个币的卖单,那前50个币按卖一成交,后30个币就要吃卖二甚至卖三的价。这个滑点就是动态的。
3.4 回测系统的验证与调试
系统搭完了,别急着跑参数。先做一件事:回测复现。
找一段历史行情,手动算一笔交易的成交价和滑点,然后跟回测系统的输出对比。如果对不上,说明你的撮合引擎或者数据有问题。
我曾经花了一周时间,发现回测系统里一个浮点数精度问题——Python的float在累加时会有微小误差,导致订单簿的累计数量差了0.0001个币。这个误差在单笔交易里可以忽略,但跑100万笔交易后,误差累积到足以影响策略评价。
解决方案?用Decimal代替float,或者用整数表示价格和数量(比如用最小tick的整数倍)。
好了,回测系统搭建就聊这么多。下一章咱们进入参数调优的核心——如何设计你的参数搜索空间。到时候我会分享一个我压箱底的「网格搜索+贝叶斯优化」混合策略,保证让你眼前一亮。