第 32 课 从回测走到模拟盘¶
历史研究可以反复重算,真实的一天只能按顺序发生。模拟盘的首要任务,是证明数据、订单、状态、日志和停机流程能够在不使用真实资金的环境中连续工作。
周一下午发生了三件回测里没有的事¶
小周已经完成一项策略研究。历史数据整齐,滚动验证也按计划结束。到了第一次模拟运行的周一下午,行情接口晚了二十分钟,三十只股票缺少收盘数据;他手动重启程序后,同一批订单被生成了两次;其中一只股票恢复交易,模拟券商只成交了计划数量的一半。
回测代码没有准备这些答案。历史文件通常已经补齐,程序从头到尾一次运行,成交则由统一规则推算。真实运行面对的是不断到来的信息。数据会迟到、重复、修订或中断,订单可能被拒绝、排队、部分成交,程序也可能在任意步骤崩溃。系统重启以后,还必须知道已经处理到哪里,不能把昨天的持仓当成零,也不能把同一订单再发一次。
因此,回测通过只说明一组历史假设值得继续检查。模拟盘要回答另一组问题。今天的数据是否完整,当前状态是否可信,信号能否准时生成,目标仓位怎样变成订单,订单回报怎样改变实际持仓,异常出现时系统能否安全停下。模拟盘不使用真实资金,却应尽量按照真实时间、真实数据和真实订单状态运行。
从研究到运行需要经过哪些台阶¶
一项教学策略可以依次经过研究冻结、历史事件重放、模拟盘和影子运行。研究冻结表示特征、参数、成交假设和放弃条件暂时不再修改;历史重放按过去数据当时到达的顺序重新喂给系统;模拟盘把订单交给模拟环境;影子运行则在真实市场时钟下生成本应发送的订单,但不会触及账户。
只有在更高权限确有必要并经过充分审查时,才可能讨论极小规模、严格受限的真实运行。本手册不连接真实账户,也不把短期盈利当作升级权限的理由。每个阶段都应有明确进入条件、观察期限、退出条件和回退方式。
stateDiagram-v2
accTitle: 策略从研究到运行的分阶段路线
accDescr: 冻结后的研究先经过历史事件重放,再进入模拟盘和影子运行;任何阶段发现时间、数据、订单或风险异常,都暂停并退回研究检查
[*] --> ResearchFrozen: 冻结研究规则与版本
ResearchFrozen --> Replay: 历史事件按到达顺序重放
Replay --> Paper: 时间与状态检查通过
Replay --> ResearchFrozen: 发现数据或执行不一致
Paper --> Shadow: 模拟盘连续稳定
Paper --> Paused: 数据、订单或对账异常
Shadow --> Paused: 运行偏差超过阈值
Paused --> ResearchFrozen: 修复并重新验证
Paused --> [*]: 终止研究
每次回退都要形成事件记录。若模拟盘暴露费用远高于回测,研究者应修改执行假设并重新跑完整验证,不能只在模拟系统里悄悄调整。运行反馈会成为新的研究信息,原先测试结果也要重新标记。
研究程序与运行系统解决不同问题¶
| 历史研究常见条件 | 模拟运行必须面对的条件 |
|---|---|
| 文件中的历史通常完整且顺序确定 | 数据可能晚到、缺行、重复和修订 |
| 一次计算整个样本期 | 每个时点只能使用当时已经到达的内容 |
| 成交由回测规则统一模拟 | 订单会经历提交、接受、部分成交、拒绝和撤销 |
| 失败后可以从头重跑 | 重启时必须恢复现金、持仓和未完成订单 |
| 错误影响研究报告 | 错误可能连续产生错误订单和风险暴露 |
运行系统不必一开始就拥有庞大架构,但它必须知道自己处于什么状态。今天的数据是否已经通过检查,信号是否生成,风险检查是否通过,订单是否发送,成交回报是否完整,持仓是否对得上,都需要明确记录。模糊的“应该已经完成”无法支持故障恢复。
一个交易日应当怎样按顺序走完¶
每日流程可以从交易日历检查开始。系统确认今天是否为交易日、使用哪个时区、预期数据何时到达。数据通过门禁后才生成特征和目标仓位,目标通过交易前风险检查后才转成订单。订单回报不断更新实际持仓,收盘后再对账、归档和检查监控指标。
sequenceDiagram
accTitle: 模拟盘一个交易日的完整运行顺序
accDescr: 数据服务先发布带时间戳的行情,策略生成目标,风险模块检查订单,模拟券商返回接受、部分成交或拒绝,最后由监控完成持仓对账和异常检查
participant D as 数据服务
participant S as 策略与仓位
participant R as 风险检查
participant B as 模拟券商
participant M as 日志与监控
D-->>S: 发布行情、股票池版本与时间戳
S->>S: 校验数据并生成目标仓位
S->>R: 提交目标、当前持仓与拟发订单
R-->>S: 返回通过或具体拒绝原因
S->>B: 发送带唯一编号的订单
B-->>S: 返回接受、部分成交、成交或拒绝
S->>M: 记录信号、订单、回报、现金和持仓
M->>M: 对账,检查异常并生成日报
任何一步失败后怎样处理,都要提前写入手册。数据不完整时继续持有旧仓、停止新增风险,还是按计划减仓,取决于策略和风险情景。系统不能在错误发生以后临时猜测,也不应默默使用上一次成功结果冒充今天新信号。
数据门禁先判断今天能不能研究¶
数据门禁是一组运行前检查。它不负责预测收益,只负责回答“当前数据是否足以安全继续”。检查项包括交易日与时区、最新时间戳、预期资产数量、关键字段缺失比例、价格关系、重复行、复权因子、股票池版本和数据源延迟。
假设策略预计在 15 时 10 分收到 1,000 只股票的完整日线。到了 15 时 30 分只有 800 只。若直接在剩余股票中排名,原来处于前 10% 的定义已经变化,缺失股票也可能集中在某个行业。把缺失行填成零同样会制造虚假信号。更安全的结果是把本轮状态标记为阻止,并保存缺失清单。
可以给门禁设计三个清晰状态。READY 表示所有关键检查通过,可以继续;DEGRADED 表示存在已知但可控的轻微问题,只允许预先批准的降级动作;BLOCKED 表示停止生成新订单并通知人工。日志中只写“好像有些缺失”无法驱动确定动作。
| 检查项 | 教学阈值示例 | 失败后动作 |
|---|---|---|
| 数据更新时间 | 晚于计划时间 10 分钟 | 标记延迟,等待到截止时刻 |
| 关键资产缺失比例 | 超过 2% | 阻止本轮新订单 |
| 重复主键 | 任意日期与资产重复 | 阻止并保存重复行 |
| 价格关系 | 最高价低于最低价等异常 | 隔离异常资产,超过阈值则阻止 |
| 股票池版本 | 与当日计划版本不一致 | 停止排名并核对来源 |
表中的数字只是教学示例。实际阈值要结合数据频率、市场和策略容忍度确定,并在上线前冻结。阈值过松会放行错误,过紧会让系统频繁停摆。模拟盘正适合观察这些阈值是否可执行。
同一天重启两次,怎样避免重复下单¶
每次运行都应生成一个可以唯一识别的任务编号,通常由策略版本、交易日、调仓批次和资产组成。程序准备发送订单前,先查询这个编号是否已经存在。若已经提交,就读取原订单状态,而不是再次创建。
这种“同一请求重复执行,最终效果仍与执行一次相同”的性质叫作幂等性。名称听起来抽象,目标很实际。网络超时以后,程序不知道订单是否到达券商,它不能简单重发,也不能假设没有到达。应先用唯一编号查询或对账,再决定后续动作。
模拟盘要主动演练重启。可以让程序在生成信号后、发送订单前、订单接受后和部分成交后分别中断,再检查恢复结果。每种恢复都应保证订单不重复、持仓不丢失、日志时间连续,未确定状态会触发暂停。
目标仓位、订单与成交是三本不同的账¶
目标仓位表达策略希望持有什么。订单表达提交给交易环境的请求。成交表达市场实际接受了多少。三者经常不同,必须分别保存。
假设组合资金为 100 万元,策略目标让股票 A 占 10%,也就是 10 万元。当前已经持有 4 万元,所以计划增加 6 万元。交易单位限制可能把订单舍入到 5.8 万元;市场只成交其中 3 万元,最终持仓约为 7 万元。系统若直接把目标 10 万元写成实际持仓,后续风险和订单都会建立在错误数字上。
订单生命周期至少包括创建、提交、接受、部分成交、全部成交、撤销和拒绝。每次状态变化都带时间戳、数量、价格和原因。部分成交以后,未成交余额是否继续等待、修改价格还是撤销,也要由事先规则决定。
收盘后的对账会比较内部记录与模拟券商记录,包括现金、持仓数量、未完成订单、当日成交和费用。若任何关键数量不同,应停止新增订单,先确定权威数据源并修复差异。继续运行会让后续每笔决策叠加在错误状态上。
交易前风险检查挡住超出边界的订单¶
目标仓位形成以后,订单发送以前,还要检查单资产上限、行业上限、总风险暴露、现金缓冲、订单金额、成交参与率、停牌、价格限制和可借数量。风险检查应集中管理,每次拒绝都保存明确原因。
下面的教学函数只检查订单金额占近期日成交额的比例。输入为订单金额和参考日成交额。若参考成交额无效,或订单超过 5%,函数返回失败和原因;其他情况返回通过。运行前可以手算,10 万元订单面对 100 万元成交额,参与率为 10%,应被拒绝。
def pre_trade_check(order_value, daily_amount, max_participation=0.05):
if daily_amount <= 0:
return False, "没有可靠成交额"
participation = abs(order_value) / daily_amount
if participation > max_participation:
return False, "订单参与率超过上限"
return True, "通过"
第一项判断防止用零或负成交额做除法。abs 让买卖方向都按订单绝对规模检查。max_participation=0.05 只是默认教学阈值,正式系统应来自统一配置并留下版本,不能散落在许多函数里。
这段函数仍然省略了许多现实细节。历史日成交额未必代表今天可用流动性,大额订单还会影响价格。参与率只是风险门槛之一,不能当作精确冲击模型。模拟盘应记录订单大小与实际滑点的关系,逐步校准回测假设。
成交偏差怎样从一笔买单开始计算¶
假设策略在价格 10.00 元时决定买入 1,000 股,模拟成交均价为 10.05 元。相对决策价,实际每股多付 0.05 元,总计多付 50 元。用决策金额 10,000 元作为比较基础,偏差为 \((10.05-10.00)/10.00=0.5\%\)。
这种从决策价格到实际执行价格的损失常称为执行偏差,英文资料中经常写作 implementation shortfall。为了让买单与卖单拥有一致的好坏方向,正式计算还要考虑交易方向、未成交机会成本和费用。教学阶段可以先分别报告买单与卖单的价格差,再逐步完善。
平均 0.1% 的偏差可能掩盖少数极端订单。报告应按资产流动性、下单时段、订单规模、市场波动和买卖方向拆分,并展示分位数与最差样本。若模拟偏差持续高于回测压力假设,应先检查成交模型、数据时间和订单逻辑,再决定是否修改策略。
日志要能够重放完整的一天¶
有用的日志不只写“任务成功”或“下单失败”。每条记录应包含统一时区的时间、运行编号、策略与数据版本、输入数据截止点、信号摘要、目标仓位、订单编号、状态变化、成交回报、现金、持仓和错误详情。
完整日志允许研究者从开盘前状态开始重放。给程序相同数据和相同版本,它应产生相同目标和订单。若无法重现,需要检查随机种子、外部依赖、数据修订或没有保存的临时状态。可重放性让故障调查从猜测变成逐步比对。
日志也要避免泄露密钥和个人信息。订单编号与资产可以保存,认证令牌、券商口令和完整账户凭据不能进入普通文本日志。运行权限应遵循最小原则,模拟环境与真实环境使用完全不同的凭据和开关。
监控应分成系统、策略和模型三层¶
系统监控关注服务是否活着。数据是否按时到达,接口是否连通,任务耗时是否异常,订单拒绝是否增加,磁盘和内存是否足够。系统正常只表示程序还在运行,不代表策略处于合理状态。
策略监控关注仓位和执行。总风险暴露、行业集中、换手、现金、订单参与率、未成交数量、实际费用和执行偏差是否超过预定范围。预期换手为 20%,模拟盘突然达到 80%,即使程序没有报错,也可能是股票池、复权或目标计算发生变化。
机器学习策略还需要模型监控。特征缺失率、输入分布、预测分布、排名集中度、模型版本和训练数据截止日都要记录。若一项特征在训练期大多位于 -3 到 3,模拟期连续出现 20,可能是市场状态改变,也可能是单位或标准化错误。
运行分布逐渐离开训练分布的现象常称为漂移。输入漂移只说明数据形状变了,尚不能证明预测关系失效;预测失效也可能在输入分布看似稳定时发生。因此监控既要看特征,又要在标签成熟以后查看预测误差、排序与成本。漂移阈值触发后可以暂停、降仓或进入人工复核,不能自动宣布模型应该重新训练。
停机条件要写成数值、动作和权限¶
“出现异常就停止”无法指导值班者。停机手册需要写明触发阈值、立即动作、通知对象、证据保存、恢复条件和批准权限。数据缺失超过 5%、内部持仓与券商不一致、订单连续拒绝、滑点超过压力假设、风险暴露超限或输入出现极端漂移,都可以成为候选条件。
停止也有不同层级。最轻一级只停止新增风险,保留已有仓位;下一层取消未成交订单并逐步降仓;紧急层才可能要求快速退出。故障时无条件市价平仓可能加大冲击,所以每种动作要结合流动性和风险权衡,并在模拟环境演练。
| 触发情形 | 立即动作 | 恢复前必须完成 |
|---|---|---|
| 关键数据缺失超过阈值 | 阻止新信号和新订单 | 数据补齐、截断重算、人工确认 |
| 本地与外部持仓不一致 | 取消新增订单并冻结策略 | 完成现金、成交和持仓对账 |
| 订单拒绝连续发生 | 暂停同类订单并通知 | 查明账户、价格、数量或接口原因 |
| 执行偏差持续超限 | 降低订单规模或暂停调仓 | 比较回测假设和实际执行分布 |
| 风险暴露超过硬上限 | 禁止继续增加暴露 | 制定受控降仓路径并批准 |
自动恢复需要格外谨慎。如果数据源持续异常,程序每隔五分钟自动恢复并重复下单,故障会被放大。恢复通常应先重放失败时段、通过门禁、完成对账,再由具有权限的人批准。恢复时间和依据也要写入日志。
模拟盘怎样评价才不会变成短期看盈亏¶
模拟盘连续三天盈利不能证明策略有效,连续三天亏损也不一定证明研究失败。短期收益噪声很大,模拟成交又未必完整反映真实排队和冲击。早期更重要的指标,是数据准时率、任务成功率、重复订单次数、拒绝与部分成交频率、对账差异、换手偏差和停机演练结果。
模拟期应覆盖正常交易日,也要主动制造异常。延迟一批数据、删掉若干字段、重复发送同一事件、让订单部分成交、在提交后中断程序、修改股票池版本。系统是否按手册进入正确状态,比一条平滑净值更能证明运行质量。
当标签陆续成熟后,再比较模拟信号与冻结研究的预期。检查同一输入是否得到同一特征和目标,真实到达时间是否晚于回测假设,成交偏差是否落在压力范围,策略分布是否发生变化。任何持续差异都要拆成数据、信号、订单、成交、费用和修订来源。
一项教学模拟盘可以把通过条件写成连续二十个计划交易日无重复订单、关键数据门禁全部留下记录、所有持仓差异当天完成解释、至少完成四类故障演练、换手与成本偏差在预设范围。具体数字需要根据任务调整,关键是提前写好,避免看完结果后移动标准。
从小规模权限开始理解容量¶
即使模拟盘稳定,规模扩大也不能按比例外推。订单变大以后,成交参与率、排队时间、市场冲击、未成交概率和退出天数都会改变。原来 10 万元订单能够在一分钟内完成,不代表 1,000 万元也能以同样价格完成。
容量研究要把持仓转换成平均日成交额占比,估计不同资产退出所需时间,并在波动放大和流动性收缩情景下重新计算。实际权限与资金决策属于更高风险范围,需要专业审查和明确授权。本手册到模拟盘与影子运行为止,重点是教会读者识别运行问题,而非鼓励接入真实资金。
容易弄错的地方¶
| 运行中的缺口 | 为什么会隐藏风险 | 应留下什么证据 |
|---|---|---|
| 模拟盘只保存理论信号 | 拒绝、等待、部分成交和费用全部消失 | 目标、订单、状态变化、实际成交和未成交原因 |
| 数据缺失时沿用昨日信号 | 旧判断会被伪装成今天重新计算的结果 | 数据新鲜度、阻止原因和恢复时刻 |
| 研究与运行各写一套特征 | 同名策略可能产生不同输入和信号 | 共享版本、每日对照和截断测试 |
| 重启后直接再次发送订单 | 网络超时可能造成重复成交 | 唯一运行编号、订单查询和幂等检查 |
| 停机条件只写“发生异常” | 值班者不知道何时停、怎样停、谁能恢复 | 数值阈值、动作层级、通知对象和批准流程 |
| 用三天模拟收益决定是否上线 | 样本太少,也未覆盖执行与故障 | 过程指标、异常演练和预先写好的通过条件 |
一分钟自测¶
策略目标持仓为 100 股,订单只成交 60 股。系统下一轮应把持仓记作多少?如果本地记录显示 100 股,应该继续下单还是先对账?
查看答案
实际持仓应按成交事实记作 60 股。若本地记录与外部回报不一致,应暂停新增订单并先完成对账,不能用目标数量覆盖实际状态。本课术语¶
| 词语 | 先这样理解 |
|---|---|
| 历史重放 | 按数据当时到达的顺序重新运行过去事件 |
| 模拟盘 | 不使用真实资金、按真实时间演练数据与订单流程 |
| 影子运行 | 生成真实时钟下的计划订单,但不提交到账户 |
| 数据门禁 | 数据不完整或异常时阻止流程继续的检查 |
| 幂等性 | 同一请求重复执行时,效果仍与执行一次一致 |
| 对账 | 核对目标、订单、成交、现金和持仓 |
| 执行偏差 | 决策价格与实际成交结果之间的成本差异 |
| 漂移 | 运行数据或模型关系逐渐离开训练状态 |
| 停机条件 | 达到明确故障或风险阈值时采取暂停动作的规则 |
| 回滚 | 恢复到已知可靠的数据、模型或程序版本 |
课后练习¶
-
基础理解。 模拟盘最先验证的是收益,还是运行流程?请列出至少五个过程指标。
提示与答案
最先验证数据、定时、信号、订单、成交、日志、对账和故障处理。过程指标可包括数据准时率、任务成功率、重复订单、拒绝率、部分成交率、对账差异和换手偏差。 -
对账计算。 目标持仓 10 万元,当前持仓 4 万元,计划订单 6 万元,实际只成交 3 万元。忽略价格变化后,实际持仓是多少,与目标相差多少?
提示与答案
实际持仓为 4 万加 3 万,等于 7 万元。与 10 万元目标相差 3 万元。 -
排错。 数据行数突然少了一半,程序用零填满并继续排名。应触发什么状态,为什么?
提示与答案
应触发数据门禁的阻止状态,停止新信号和订单。用零填充会改变排名和股票池含义,也会把未知数据伪装成真实数值。 -
动手。 为毕业策略写三项停机条件。每项包含数值阈值、立即动作、通知对象和恢复证据,并设计一次模拟故障演练。
提示与答案
可选择数据延迟、订单拒绝、持仓不一致或滑点超限。恢复至少包含排查、重放、对账、门禁通过和人工批准,不能只写“问题解决后恢复”。 -
开放思考。 为什么规模扩大后,不能按原模拟盘的收益和滑点线性推算?如果必须评估容量,你会记录哪些数据?
评价要点
更大订单会改变参与率、排队、市场冲击、未成交和退出时间。应记录订单占成交额比例、盘口或成交量、实际滑点、部分成交、波动状态、持仓集中和极端情景下的退出天数。
模拟盘的一天从数据门禁开始,经过特征、目标、风险检查、订单和成交,收盘后还要对账与查看监控。任何一步的状态若没有保存,重启就可能重复下单。为数据缺失、持仓不一致和执行偏差写出明确停机动作,模拟盘才真正承担起检查系统的工作。