21、系统测试:单元测试、集成测试、压力测试、模拟盘测试

做市系统写完了,代码能跑起来,就万事大吉了?

说实话,我见过太多团队,代码写完直接上实盘,结果被行情一冲就崩了。我自己早期也吃过这个亏——一个订单管理的bug,让系统在盘口剧烈波动时重复撤单,亏了不少手续费。从那以后,我对测试这件事,再也不敢马虎。

今天我们就聊聊做市系统的测试。说白了,就是四个层次:单元测试、集成测试、压力测试、模拟盘测试。每一层都有它的意义,缺一不可。

核心观点:测试不是浪费时间,而是保护你的资金安全。一个没有经过充分测试的做市系统,本质上就是在赌运气。

21.1 单元测试:把每个零件都检查一遍

单元测试,就是测试系统里最小的可测试单元。比如一个计算订单价格的函数、一个校验参数的模块、一个风控规则。

我个人习惯,每个核心函数都要写单元测试。为什么?因为做市系统里,很多逻辑是环环相扣的。一个函数算错了价格,后面所有逻辑都会跟着错。

哪些东西必须测?

  • 价格计算函数:比如根据盘口数据计算最优报价,要测各种边界情况
  • 订单管理模块:创建订单、取消订单、查询订单状态,每个操作都要验证
  • 风控规则:最大持仓限制、最大订单金额、最大撤单频率,这些规则必须准确
  • 数据解析模块:行情数据、成交回报,格式对不对,字段全不全

我的小技巧:写单元测试时,不要只测正常情况。多想想「如果行情数据突然为空怎么办?」「如果交易所返回了错误码怎么办?」。这些异常情况,才是真正容易出bug的地方。

举个例子,一个简单的价格计算函数测试:

// 测试:根据盘口计算最优买价
function test_calculate_bid_price() {
    // 正常情况
    let orderbook = { bids: [[100, 10], [99, 20]], asks: [[101, 15], [102, 10]] };
    let price = calculate_bid_price(orderbook, 5);
    assert_equal(price, 100);  // 应该取最优买价
    
    // 盘口为空的情况
    orderbook = { bids: [], asks: [] };
    price = calculate_bid_price(orderbook, 5);
    assert_equal(price, null);  // 应该返回null
    
    // 盘口深度不足的情况
    orderbook = { bids: [[100, 1]], asks: [[101, 15]] };
    price = calculate_bid_price(orderbook, 5);
    assert_equal(price, null);  // 深度不够,不报价
}

21.2 集成测试:看看零件能不能配合工作

单元测试过了,不代表系统就能正常工作。为什么?因为模块之间要配合。比如行情模块把数据传给策略模块,策略模块再传给订单模块,中间任何一个环节出问题,整个链条就断了。

集成测试,就是把这些模块串起来,看看它们能不能协同工作。

集成测试的重点:

  • 数据流是否通畅:行情数据能不能正确传递给策略模块
  • 接口是否匹配:模块之间的输入输出格式是否一致
  • 时序是否正确:先收到行情,再计算策略,最后下单,这个顺序不能乱
  • 错误处理是否到位:一个模块出错了,其他模块能不能正确处理

注意:集成测试最容易发现「接口不匹配」的问题。我曾经遇到过一个情况:行情模块返回的价格是字符串类型,但策略模块期望的是浮点数。单元测试各自都过了,但一集成就报错。这种问题,集成测试一跑就能发现。

21.3 压力测试:看看系统能扛多大压力

做市系统,最怕的就是行情剧烈波动。平时风平浪静,系统跑得稳稳的。但一旦行情爆发,订单量暴增,系统可能就扛不住了。

压力测试,就是模拟极端行情,看看系统能不能撑住。

压力测试要测什么?

测试项 说明 目标
高并发订单 模拟大量订单同时到达 系统不崩溃,订单不丢失
高频行情 模拟行情数据快速更新 策略能及时响应,不延迟
网络延迟 模拟网络不稳定、延迟高 系统能正确处理超时和重连
资源耗尽 模拟内存、CPU、连接数耗尽 系统有保护机制,不崩溃

我个人习惯,压力测试要跑到正常负载的 5-10倍。比如平时每秒处理100笔订单,那就压到每秒500-1000笔。只有这样才能发现系统的瓶颈在哪里。

避坑指南:我曾经压测时发现,系统在每秒300笔订单时还能正常处理,但到了500笔时,内存占用突然飙升。后来一查,是某个缓存模块没有设置上限,导致数据越积越多。这种问题,不压到极限是发现不了的。

21.4 模拟盘测试:在真实环境中跑一遍

单元测试、集成测试、压力测试都过了,是不是就可以上实盘了?

别急,还有最后一步:模拟盘测试

模拟盘测试,就是把系统接入交易所的模拟环境(或者用历史数据回放),用真实的市场数据来跑。这时候,系统会像实盘一样运行,但不会产生真实的交易。

模拟盘测试的价值:

  • 验证策略逻辑:在真实行情下,策略能不能按预期运行
  • 检查订单流程:从下单到成交到回报,整个流程是否顺畅
  • 发现隐藏问题:有些问题在模拟环境中不会出现,但在真实行情下就会暴露
  • 积累运行数据:记录系统的运行日志,方便后续分析和优化

我的建议:模拟盘测试至少跑 1-2周。不要只跑一两天就急着上实盘。因为有些问题,比如周末的行情、月末的结算、节假日的特殊规则,只有跑足够长的时间才能遇到。

21.5 测试流程总结

这四个层次的测试,不是互相替代的关系,而是层层递进的关系。我习惯用下面这张图来表示:

做市系统测试层次 单元测试 测试每个函数、每个模块的正确性 集成测试 测试模块之间的协作和数据流 压力测试 测试系统在高负载下的稳定性和性能 模拟盘测试 在真实市场环境中验证系统 基础 最终验证

你看,从单元测试到模拟盘测试,是一个逐步递进的过程。每一层都解决了不同的问题,每一层都不可或缺。

最后提醒一句:不要跳过任何一层测试。我见过有人觉得「单元测试太麻烦,直接上模拟盘吧」,结果模拟盘跑了一周,发现一个基础函数算错了,所有数据都得重来。嗯,这种教训,一次就够了。


交易系统化学习资料 微信Strategy888888