做策略这几年,我见过太多技术出身的人一头扎进回测系统里出不来,也有不少朋友在实盘里被打得晕头转向之后才反应过来:真正让资金曲线崩掉的,往往不是指标用得不够多,也不是代码写得不够快,而是你用“技术思维”在解决一个“工程问题”。这篇内容是这个认知系列的其中一期,但就算你没看过前面的篇目,也能独立读完。我打算用一期完整的复盘,把技术思维和工程化思维在交易策略这件事上的边界、误区、落地步骤一次讲透,适合正在自己折腾策略的开发者,也适合从主观交易转向系统化交易、但总觉得哪里不对劲的人。
1. 技术思维下的交易病:贪最优解、迷回测、爱上炫技
技术思维本身不是坏东西,分析能力、建模能力、工程实现能力都是做量化交易的底子。问题在于,交易策略的生存环境并不是一个能被“静态求解”的函数,市场会变,规则会变,参与者的行为也会变。当一个人把写代码、调算法时养成的习惯直接搬过来做策略,很容易掉进几个看似合理、实则致命的坑。
1.1 最容易被忽视的“参数血案”
技术思维最典型的动作就是调参。面对一个策略,很多人会顺手把参数区间一划,然后让程序在历史数据里跑一圈网格搜索,最后挑出回测收益最高、回撤最小的那一组参数,感觉像找到了圣杯。
我在某个学习小组复盘过一个模拟项目:一个用双均线逻辑开发的策略,开发者把快线从5到30、慢线从20到120分别扫了一遍,然后用收益率最高的一组参数重新回测,结果曲线确实漂亮,训练段年化收益做得非常高。可一旦放到没有参与调参的后续数据里,策略立刻变样,亏损速度比之前赚的速度还快。
问题出在哪?很简单,这是典型的样本内过拟合。你在同一批数据上反复试探,本质上不是“发现规律”,而是“记住答案”。更糟的是,这类最优参数往往落在“针尖”上,参数稍微偏一点,策略表现就断崖下跌。工程化思维反而会刻意避开这种针尖解,去找那种“参数在很大一个范围内都表现稳定”的高原解。策略不是考试题,不需要追求满分答案,要的是在真实市场的不确定性里还能有稳定的正期望。
1.2 回测好看不等于能实盘
技术思维对回测结果特别容易产生信仰。一旦代码跑出一根漂亮向上的曲线,有的人连鼠标都舍不得往下划,心里已经开始盘算上多大的仓位。但回测这件事本身有一大堆暗坑:前视偏差、幸存者偏差、数据复权和换约处理不当、信号触发价和实际成交价不一致,随便中一个,历史曲线都能被画得比实际强得多。
举个常见的例子。某开发者做期货策略,回测时用了不复权的收盘价,恰好样本区间里有几次大比例分红和除权,价格出现断层,策略在断层处产生了本不该出现的“跳空利润”。后来把数据换成复权口径重新跑,那些利润直接就没了。像这样的回测失真,技术思维往往被“好看的结果”冲昏头脑,懒得去排查,等到实盘被现实矫正一次才理解“回测是筛选器,不是印钞机”。
工程化思维对回测的态度完全不同:回测的最高使命是帮你剔除明显的坏想法,而不是证明某个想法一定赚钱。跑完回测之后,至少要追问三件事——数据有没有对齐、有没有引入未来信息、换一组合理的参数结论是否还在。这三件事过不了关,曲线再漂亮也先放一放。
1.3 工具越来越重,逻辑越来越薄
技术思维还有另一种倾向:喜欢堆工具。因子库越写越大,模型越换越复杂,从线性回归一路升级到神经网络,机器学习的训练框架搬上来,GPU不够再搞多机并行。这些能力当然有价值,但如果连“这个策略凭什么赚钱”这个最基本的问题都没回答清楚,工具越重,掩盖问题反而越彻底。
我之前看过一个策略,逻辑里塞了几十个因子,信号模块写得极其复杂,可问项目负责人“这个策略在什么市场状态下有效,什么状态下无效”,答不上来。团队每天忙着加因子、调权重,却没人去验证最底层的行为逻辑是否成立。结果策略在训练集上表现尚可,到了模拟盘就开始随机抽搐。
技术思维喜欢说“我用更复杂的工具解决了更复杂的问题”,但交易策略恰恰相反,很多时候更简单的逻辑、更清晰的链条,反而更容易做出稳健的曲线。工具是放大器,不是论证,如果你想不清楚策略赚的是哪份钱,任何复杂工具都不会替你想清楚。
2. 工程化思维的交易系统:把策略当成一条可维护的流水线
聊完技术思维的问题,再来看看工程化思维究竟在讲什么。工程化思维不是让你把代码写得更好,而是让你换一种眼光看交易:市场不可预测,但系统可以被设计;单次盈亏不可控,但期望值可以被管理;策略会失效,但迭代机制可以让你永远有机会处在“正在验证”的状态。
2.1 从“预测对错”转向“赔率分布”
技术思维的人容易把交易当成判断题,问得最多的是“明天涨还是跌”“这次信号准不准”。工程化思维的人脑子里装的不是判断题,而是一个期望值公式:胜率乘以平均盈利,减去败率乘以平均亏损,只要这个值长期为正,策略就有存在价值。
这也是为什么技术思维特别容易被“高胜率”吸引。一个胜率85%的策略听起来很诱人,可如果每次赚1块钱、亏的时候亏10块钱,这个策略的期望值依然是负的。反过来,很多趋势策略胜率不到40%,但靠着盈亏比把期望值拉正了,照样能活。工程化思维要的不是每次都猜对,而是确保在足够多的交易次数里,概率和赔率的组合对自己有利。
实际上我见过不少开发者,技术能力很强,却不愿意接受“连续止损是策略的正常摩擦成本”。信号连续错几次就开始怀疑系统,然后手动干预,把一个本来有正期望的系统变成了“被情绪反复打断的残缺版本”。工程化思维会把回撤和连续止损当作业务运营成本来对待,只要没有触发系统预设的退出条件,就继续按计划执行。
2.2 模块边界:信号、仓位、执行、复盘各管一摊
工程化思维很看重系统边界。交易系统至少要拆成几个独立模块:信号模块负责产生交易方向,仓位模块负责决定下多少手,执行模块负责把订单送到市场,复盘模块负责记录一切结果并给出反馈。每个模块只干一件事,输入输出尽量标准化。
为什么一定要做模块拆分?因为出了问题可以快速定位。信号没触发,还是仓位算错了?是行情软件数据源断了,还是执行接口滑点太大?如果所有逻辑混在一堆代码里,任何一环出错,你都得从头排查,而且很难判断策略本身有问题还是系统有bug。模块化设计这件事,本质上是让系统具备“可诊断性”。
这里可以用一条流水线来打比方。信号模块是生产计划,仓位模块是工厂排产,执行模块是物流配送,复盘模块是质量检测。任何一条环节异常都能单独拿下来检修,而不是整条产线停产。做交易也一样,模块独立、可开关、可替换,系统才可能长期健康运转。
2.3 日志、监控与“系统状态”
技术思维的人在开发阶段往往不重视日志,反正代码在自己电脑上跑,跑通就行。可交易系统一旦进入模拟盘或者实盘,日志就变成了最重要的资产。
工程化思维要求每个关键动作都留下痕迹,至少要把这些字段记录下来:信号触发时间、当时价格、预期成交价、实际成交价、滑点、仓位比例、止损价、持仓时长、盈亏金额。有了这些数据,你才能回答那个最核心的问题——“我的系统实际跑出来的表现和回测预期差在哪里”。
日志字段整理成表格大概是这个样子:
| 记录项 | 作用 | 常见问题 |
|---|---|---|
| 信号时间 | 判断信号与成交的时间差 | 时间对不齐会掩盖滑点问题 |
| 预期价格 | 回测模型假设的成交价 | 与实盘差距过大说明模型失真 |
| 实际成交价 | 真实参与市场的价格 | 记录不全将无法复盘执行质量 |
| 滑点成本 | 预期与实际的差值 | 高频策略尤其要统计稳定程度 |
| 仓位比例 | 本次交易承担的风险 | 方便计算账户整体风险敞口 |
| 持仓状态 | 当前是否在场内 | 避免遗漏持仓导致第二天混乱 |
有了这些日志之后,监控就有了抓手。信号触发了但成交没出现,要告警;连续止损次数超过预设阈值,要告警;账户回撤接近警戒线,也要告警。系统不能装死,你得时刻知道它处于什么状态,才能在每个决策节点做有依据的判断。
3. 一个模拟策略的解剖:技术思维是怎么把好牌打烂的
光讲理论比较抽象,我按完全虚构的方式复盘一个模拟项目中A同学的案例。这个案例的细节做了脱敏处理,所有数字仅用作示意,不代表任何具体策略的收益承诺,但它非常典型地呈现了技术思维到工程化思维切换的全过程。
3.1 A同学的“自适应多因子择时系统”
A同学本身代码功底不错,日常工作里也经常处理数据分析。最初他只做了一个双均线策略,逻辑简单,回测也过得去,后来觉得不够“高级”,开始不断叠加新东西:成交量确认、MACD背离过滤、波动率自适应仓位、情绪类因子,甚至还想上一套机器学习模型来合成信号。
每一轮加完新东西,他都会重新回测,惊喜地发现样本内的曲线又好看了一点。真正的问题出现在模拟盘阶段:信号频繁闪烁,方向经常反复,连续成交几笔之后账户开始出现预料之外的亏损。A同学的第一反应不是停手,而是赶紧改参数、调阈值,想用最快的速度把曲线修回来。
结果可想而知,参数越调越乱,系统最后成了一个没人说得清楚的规则泥潭。他自己复盘时承认,已经说不出策略到底是靠什么逻辑在赚钱了。这个状态我有专门的话来总结:系统失去了“可归因性”,任何一笔赚钱和亏钱的交易都说不清具体原因,后续优化自然无从谈起。
3.2 解剖结果:问题远不止“行情不好”
做完问题清单梳理,A同学的策略问题可以整理成一张表格:
| 问题 | 具体表现 | 导致的后果 |
|---|---|---|
| 规则叠加过载 | 十几个指标层层过滤,信号被改得面目全非 | 无法判断哪一个逻辑真正有效 |
| 样本内过拟合 | 参数在训练数据上反复调试 | 样本外数据表现严重下滑 |
| 缺少样本外冻结区 | 同一批数据既调参又做验证 | 回测结果失真 |
| 没有完整日志 | 模拟盘跑完只有成交记录,没有状态快照 | 事后无法精确复盘 |
| 没有退出机制 | 亏损扩大后手动干预 | 系统纪律被破坏,风险失控 |
这张表里的每一条,单看都像是“技术问题”,但合在一起,暴露的却是系统设计的空白。A同学不是技术不够,而是太相信技术能解决策略问题,忘了先把问题本身定义清楚。
3.3 重构:砍到只剩双均线
后面我们把A同学的策略推到重来,核心就一句话:先做最小可运行系统。信号先回到双均线,仓位用固定风险比例,止损按账户比例设定,关闭所有花哨的过滤条件。整个重构花了两周,逻辑简单到三句话能讲完:快线穿越慢线做方向判断,每笔交易承担账户的固定风险,触及止损离场。
重构后的版本最开始看着很平淡,但每一笔交易都可以被解释,每个参数都能被单独验证。之后每一次加入新的过滤条件,都有严格流程:先写假设,再做样本外回测,再对比加过滤前后的整体表现,表现没有提升就回滚。跑了两个月的模拟盘下来,系统虽然收益不惊艳,但稳定、透明、可迭代。
A同学后来感叹,最浪费时间的事情不是重构,而是之前拼命“优化”的那些日子。技术思维让人沉迷于把系统修得很复杂,工程化思维却让人敢于承认“不完美的简单系统,好过复杂到失控的系统”。
4. 从想法到实盘的工程化六步路:每一步都要写验收标准
工程化思维听起来是个方向,但要落地还是得有路线。这几年我逐渐把策略开发整理成六个步骤,每一步都要求必须有可验收的标准,下面直接把这套方法完整列出来。
4.1 第一步:把策略写成一个可证伪的假设
很多人动手写代码之前,根本说不清自己在做什么。策略开发开始之前,我要求先写下这样一句话:在什么样的市场环境下,利用什么样的行为逻辑,通过什么样的信号表达,预期获得什么样的超额收益。
举个例子,一个趋势策略的假设可能是:市场在趋势行情中会出现动量延续,均线多头排列之后继续顺着方向运行的概率较高,因此可以设计均线穿越信号捕获趋势段收益。这句话写清楚之后,后面所有工作才有明确指向。如果说不清策略赚的是哪份钱,代码写再多也只是在做一个随机规则生成器。
4.2 第二步:划分样本内与样本外,冻结验证区
数据划分这件事极其重要。一般做法是把完整历史数据切成两段:前半段是开发样本,供你调参和优化;后半段是验证样本,从头到尾不参与任何调试,只有策略逻辑完全冻结之后才能碰一次。
技术思维常见的问题就是“忍不住”去碰验证区,结果验证区慢慢也变成了开发样本的一部分,整个回测可信度归零。工程化思维要求你像一个质量控制员一样管理数据:验证区就是不可触碰的封印区域,能在里面跑一次就已经很奢侈,绝不允许在里面做参数调整。
为了提高可信度,很多团队还会做滚动前推验证:用一段历史数据开发策略,然后在下一小段未用过的数据上验证,再逐步向前推进。这种方式比一次性划分样本内外更贴近真实场景,也能暴露策略在不同市场阶段的稳定性。
4.3 第三步:做最小可运行系统,而不是最大可行系统
每个开发者心里都有一个“终极策略”的梦:多品种、多周期、多因子、多策略组合。工程化的第一步恰恰相反,先把最小化的系统跑通。
固定一个品种、一个周期、一个信号逻辑、一个仓位规则、一个止损规则,把它完整跑完一个验证周期,记录所有结果。看起来简陋没关系,重要的是先建立一条贯穿全流程的管道,之后再在这条管道里逐步增加复杂度。前面讲到的A同学重构案例,用的就是这个思路,先有了干净管道,后续每加一个东西都能独立验证,系统才不会失控。
4.4 第四步:参数敏感性、压力测试与滚动前推
策略逻辑确定之后,参数就当配角来测。常见的做法是参数敏感性分析:把关键参数在合理范围内做扰动,观察策略表现是剧烈波动还是平稳过渡。如果参数稍微动一点,结果就冰火两重天,说明策略在依赖一个不稳定的巧合;反过来,只要参数在很大一片区域里表现稳定,策略本身才具备鲁棒性。
压力测试同样不能省。可以人为构造一段极端行情测试场景,比如连续熔断级别的跳空、长时间横盘震荡、成交量突然萎缩,观察策略在这些环境下会不会触发不可控的极端交易。止损设置得不合理、仓位计算有漏洞、流动性假设过于乐观,压力测试都能暴露出问题。滚动前推验证也可以放在这步,不断把验证区间向外推,模拟“历史复现不会简单重复”的真实环境。
下面的表可以把这四个验证维度以及各自要回答的问题做个对照:
| 验证项 | 考察重点 | 核心问题 |
|---|---|---|
| 参数敏感性 | 参数高原 vs 参数针尖 | 换一组参数还会不会赚钱 |
| 交易成本冲击 | 滑点与手续费假设 | 成本翻倍后策略是否仍为正期望 |
| 极端行情压力 | 尾部风险暴露 | 出现连续极端波动能否生存 |
| 滚动前推 | 跨时间的稳定性 | 在陌生时间段里策略是否依然有效 |
4.5 第五步:模拟盘与上线清单
回测再严格,也只是历史的模拟。正式上实盘之前,强烈建议先跑一段模拟盘,时间至少覆盖若干完整的持仓周期,让策略经历足够多次信号和亏损。模拟盘阶段要把日志系统彻底跑顺,确保每个信号、每次成交、每次止损都有记录可用。
同时,上线前要过一遍完整清单。我自己的清单通常包含:行情数据源是否稳定、断线重连是否正常、交易接口权限是否开通、订单超时是否有重试机制、账户权益与日志记录是否对齐、警报通知是否已经配置。别小看这些杂事,很多策略的问题根本不在策略,而在上线当天才发现接口支持不了预期的下单方式。
4.6 第六步:退出与迭代机制
工程化思维有一块内容是技术思维特别容易忽略的:退出机制。策略什么时候算失效,什么时候必须停掉,这个必须提前定义。
常见的退出标准可以写成几条规则:账户回撤达到预设百分比,暂停策略;连续N次交易止损且频率超过阈值,转入诊断状态;滚动前推验证表现持续低于基准,启动策略退役流程。把退出写进系统,不是悲观,而是为了在情绪还没失控时就用规则保护账户。
迭代机制同样要规则化。每次策略调整都走同一条路径:先说明修改的假设,再在样本外验证,接着小仓位模拟,最后才考虑正式上线。整套机制运行久了你就会发现,策略本身能不能赚大钱是次要的,关键是你能在一次次迭代中活下来,每次失败都知道为什么。
5. 切换思维后最容易踩的三个暗礁:数据、心态、复盘
从技术思维转向工程化思维,理念上想通之后,执行层面还有一些暗礁特别容易翻船。这里我把最常踩的三个单独拿出来说,每个背后都有真实的项目教训。
5.1 数据暗礁:对齐与复权是翻车重灾区
数据问题看着最基础,毁掉策略的速度却最快。技术思维的人拿数据就开始算,工程化思维的人会先问数据口径。时区有没有统一、日线到底以哪个时区收盘为准、股票除权除息用的是前复权还是后复权、期货合约换月时价格跳空怎么处理、停牌股票要不要特殊标记,这些都没有标准答案,但都必须形成明确约定。
我见过一个典型的案例,某策略在日线上跑得很好,一检查才发现数据源的交易日期和本地时区差了一天,信号全部滞后了一根K线。还有做期货策略的,换月当天如果不缝合价差,回测里就会出现本不该存在的巨大跳空,策略误以为那是趋势信号,实际上只是合约变更带来的伪影。
数据检查本身也值得做成一个独立模块,每次跑回测前先跑一遍数据完整性检查:时间序列是否连续、是否有异常的极端值、除权除息日是否被正确标注。数据完全可信,回测才有意义。
5.2 心态暗礁:连续亏损后“手痒症”
技术思维的人特别容易犯一个病:策略连续亏了几笔之后,盘中手痒,总想改点什么。可能是临时关掉某个信号,可能是把止损挪远一点,也可能干脆手动下一单“帮系统纠正方向”。这种行为在代码层面是即时响应,在系统层面却是灾难。
工程化思维讲一句话:盘中只做执行,不做修改。系统在跑的时候,你唯一该做的事是监督它按计划执行,发现问题记录在案,等到盘后再做系统性的分析和变更。想要管住手痒,可以把规则下沉到系统层面:所有参数在交易时段内锁定,必须通过变更流程才能修改,且变更生效至少等到下一个交易日。
我自己还会再加一条冷却期规则:任何想改策略的冲动出现后,先写一段变更说明,写下“为什么改、预期改变什么、如何验证”,然后强制等24小时。很多时候,睡一觉之后再看,那个“灵光一现”其实只是连续亏损带来的心理波动。
5.3 复盘暗礁:只问输赢,不问是否照做
复盘这件事,技术思维容易走偏成“结果导向”:赚钱了就觉得自己厉害,亏钱了就急着找系统的问题。工程化思维会先把结果分成两个维度:执行维度跟策略维度分开看。
每次复盘先从日志里调出实际成交,对照系统信号,逐一确认是否完全遵循系统规则。如果某笔交易没有按照系统执行,不管这笔最终是赚是亏,第一优先级都是找到原因,修正执行问题。只有当所有交易都按规定执行了,策略本身的盈亏才有分析意义。
复盘模板可以参考下面这个思路,我平时复盘就用它打底:
| 复盘项 | 自问自答 |
|---|---|
| 执行一致性 | 今天所有成交是否严格遵循系统信号 |
| 偏差交易 | 如有偏离,原因是什么,如何防止再发生 |
| 滑点情况 | 平均滑点是否在回测假设范围内 |
| 风险指标 | 当前回撤是否在预设阈值内 |
| 系统信号质量 | 信号被触发后的走势是否符合策略假设 |
复盘不是找借口,也不是自我表扬,而是把每一笔交易都变成系统迭代的养料。长期坚持下来,你对策略的理解会比任何参数优化都更深。
最后说一点我自己的体会。技术能力教会你“怎么把策略做出来”,工程化思维教会你“怎么让策略活得久”。两者不是对立的,技术是武器,工程化是使用武器的规则。想要在交易这条路上走远一些,缺了任何一边都不行,但真正决定账户下限的,往往是工程化那一侧有没有做到位。我自己的习惯是:每次想改一个参数之前,先强迫自己写下变更假设,等24小时再回头看。这个看似简单的动作,帮我挡住了无数个来自盘中冲动的蠢主意。如果你也在做策略开发,建议你把这个习惯直接抄走,体验一下被规则保护的感觉。