研究代码的质量标准与业务软件不同:它允许探索期的凌乱,但任何要进入回测或实盘的逻辑必须达到生产质量——因为一个 sign 错误、一个 off-by-one,亏损的是真金白银。本篇用同一个交易函数贯穿四个话题。
一个函数的四重进化
需求:给定持仓与当日最高最低价,判断固定百分比止损是否触发。
| |
隐患:参数含义无文档;跌停无法卖出的情形未处理;无法防止未来有人把 low 传成收盘价。
| |
| |
测试用例从哪里来?从真实事故里来。 「恰好等于不触发」这种边界,是无数实盘纠纷(触发价 vs 成交价)换来的。量化代码的测试金字塔:纯函数(信号计算、止损判断、仓位计算)全量单测;数据管道用「黄金样本」测试(一小份已知答案的历史数据,跑完比对输出);回测引擎用端到端回归测试(改动前后对同一数据集的净值曲线 diff)。
类型注解:Pandas 时代尤其实用
Python 的动态类型在量化里的代价极高:pd.Series 与 pd.DataFrame 传错(一个是列一个是表)、日期是 str 还是 Timestamp、收益率是小数还是百分数——这些错误运行时才爆,而且爆在三层调用之外。类型注解 + mypy(或 pandas-stubs)能在 IDE 里当场标红:
| |
渐进式采用即可:新代码全部注解,老代码改动时顺手补。团队收益巨大——类型就是最小的可执行文档。
规范:让 code review 聚焦逻辑而不是格式
- 格式交给工具:
black(格式化)+ruff(lint,含 import 排序、未用变量)+ pre-commit 钩子,仓库里零配置争议; - 命名约束写进 README:收益率字段统一
ret后缀、因子表列名统一factor_xxx、日期列统一date(Timestamp 类型)——跨策略的字段口径一致,是多人协作里最省钱的决定; - 函数纪律:单个函数不超过一屏;回测里禁止出现魔法数字(
0.001必须命名COMMISSION_RATE); - research 包结构模板:
data/(加载与清洗)、factors/(一因子一文件一测试)、backtest/(引擎与成本模型)、portfolio/(优化与权重)、utils/——研究与回测共享同一份因子实现,杜绝「研究用 A 实现、回测用 B 实现」的分叉。
依赖管理与虚拟环境
「在我机器上能跑」在量化里的具体形态是:两年后重跑因子,numpy 新版改变了某个函数的默认行为,结果全变。对策:
- 一项目一虚拟环境(
python -m venv/ conda / uv 任选),绝不往系统 Python 里装包; - 锁文件进仓库:
pip freeze > requirements.lock或用uv lock/conda env export——精确到版本号的依赖是复现的必要条件; - 升级纪律:依赖升级也走分支 + 回测回归测试——numpy/scipy/pandas 的大版本升级等同于「换了一次底层库」,净值曲线 diff 必须过;
- 内网机构场景:搭建私有 PyPI 镜像,锁定数据商 SDK 版本。
关联阅读:Git 与协作 让质量门禁落在合并时刻;回测框架设计 定义哪些模块最值得测试;DevOps 与 CI/CD 把 pytest/mypy 自动化到每次提交。