股票回测零成交怎么查:沿数据、信号、目标与执行逐层定位
股票回测有净值曲线却零成交,应沿首个失效阶段查:有效行情、策略证券键、热身、非零信号、目标数量和执行许可。仅凭平直曲线,不能判断哪一层出了问题;不断降低阈值,可能只是掩盖原来真正的缺陷,同时悄悄改变策略含义。
本指南交付逐阶段定位账,包含六类独立故障和一条修正路径。标准库样例使用虚构美股及合成价格,不是真实引擎日志,也不证明CoTrading诊断功能已存在,相关能力仍为规划或待核实。结论范围限定为明确输入下的诊断分类。
先保留一次运行,再做修改
保存原配置、源码版本、输入样本、请求代码、信号工件、目标工件和可见拒绝日志,记录运行编号与时间区间。某层没有输出,就写未观察,不能推断它已经正常。没有拒单日志也不证明没有拒单,可能只是引擎没有暴露这项证据,需补最小复现才能判断。
首轮选择一只证券和一个预期机会,不要先看上千只股票的总数。每层保存输入数、输出数、首个相关日期和原因码。解释停在最早有证据的失败点,后续未知保留待查。这样修正一个阶段后,能够继续发现被它遮住的问题,而不把所有错误混在同一次猜测中。
净值文件的生成时间不是成交证据。有些系统没加载任何股票也会写初始现金快照;有些使用旧报价估值,也能画出一条线。调查对象应是哪些事件改变账户,而不是绘图函数是否成功。现金、持仓与订单要分别有记录,不能从一张图反推全部状态。
先查行情与证券身份
确认请求股票解析到预期市场,策略区间确实存在可用行。检查必需列、有限正价格、唯一有序时间戳,以及热身与绩效区间的区别。非空下载仍可能没有指定模型所需的开盘,因此“数据不为空”只是很弱的条件,不能直接证明具备可执行行情。
样例空列表返回data:no_rows;之后精确检查键US:ALFA。若传裸键ALFA,即使数值行存在,也返回signal:symbol_key。这把缺行情与接口键不匹配区分开。修复需要确认的标识映射,不是放松信号条件,更不是把所有代码批量改成相同格式就算解决。
定位账同时保留原标识与标准标识。无差别重命名可能合并股类,或隐藏错误市场路由。映射修正后,先用同一输入确认策略真的接收到数据,再扩大日期范围;否则一次改变两个原因,就无法知道是哪项修正有效,也难以解释后续复发。
热身不足与合法零信号不同
基线收盘为十、十一、十二,要求窗口三,阈值十一。若仅把窗口改成一百二十,首个失败是signal:warmup。还没形成完整窗口,与已完整计算后决定不持有,是不同状态。覆盖报告要把热身行和有效决策行分开,不能统一写成全零信号。
按既定规格补足更早行情,或明确推迟允许交易的开始日;不能为了出现成交就把一百二十日缩成三日。若每一行都在热身,这次运行根本没有产生符合规格的决策机会。对此应报告区间与窗口不匹配,而不是声称策略在样本中选择观望。
窗口完整但阈值改成十三时,最终十二不满足条件,返回signal:zero。这可能完全正确。先手算一行,核对预期运算,再决定有没有故障。严格规则在一段数据里没有机会,是合法结果。修改阈值属于新策略版本,不能借排错之名优化到刚好有交易。
非零信号还要走到可买数量
阈值十一时,最终收盘满足条件。账户预留虚构佣金一,再用可用资金除给定执行价十并向下取整。一百零一现金留下可用名义金额一百,能买十股;只有五现金时,数量为零,报告target:zero_quantity。两次信号相同,失效发生在仓位层。
因此证据应包含现金、费用预留、执行价、数量步长和目标分配。其他市场可能需要按每手数量取整,应另查真实规则,不能把本例的一股步长推广到所有股票。只看信号图会误以为执行忽略策略,实际可能从未形成正数可买计划。
提出修正前,核对账户是否真的允许碎股、杠杆或最低名义金额。它们是执行模型变化,不是通用调试开关。本例恢复已批准的一百零一现金,就能得到十股,不必修改阈值,也不需要凭空创造碎股成交。真实研究还应核对已有持仓与卖出释放资金。
最后才查执行许可
目标数量为正,但显式许可为假时,结果是execution:blocked。本例不把这个布尔值解释成某个真实市场限制。实际定位要取得日期、证券、方向、规则输入和拒绝原因,没有记录就保留未知,不能从零成交直接断言是涨停、停牌或券商故障。
Investor.gov官方订单资料区分市场、限价和止损指令。目标本身不是已成交订单,价格条件也有影响。美股限价单可能不成交;其他市场需查各自制度和历史版本,不能把所有无成交都套用一种市场规则。实际可见证据优先于经验猜测。
同时核对时间线。最后收盘才出现非零目标,数据却没有后续开盘,本来就可能没有执行机会。若策略和引擎各延迟一次,还可能把目标移出区间。先保存信号日期和计划成交日期,再判断引擎是否忽略有效订单,避免将对齐问题误诊为市场阻止。
执行故障注入表
文件为docs/growth/research/round-5/examples/R595.py,同一个确定函数每次只改变一个输入。最前面顺序是:
if not rows:
return 'data:no_rows'
if key != 'US:ALFA':
return 'signal:symbol_key'
if len(rows) < window:
return 'signal:warmup'
随后判断最终信号、可买数量与许可。运行python docs/growth/research/round-5/examples/R595.py,输出依次包含无数据、键错误、热身不足、零信号、零数量、执行阻止,以及修正后的fill:10。断言核对所有分类,并检查数据为空且许可也为假时,优先报告数据层,不把下游状态当首因。
执行阻止与普通零信号是不同机制反例:外观都零成交,前者已经有有效正目标,后者没有。本样例只证明对这些显式输入能正确分类,不能代替真实引擎流水,也不能说明一个没有提供工件的实际运行一定是哪一种原因。分类器必须接收证据,不能补造证据。
修复验收不以凑成交为目标
每次只修改已确认缺陷,重跑最小路径,再检查下一层。键修正后可能才暴露真实热身问题,应把这个顺序保留在问题记录,而不是发现后续故障就重写最初原因。最小路径到达执行后,再运行原配置,核对实际订单、现金和持仓,确认改动没有引入其他偏差。
首个失败阶段有证据、修正可复现、下游预期被观察到,才能关闭故障。若规则确实评估过且从未请求可执行仓位,合法零成交也可以关闭调查。来源、标识、窗口、数量或市场规则变化后重新检查。目标是一份解释清楚的运行,不是强迫每次回测出现交易。
下载完整示例,保存为R595.py,使用Python 3.12及以上运行python R595.py。仅使用标准库与合成数据。
修正成功后也保留定位账
每项故障保存前后对照,写明改了哪个输入,以及首个新出现的下游证据。代码映射修正后,证据可能只是生成器终于收到非空数据,还不是成交;数量修正后,应先看到正数计划,再看执行许可。这样最终成功结果不会抹掉原来确定原因的过程,后续复发也能复用同一最小样本。
多个缺陷并存时,按发现顺序报告,每次改动后重跑之前检查。新的数据源可能补齐覆盖,同时引入另一套证券键。诊断完成只对应最终保存配置,不能把修正版样例的十股成交移用于别的运行。未解释阶段继续保留,不因为已经看到一笔订单就宣布整个回测无误。
对外报告也应区分“证明原因”和“提出可能原因”。有原始行、规则输入和复现输出时,可以说明具体失败;只有图表和总成交数时,只能列下一步需要的工件。本例故意让每个原因都由显式输入控制,真实场景若拿不到这些证据,就沿同样结构补采,而不是用分类器替用户补完不存在的日志。
常见问题
是否应该一直降低阈值直到有成交?
先定位首个失效阶段。阈值变化不能修复缺数据或键错误,而且会改变策略。
没有成交能是正常结果吗?
可以,前提是有效输入已完整评估,既定规则确实从未请求可执行持仓。