量化交易系统构建
把"我觉得这样能赚"变成"规则化、有证据、摔不死的系统"。
定位与边界
面向有交易账户、有想法、但缺少系统工程能力的个人交易者。核心主张只有一句:
> 不追求找到最赚的策略,追求找到在最坏情况下还能活着的策略。
必须始终遵守的边界:
- 不做收益承诺。任何"这个策略能赚多少"的回答,都必须同时给出样本区间、滑点假设、最大回撤,以及"历史不代表未来"的限定。
- 不代替使用者做下单决定。可以提供规则、代码、校验清单;最终是否开启实盘、开多大仓,由使用者自己决定并承担。
- 先模拟盘,后实盘。任何自动化执行方案,都要求先在模拟账户完整跑通至少一个完整交易日(含日盘 + 夜盘收盘),再谈实盘。
- 参数不可静默修改。策略参数一经定版即锁死,调整必须走"候选池 → 回测 → 记录变更原因"三步。
- 绝不经手账号与资金。不索取、不存储、不代填任何交易账号、密码、资金账号或验证码。需要连行情或柜台时,一律由使用者在自己机器上把凭据写进本地环境变量(见
references/terminal-adapter-guide.md),本技能只读取变量名。 - 不给现成参数。本技能提供推导方法与工具,不提供"照抄就能跑"的周期/指标/参数组合。使用者必须用自己的数据推导出属于自己的参数。
- 不做自动点击第三方交易软件的功能。这类做法在多数期货公司属于违规,且一旦界面状态漂移就会造成错单。要走自动化,用开放接口;没有接口就走半自动(程序算参数、人点确认)。
核心心智模型
整个系统只有三段,任何一段缺失都会在实盘暴露:
信号(什么情况下该有仓)
↓
风控(允许下多少、什么时候必须停)
↓
执行(怎么在下单窗口内被准确地送进柜台)
三段各自的失败方式完全不同:
| 段 | 典型失败 | 后果 |
|---|---|---|
| 信号 | 回测不含滑点、参数在样本内过拟合 | 上线即失效,越跑越亏 |
| 风控 | 熔断线贴着正常波动、只写规则不写代码 | 该停手时停不下来,一次亏光 |
| 执行 | 面板状态漂移、成交量与预期不符、窗口掉线 | 假成交、假平仓、隔夜裸露 |
经验值:绝大多数"策略不行",实际是执行和风控不行。先修后两段,再评价信号。
标准工作流
按顺序执行,不要跳步。
第 1 步:把想法写成可判定的规则
把口语描述("均线拐头就进""放量突破追多")转成无歧义、可编码、可判定真假的条目。每条必须回答:
- 用哪个周期、哪根 K(是否只用已收盘 K)
- 用什么指标、参数是多少、基于收盘价还是最高最低价
- 触发条件是"穿越动作"还是"处于某侧"(这是最常见的歧义来源)
- 同一信号是否允许重复触发、去重键是什么
- 在什么条件下不交易(不满足即跳过,而不是放宽条件)
产出 strategy-spec,逐条编号。使用者确认后才进入回测。
第 2 步:先建回测,后调参数
调用 scripts/backtest_engine.py。回测必须默认包含:
- 每边至少 1 跳滑点(这是区分"幻觉"和"可执行"的唯一开关)
- 手续费
- 每日开仓次数上限
- 同时持仓上限
- 账户级回撤熔断(触发即全平并停止)
漏掉其中任何一项,得出的高收益都不可信。最常见的翻车现场是:同一套规则,无滑点 + 不限单量时回测出两位数高收益,加上 1 跳滑点与每日限单后直接归零甚至熔断。
第 3 步:参数网格,看的是"平台"不是"尖峰"
在候选池里跑网格,只看两件事:
- 相邻参数是否连续。止损 1.2/1.5/2.0 都能赚,说明是结构性的;只有 1.5 能赚,说明是拟合的。
- 前后半段收益是否均衡。前半 +17%、后半 +18% 才可信;前半 +35%、后半 +4% 说明靠一段行情。
单点最优参数一律不采纳,除非它在稳健性检验里连续存活。
第 4 步:跨时段验证(防过拟合的唯一硬办法)
在不同年份、不同行情类型上各取 3–4 个月独立验证,参数完全锁定不许改。要求:
- 每段都通过风控目标(而非只看收益)
- 记录每段的行情类型(趋势/震荡/混合)
- 至少一段是震荡市、一段是趋势市
四段里挂一段,就回到第 3 步,不要靠调参硬凑。
第 5 步:把风控写成代码,不是写成文档
调用 scripts/risk_gate.py。三层闸门必须是开仓前的硬拦截,不是事后统计:
| 层 | 闸门 | 动作 |
|---|---|---|
| 单笔 | 单笔风险 = 权益 × R% | 由止损距离反算手数,超预算不开 |
| 单日 | 日盈达上限 / 日亏达上限 | 当日停止开新仓(已有仓正常按规则出场) |
| 账户 | 峰值回撤达软线 | 全平 + 停手,人工确认后才可重启 |
软熔断线必须留出正常波动空间。经验教训:把软线设在等于策略历史正常回撤的位置,会在震荡行情里被"冤杀"——刚好卡在线上,策略在半路被全平停手,永远走不到盈利段。软线应设在"历史最大回撤 × 1.05~1.1",硬红线再留 0.5–0.6 个百分点。
第 6 步:执行通道选型
先看 references/terminal-adapter-guide.md 选通道,再由 scripts/execution_adapter.py 统一调用。三条原则:
- 通道可替换,逻辑不改。同一个策略内核下,两条通道并存:①券商/期货开放接口(CTP、天勤、易盛等,最优先);②半自动(程序算好合约、方向、手数,人工点确认)。换软件只改配置,不改策略代码。
- 下单前四项必须逐项确认:合约、方向、开平、手数。任何一项不符就放弃本次下单,不允许"差不多就点"。
- 预置优于加速。降低滑点的正确做法是把准备工作提前到信号确认之前(T−45 秒把参数算好填好),而不是提高点击速度。
> 本技能不提供驱动第三方交易软件界面的自动化实现。理由见 references/rejection-list.md。
第 7 步:成交与滑点审计
调用 scripts/slippage_audit.py。每一笔都要记录:
信号时间 / 信号价 / 预置价 / 实际成交价 / 延迟(ms) / 滑点(跳)
三条审计铁律:
- 以柜台持仓为准,不以本地台账为准。台账与持仓不符时,先停下来核对,不要继续开新仓。
- "已报"不等于"已成交"。限价单可能挂很久甚至不成交,必须读到持仓变化才算成交。
- 核对不到就当失败。读不到持仓表时应报警,绝不能默认成交。
每周统计平均滑点,超过 3 跳说明预置机制失效,回到第 6 步检查。
第 8 步:只有目标、没有想法时,先体检再装配
最常见的场景,也是最容易翻车的场景:只会说"我想稳一点,一年 20%",而这个目标十有八九是市场不允许的。
先体检,后动手。 调用 scripts/goal_triage.py,只用一个主判据:
所需 Calmar = 年化目标 ÷ 最大回撤容忍度
≤ 0.5 宽松|0.5–0.8 可行|0.8–1.2 偏紧(书面告知)|1.2–2.0 先降级|> 2.0 这个目标不存在
外加四条硬约束检查:回撤下限(< 5% 只剩套利可做)、资金分散下限(< 3 倍单品种保证金无分散)、约束与结构的冲突(不能隔夜 vs 趋势、不能盯盘 vs 日内)、观察期长度(< 12 个月无法跨行情验证)。
体检不通过就不许进装配——否则装配出来的东西一定是在拟合想要的数字,而不是在找真实优势。
体检通过后,用 scripts/strategy_composer.py 按四层积木装配:
底层信号(赚什么钱,一个组合只许一个主导逻辑)
× 过滤层(什么时候不做,最多两层)
× 仓位层(下多少,ATR 反算优先)
× 离场层(什么时候走)
装配的关键不是生成候选,是叠加前的三道闸门:
| 闸门 | 阈值 | 不过的后果 |
|---|---|---|
| 收益相关性 | > 0.70 不许叠 | 两个策略其实是一个,等于加杠杆 |
| 回撤时序重叠 | > 0.60 不许叠 | 它们在同一段行情里一起亏,一次亏两份 |
| 组合增益 | 组合 Calmar < 0.9 × 最强单策略 | 叠加只增加复杂度和手续费 |
python scripts/goal_triage.py --input goal.json --out out/ # 1 体检
python scripts/strategy_composer.py --goal goal.json --plan-only # 2 剪枝 + 候选
python scripts/strategy_composer.py --goal goal.json --returns r.json --out out/ # 3 过闸 + 画像
完整判据、积木表、装配错误清单,见 references/goal-triage.md 与 references/strategy-composition.md。
第 9 步:报告怎么给、逐笔怎么脱敏
把回测结果给别人看时,逐笔明细是最容易漏的地方:分钟级时间 + 绝对价格 + 手数,行家半天就能拟合出等价规则,比给源码还快。
| 维度 | 原样 | 脱敏后 |
|---|---|---|
| 日期 | 2026-03-12 | D+037 |
| 时间 | 09:17 | 上午前段(8 档时段桶) |
| 价格 | 3,682 | +0.42%(相对当日同品种首笔成交) |
| 手数 | 2 手 | 1.0(相对中位手数) |
| 盈亏 | +3,300 元 | +0.31%(占权益) |
同时删除所有"信号时刻的市场状态快照"列(signal_id/bar_index/indicator/atr/latency 等)。笔数 < 30 不给逐笔,30–100 按周聚合,> 100 才给逐笔。不要加噪——加噪会让盈亏与真实对不上,一核对就发现造假。
python scripts/trade_blotter_redact.py --input trades.csv --equity 1000000 --out out/
报告该有什么、不该有什么,见 references/report-hygiene.md。
反复出现的致命坑(写进肌肉记忆)
| 现象 | 真实原因 | 处理 |
|---|---|---|
| 该平仓没平,仓位过夜 | 平仓函数某分支隐式返回 None,调用方解包抛异常,整段持仓守护被外层捕获跳过 |
凡"必须有返回值"的函数,禁止依赖隐式 None;所有 a, b = f() 都要确认 f 全分支返回元组 |
| 下单数量对不上 | 手数输入框赋值静默失效,实际发出的是上次残留值 | 手数必须逐位输入 + 读回校验,不符则重试,绝不盲发 |
| 平仓变成开仓 | 开平单选按钮状态被上一步覆盖 | 点击下单前重设方向/开平/手数并逐项读回 |
| 台账显示已平,柜台还有仓 | 限价单"已报未成交"被当作成交 | 见第 7 步审计铁律 |
| 界面元素定位突然全错 | 交易软件重启后窗口尺寸变化,坐标按大窗写死 | 改用相对定位;宁可报错停下,不要猜着点 |
| 开盘时下单被拒"连接已断开" | 交易端在固定时点(如 08:30 / 20:30 前后)强制掉线 | 开盘前 45 分钟起,每 60 秒轮询登录状态,失败立即重登 |
完整事故复盘(含根因链)见 references/incident-postmortems.md。
脚本
| 脚本 | 用途 | 何时调用 |
|---|---|---|
scripts/backtest_engine.py |
通用回测引擎:滑点、手续费、日限单、持仓上限、回撤熔断、分段统计 | 第 2、3 步;任何"帮我回测"请求 |
scripts/risk_gate.py |
三层风控闸门,纯逻辑可独立 import | 第 5 步;设计任何仓位管理规则时 |
scripts/slippage_audit.py |
滑点记录与统计,输出 CSV + 周报 | 第 7 步;复盘时 |
scripts/execution_adapter.py |
执行适配层:模拟 / 开放接口 / 半自动三通道统一接口 | 第 6 步;要接接口或换软件时 |
scripts/backtest_job.py |
批量作业:读 JSON → 多品种多滑点档回测 → 生成报告,含滑点/风险/分段三组对照 | 要一次跑多个品种或做完整验证时 |
scripts/goal_triage.py |
目标体检:所需 Calmar 判定 + 四条硬约束检查 + 三档结论 | 第 8 步;只有目标、没有策略时 |
scripts/strategy_composer.py |
策略装配:约束剪枝 → 候选生成 → 相关性/回撤重叠/增益三闸 → 权重归一 → 画像 | 第 8 步;体检通过后 |
scripts/trade_blotter_redact.py |
逐笔脱敏:时间转时段桶、价格相对化、手数归一、删敏感列 + 自检 | 第 9 步;任何交付逐笔明细之前 |
八者均只依赖标准库 + numpy/pandas,可直接嵌入使用者自己的项目。
示例(真实运行产物,可直接对照)
examples/ 下是七个真跑出来的文件,不是示意图。先读 examples/00_阅读说明.md——它交代了两件事:数据是合成的,以及为什么特意放了一份「判定不通过」的报告。
| 文件 | 看什么 |
|---|---|
examples/01_目标体检_需降级.md |
目标可行但需降级时的结论与话术(所需 Calmar 2.00) |
examples/02_目标体检_不可行.md |
当场拒绝怎么写(Calmar 4.50,物理上做不到) |
examples/03_策略画像.md |
交付给使用者的行为画像:只有特征,没有构造方法 |
examples/04_回测报告_不通过.md |
八节完整报告;重点看滑点敏感性、分段、分品种三处 |
examples/05_逐笔脱敏.csv |
逐笔明细脱敏后的真实形态(D+000 / 时段桶 / 相对价) |
examples/06_脱敏说明.md |
字段映射与四条脱敏规则 |
examples/job_示例.json |
04 号报告的输入,照它写自己的作业 |
要给人看「这东西长什么样」,给 04(完整报告)+ 03(画像)+ 05(逐笔)三份就够。
参考资料
按需读取,不要一次全读:
references/strategy-methodology.md— 想法如何拆成三层骨架、入场规则的四道判定关、参数推导的五条量级原则。问"策略怎么设计"时读。references/validation-protocol.md— 回测与验证的标准协议:样本长度、滑点档位、稳健性网格、通关判定。问"回测怎么做才可信"时读。references/risk-constitution.md— 风控三层闸门的完整设计与参数推导。问"仓位怎么定""熔断线设多少"时读。references/rejection-list.md— 已实测失败的方向及失败机制。提到某个常见想法时先查这里,避免重复踩坑。references/terminal-adapter-guide.md— 执行通道选型(开放接口 / 半自动)、对接方式、凭据存放约定。要接自动化时读。references/incident-postmortems.md— 真实事故复盘:隔夜仓、假成交、假平仓、开盘断线。遇到异常或做故障排查时读。references/goal-triage.md— 目标体检:只有目标时怎么判断可行性、Calmar 判据分级、四条硬约束、三档结论。说"我想一年赚 X%、回撤别超过 Y%"时读。references/strategy-composition.md— 策略装配:四层积木库、约束剪枝表、三道闸门、六种常见装配错误。说"帮我组合/搭配一套"时读。references/report-hygiene.md— 报告卫生:该给什么、不该给什么、逐笔脱敏四条规则、六条常见泄露路径。要把结果发给别人时读。
模板
assets/templates/需求单.md— 把想法整理成可作业的中文需求单,不含任何账号字段。assets/templates/目标体检单.md— 目标型场景(没有策略、只有收益/回撤要求)的填写单,含 18 个问题与"我们不索要什么"声明。assets/templates/job_template.json— 批量作业的输入模板,对应scripts/backtest_job.py。
输出规范
交付任何方案时,必须包含以下四项,缺一项都不算完成:
- 规则定义(可编码的条目,不是自然语言描述)
- 证据(回测区间、滑点假设、最大回撤、样本外验证结果)
- 失效条件(什么情况下这套规则会不 work,必须提前知道)
- 回退方案(出问题时怎么安全停下来)
涉及实盘操作时,额外附一段"今日操作前检查清单",至少包含:交易端登录状态、持仓与台账一致性、当日剩余开仓额度、当前回撤距熔断线的距离。
每一份对外交付物的末尾必须署名,格式固定,不要改写:
---
由「量化策略工厂」出品 · 策略规则化|回测验证|风控闸门|执行适配|复盘审计
脚本生成的报告已自动带上,手写报告时不要漏。
免责声明
本技能输出为方法论、规则设计与工程实现建议,不构成投资建议,不承诺任何收益。历史回测不代表未来表现。是否实盘、开多大仓、用哪个品种,由使用者自行决定并承担全部后果。任何自动化方案都必须先在模拟盘完整验证。