做量化这几年,我最大的感悟是:大部分策略都在赚“顺势”的钱,趋势来了重仓追、震荡来了轻仓熬。但市场真正容易出大机会的地方,反而集中在急跌后的“抄底”环节。传统做法靠盘感,最多挂个条件单,本质上是拿真金白银赌“我觉得跌够了”。直到我把这个环节交给机器学习,才第一次觉得“猜底”这件事也有了一套可以复盘、可以迭代、可以交给系统自动执行的流程。第十五期线上培训,我们准备专门讲这块——用机器学习训练一个“激进抄底”模型,让量化系统在下跌行情里也能找到高赔率的入场机会。
这篇文章我会把这次培训背后的技术思路完整梳理一遍:为什么要做“激进抄底”、样本和标签怎么设计、特征怎么构造、模型怎么训练和检查、回测和风控怎么落地,以及我们实操中踩过的坑。适合三类人看:一是正在做量化但只会趋势策略的交易员,二是想入门机器学习但不知道从哪里下手的开发者,三是已经在跑ML模型但总觉得预测结果不稳定的朋友。哪怕你暂时不报名培训,把这套方法论吃透,也足够自己搭一个能跑的抄底模型。
1. 为什么量化系统需要“激进抄底”模型
1.1 传统策略在下跌行情里的集体失灵
趋势跟踪策略的假设是“价格会沿着已有方向继续运行”,这在单边上涨里很香,但在急跌行情里就是灾难。你按信号做空,结果超跌反弹直接打掉止损;你不做空,又眼睁睁看着趋势利润回撤。很多CTA策略在2022年以后回撤加大,本质原因不是因为模型不聪明,而是行情风格从“慢趋势”变成了“急跌急涨”,传统止盈止损根本跟不上。
网格策略更头疼。下跌时网格一层层买进去,刚买到第五层,行情直接加速跳水,仓位越接越重,最后变成被动长线。我见过太多人把网格做成“越跌越买、越买越套”的现货套牢法,原因就是网格没有“止损”概念,也没有判断“这个位置值不值得买”的能力。它只是在机械地执行价格间隔,完全不看估值、不看情绪、不看超跌程度。
至于人工抄底,问题就更明显了。价格跌到心理价位,忍不住加仓;反弹了又舍不得卖,总想着“还能再涨”;深套了就装死。这些行为本质上都是情绪决策,不是统计决策。我最早做抄底策略的时候也一样,复盘时发现:我的胜率不低,但盈亏比烂得离谱,赢的时候赚5%,输的时候亏30%,等于把“抄底”做成了“接飞刀”。
1.2 机器学习解决的是“该不该买”的问题
传统量化策略擅长回答“在什么价格买”和“买多少”,但很少回答“现在这个位置值不值得买”。机器学习模型恰恰擅长干这个:它可以从历史数据里学习“过去哪些超跌形态之后真的反弹了”、“反弹的幅度和概率是多少”、“什么样的环境不适合抄底”。
我们给这个模型起名叫“激进抄底”,这里的“激进”不是让你满仓干,而是指它在风险预算可控的前提下,愿意承担比普通策略更高的不确定性,去博取高赔率。换句话说,普通策略要求90%的胜率才敢出手,激进抄底模型可能只在35%到45%的胜率下就敢入场,但一旦对了,盈亏比可以做到3比1甚至5比1。这不是拍脑袋定的,而是用历史数据回测出来:很多超跌反弹的幅度远大于继续下跌的幅度,只不过反弹概率不高,导致普通人不敢买。
机器学习在这个场景下还有一个独特的价值——可复盘。人工抄底亏了,你很难说清楚是“判断错了”还是“运气不好”;模型抄底亏了,你可以打开特征重要性、预测概率分布和样本回看,搞清楚到底是哪几个特征误导了模型。这种“能解释的失败”是长期迭代的基础。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心思路:先把“抄底”定义成机器学习任务
2.1 任务定义:分类还是回归
建模之前必须先回答一个问题:我们要预测什么?
常见的做法有两种。第一种是分类任务,定义正样本为“未来5个交易日内涨幅超过3%”,让模型输出一个概率值;第二种是回归任务,直接预测未来5日收益率,再用阈值筛选入场。两种我都试过,给新手的建议是:优先做分类。原因很简单,分类任务的评价指标更直观,准确率、召回率、AUC都是现成的,业务上也更好解释——“模型说这个位置有40%的概率反弹5%以上”。
如果你要做回归,也不是不行,但会遇到两个麻烦:一是回归模型对极端值非常敏感,好日子和坏日子的收益差距太大,模型容易变成在拟合异常值;二是回归误差的分布通常不正态,直接用MSE做损失函数会有偏差。所以我推荐用分类方案起步,等把整个流程跑通之后,再考虑用回归输出做精细化仓位管理。
2.2 样本池构建:不是所有K线都能进训练集
这里非常关键。如果直接把全市场所有股票的所有交易日都丢给模型训练,模型大概率学到的是“市场长期上涨”,而不是“超跌之后会反弹”。我们需要先圈定一个候选样本池,只保留“超跌状态”的样本。
我的做法是:先计算每个股票过去20个交易日的累计跌幅,当累计跌幅低于某个阈值(比如-12%)时,把这一天标记为“超跌观察日”。然后对这个观察日之后的N天收益做标签。这样做的逻辑是:我们是在回答“已经跌了很多之后,该不该买”,而不是在回答“任何时刻该不该买”。
阈值怎么选?不推荐固定死,而是要根据股票的波动率做标准化。比如把“过去20日跌幅”除以“过去40日的年化波动率”,得到类似“N倍标准差”的指标。低波动的银行股跌5%已经算超跌,高波动的科技股跌5%可能只是日常波动,放在一个模型里会比较失衡。标准差标准化之后,样本之间就具备可比性了。
2.3 标签设计:防止未来函数的一票否决
做机器学习量化最怕的就是标签穿越,也就是把未来信息混进样本。常见的坑有两个。
第一个坑:未来复权因子泄露。如果你用的是后复权价格,那么当前K线的价格可能包含了未来除权除息的信息,标签和特征同时在用后复权价,模型会在训练时“偷看”未来的分红配送信息,实盘时却拿不到。正确的做法是训练时用前复权或原始价格计算收益率,特征尽量用非复权数据衍生,或者至少保证特征和标签来自同一价格口径且没有未来信息的引入。
第二个坑:标签窗口跨度过长。比如你预测未来20日的收益,但样本在最后20日内到期,收益没有走完,会造成标签截断偏差。我建议在标签计算时,剔除“从观察日到样本结束日不足完整窗口”的样本。同时,窗口期的长度也要和交易逻辑匹配。激进抄底通常看5日到10日的反弹窗口,太短容易被噪音主导,太长又变成赌beta,没有意义。
标签计算的代码大概长这样:
python复制import pandas as pd
def make_label(df, forward_days=5, ret_threshold=0.03):
# df必须包含前复权close,且按股票代码和时间排序
df = df.sort_values(['code', 'date'])
future_ret = (
df.groupby('code')['close']
.shift(-forward_days) / df['close'] - 1
)
df['forward_ret'] = future_ret
df['label'] = (df['forward_ret'] > ret_threshold).astype(int)
# 剔除未来窗口不足的样本(尾部样本)
df['is_complete'] = future_ret.notna()
return df[df['is_complete']].copy()
这段代码有个细节:shift(-forward_days) 用的是每个股票分组内的向前偏移,天然规避了股票之间的数据污染。标签阈值3%可以根据品种和周期调整,如果目标周期只有3天,阈值要降低到1.5%到2%,否则正样本太少。
3. 特征工程:把“跌无可跌”翻译成模型能懂的信号
3.1 超跌类特征:抄底模型的“基本面”
这一类特征是核心中的核心,用来刻画“这只股票跌得有多深、多快、多反常”。我常用的特征包括:
- 过去5日、10日、20日累计跌幅
- 乖离率:收盘价与20日均线的偏离百分比
- RSI(6)、RSI(14):低于30的超卖区间
- 布林带位置:收盘价在布林带下轨之外的距离百分比
- 年化波动率分位数:波动率处于过去一年哪个分位
这些特征不需要全部用,但至少要保证覆盖“跌幅”和“超卖程度”两个维度。我的经验是:乖离率和波动率分位数的组合特别有用,因为它能区分“跌得很惨但波动极低”和“跌得很惨但波动极高”两种完全不同的形态。前者可能是错杀,后者可能是踩踏。
3.2 盘中与交易行为特征:确认抛压是否衰竭
光看价格不靠谱,还要看交易行为。抄底最怕的是“下跌没结束”,所以我们要找那些“卖压在衰竭”的证据。
- 成交额变化率:过去3日平均成交额 vs 过去20日平均成交额
- 换手率是否出现明显放大或缩小
- 大单资金净流入:用Level-2数据的买单金额减去卖单金额
- 买卖价差:价差收窄说明流动性改善
- 低价股附近的价格档位挂单结构
这里有一个实操心得:成交量的量价配合非常关键。如果下跌是放量的,说明抛压还在释放,不要急着抄;如果下跌到末端出现缩量止跌,反弹的概率会明显提高。模型端不需要你手动做这种判断,但你给它的“量能变化”特征越丰富,它越容易学到这个规律。
3.3 市场环境特征:别在泥沙俱下时单独接飞刀
个股的超跌反弹概率,和市场整体环境高度相关。大盘单边下跌时,个股超跌反弹的成功率会显著下降;大盘本身已经企稳时,个股超跌反弹几乎是指数级别的。所以特征里一定要加入市场环境变量:
- 上证指数或宽基指数的20日跌幅
- 指数RSI
- 市场情绪指标:上涨家数占比、涨停家数、连板高度
- 行业指数相对强度:个股所属行业板块近20日排名分位
这类特征可以从板块层面做groupby聚合,再map回个股。实现也很简单,先算指数特征,然后按日期纵向合并即可,不需要搞复杂的时序对齐。
3.4 特征清洗与保存:别忘了做分位数截断
特征工程做完之后,别忘了做极端值截断。机器学习模型对离群值敏感度不一,但LightGBM这类树模型对极端值的容忍度相对高,xgboost也还行,但如果你后续要切换神经网络模型,不做清洗会直接影响损失函数。实践里我建议用分位数截断(上下1%或0.5%)把极端值拉回正常范围,而不是直接删除样本。特征统一做标准化或归一化,在树模型里不一定要做,但如果你打算做模型融合、后续上深度网络,标准化就是必须的。
特征保存格式统一用parquet,按日期分区存放,训练时按时间段加载。不要用CSV堆大文件,否则后面滚动训练时读数据能等哭你。
4. 模型训练与工程落地细节
4.1 模型选型:为什么主力还是GBDT
深度学习这两年很火,transformers、扩散模型、世界模型各种名词满天飞,但在量化抄底这个场景下,我的主力模型依然是LightGBM和XGBoost。原因有三点。
第一,样本量不够。所谓“超跌样本”本身在历史上就占少数,再按股票和时间分去重之后,普遍只有几万到几十万条,这点数据量深度学习根本吃不饱。第二,特征维度适中,几十个特征用树模型足够表达复杂交叉关系。第三,可解释性。金融模型背后是真实资金,你不能在模型预测错误时只说“神经网络的黑盒效果”,你需要知道是哪个特征让它做出了错误判断。LightGBM的feature_importance、plot_tree都是现成的诊断工具。
这不代表深度学习没有用。我们的规划里,后续会用LSTM或Transformer模型做序列特征提取,再和GBDT做融合,但这是训练进阶阶段的事,刚入门的同学先把GBDT跑通再说。
4.2 时间序列验证:普通K折是错的
机器学习入门教程里常用的train_test_split和K折交叉验证,在量化场景里都要慎用。原因很简单:金融数据是有时间顺序的,用未来数据训练、历史数据验证,等于作弊。你拿2023年的数据训练,用2022年的数据验证,模型当然会觉得“未来都知道了,预测个啥都准”。
正确做法是滚动时间窗口验证:用第1到第36个月训练,第37个月验证;然后第2到第37个月训练,第38个月验证,以此类推。这样每一步训练都只用过去信息,验证的是模型对未来一个月的真实泛化能力。
python复制from lightgbm import LGBMClassifier
def rolling_train(df_features, months_train=36, months_val=1):
all_months = sorted(df_features['month'].unique())
models = []
for i in range(months_train, len(all_months) - months_val + 1):
train_months = all_months[i - months_train:i]
val_month = all_months[i]
train = df_features[df_features['month'].isin(train_months)]
val = df_features[df_features['month'] == val_month]
model = LGBMClassifier(
n_estimators=500,
learning_rate=0.02,
max_depth=5,
num_leaves=31,
colsample_bytree=0.8,
subsample=0.9
)
model.fit(
train[feature_cols], train['label'],
eval_set=[(val[feature_cols], val['label'])],
callbacks=[early_stopping(50)],
)
models.append(model)
return models
注意这里的early_stopping也是基于滚动验证集,不是基于训练集。这样才能真实反映泛化能力。
4.3 正负样本不均衡:别让模型学到“永远不抄底”
超跌反弹本身是少数事件,正样本比例可能在5%到15%之间。如果不做处理,模型会倾向于把所有样本都预测为负样本,因为这样准确率也能到90%以上,但毫无意义。处理办法有三个。
第一是负样本降采样,随机抽取一部分负样本,让正负比接近1比2到1比3,树模型在小数据量下效果就很好。第二是样本加权,给正样本一个更高的权重,相当于告诉模型“预测错了正样本代价更大”。第三是调整决策阈值,不要用默认的0.5做分类阈值,而是画出PR曲线,找到precision和recall的平衡点。激进的抄底策略通常更关注recall,宁可错过也别在危险位置频繁交易,所以阈值一般会设在0.3到0.4之间。
我实际跑下来,负样本降采样效果最稳,也不容易引入额外的调参维度。样本加权在极端不平衡时用,但一定要配合滚动验证观察稳定性。
4.4 模型融合与蒸馏:一个被低估的组合拳
单模型在金融数据上经常出现“过拟合某一段行情”的问题,比如某段时间模型学会了大涨股的特征,下一段行情就失灵。一个简单有效的对策是模型融合:把LightGBM、XGBoost、CatBoost三个模型同时训练,然后对它们的输出概率做加权平均或排名平均。
最初我担心融合会让模型变得迟钝,但实测下来,融合之后的是AUC通常比最优单模型高0.02到0.05,回撤有明显降低。原因是不同模型对特征的敏感区间不一样,融合后就抵消了一部分噪音。激进抄底模型这个场景特别适合融合,因为它本身面对的信号噪音就大。
融合之后还有一个进阶操作——模型蒸馏。蒸馏的思想是大模型/集成模型负责学习“高精度答案”,然后让小模型去学习“大模型的输出分布”,从而在保持精度的前提下大幅降低推理耗时。实盘场景里,如果你用3个树模型做融合,每个下单信号要跑3次推理,延迟会高不少,尤其高频场景下很难接受。蒸馏到一个单模型后,精度只损失0.5%左右,但速度能提升3倍。我推荐用LightGBM的带soft label训练功能做蒸馏,实现起来非常方便。
4.5 用“模型检查器”盯住训练过程
训练过程中一个很容易被忽略的环节是模型检查器。所谓“模型检查器”,其实就是一套自动化的检查工具,在训练完成后自动输出一系列“体检报告”,包括特征分布、特征重要性排序、预测概率分布、按时间维度的表现分段、自定义规则的违反情况等。
为什么需要专门做这一步?因为我踩过一个大坑:有几次跑完训练,AUC和准确率都很好看,但是实盘效果很差。后来才发现是训练样本的时间分布不均匀,早期样本远多于近期样本,模型学到的基本是几年前的规律。模型检查器里的按月度表现分段就能一眼看出这种问题。
我建议每一个量化训练任务都要配一个简易模型检查器,至少包含这几项检查:
- 特征缺失率:有没有新增股票把特征变成NaN
- 特征值范围:有没有突然出现超出训练分布10倍的值
- 特征重要性:最重要的特征是否随训练月份稳定,而不是每个月都在变
- 预测分布一致性:训练集和验证集的预测概率分布是否接近
- 分组表现:按月份、按行业、按市值分组看AUC有没有明显短板
python复制def check_predict_shift(val_df, model, feature_cols):
val_df = val_df.copy()
val_df['pred'] = model.predict_proba(val_df[feature_cols])[:, 1]
monthly = val_df.groupby('month')['pred'].agg(['mean', 'std', 'median'])
# 检查预测均值是否在某个月出现明显跳变
mean_all = monthly['mean'].mean()
shift_thresh = mean_all * 1.5
bad_months = monthly[monthly['mean'] > shift_thresh].index.tolist()
return bad_months
这套检查器不复杂,但能省下大量实盘踩坑的时间。我们在第十五期培训里会专门留出一个课时,教大家从零搭建这个模型检查器,并配置成训练完成后自动运行。
5. 回测与风控:别把回测神话,也别把模型裸奔
5.1 回测里的“隐形杀手”:交易成本与涨跌停
模型训练完了,下一步最激动人心的是跑回测。但回测界有一个广为人知的潜规则:回测曲线有多漂亮,实盘亏损就有多惨烈。尤其抄底模型,回测时如果不处理涨跌停,问题会特别大。
比如模型在某天下午选出某只跌停股,回测系统默认你能以跌停价买入,第二天涨停卖出,收益算出来能上天。但实盘里跌停板上你根本买不进去。所以回测必须设置涨跌停不可成交的约束,并且对买入价加上滑点。我给新手的建议是:每次买入模拟价加0.1%到0.3%的滑点,卖出也加,不要只算单边。频繁交易的模型,双边成本叠加后收益会缩水一大截。
另一个容易忽略的点是停牌处理。A股个股停牌频繁,回测时如果不剔除停牌日的数据,标签计算时会把停牌那几天的零收益也当成长时间横盘,导致信号失真。
5.2 风控模块:激进不代表裸奔
模型名字叫“激进抄底”,但风控恰恰要更严格。我在实盘里给抄底策略设计了四层风控:
- 个股止损:入场后单笔亏损超过8%,无条件止损离场,亏损超过8%说明“超跌反弹”的前提被证伪了
- 组合最大回撤:策略总体回撤超过15%,停止开新仓,进入冷却期
- 单日最大买入市值:防止某一天模型突然输出大量买入信号,导致仓位过度集中
- 行业敞口限制:单行业持仓占比不超过30%,避免一个板块的集体踩踏把整个组合带崩
这些风控规则不复杂,但能直接决定模型能不能长期活下来。抄底策略最怕的不是连续错三五次,而是连着错的时候一次比一次仓位重,最后本金直接腰斩。所以仓位管理大概率比模型本身更重要。常见做法是根据模型的预测概率分档,概率高的仓位高,概率低的仓位低,而不是要么满仓要么空仓。
5.3 模型上线与监控:模型也会“过期”
机器学习模型不是训练完就可以永久使用。市场的统计特征会漂移,比如2023年之前有效的“小市值超跌反弹”规律,在量化资金大量进入之后可能就失效了。我建议实盘模型至少每月重新训练一次,每次训练后跑模型检查器,对比新旧模型的预测分布和特征重要性。
还要监控一个指标叫PSI(群体稳定性指数),它可以衡量线上模型的预测概率分布和训练时的分布是否偏离过大。PSI超过0.25,基本可以确定市场环境发生了结构性变化,这时候要果断降仓位或者停用模型,不要跟市场硬刚。我在培训里会讲怎么用Python一行行算PSI,以及如何设置自动提醒。
6. 常见问题与排查技巧实录
6.1 模型AUC很高,实盘却亏钱
这是量化新人最爱问的问题。原因通常是三选一:一是前视偏差,回测中不小心用了未来数据,典型如用了后复权价格,或者在特征里混入了未来财报数据,这点在特征工程部分已经强调过;二是过拟合,AUC高是因为模型把训练样本都背下来了;三是回测和实盘的成本假设不一致,回测没算滑点和冲击成本。排查顺序建议先检查成本假设,再检查数据口径,最后降低模型复杂度测试是否显著掉点。
6.2 特征重要性每个月都变,怎么办
训练完看LightGBM的feature importance,发现重要特征每个月都在换,说明模型没有学到稳定规律,只是在拟合噪音。解决办法有几种:一是增加训练数据量,用更长的历史跨度;二是对特征做去相关性,把高度相关的特征合并或剔除;三是减少模型复杂度,树深度从6降回4,叶子节点数降小。还有一个小技巧是加入特征子集稳定性检查:用三个不同时间窗口跑模型,取特征重要性的交集,交集特征才是真正值得信任的。
6.3 预测概率集中在0.5附近,拉不开差距
这种情况一般是特征区分度不够,或者正负样本重叠度过高。我做过的有效改进有两个:一是给特征增加交互项,比如“乖离率×波动率分位数”,把原本线性不可分的分布拉开;二是增加更强的行业中性化处理,把个股的上涨部分剔除大盘或行业的beta贡献,让模型专注捕捉alpha。很多时候,不是模型不行,而是你让它预测的对象本身含了太多市场噪音。
6.4 极端行情下模型反复止损
反弹模型在单边下跌的熊市尾巴里表现会特别惨。不是模型失效,而是它的假设“超跌之后会反弹”在极端风险事件中可能被暂时打破。我的经验是:给模型加一个市场环境开关,当大盘指数站上20日均线下方超过一定天数时,强行降低抄底信号的可交易金额;或者直接用市场情绪特征作为模型输入,让模型自己在极端环境下选择“不做”。这种“不做”的决策也是机器学习能给量化系统带来的智慧。
7. 第十五期线上培训详解
7.1 课程大纲与形式
这次培训不是录播课,而是线上直播加答疑,持续两周,每周三节课,每节课两小时左右,课后留实战作业。大纲按照我们上面这套方法论展开,但比文章详细得多,每一步都有代码演示和运行结果:
- 第一周:机器学习环境搭建、数据获取与清洗、特征工程完整示例
- 第二周:样本标签设计、滚动训练与验证、模型融合与蒸馏、模型检查器配置
- 第三周:回测系统搭建、涨跌停与交易成本处理、风控模块实现、模型上线与监控
核心交付物是一个可以直接跑通的“激进抄底”策略代码库,包括数据预处理、特征构建、训练脚本、模型检查器、回测引擎和风控模块。你拿过去换自己的股票池参数就能跑。
7.2 适合人群与常见误区
我特别想提醒几类朋友:第一类是刚学完Python基础、还没碰过机器学习的,可以直接来,我们有环境搭建和代码讲解;第二类是已经在用现成的机器学习库做别的场景、想迁移到金融领域的,可以重点听特征工程和回测部分;第三类是已经在跑某些开源量化框架的,可以带着自己的模型和问题来,答疑环节专门留了时间。
但如果你以为听完课就能躺赚,那还是省省。量化交易是系统工程:数据质量、特征逻辑、风控纪律,每一样都比模型本身重要。我们的培训教的是这套系统怎么搭、怎么避坑,不是给你一个稳赚的“黑盒”。
7.3 报名方式与注意事项
报名方式是直接扫码或添加助理企业微信,备注“第15期培训”即可。为了保证答疑和作业批改质量,每期限额50人,目前已经报了三十多位。开课前一周统一拉群发课程链接和代码环境准备清单。课程结束后会保留三个月答疑群,平时跑模型卡住了可以直接在群里问。
有一点需要强调的是,培训内容涉及的所有代码、数据样例和讲义,只供学员个人研究学习使用,不包含任何荐股和代客理财服务。我们讲的是方法论,不是内幕信息,也不是收益承诺。
写在最后:一个过来人的心里话
做了这么多年的量化模型,我最大的体会是:模型再聪明,也取代不了纪律;信号再准,也抵不过仓位失控。“激进抄底”这个名字看起来是在鼓励大胆操作,但实际上它背后是一整套关于概率、风险和应对失败的工程标准。大家在实盘里一定要记住:抄底模型给的信号只是一个可能性,不是保证。配合好止损、仓位和回撤控制,你可以活到下一次大机会来临;如果丢开风控去赌“这次一定能反弹”,那不管机器学习还是人工判断,结局大概率都是一样的。
最后再分享一个我自己常用的习惯:每跑完一轮训练,我都会把模型检查器的报告截图存下来,和当月的实盘业绩对照。坚持三个月,你会发现那些“模型回测好但实盘差”的问题,其实早就写在检查报告里,只不过当时没有仔细看。希望这次的分享和第十五期培训,能帮你少走一段弯路。
