QUANT TRADING · BUILD LOG
我花一个月写了个自动炒股程序,然后它自己止损了
9 月 11 日早上 9 点 55 分,我手机震了一下。
那是我写的程序人生第一次自动卖出。九天前它在突破位买入了这只有色金属 ETF,九天后价格跌破 10 日低点,它自己割了肉,亏损 353 块,然后给我发了条通知。
说实话,收到通知的那一刻我挺高兴的。亏钱还高兴,听起来有点毛病——但那笔 -353 块意味着一件比钱重要的事:我写的风控系统,真的在替我工作。
起因很简单
8 月初我决定做这件事的时候,想法朴素得不能再朴素:我一直对量化交易好奇,网上教程一堆,但没有一个真正把「从调研到跑起来」的全过程讲清楚。那就自己来。
给自己定的边界也很清楚:一万元起步的模拟盘(后来提到十万)、只碰 T+0 的 ETF、低频策略、先模拟后实盘。不碰个股,不做高频,不碰期货杠杆。
一个月后的现在,它长这样:7 只 ETF(黄金、豆粕、有色、恒生、纳指、标普)共享一个账户,工作日自动开盘,每 30 分钟检查一次信号,唐奇安突破策略决定买卖,收盘后自动写日报进我的知识库。Python 八千多行,161 个测试,61 次提交。
但我今天想聊的不是收益
先交底:回测里这套策略在趋势行情有正期望,黄金 ETF 那段 +35%;实盘一个月,-1.7%。如果你是想来找「跟着买就能赚」的东西,这篇可以关了——何况模拟盘本来就没有任何跟单意义。
我想聊的是三个写代码写出来的故事。它们比收益率值钱。
故事一:161 个测试全过,风控却是断的
写完系统那阵我挺得意的:49 项风控演练全部通过,组件测试 100% 覆盖。直到某天我做例行体检,随口问了一句「连亏熔断上次触发是什么时候」——
翻遍日志发现:从来没触发过。不是因为行情好,是因为线根本没接上。断路器的盈亏统计方法只在回测引擎里被调用,实盘的模拟引擎压根没喂过它数据。「单日亏损 6% 熔断」「连亏 3 笔停止交易」这两条我郑重其事写进需求文档的规则,在生产里一直是摆设。
修完接线三周后,就是开头那笔止损。这一次我盯着审计日志核对:连亏计数 +1,亏损记账精确到分,通知、日报、往返配对全部一致。
这件事之后我改了一条原则:组件测试通过只说明零件是好的,不说明机器在转。
故事二:日志零字节的凶手
有一阵模拟盘总是无声消失:进程没了,日志一个字都没有,看门狗每半小时把它救活一次,新进程几秒后又死。连着三天。
最后抓到的凶手相当离谱:launchd(macOS 的任务调度器)拉起引擎后,任务脚本本身退出了,系统顺手清理整个进程组——刚出生的引擎一起陪葬。死的时候连一行日志都没来得及打。
解法是把启动器改成双 fork 加 setsid,让引擎彻底脱离调度器的会话。但这个 bug 留给我的是另一件事:「日志是空的」本身就是最重要的线索。后来引擎的心跳、看门狗的告警、日报里的健康检查,都是这套追凶经验的产物。
故事三:说「不」的那一半
做策略参数的时候我发现,每只 ETF 的最优参数都不一样:有色的最佳离场周期如果照抄其他标的的惯例,回测夏普比率只有 0.05,换掉之后 0.79。恒生科技我试遍了参数,全部零交易——两年里它就没有走出过一次像样的趋势。
最难的不是找到「什么能做」,是给「什么不做」也找到依据:债券 ETF 虽然天天创新高,但没有波动,突破策略做不了;能源化工看起来热闹,进去只会产生假信号。一个策略系统的成熟度,一半在于它拒绝了多少听起来很美的机会。
现在它在干嘛
每天早上 9 点 25 分,我 Mac 上的定时任务把它叫醒;下午 3 点 05 分收盘,它自己写好当天的日报,同步进我的知识库。风控状态、离场线、溢价预警都画在仪表盘上。国庆休市它也知道(行情接口的日期停在节前,它就自动放假)。

模拟盘账户权益曲线 · ¥100,000 本金 · 全程无人值守 · 数据来自系统审计日志
接下来它就安静地跑着攒数据。等哪天资金量到了、也找到了愿意给个人开量化接口的券商,这套系统可以直接切到实盘——代码早就写好了,改一行配置的事。
而在那之前,它每自动止损一次,我都会高兴一下。