第二十讲:回测系统设计

回测系统,说白了就是量化策略的「时光机」。你写了个策略,能不能赚钱?回测告诉你。但这里有个坑——回测漂亮不代表实盘能打。我见过太多团队,回测曲线美如画,一上实盘就崩盘。今天我们就聊聊怎么设计一个靠谱的回测系统。

一、事件驱动回测:让策略「活」起来

我个人习惯把回测引擎分成两类:向量化回测和事件驱动回测。向量化回测快,但不够真实。事件驱动回测慢,但更贴近实盘。

什么叫事件驱动?就是模拟真实市场的消息流。比如:

  • 收到一条成交回报
  • 收到一条行情Tick
  • 收到一条订单状态变更

每个事件触发一个回调函数。你的策略就挂在这些回调上。

核心架构:

class EventEngine:
    def __init__(self):
        self.queue = Queue()
        self.handlers = {}
    
    def register(self, event_type, handler):
        self.handlers[event_type] = handler
    
    def run(self):
        while True:
            event = self.queue.get()
            handler = self.handlers.get(event.type)
            if handler:
                handler(event)

嗯,这里要注意:事件队列不能阻塞。我曾经在一个项目中,因为事件处理太慢,导致回测结果严重失真。后来加了异步处理,才解决问题。

二、多资产回测:别只盯着一个品种

做市商系统很少只做一个品种。你想想看,一个结构化产品可能挂钩5个标的,每个标的又有多个期限。这时候单资产回测就不够用了。

多资产回测的核心难点在于:

  • 时间对齐:不同资产交易时间不同,怎么对齐?
  • 资金分配:总资金怎么分配到各个资产上?
  • 相关性处理:资产之间的相关性怎么模拟?

我建议的做法是:

  1. 统一时间戳精度到毫秒级
  2. 用「资金管理器」统一管理头寸
  3. 引入协方差矩阵做联合模拟

避坑指南:我曾经遇到过一个坑——不同交易所的节假日不同。比如A股休市,港股还在交易。这时候你的多资产回测必须考虑「部分资产停牌」的情况。否则回测结果会虚高。

三、市场冲击模型:大单的隐形杀手

很多新手做回测,假设「想买就能买,想卖就能卖」。这是最大的幻觉。真实市场中,你的大单会推动价格变化。这就是市场冲击。

常用的冲击模型有几种:

模型名称 核心公式 适用场景
线性冲击模型 ΔP = λ × Q 流动性较好的市场
平方根冲击模型 ΔP = λ × √Q 流动性一般的市场
Almgren-Chriss模型 ΔP = α × Q + β × σ × √(Q/V) 最接近真实市场

我个人比较推荐Almgren-Chriss模型。它同时考虑了永久冲击和临时冲击。我在做期权做市商系统时,用这个模型校准过冲击参数,回测结果和实盘偏差控制在5%以内。

注意:冲击模型的参数需要定期校准。市场环境变了,参数也要跟着变。我见过有人一套参数用三年,结果回测越来越不准。

四、回测过拟合防范:别被漂亮曲线骗了

这是回测系统里最容易被忽视的问题。你调参数、改策略,回测曲线越来越漂亮。但这是真的吗?

过拟合的典型症状:

  • 回测夏普比率超过3
  • 策略参数极其敏感
  • 样本外测试一塌糊涂

怎么防范?我分享几个实战经验:

  1. 交叉验证:把数据分成训练集、验证集、测试集。训练集调参,验证集选模型,测试集做最终评估。
  2. 参数稳定性测试:稍微改变参数,看策略表现是否剧烈波动。如果是,说明过拟合了。
  3. 蒙特卡洛模拟:对回测结果做1000次随机扰动,看收益分布是否稳定。

一个实用的过拟合检测方法:

def deflated_sharpe_ratio(sharpe, T, N):
    """
    计算缩水夏普比率
    sharpe: 回测夏普
    T: 样本数量
    N: 尝试的策略数量
    """
    import scipy.stats as stats
    E_max = stats.norm.ppf(1 - 1/N)
    V_max = stats.norm.ppf(1 - 1/N * np.exp(-1)) - E_max
    return (sharpe - E_max) / np.sqrt(V_max / T)

这个公式可以告诉你:在尝试了N个策略后,你的回测夏普有多少是「运气成分」。如果缩水后的夏普低于1,那基本可以判定过拟合了。

五、回测系统的整体架构

说了这么多,我们来看看回测系统的整体架构。下面这张图是我在实际项目中总结出来的:

回测系统架构图 数据层 历史行情数据 因子数据 事件日志 引擎层 事件驱动引擎 多资产调度器 市场冲击模拟器 过拟合检测器 策略层 信号生成 风控模块 订单管理 输出层:绩效报告、风险指标、交易日志

这张图展示了回测系统的四个层次。数据层负责数据清洗和对齐,引擎层负责事件调度和模拟,策略层跑你的交易逻辑,输出层生成报告。每一层都可以独立替换,方便做单元测试。

我的经验:回测系统一定要做「回放模式」。就是逐笔回放历史数据,看策略在每个时间点的决策。这比看最终曲线有用得多。我曾经靠这个发现了一个隐藏的bug——策略在收盘前最后一秒还在下单,而实盘根本来不及成交。

好了,回测系统设计就聊到这里。记住一句话:回测是用来发现问题的,不是用来证明策略牛逼的。保持怀疑,多问几个「为什么」,你的回测系统才能真正帮到你。

无相订单流研究社 微信Lucian808555