如果你在量化交易这条路上走过超过一年,大概率会撞上一堵墙:传统机器学习模型在拟合历史数据时效果好得惊人,一旦进入实盘,净值曲线却像被谁按了暂停键。问题往往不出在模型复杂度,而出在我们看待概率的方式。《Machine Learning for Algorithmic Trading》里有一整块内容专门讲贝叶斯机器学习(Bayesian ML),它跟常见的深度学习、XGBoost路线完全不同,几乎是用一套新世界观在解决交易决策中的核心矛盾——数据太少、市场不平稳、参数不确定。
我最早翻到那本大部头的贝叶斯章节时,心里想的是“这不就是贝叶斯公式套上PyMC嘛”,结果真正拿自己的策略做过一轮之后才意识到,贝叶斯方法在算法交易里解决的远不止“求个后验分布”这么简单。它能把你对市场的先验判断、样本观测和未知参数的不确定性全部揉进一个框架里,最后输出的不是“明天涨还是跌”这种单点预测,而是“上涨概率是多少、这个概率本身有多可靠”。这篇文章就围绕书里贝叶斯ML这条主线,把核心原理、可落地的建模流程、参数选择逻辑,以及我踩过的坑一次讲清楚。
1. 为什么算法交易需要贝叶斯,而不是单纯堆模型
1.1 交易的残酷现实:样本少、非平稳、信号弱
先看一组让所有量化人都头疼的数字。日频策略一年大约只有250个交易样本,就算加上滚动窗口,有效独立样本也就几百到几千个。这个量级扔给深度神经网络基本等于盲人摸象。更麻烦的是市场分布时刻在变,2018年有效的因子,到2021年可能就是负贡献。传统频率派统计学把参数当成固定常数,用极大似然去点估计,本质上是在“假设历史会重复”的前提下找唯一答案,这个假设在交易里站不住脚。
书里反复强调一个观点:交易本质上是个序贯决策问题。你今天判断的不是一个永远不变的“真实参数”,而是“当前状态下参数大概在什么范围”。贝叶斯方法把参数看作随机变量,每次新数据进来,后验分布自动更新,模型天然具备自适应能力。这就是为什么Bayesian ML在书里占了相当篇幅——它不是用来跟LightGBM比AUC的,而是用来处理那些“数据不多但决策后果很重”的场景。
1.2 先验知识不是偏见,是交易老手的护城河
我在实际应用中最大的感受是:贝叶斯框架允许且鼓励你把行业直觉写进模型。比如你做了五年低频CTA,知道某个动量因子的系数大概率是正的,但幅度不确定。换成传统线性回归,你得祈祷数据自动学到这个方向,样本一少系数就乱飘。在贝叶斯建模里,你可以直接给这个系数设定一个均值大于零的正态先验,让模型在数据不足时“偏向”你的经验,数据足够时又会被数据拉回真实位置。
这个过程相当于给模型装了“阻尼器”。我做过一个实验:对同一个因子收益模型,分别用频率派OLS和贝叶斯线性回归做滚动预测,样本量为100时OLS的系数正负号切换了七次,而带温和先验的贝叶斯模型只切换了两次。代价是极端真实信号出现时贝叶斯收敛慢一点,但交易里“保守地稳定”往往比“激进地跳变”活得更久。
1.3 贝叶斯ML在量化里的几个典型战场
书里并不是把贝叶斯当成单一算法,而是当成一套可以覆盖多种任务的方法论。我总结下来,贝叶斯ML在算法交易里至少有四个高频战场:因子收益建模(估计因子系数的分布)、波动率与变点检测(识别市场状态切换)、策略参数优化(贝叶斯调参替代网格搜索)、交易信号的概率化输出(把预测转成可执行的置信度)。后面我写的场景基本都是围绕这四块展开,这也是我认为这本书贝叶斯章节最有工程价值的部分。
2. 贝叶斯推断核心概念拆解,以及交易语境下的直观理解
2.1 先验、似然、后验:一次讲清楚这个三角关系
很多教程把贝叶斯公式写成 P(θ|D) = P(D|θ)P(θ) / P(D),符号摆一堆,看完还是不知道θ该设什么。我用交易场景重新翻译一遍:θ是你的模型参数,比如动量因子的真实收益率贡献;P(θ) 是先验,代表你在看数据之前对这个参数的理解,可能是“过去五年这个因子平均月超额是0.5%,标准差大概0.2%”;P(D|θ) 是似然,意思是“如果参数真的是θ,那出现当前这串历史收益数据的概率有多大”;P(θ|D) 是后验,就是看完数据之后,你对该参数的修正认知。
逻辑上它就是一部“经验+证据”的加权器。先验像开盘前你的主观判断,似然像盘中不断涌入的成交数据,后验就是收盘后你对该参数新的置信区间。如果数据量巨大,后验基本等于频率派估计;如果数据量小,后验主要由先验主导。这个性质特别适合交易:市场经常出现样本稀少的新状态,比如某种极端波动后的恢复期,这时候先验能帮你稳住模型。
2.2 共轭先验与采样法:什么时候能算,什么时候得“抽签”
贝叶斯推断的数学难点在于分母P(D)通常没有解析解。书里给出了两条路线:一是用共轭先验,让先验和似然在数学上“配对”,比如Beta先验配二项分布似然,后验还是Beta分布,直接笔算;二是用MCMC(马尔可夫链蒙特卡洛)采样,在参数空间里随机游走,生成大量参数样本,这些样本的分布就近似后验分布。
我做策略评估时就经常用Beta-Binomial这个共轭组合。假设你回测了50笔交易,其中30笔盈利,你想知道真实胜率的后验分布,直接用 Beta(30+α, 20+β),如果先用一个 Beta(α=2, β=2) 作为“中性偏保守”的先验,后验就是 Beta(32, 22),期望胜率是 32/(32+22)≈0.593,同时你还能给出95%置信区间。这在传统框架下要绕好大一圈,贝叶斯公式十行搞定。
2.3 MCMC采样为什么会发散,以及PyMC里怎么判断是否收敛
真正复杂的模型,比如带变点的时序模型,共轭先验就不够用了,得上采样。MCMC的思想简单说就是让一组“粒子”在参数空间里按规则随机游走,游走方向受后验密度影响,密度高的地方粒子多。PyMC、Stan这些概率编程库帮你封装了采样细节,但基本概念你得懂,否则连报错都看不懂。
实操中最重要的一件事是检查R-hat(Gelman-Rubin统计量)。R-hat接近1表示不同采样链收敛到同一分布,一般要小于1.05才算可用。我第一次调变点模型的时候,四个链条的R-hat飙到1.3,怎么调都降不下来,最后发现是switch函数写错了,导致模型在不同状态之间疯狂切换。这个排查过程非常折磨,但也是真正理解贝叶斯建模的开始。
2.4 概率编程工具选型:PyMC、Stan、还是自己手写
书里示例主要围绕PyMC和Stan风格代码展开,我自己在项目里用过PyMC3/5、CmdStanPy,也试过NumPyro。如果你刚起步,我建议直接用PyMC,它的API设计最接近“建模-采样-诊断”的自然流程,文档也全。Stan的建模表达能力更强,尤其在复杂分层模型上,但语法需要单独学一套。NumPyro优势是GPU加速,数据量大时快很多,不过生态相对没前两个成熟。
别自己手写Metropolis-Hastings或者Hamiltonian Monte Carlo,除非你想读博。一来数值稳定性难保证,二来现代采样器里一堆自动调参技巧(比如NUTS自动选择步长),手写轮子既花时间又容易出bug。把精力花在模型设计上才是正路。
3. 贝叶斯建模实践:因子收益模型、变点检测、策略后验评估
3.1 实战一:用贝叶斯线性回归估计动量因子收益
这是最常用的入门场景。假设你有一个动量因子暴露序列momentum,以及对应周期内的实际收益率returns,你想知道该因子的真实系数 beta 和噪声 sigma 的分布。传统回归给的是“beta=0.03,p<0.05”,贝叶斯给的是“beta 的后验均值是0.03,90%最高密度区间是[0.01, 0.05]”。后者直接告诉你这个因子“可能有多赚钱”,以及“我们对它的确信程度”。
一个典型的PyMC建模代码如下:
import pymc as pm import numpy as np with pm.Model() as factor_model: # 先验:系数均值0,标准差0.5,表示我们不确定方向 beta = pm.Normal("beta", mu=0, sigma=0.5) # 噪声先验:半柯西分布,厚尾,允许偶尔的异常波动 sigma = pm.HalfCauchy("sigma", beta=1) # 线性预测 mu = pm.Deterministic("mu", beta * momentum) # 似然:假设收益率围绕均值呈正态分布 returns_obs = pm.Normal("returns_obs", mu=mu, sigma=sigma, observed=returns) # 采样:4条链,每条2000后验样本,前1000为预热 trace = pm.sample(2000, tune=1000, chains=4, cores=4)这里有几个设计决策值得说一下。beta先验的标准差我故意设为0.5而不是1,因为动量因子的收益弹性通常在±0.2以内,太大的先验方差会让采样初期在无意义区域浪费大量时间。HalfCauchy噪声项是我在经历了两次极端行情后发现的好处:它厚尾特性允许模型把偶发大波动归为噪声,而不是硬生生扭曲系数估计。换成普通正态噪声先验,一次大幅亏损就能让后验区间剧烈变形。
跑完之后最重要的一件事是做后验预测检查。把采样得到的beta和sigma代回去,重新生成模拟收益序列,如果模拟序列的分布跟真实收益分布差距很大,说明似然函数选错了,比如应该用StudentT而不是Normal。我当时用正态似然时,尾部预测明显偏窄,换成自由度较低的StudentT之后,95%区间才跟实盘极端情况对得上。
3.2 实战二:变点检测,自动识别市场状态切换
策略失效的最常见原因不是模型错了,而是市场状态变了。贝叶斯变点检测就是解决“状态到底何时切换”的问题。核心思想是:数据里可能存在一个或多个时间点 tau,在tau之前收益分布参数是θ1,tau之后是θ2,我们同时推断tau和两套参数的后验分布。
我举一个简化代码,检测收益率均值变点:
with pm.Model() as cpd_model: # 变点位置:在0到n-1之间均匀分布 tau = pm.DiscreteUniform("tau", lower=0, upper=n-1) # 变点前后的收益率均值 mu_before = pm.Normal("mu_before", mu=0, sigma=0.5) mu_after = pm.Normal("mu_after", mu=0, sigma=0.5) # 公共噪声项 sigma = pm.HalfCauchy("sigma", beta=0.5) # 根据tau选择均值 mu = pm.math.switch(pm.math.lt(np.arange(n), tau), mu_before, mu_after) # 似然 obs = pm.Normal("obs", mu=mu, sigma=sigma, observed=returns_series) trace_cpd = pm.sample(2000, tune=1000, chains=4)这个模型的输出会让你看到tau的后验分布呈现一个尖峰。如果尖峰明显集中在一个日期附近,说明市场状态在那个时点发生了显著切换;如果tau的后验分布平坦得像均匀分布,说明数据里没有明显变点,你该想想是不是模型设错了。
我实操中遇到过最典型的误报场景:把波动率变点当成均值变点。有一段时间策略连续回撤,我用均值变点模型检测,结果tau后验分布没有尖峰,反而sigma(噪声)后验分布明显变宽。后来才意识到那波行情是波动率放大而不是收益率中枢下移,应该用波动率变点模型,把噪声项拆成sigma_before和sigma_after。这也是书里强调的一个观点:变点检测的“变”是什么性质,必须由业务假设先定清楚。
3.3 实战三:用Beta-Binomial监控实盘胜率,不再被短期运气欺骗
当你有一套策略在实盘跑,最焦虑的事情就是“最近连亏三次,策略是不是失效了”。频率派的做法是算一下胜率是否显著低于历史均值,但样本太少时很容易误判。贝叶斯做法轻松得多:实时更新胜率的后验分布。
建模思路不复杂。历史回测给你一个胜率先验,假设你过去的胜率在55%左右,但你又不想过度自信,于是把先验设成 Beta(α=50, β=40),对应均值约55.6%,且方差不算太小。之后每完成一笔实盘交易,盈利就更新为 Beta(α+1, β),亏损就更新为 Beta(α, β+1)。几笔交易下来,你会得到一个实时胜率后验分布。如果连亏三笔,先验比较稳健的话后验均值可能只是从55%滑到54%,你不会手忙脚乱;如果后验区间明显右移甚至均值跌破50%,那才值得起动策略熔断。
这个模型的工程价值在于:它把“策略是否失效”从拍脑袋变成了概率判断。你还可以叠加一个决策规则:当后验均值低于某阈值且95%区间上限也低于历史胜率时,自动降仓。我实盘里用这套逻辑过滤过两次假失效警告,也真的在一次区间持续下移时提前降低了仓位,整体体验比盯着累计净值曲线猜舒服得多。
3.4 实战四:贝叶斯超参数优化,比网格搜索省出几十倍算力
书里的贝叶斯优化章节虽然不完全属于Bayesian ML的推断部分,但思想上是一脉相承的:用高斯过程(GP)代理模型替目标函数建模,每次评估完一组参数后更新代理模型,再通过采集函数(比如EI,期望提升)选择下一组最有希望的参数。
我做过一个对比实验:对某个择时策略的10个参数做调优,网格搜索假设每个维度10档,总组合就是10^10次回测,根本跑不完。换成贝叶斯优化,用Optuna这类工具,300次回测就摸到了接近最优的参数区间。核心原因是它把“已试验过的参数区域”和“未探索但可能更好的区域”做了平衡,而不是盲目穷举。Optuna虽然封装得很好,但你要理解它背后的采集函数逻辑,才能判断是调大 exploration 还是 exploitation。我的经验是:初期用高 exploration 快速铺开搜索空间,后期收窄到最优区间做精细搜索。
4. 工程落地的硬经验:计算性能、先验敏感性、回测偏差
4.1 采样速度太慢怎么办:先减小模型,再升级硬件
贝叶斯MCMC最被人诟病的就是慢。一次正常的采样任务,几百个数据点、四五个参数,PyMC跑起来大概几十秒到几分钟,还可以接受。但如果你做滚动窗口的逐日更新,比如每天重采样一次,一年就是250次,时间成本立刻上来了。
我常用的三个优化手段,按性价比排序:第一,用变分推断(ADVI)替代完整MCMC做快速原型验证,速度能快几十倍,精度虽然略差,但足够你判断模型方向对不对;第二,减少采样步数,把 chains 从4降到2、draws 从2000降到1000,代价是R-hat可能不够稳,适合快速筛选;第三,改用NumPyro跑GPU版NUTS,适合参数维度高的模型。还有一个容易被忽略的点:检查你的数据有没有标准化。如果动量因子和收益率的量级差太远,NUTS的步长自适应会很痛苦,先对特征做标准化能显著提速。
4.2 先验敏感性分析:你的结论是数据的功劳,还是先验的功劳
贝叶斯模型最容易被人质疑的就是“后验是不是被你用先验偷偷操纵了”。应对办法是先验敏感性分析:至少跑三组先验——强先验、弱先验、平坦先验——然后对比后验分布是否稳定。如果换先验后结论方向直接反转,说明数据信息量太弱,模型不建议用于实盘。如果后验均值变化不大,只是方差略有出入,说明数据主导了推断,模型的结论更可靠。
我做过一个印象深刻的测试:对某个新因子的系数,先验从Normal(0, 1)改成Normal(0.1, 1),后验均值竟然从0.02翻到0.08。明眼人都看得出来,这个变化不是因为因子信号强,而是先验均值起了锚定作用。后来我把这个因子的样本量扩大了一倍,后验才对先验不再敏感。所以我现在做任何新因子分析,第一件事不是写模型,而是先跑三组先验对比,数据不足时宁可不上线。
4.3 贝叶斯方法如何配合回测,避免“未来函数”和“样本内过拟合”
贝叶斯方法本身没有免疫过拟合的超能力,但它的框架让过拟合更容易暴露。比如你在回测里做了参数后验更新,那么实盘模拟时必须严格用“当时可得的数据”逐日更新,不能用全样本后验替代。这跟传统机器学习里“避免标签泄露”是一个道理,但贝叶斯时序建模里更容易犯,因为后验更新看起来太自然了,常常一个不小心就用了未来数据。
我实操时的做法是写一个滚动更新框架:每个交易日只用截至当天的数据重新采样,保留当天的后验预测结果,然后前滚一天。这种walk-forward方式的贝叶斯评估,计算量非常大,但效果非常踏实。书里虽然没有给出完整代码,但这个思路在“backtesting”相关章节反复出现过,跟贝叶斯结合之后,相当于给回测加了一层“概率韧性”——你的回测不再是一个孤零零的收益数字,而是一个包含不确定性的收益分布。
5. 常见问题与排查技巧实录
5.1 采样发散(divergence)怎么排查
采样发散是NUTS最常见的报错性症状,标志是在后验样本里出现大量极端跳跃值。第一步不是调模型,而是调采样器的target_accept,我一般先设到0.9,如果还发散就继续往上到0.95,代价是采样更慢。第二步检查参数的参数化方式,比如标准差用HalfCauchy还是LogNormal,不同的参数化对采样几何有影响。第三步才是怀疑模型本身。记住一个经验:发散多的时候,先怀疑先验尺度不合适,再怀疑模型结构,最后才怀疑数据。
5.2 R-hat一直偏高,但人眼看得后验挺光滑
这个坑我踩过好几次。看起来四个链的分布形状差不多,但R-hat就是降不下来,通常是因为链之间在某个参数的高维空间里没有真正混合,二维边缘分布看起来一致,三维联合分布却分成了两簇。解决办法是看trace图而不是只看后验统计表,或者用az.plot_pair画二维联合密度对比。再不行就涨tune步数。我一般最少设1000,复杂模型设2000以上,给它足够的时间耗散初始状态。
5.3 先验写得太强,后验被吸走
所谓“数据没说话,先验先赢了”。判断标准很简单:后验均值和先验均值几乎重合,且后验方差远小于先验方差。这时先验太大刀阔斧了,适当放宽方差。我习惯把先验设计成“有方向但没把握”的状态,比如均值带符号,方差设成能让数据在百来个样本量级改变均值符号的程度。这样既保留了经验约束,又给数据留了纠偏空间。
5.4 贝叶斯模型的输出怎么转成实盘信号
后验分布本身不是一个可执行信号,你需要一个决策规则。常见做法是把后验预测分布的分位数映射成仓位:预测上涨概率大于70%且区间下界为正时满仓;概率在55%~70%且区间包含零时半仓;概率低于55%空仓。这个规则看似简单,但好处是它强迫你同时关注点估计和不确定性。我从书里学到的另一个技巧是对预测分布做风险调整,比如用后验样本的5%分位收益作为“安全边际”,比单纯看均值更稳健。
5.5 什么时候不应该用贝叶斯
这句话听起来有点反教材,但在工程决策里很重要。如果你有海量数据、特征维度很高、核心任务是做预测而不是做推断,那么深度学习或梯度提升树的上限通常更高,强行套贝叶斯只会拖慢迭代速度。贝叶斯的优势场景是数据量适中、参数可解释、需要不确定性估计、或者需要融合业务先验。选错工具,再好的方法论也会变成负担。
最后聊两句我的体会。书里贝叶斯机器学习这部分,不是我读一遍就敢拿上实盘的,真正让我理解它的是那几次回测里的深夜排查:R-hat降不下来、后验被先验绑架、变点被误检。如果你也想把贝叶斯方法引入自己的策略体系,我的建议是不要一上来就搭一个全贝叶斯交易系统。先从单因子收益模型做起,把先验敏感性分析和MCMC收敛诊断这两件事练成肌肉记忆,再去碰变点检测、实时后验更新这些进阶玩法。贝叶斯方法救不活一个本身没有alpha的逻辑,但它能帮你诚实面对自己的交易系统——哪些是数据告诉你的,哪些只是你以为的。这大概就是这本书在这个话题上,最值得带走的东西。