本地股票数据怎么接入回测:检查行情到data_map的转换
本地股票数据只有在下游能按预期字段、顺序和单位读取时,才准备好进入回测。清洗后的CSV与“证券标识到带索引行情表”的映射不是同一个对象。应在两者之间建立范围明确的适配层,先用最小读取器验证输出,再启动策略逻辑;不能等策略报错后才猜输入结构。
本文实际验证标准库形式的数据交接,同时说明静态检查过的Vibe参考代码还需要哪一道pandas边界。样例不导入Vibe、不运行回测,也不验证CoTrading集成。它证明转换与拒绝规则能执行,不证明产品加载器已经可用,更不评价策略收益。真实引擎集成还需要下文列出的单独检查。
先写清消费者要求什么对象
本文静态查看的参考接口通过SignalEngine.generate(data_map)接收逐证券数据,加载协议返回证券到pandas DataFrame的字典。这只是代码接口证据,不说明任意本地文件加载器已注册、可用或经过真实运行。接入前必须查看自己所用版本的接口,而不是只复制变量名。
独立样例中,每个证券映射到日期与行情字典组成的序列。行情字典包含小写open、high、low、close、volume。同一证券日期唯一,转换后递增;整个批次采用一个币种。适配层直接拒绝混币种,不因为价格看起来都像普通数字就认定能够合并记账。
| 边界 | 需要保留的证据 |
|---|---|
| 文件到标准行 | 已接受字段、类型、币种及复权元数据 |
| 标准行到逐股对象 | 行数一致、日期唯一、次序递增 |
| 对象到真实引擎 | DataFrame类型、索引、列和加载注册 |
| 策略运行 | 另外验证的执行行为 |
行转换器通过,仍可能在引擎入口类型不匹配;DataFrame结构被接受,也可能成交量单位不对。两类检查都要存在。把元数据放到对象里,也不意味着下游真的读取或强制执行这些元数据,需要核对消费者如何使用。
分组之前验证身份、单位和日期
为每只股票保留带市场标识与声明报价币种。开高低收使用一致的原始或复权口径,来源记录保留该选择;不要把复权收盘与原始最高最低直接拼起来。成交量另存单位,不能从整数外观推断是股、手还是金额。本例统一CNY与原始股价,不涉及汇率转换。
两条AAA输入故意倒序,2026年10月20日在前、19日在后。两日开盘10、最高12、最低9、成交量1000;20日收盘11,19日收盘10。适配器解析ISO日期、转换数字并按日期排序。Python datetime文档支持日期解析用法;日级日期测试并没有解决日内时区、夏令时和交易时段归属。
逐行检查五个数值字段有限、价格为正、成交量非负,且最高最低包住开盘与收盘。缺必需字段直接报错。输入约定允许无序,因此可以排序;重复日期没有商定覆盖优先级,因此拒绝。排序不能代替唯一性检查,一条时间轴即使递增不减,仍可能包含重复日期。
构造数据对象后再读回来
核心转换只对已验证行情分组,并返回新的有序结构,不在准备过程中修改调用者原始输入。生产实现可以把验证与构造分为两步,但两步必须使用同一组已接受记录。
output = {}
for row in rows:
symbol, day = row["symbol"], date.fromisoformat(row["date"])
bars = output.setdefault(symbol, {})
if day in bars:
raise ValueError("duplicate_date")
bar = {key: D(str(row[key]))
for key in ("open", "high", "low", "close", "volume")}
bars[day] = bar
data_map = {symbol: [(day.isoformat(), bars[day]) for day in sorted(bars)]
for symbol, bars in output.items()}
完整标准库文件docs/growth/research/round-5/examples/R538.py包含所有检查。实际执行转换后读取收盘序列,断言是[10, 11]。输出记录AAA、两行、起日2026-10-19、末日2026-10-20。另外三组注入输入分别被重复日期、混币种和缺close阻断,说明故障在策略之前被识别。
下载完整示例。使用Python 3.12+,仅需标准库,全部为合成数据;下载后运行python R538.py。
对账应发生在任何后续筛选之前:本例两条已接受输入变为两条输出。未来适配器如果主动丢行,要交付丢行原因和数量,不能称输入原样交接。再抽查第一和最后一根行情,对比价格与原始标准行。只验证对象存在或列名正确,会漏掉排序后价格错位这类错误。
明确跨越pandas边界的额外步骤
真实消费者若要求pandas,就不能把标准库序列直接传进去。应从已验证行情记录构造DataFrame,用日期构造时间索引,显式选择OHLCV列,并转换成消费者支持的数值类型。DataFrame.from_records官方参考说明记录转换,DatetimeIndex官方参考说明日期索引对象。文档解释构造方法,不替代目标引擎集成测试。
这一步要再次断言列集合、支持类型、索引唯一递增、行数未变,并保存币种、成交单位、复权和来源修订。若把Decimal转成浮点,应检查数值是否仍在允许误差范围,不能因类型转换就放弃价格核对。时间索引的日级和日内约定也应分别检查。
本标准库样例没有实际执行pandas构造,也没有注册真实加载器。使用参考引擎前,必须另做集成:由选定加载器返回真实DataFrame,再让最小只读消费者读取同样两日和两个收盘价,比较行数、列与范围。本文通过只是前置方法验证,不应声称额外集成已经完成。
拦住策略代码无法修复的输入错误
不同机制反例是在CNY批次里增加USD行。它的所有价格都可能有效,日期也可能唯一,但单币种记账消费者没有定义好的汇率层,就不能将它与CNY合并。适配器在分组前拒绝整个混合批次。把数字转成浮点或按比例缩放到相近区间,都无法修复金融计量不一致。
重复日期针对身份与优先级冲突,缺收盘针对结构完整性,混币种针对记账口径。错误分别输出,数据负责人才能知道要解决来源冲突、修字段映射还是设计汇率支持。不要为满足数字列要求把缺收盘填零,也不要让策略自己猜哪条重复记录更可信。
交付适配器版本、输入快照、逐股对账表、拒绝结果与未完成集成项。加载接口、依赖版本、时区约定或来源格式变化后重新验收。消费者真正通过结构与语义检查后,才有明确输入可用于策略测试;数据准备本身并没有覆盖成交成本、市场规则或盈利能力。
保存逐股交接验收记录
对每只证券记录输入行数、适配后行数、首末日期、必需列检查、声明币种和成交单位。最小读取器要请求最终策略真正需要的字段;策略另需VWAP或基本面时,不能为了导入成功就生成一列零值或未经说明的近似值,而要扩大输入约定,取得对应观测或明确指定计算方法。字段存在与数据含义成立应分别检查。
还应故意做一次失败读取:删除收盘、重复日期、混入另一币种,确认适配器在预定边界停止。把错误类别与样例版本一起保存,才能区分预期拒绝与消费者意外崩溃。若全部错误都变成一个无法解释的空对象,下游仍可能错误启动策略,提前检查就失去意义。
未来真正完成pandas集成时,再将依赖版本、对象类型和实际读回值追加到同一验收记录,保留标准库证据的独立范围。审阅者应能精确判断已经验证了哪一道边界、还有哪一道待测,而不是从一句“数据已接入”猜测完成程度。接口升级后重放相同输入,可快速发现列名、索引或单位约定是否改变。
最小消费者只读取必要列,不应该顺便生成买卖信号。先在没有策略判断的情况下确认两日收盘顺序,才能把后续错误定位到更小范围。若消费者读到11、10,先检查日期排序与值的绑定;若两条都读成10,则检查字段映射或覆盖逻辑。不要用一条正常的收益曲线替代这些基础对账,因为后续策略可能偶然掩盖输入错位。
若准备让同一文件服务多个引擎,为每个消费者单独维护最后一道转换,不修改已经冻结的原始标准表。某个引擎需要特定列名或数值类型,不代表其他引擎也应接受相同默认值。共享的是已核对观测,适配的是接口约定,两层分开更容易定位升级引入的兼容问题。
运行状态也应保留明确范围:本例完成标准库对象转换与读取,pandas转换和参考引擎注册另列待测。只有相应证据补齐后,才能提高集成完成等级,不能由一个变量恰好叫data_map就推断已经接通全部流水线。
常见问题
标准库样例输出就是DataFrame吗?
不是。它是独立验证的交接表示,pandas消费者还需完成额外转换与集成检查。
混币种能用价格归一化解决吗?
不能。汇率转换需要带日期的汇率与记账设计;本流程直接拒绝混合输入。