天智这一周:给坏掉的系统打了三周分,我却浑然不觉
本文最后更新于 2026年7月19日 下午
上一篇我写这套系统让它自己开口说话,顺便把我挖的坑一个个填上,结尾撂了一句挺满意的狠话:
“一个失败得很安静的系统,你迟早会栽在它手里。”
这一周,账单到期了。
我原以为要接着上周继续往系统上加东西,结果这七天几乎一件新功能都没做。真正干的事只有一件:把一堆一直在悄悄坏掉、我却从没发现的东西,一个个翻出来。
其中最难堪的一个是——上周我兴冲冲开了个新账户,去测”大盘走弱到底该不该停手”。这周我发现,那道我用来测试的闸门,从上线起就没生效过。 我拿一把坏尺子,认认真真量了三个礼拜。
一、上周我立的那个 flag,这周先塌了
上一篇的高光,是我给”大盘择时到底有没有用”开了个独立账户——择时盘。设计我还专门吹了一段”唯一变量”的哲学:它和天智精选选股完全同源,唯一的差别是叠加一道大盘趋势闸,走弱时暂停建仓。只有当两个账户只差一个变量时,净值差才能归因到那个变量上。
道理没错。可这周我去核对那道闸的时候,发现了两个让整段哲学瞬间作废的事实:
- 它盯错了大盘。 趋势闸用的是沪深 300——一个大盘蓝筹指数。可天智精选选的票,大量是中小盘。我拿着蓝筹的脸色,去给中小盘放行或叫停,牛头不对马嘴。
- 它的判据钝得像块砖。 就算指数已经跌破 20 日均线了,它还常常判成”中性”,照样放行。说是趋势闸,其实约等于常开。
换句话说,我上周郑重其事介绍的那个”唯一变量”,那个变量本身根本没在工作。 择时盘和天智精选跑出来的任何差异,都不是”择时”造成的,是噪声。
修法是把闸换成中证 1000(跟选股池的市值风格对上),并且一跌破 20 日均线就判弱、直接停买,不再和稀泥。(ee08662)
但这里必须钉一句丑话,因为它关系到所有历史数据的可信度:这是一次选股/交易口径的变更。7 月 13 日之前和之后,择时盘的数据不可直接比较。 我不能假装那道坏闸跑出来的历史是干净的——它不是。
上周我说”给直觉开个户,让它接受审判”。这周的教训是:开户之前,先确认你的尺子没坏。 一个坏掉的裁判,判出来的每一场胜负都是假的。
二、更糟的:有两个策略,从上线那天起,一票没出过
顺着那道坏闸查下去,我扯出了一整根藤。
天智精选背后其实挂着九张策略表(放量突破、高而窄的旗形、海龟交易……每张表命中就投一票,多策略共振才入选)。这周我盯着看板,发现一个诡异的规律:入选的票数,永远恰好是 3。 不多不少,天天是 3。
真实的市场不会这么听话。这个”恰好”,是坏味道。
扒开一看,九张表里实际只有七张在干活,另外两张,从上线那天起就没投出过任何一票:
- 一张判”有没有大幅回撤”的策略:它拿一个负数当哨兵值,结果这个负数被当成了除法的分母——第一轮计算就必然返回 False,永远。它不是偶尔漏票,是结构性地一票不投。
- 一张挑”低波动成长股”的策略:一段
if / elif把候选行锁死了,再加一个阈值填错了位数(本该是0.1,写成了1.1)——股票涨得越猛,它反而越选不出来。 逻辑整个拧了。
这两张表,自上线以来从未产出过任何一个选股结果。而我这两个月,一直以为九张表都在投票。(93dba0d、fe7a94e;顺手用库里三年真实 K 线把低波动那张表的阈值重新定标到 0.3,不再靠拍脑袋。)
这和上一篇那个”总有票没名字”的 bug,是同一种病:系统忠实地跑着,看板也天天有数,一切看起来都正常——只是其中一部分,从来就没真的活过。 沉默的失败最擅长的,就是伪装成”一切正常”。
三、我给你看的价格,错了十五个交易日
如果说前两个是”逻辑坏了”,这一个是”数据坏了”,而且是我亲手把它坏掉的。
现象:看板上某些股票的历史价格,对不上真实行情。查下去,根因让我脊背发凉——
每次我重新部署服务,容器一启动就会触发当天的日批;而日批算日期的时机有问题,会把”当天的实时行情”,写进”前一个交易日”的格子里。
我这两个月部署了无数次。也就是说,每部署一次,就往前一天的历史里灌一次脏数据。 累计下来,十五个交易日的价格被污染了。
我盯着这个数字看了很久。然后去查了一件最要紧的事:污染有没有影响选股和交易?
查完,长出一口气:没有。 资金流那张底表(选股真正依赖的原料)完好无损。也就是说——这两个月,选出来的票是对的,纸面盘的买卖是对的,坏掉的只是”显示给人看的那个价格”。 系统的大脑没坏,坏的是它的脸。
修法两步:给日批加一道时间闸,杜绝它再往历史里写当天数据(1b9a591);再用干净的三年 K 线底库,把被污染的53861 行价格全部回填重算。
这件事最深的一课,其实是一个操作纪律:验证一个系统”有没有正确落库”,永远直连数据库去看,不要用它自己的 API 反推。 因为 API 读到的,可能也是被同一个 bug 污染过的——你用坏掉的眼睛,是检查不出自己眼睛坏了的。
四、一个骗了我自己的 bug
接着上一条。为什么这么明显的污染,我这么久才发现?因为有另一个 bug,专门负责骗我。
天智数据那个长连接的数据库连接,漏配了一个参数:autocommit。少了它,MySQL 会进入一种叫”可重复读”的隔离级别——听起来是好事,实际后果是:这条连接会把它第一次读到的数据,冻成一张快照,之后无论库里怎么变,它永远只给你看那张老快照。
于是活见鬼的一幕出现了:库里明明已经有 90 只票了,API 却咬定只有 43 只。API 和纸面盘,长期在读几天前的陈旧数据,还一脸真诚地告诉我”这就是最新的”。(5103736)
最讽刺的是,这个 bug 甚至骗过了我对它的排查。有一次我明明成功重算了数据、写进了库,可 API 反馈回来的还是旧数字,我据此误判”这次重算失败了、大概是内存爆了”。 我冤枉了一次完全成功的操作,只因为我用来验证它的那只眼睛,看的是三天前的世界。
上一篇我说”一个失败得很吵的系统,好过一个失败得很安静的”。这一条是它的加强版:最危险的不是安静地失败,是自信地给你一个错误答案。 一个坦白说”我不知道”的系统,远比一个笃定地告诉你旧数据的系统安全。
五、回测又一次让我闭嘴——这次连我最有把握的直觉都被判了死刑
把坏掉的数据修干净之后,我做的第一件事,是拿这份终于可信的数据跑回测。它给我上的课,一如既往地不留情面。
第一巴掌:追涨到底接不接盘?
我原本担心天智精选会”追涨接盘”——追进那些已经涨了一大截的票,然后站岗。可干净数据(227 只样本)跑出来的结论正相反:信号当天涨幅超过 7% 的票,次日平均还涨 0.73%、胜率 54%;反倒是那些温和上涨的,次日是负的。 这直接证明——用户六月底删掉”涨幅上限”那个决定,是对的。我以为的风险,其实是这套策略为数不多的正期望来源。 我又一次凭直觉猜错了方向。
(同一批回测还印证了一件事:推送 ≠ 交易。 裸信号本身五日期望是负的,但纸面盘因为多了一道”买入闸”,实际表现明显更好。所以我给飞书推送也加上了明确的风险提示——b3f00ba——别让读者把”今天选出这些票”误读成”闭眼买这些票”。)
第二巴掌,也是这周分量最重的一个:动量因子,是毒药。
这事我追了整整两周,用了三个互相独立的数据窗口去验证同一个假设:”股票的近期涨势(动量),到底该不该作为选股的加分项?”几乎所有人都相信”强者恒强”。我也信。
结果三扇窗户,异口同声:
| 窗口 | 结论 |
|---|---|
| 近 23 个交易日(下跌段) | 去掉动量,几乎无损 |
| 聚宽 10 年(2016–2026) | 带动量 −50%,去掉动量 +116%(α 8.5%) |
| 聚宽样本外(近一年牛市段) | 动量仍是负贡献,−3.1 个百分点 |
A股的短期不是”强者恒强”,是”强者反转”——这是个十年尺度的结构性规律。 我押在”动量有用”上的直觉,被三次独立的实验,判了死刑。
于是就在今天,我做了这周唯一一次真正动策略的改动:把选股综合分里的动量类因子整个剔除(动量分照旧计算、照旧展示,只是不再计入总分)。(fb1ee63)
但我必须给自己泼盆冷水,这也是回测教我的诚实:估值、质量、成长这几个”好”因子,是防守型的。 十年里它们的超额收益,主要来自”下跌段少亏”,而不是”上涨段多赚”——牛市里它们基本只是跟住大盘。所以就算剔了动量,也别指望这套策略在牛市里立刻起飞。它的价值,要等回撤来的时候才兑现。
回测是证据,不是判决。 三扇窗户一致,只够把”剔除动量”排到”该上实盘验证的第一位”,不够让我把它当成真理焊死。最终裁决权,还是交给真金白银跑出来的那几个盘。
六、还有一整周,花在了不性感但承重的地方
上面全是”发现问题”。这周还有一大块时间,花在了那些写出来没人点赞、但塌了就全完的地基上。
- 飞书通知,收口成一根管子。 上周那次”被另一套系统刷屏”的事故让我下了决心:现在所有飞书推送,只走唯一一个出口,自带三次重试,失败了就大声报错(
SystemExit),绝不静默吞掉。七个脚本全部切过去。(de3bd89)一个每天该说话的机器人,最可怕的不是说错,是某天悄悄不说了、而你以为它还在。 - 一个用真金买来的排查纪律。 这周我痛失了一份日报——排查它为什么丢失时,我先重新部署了,才想起去看日志。而重新部署这个动作,恰好会同时销毁容器里的日志和平台上的旧部署日志。证据两头都被我自己毁了,根因永远查不出来了。 从此立规矩:排查线上定时任务,先抓日志,再动部署。 顺手把所有定时任务的输出接进了平台面板,让它们不再只活在会被销毁的容器里。
- 数据库瘦身。 发现 binlog(数据库的操作日志)胀到了 4.7G,而真实数据才 733M——日志是数据的六倍半。 清掉、把保留期从 30 天砍到 3 天,一把释放 4.1G。
- 每晚备份 + 异地容灾。 给整套系统配了每晚 02:30 的自动备份(数据库 + 纸面盘台账,多槽位轮转,而且实测验证过能恢复——没验证过的备份不叫备份),再用一个钩子把它推到异地的 Google Drive。数据这东西,在一个地方等于没有。
- 把自己那台服务器焊死。 我这套系统(连同我这个 AI 助手本身)都跑在同一台独立服务器上。这周查日志发现,它在 18 天里被暴力破解了 20 万次。当即关掉密码登录、只留密钥,并清理出 6G 空间。一台裸奔在公网上的服务器,不是”会不会”被攻破的问题,是”已经被敲了多少次门”的问题。
七、这周的记分牌,我不打算给你看
上一篇结尾,我摆了张六个盘的成绩单,还挺郑重。这周你可能等着看新的一张。
但这周我不给。 因为如果我诚实的话,这张记分牌根本不能信——
- 择时盘的闸,一半时间跑的是坏的;
- 两张策略表,全程一票没投;
- 看板上的价格,被污染了十五天;
- API 还在时不时喂我陈旧快照。
在这样的一周里报一张精确到小数点后两位的收益表,本身就是一种撒谎。 那个精确度是假的,它会让你误以为背后的一切都可信。
所以我做的不是”报分”,而是把记分牌本身修好,然后把计时器归零。7 月 13 日口径变更之后,才是这几个盘第一次在”尺子没坏、数据干净”的条件下起跑。真正能拿来对照大盘、能拿来裁决”哪个盘该留”的成绩单,得从这周往后重新计。
上周我说”相信账、别信直觉”。这周补一句前提:账要能信,得先保证记账的笔没漏墨。 一套自动化系统真正的护城河,从来不是它最聪明的那部分,而是它的账本干不干净。
八、写在最后
这一周的成果,摆出来是这样:
1 | |
回头看,这七天没有一行代码是在”让系统更聪明”。做的全是些更难堪的事:发现它其实一直有点坏,然后一处处修。
上一篇我得意地写下”一个失败得很安静的系统,你迟早会栽在它手里”。我没料到,第一个栽进去的就是我自己——而且不是栽一次,是同一周里,被四个不同的、安静的失败,接连绊倒。
但我现在反而踏实了。因为这些坑,要么是我自己挖的,要么是我一直没敢细看的。它们被翻出来的这一周,是这套系统两个月来最不光鲜、却最扎实的一周。
上一篇的收尾我说”最难补的洞在按下止损键的那只手上”。这一篇,我想把那句话往前推一步——
在你能相信自己的判断之前,得先能相信你的记分牌;而在你能相信记分牌之前,得先亲手确认:它没有在悄悄地,对你撒谎。
👉 欢迎光临「天智精选」 tianzhi.vgtmy.com ,请提出宝贵意见。
本文仅记录个人系统的设计思路,不构成任何投资建议;文中系统为纸面模拟,不涉及真实下单。