跳到正文

研究指南

股票策略开发

同一股票策略代码为什么输出不同:排查模型、日期和隐藏数据

固定规则股票策略应披露所有能改变输出的输入。价格与配置相同,函数仍可能读取当前时钟、全局随机数、环境、网络或模型。先在函数边界盘点并阻止这些依赖,再核固定夹具的重复信号。参数列表看起来只有行情,不代表函数真的只由行情决定。

本题隔离单个合成信号函数,不沿整个回测的数据、配置、成交和报告层查首差。CoTrading依赖审计仍为规划或待核实。样例不连接网络和模型,也不把一致性说成历史资料正确或策略盈利。它交付的是可枚举依赖与实际阻止证据,而不是通用代码安全沙箱。

盘点实际查找位置

读源码列外部读取、模块状态、时间、随机与模型包装函数。每项保存查找命名空间、用途、版本及是否属于固定历史规则。函数内部读取全局对象时,签名不是完整输入清单。导入别名、默认表达式和缓存也可能影响调用,不能只搜索一个函数名就宣称全部排除。

模型帮助写代码与模型逐期决策分开。前者可生成确定函数,后者每次调用的响应、提示和上下文都成为运行输入。不能因为客户端用Python包住,就称第二种为纯价格固定规则。需要哪种架构先讲清,再选择对应复现方式,不把未保存模型回答当可随时重建历史事实。

本夹具模型包装器只抛无害哨兵异常,不是真实客户端。网络控制使用故意无效示例地址,并在调用前替换。这样能发现禁止行为,不发外部请求、不用凭证。输出如果写“模型被阻止”,含义仅限这个显式包装点,不表示测试过所有供应商或所有可能调用路径。

从声明纯函数开始

批准函数只收完整收盘,当前高于含当前及前两条均值为一,前两条零。十、十、十二得到[0,0,1]。没有当前时间、随机、环境或外部资料。重复调用输入相同得到同序列,但这条观察单独不充分,因为时钟可能短时间没跨边界,缓存也可能掩盖依赖。

因此同时做依赖阻止和受控变化。真实实现若会改输入,应保留前后快照;签名不变也不能防止对象或模块积累状态。本例列表推导产生新输出,没有跨调用策略实例。固定初态是复现契约一部分,不能只固定价格而让旧状态不受控。

测试目标不是让所有函数都无状态,而是任何必要状态必须被声明、保存和重建。如果持仓是规则输入,就从历史账户传入;如果某个日期影响行为,就来自历史会话,不读取今天。依赖归属明确,才有条件判断差异应由策略解释还是属于实现故障。

阻止列举的外部点

Python unittest.mock文档介绍替换被查找对象并检查调用。脚本替换所引用时钟、模块随机、环境读取、URL打开器及合成模型包装器,每个一调用就抛异常。不是等网络自然失败,再凭没有报错推断代码未联网。

批准函数在替换范围内运行两次,仍须返回[0,0,1],全部mock均未调用。证明被执行路径不依赖这五项,比只看重复相等更有力。但它仍是已枚举查找点测试,不能拦截任意生成代码的所有潜在能力,也不应被描述为隔离运行不可信程序的安全系统。

必须在对象真正查找处替换。若函数提前导入另一别名,只补原模块可能绕过;盘点别名并替换正确命名空间。实际审阅发现未覆盖点时保留清单,不因为主体路径通过就删除。否则报告的“禁止网络”与实际仅禁止一个API会产生重要范围差异。

检测器也要有故意违规控制

五个控制函数各读取一类隐藏输入:当前时钟、共享随机、夹具环境键、被替换网络打开器和模型哨兵。每个必须抛对应阻止异常,记录函数名及原因。控制悄悄通过,说明补丁位置或检测器不完整,不能把没有看到异常当成更稳健。

保留已知失败控制,才能区分纯函数真无调用与测试根本没观察到调用。环境例不读.env或用户秘密,只使用合成键与替身;网络和模型在真实请求前失败。不能说验证过供应商中断,也不能把一个mock响应一致当成真实模型服务可复现证据。

这也是本题不同于整次运行定位之处:测试范围是一个函数的外部输入边界,不比较行情文件、撮合记录和最终报表。整次运行差异可以另查,但不能用这里一个绿色纯函数结果跳过下游检查,也不能把多个层面的未知都笼统归为模型随机。

价格不变,受控时钟改变

阻止测试之外,通过替身让时钟分别返回零和一,时钟依赖函数在同样收盘下输出全零与全一。直接证明结果由未声明运行值改变,不是市场噪声,也不是订单匹配差异。根因已隔离,修复应删除依赖、显式传历史时间,或重新定义保存时间输入的规则。

不能只重跑直到两次碰巧相同。合理会话时间来自历史数据契约,今天墙上时钟通常不属于历史价格比较器。修复改变的是输入所有权,不仅仅是加随机种子或吞掉异常。若时钟确实用于日志且不影响信号,也应把日志作用与决策作用分开,避免过度归因。

必要随机性明确管理

Python random官方文档区分共享状态与本地生成器并说明种子。本例每次三次抽样都新建一个种子七的本地生成器,两序列相等且不只有一个重复值。这只是声明复现方式,不是向原纯规则添加随机性的理由。

确实需要随机时保存算法、种子、初始化点和解释器依赖版本。固定种子控制不了模型服务、外部修订和时钟,所以不替代依赖表。每次独立运行重置一个本地实例,与每次抽样前都重置不同;后者只重复首值,共享实例跨运行又让调用顺序成为隐藏状态,均需有意选择。

执行函数隔离包

下载完整示例,保存R581.py,用Python 3.12及以上运行python R581.py。仅标准库和合成输入,源文件docs/growth/research/round-5/examples/R581.py不接触实际模型与网络。异常发生前就截住列举调用,不执行真实外部动作。

断言核纯信号重复一致、禁止点未调用、五个控制被检出、时钟输出不同、本地种子序列一致。输出声明范围,不把依赖隔离当完整回测或安全边界。报告应同时含通过主体和失败控制,否则读者无法确认测试本身确实能观察到它声称禁止的行为。

交付有限且可用的结论

源码版本、声明输入、依赖表、替换位置、运行版本和真实输出一起归档。列未测分支、缓存和别名,单分支通过不删除未解决项。修复后重跑纯夹具与控制,再根据需要做时间泄漏和整次运行复现,不能把全部验证压成一句固定种子已设置。

完成条件是被测试固定规则函数从声明输入完成计算,禁止列举点可被发现,未测范围清楚。若后来加入外部模型、时间或文件,就创建新依赖版本并补样例;旧绿色只属于旧边界。这样一致性成为可以解释的证据,而不是把两次相同输出当成对任何未来变更的保证。

阻止范围从函数调用开始,不证明任意模块在较早导入时没有外部动作。导入期执行需另审并保存该阶段证据,不能把这里五个控制失败当成整个加载链无副作用。同样,未列文件读取和缓存别名不会因为原API被替换就自动拦截;实际盘点发现什么,报告就保留什么范围,不向安全沙箱结论升级。

有用交接应列已观察查找点、故意违规控制和仍未覆盖来源三部分。新增依赖先进入清单,再进入声称固定规则的实现,随后补对应阻止和受控变化。否则后续加入一个快捷模型调用,旧测试也许仍绿,却验证的是过时边界。复现声明跟随源码和依赖版本,才能持续准确,而不是首次通过后永久沿用。

常见问题

用模型写代码会让策略必然不确定吗?

不一定,辅助创作与运行时模型调用是不同依赖。

两次信号相同就没有隐藏输入吗?

不能,需要盘点、受控变化和定点阻止共同检查。

相关阅读