FreqAI:机器学习长在一个真实交易系统里是什么样
- 用「学徒进车间」这套类比,说清一个真实交易系统会给机器学习加上哪四条工程约束,以及每一条各自在挡什么
- 说清「陌生就不答」和聊天式 AI「永远有话说」的根本差别在哪,从此知道该向对方要什么东西
- 认出这套约束挡不住的部分——它管不了你把题目出错,也管不了特征堆太多堆出来的好看结果
你打开一个聊天窗口,问它明天大概怎么走。它答了。你换个说法再问一遍,它还是答,而且答得挺完整。你甚至可以编一个根本不存在的标的名字扔进去,它照样能给你分析出个一二三来。
不踏实的地方不在于它偶尔答错——人也会答错。真正让人心里没底的是:你完全没办法从它的语气里,看出它这次到底有没有把握。 它对烂熟于心的问题和对闻所未闻的问题,表现出来的自信是一模一样的。
现在把镜头切到另一边。有一类机器学习不是长在聊天窗口里,而是长在一个真的会替你下单的程序里。它每隔一段时间要醒一次,看一眼最新的行情,然后给出一个数——这个数会直接变成买或者不买。这种场合下,"永远有话说"就不是优点了,是灾难。
这篇要看的就是这么一个东西:开源交易框架 freqtrade 里那个叫 FreqAI 的模块。它值得单独拿出来讲,不是因为它的模型多先进——恰恰相反,它用的都是很普通的机器学习库。它值得讲,是因为它是少数几个把机器学习塞进一个真正要执行订单的系统里的开源样本。论文附带的代码只需要在最后交出一条曲线,它不行;它必须在每一根K线上回答一个非常具体的问题:这次的预测,你信不信?
先说人话:把一个学徒放进真实车间
想象一家做鉴定的老店。后面有个研究室,几个人整天拿着历史资料做课题,写出来的报告好看得很。前面是门店,客人把东西往柜台上一放,你得当场给个说法,而且你说完客人就掏钱了。
现在老板要把研究室里那个成绩最好的学徒放到前面柜台上。研究室里怎么干都行,但柜台是要负责任的地方,所以老板给他立了四条规矩。
第一条:你只准看清单上列的那些线索。 掂重量、看纹路、量尺寸、闻味道——想看什么,事先写进清单,写进去了才准看。为什么这么死板?因为研究室里出过一件事:有个学徒的判断准得离谱,后来才发现他偷偷瞄了客人的收据,收据上写着东西是从哪儿收来的。他不是眼光好,他是看了答案。柜台上没有收据可瞄,那份准就一钱不值。
第二条:每隔一段时间回炉重学一次。 不是学一次管一辈子。市面上的东西一直在变,做旧的手法一直在翻新,去年的经验今年就钝了。所以他隔一阵子就要拿最近这一批新样本重新过一遍,学完了换上新的本事,旧的那套作废。
第三条:碰到没见过的东西,必须说"我不确定"。 这条最难,也最值钱。客人拿来一件他从没在任何样本里见过的东西,他心里那套判断照样能转出一个结果来——但那个结果是瞎猜。所以规矩是:先判断"这东西像不像我学过的那批",不像就直接摊手,不许硬答。
第四条:他的上岗证有有效期。 老板在墙上挂了张牌子,写着他上次回炉是什么时候。要是隔太久还没轮上回炉,那这段时间他说的话,柜台上要打个问号,甚至干脆不采信。
这四条规矩,就是这篇要讲的全部内容。它们不是机器学习的算法创新,一条都不是。它们是工程约束——把研究室里"应该注意"的事,变成柜台上"不注意就干不成"的事。
到投资里,这四条各自在挡什么
规矩听着都对,但你得知道每一条是在挡哪一种具体的翻车。
第一条挡的是"看了答案"。 在投资里这个毛病叫前视偏差:你用了一个在当时根本拿不到的信息去做判断。它可以隐蔽到什么程度?你算一个"这只票的估值处在过去五年的什么分位",这个数字里就藏着未来——五年后的数据参与定义了五年前的那个分位。历史成绩因此变得非常好看,实盘里一天都复现不出来。把"允许看什么"做成一个必须显式声明的清单,等于给这件事装了个物理门槛:没写进清单的东西,模型根本拿不到。这一层的机制细节,特征与标签 那篇拆得更透。
第二条挡的是"用去年的地图找今年的路"。 一个在历史上表现很好的模型,上线之后会慢慢变钝,不是因为它坏了,是因为它当年学的那个市场已经不在了。这件事没有例外,只有快慢。所以真正要管的东西从来不是"我找到的这个模型有多好",而是"我能不能稳定地、按时地造出下一个来替换它"。模型会过期 那篇专门讲这个视角上的翻转。
第三条挡的是"外推当插值"。 模型学过的那片区域,它的判断是有依据的;离开那片区域,它的输出仍然是个数,但那个数已经不含任何信息了。麻烦在于,从输出上你看不出区别——一个有依据的判断和一个纯外推的猜测,长得一模一样,都是一串小数。所以必须有一个独立于预测本身的东西来告诉你:这次的输入,离我学过的东西有多远。
第四条挡的是"沉默的失效"。 系统出故障往往不是轰然崩塌,而是某个环节悄悄不动了。训练线程卡住了、数据没下来、机器重启后没接上——预测照常在产出,只是产出它的那套本事已经好几天没更新过了。给模型加一个"上次训练是什么时候"的时间戳,等于给这种沉默的失效装了一个会响的铃。
系统层:这四条规矩在框架里长什么样
规矩一:允许看的东西,必须写在指定的地方
FreqAI 的做法是:你想让模型看的所有线索,都得写在策略文件里几个专门的函数里,而且每一个都要带上一个前缀符号才会被认领。要模型去猜的那个答案(也就是标签),带的是另一个不同的前缀。
这个设计乍看有点土——不就是个命名规范吗?但它干的事挺狠:它把"输入"和"要猜的答案"这两类东西,在命名这一层就强行分开了。 一份宽表里有几千列,哪些是喂给模型的、哪些是要它预测的,不靠你记性好,靠符号。你要是不小心把一个含了未来信息的列当成输入写进去,框架不会拦你——但至少这份清单是明摆着的,可以被人一列一列看过去。
# 概念示意:特征写在专门的函数里,且必须带前缀符号才被识别
def feature_engineering_expand_all(self, dataframe, period, metadata, **kwargs):
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
dataframe["%-relative_volume-period"] = (
dataframe["volume"] / dataframe["volume"].rolling(period).mean()
)
return dataframe
# 来源:freqtrade 示例策略模板(快照 b3404c9),此处仅作概念注解
顺带说一件很容易被误读成"好功能"的事。这套函数支持自动展开:你写下一个指标,框架会替你在多个周期、多个时间尺度、多个相关标的、多根历史K线上把它复制一遍,一条定义膨胀成几十上百列。官方文档自己把这当成卖点在讲,说的是能轻松搭出规模很大的特征集。
省事是真省事。但你要清楚这意味着什么:你写下的不是几个特征,是一大片。 特征越多,模型在历史上找到某种"恰好成立"的巧合的机会就越多。这不是 FreqAI 的毛病,是所有大规模特征工程共有的代价,过拟合 那篇讲的就是这台噪音制造机怎么转起来的。框架里也确实配了降维之类的手段去压这个问题,但压不等于消。
规矩二:训练是滚动的,而且回测里也照样滚
这是 FreqAI 和大多数"机器学习选股教程"最不一样的一点。
教程里的流程通常是:数据读进来,切成训练和测试两块,训一次,评一次,出一张图,结束。FreqAI 不这么干。它跑起来之后是一个不断向前挪的窗口:拿最近一段历史训一个模型,用它去预测接下来一段时间;时间走过去了,窗口整体往前挪,再训一个新的,替换掉旧的。周而复始。
关键在下一句:它在回测里也是这么干的。 回测同一段历史时,框架会按同样的节奏一次次重新训练,模拟"当时的你只能用当时能拿到的数据训出当时那个模型"。这跟"拿全段历史训一个模型再回头预测全段历史"是两件性质完全不同的事,后者出来的成绩基本没有参考价值。
为什么必须这样,时序交叉验证 那篇用天气卡片的例子讲得很清楚:随机打乱数据做出来的高分,考的是"知道前后两天猜中间那天"的填空能力,而你真正要用的是"站在今天往前一片漆黑"的外推能力。按时间滚动,就是把考试形式从填空改回外推。
至于"多久重训一次",框架里确实有参数让你控制最短间隔和数据窗口长度。这里不给你任何具体数——不是藏私,是这个数根本没有通用答案:你的模型多大、机器多快、标的多少、市场变得多急,每一样都会把它推向不同的方向。你能带走的只有那个权衡本身:重训得越勤,模型越新鲜,但新旧模型对同一批标的的看法一变,你的持仓就得跟着动一次,交易成本实打实地增加。这笔账不算,你很容易得到一个"越勤越好"的漂亮结论,然后被成本吃光全部改善。
规矩三:每个预测,都带着一张信任标记
这是我认为 FreqAI 最值得被抄走的设计。
模型算完之后,输出的不只是那个预测值。旁边还跟着一列东西,可以理解成一张信任标记:这次的输入,我认不认得?框架里这列叫 do_predict,名字很朴素,作用一点也不朴素——它是一个可以被反复扣分的整数,满分表示"这次输入落在我学过的地盘里,可以信",每被质疑一次就扣一分。
谁来质疑它?框架里备了几种互相独立的判断方式,各管一个角度:
- 一种是量"距离":把这次的输入和训练时见过的所有样本比一比,看它离那团数据有多远。远得离谱,就说明这是一片模型没去过的地方。
- 一种是训练一个专门认边界的小模型,让它单独回答"这个点在不在我熟悉的范围内"。
- 还有一种是做聚类:训练样本自然会聚成若干团,落不进任何一团的孤零零的点,就被当成异常。
这几种方法各有各的盲区,所以它们不是互相替代,而是叠加——每一种觉得可疑,信任标记就掉一分。掉到什么程度算不能用,由你在策略里自己决定。
于是策略里那句买入条件就长成了这样:信任标记正常,并且预测值满足我的条件,才买。 两个条件是"并且",不是"或者"。模型说得再肯定,只要这次的输入被判成陌生,这一单就不下。
规矩四:模型会过期,而且过期这件事本身会被写进输出
框架里有一个很短的检查:拿当前时间减去这个模型的训练时间,看隔了多久;超过你设定的时限,这个模型就被判为过期。你可以选择不设时限,那就永不过期——但那是你自己做的选择,不是默认没这回事。
过期之后发生什么?不是报错,也不是停机,而是那张信任标记被打上一个专门的值,告诉下游"这次的预测来自一个超龄的模型"。策略里可以据此决定是照旧用、还是暂时不开新仓。
我很喜欢这个处理方式,因为它把一件本来看不见的事变成了看得见的数据。模型的"新鲜度"不再是运维日志里某行没人看的记录,而是和预测值并排、一路流到决策那一刻的一列。结果能过期,而且过期状态跟着结果一起走——这是研究型代码里几乎不会有、生产系统里迟早要补上的东西。
「陌生就不答」和「聊天窗口永远有话说」
上面四条里,第三条值得单独拎出来再说一遍,因为它是理解"AI 投研到底靠不靠谱"的一把钥匙。
一个跑在真实交易系统里的模型,被强制要求回答两个不同的问题:"我的判断是什么",和"这个判断可不可信"。 后者不是从前者里推出来的,是另一套机制独立算的——它甚至根本不看预测值,只看输入长得像不像它熟悉的东西。
而你在聊天窗口里面对的东西,结构上就不长这样。它的输出是一段话,一段话里没有位置放那张信任标记。你问它一件它烂熟的事,它给你一段话;你问它一件它压根没见过的事,它还是给你一段话,句式一样流畅,语气一样笃定。它不是在骗你,是它的输出格式里就没有"我不确定"这个格子。
所以这两者的差别,根本不在于谁更聪明。差别在于:一个被工程约束逼着承认自己的边界,另一个没有任何机制逼它承认。
这件事直接决定了你该怎么听别人讲 AI 投研。下次有人拿一套"AI 预测"来跟你说话,与其纠结它准不准,不如问一句更要命的:它什么情况下会说"这次我不知道"? 如果对方答不上来,或者答的是"我们的模型泛化能力很强",那你基本可以判断:这套东西没有第三条规矩,它对任何输入都会给你一个答案,包括那些它其实一无所知的输入。
再往深一层,AI 能不能预测股价 那篇拆过"猜下一个词"和"猜下一个价格"在机制上的差别。把那篇和这一节合起来看,结论就很清楚了:语言模型的自信是生成出来的,而这里的信任标记是算出来的。 一个是文风,一个是度量。听起来像的东西和能被检验的东西,从来不是一回事。
它挡不住的那些事
把上面这些说完,还得把边界划清楚,不然容易读出一种"用了这套就稳了"的错觉。
它管不了你把题目出错。 标签是你自己定的:让模型猜方向、猜涨跌幅、还是猜排序,是三件难度完全不同的活。你要是把题目出成一道本身就没什么信息量的题,四条规矩一条不落地执行完,你得到的只是一个规规矩矩产出的废物。这一层归你,框架不替你想。
它管不了特征堆太多堆出来的好看成绩。 前面说过,那个自动展开机制能让一条定义膨胀成几百列。列越多,在历史上撞出巧合的机会就越大。离群检测能拦住"这次输入太陌生",但拦不住"我在历史上找到的这个规律本身就是噪音"——后者在训练集里看起来一点都不陌生。
它管不了你为了让成绩好看反复重跑。 这个动作有个专门的名字叫数据窥探:同一份历史被你翻来覆去试了几十遍,最后留下那个最好看的,它好看的原因很可能只是被试出来的。这块和超参优化纠缠得最深,超参优化 那篇专门讲这件事,这里不展开。
它不保证赚钱,框架自己也从没这么说。 FreqAI 的文档在介绍示例策略时明确写了:那份示例是为了展示各种功能、为了能在小机器上跑起来做的,不是给生产环境用的。这句话很值得记住——一个开源项目愿意把"这不是给你直接拿去用的"写在最显眼的地方,比任何宣传都诚实。
顺带补一句边界之外的边界:这个模块解决的是"模型怎么活在系统里",它上面还有一整套框架在管下单、管持仓、管风控。那部分是什么、又不是什么,freqtrade 是什么,又不是什么 那篇讲过。而模型变钝到底是"该重训了"还是"这个规律已经死了"——这两种情况的处理方式完全相反,信号衰减 那篇讲了怎么区分。
还有一句话必须说清楚:本篇看的是一份源码快照,是读出来的机制,不是跑出来的结论。这里没有任何一句"照着做就能跑通"的承诺,也没有任何实测数据。你要真去用,一切以你手上那个版本的官方文档为准。
说人话
把一个会学习的东西放到会花钱的地方,多出来的不是算法,是四件麻烦事:说清楚它能看什么,让它定期重学,让它敢说"这个我没见过",以及让它的结论带上保质期。
聊天窗口里的 AI 之所以让人不放心,不是因为它笨,是因为它没有第三件——它永远有话说。而你真正该找的,是那个会告诉你"这次我不知道"的东西。
本文为投资教育整理,关键数据与结论请结合下列权威来源验证。