ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

决策树做交易为何频频翻车?从特征工程到过拟合的实战拆解

决策树做交易为何频频翻车?从特征工程到过拟合的实战拆解 如果说这两年量化圈子里有什么被反复提起、又反复翻车的入门方向“决策树做交易”绝对算一个。很多人一看这名字就觉得亲切决策树嘛sklearn 里几行代码就能跑还能画成树状图看模型在琢磨什么比神经网络那种黑箱强多了。可真把行情数据丢进去让树老老实实训练完再拿去回测、实盘走一圈十个里有九个会皱眉——回测曲线漂亮得不像话实盘一上手就开始还债甚至换个时间段重新训练同一套代码跑出来的结果完全是两个世界。这篇我打算把“训练一棵决策树做交易到底难在哪”这件事彻底掰开从特征、标签、过拟合、市场状态四条主线一条条拆最后附上我从零搭到能落地的完整实操过程以及我踩过的那些能用钱买来的坑。先说清楚它能干什么。决策树在交易里最常规的用法是把它当成一个“信号发生器”输入一堆跟行情相关的特征比如过去几天的涨跌幅、均线差、波动率、成交量变化让它学一个映射关系——这些特征组合出现时未来一段时间行情更可能上涨还是下跌。模型输出的是方向判断再叠加仓位管理、止损止盈就凑成一套可以跑回测的策略。它解决的核心问题是把“涨跌”这件事从人的直觉判断变成一个可复现、可回测、可解释的规则集合。适合谁来参考凡是刚进量化门、想拿机器学习做交易但还没被市场毒打过的新人或者已经在用技术指标手工做交易、想把规则自动化验证一遍的人这篇文章都值得你花十分钟读完。接下来我不讲教科书只讲实战里那些真正卡住你的东西。1. 内容整体设计与思路拆解为什么偏偏是决策树又为什么它这么容易翻车1.1 决策树做交易的基本逻辑把行情分类问题化先建立一个统一框架。交易这件事本质上是“基于当前已知信息对未知未来做判断并根据判断下注”。决策树做的事情高度吻合它把当前已知信息特征按一系列“如果……那么……”的规则拆开最后在每个分支末端给出一个结论涨/跌或者一个数值未来收益预测。用生活中的例子类比决策树就像你妈判断你要不要带伞的逻辑。“如果今天下雨概率超过70%那么带伞否则如果昨天天气预报说降温那么加件外套否则不带。”每一层都是一个条件判断层层递进最终落到一个行动建议。量化交易里的决策树一模一样它不需要你预设“金叉买入、死叉卖出”这种死规则而是从历史数据里自动长出一组条件让样本落在不同分支后得到的“纯度”最高——也就是说落在同一分支的样本它们的未来收益方向尽可能一致。所以你会发现决策树最吸引人的点有三个一是门槛低sklearn 一行DecisionTreeClassifier()就能初始化二是可解释性强训练完可以tree.export_graphviz()导出来每个节点的划分特征和阈值都清清楚楚三是不用像神经网络那样做大量特征缩放、正则化调参对异常值也不那么敏感。这三个优点放在别的领域没问题放到交易里却恰恰埋下了翻车的种子。1.2 为什么“数据丢进去就能训练”的想法在这里行不通很多新人踩的第一个跟头是把决策树当成一个万能分类器行情数据下载下来整理成结构化表格特征选几个技术指标标签设成“明天涨还是跌”丢进训练集就开始调参。等你把max_depth、min_samples_leaf调得回测曲线一路向北心里开始盘算“今年目标年化 80%”的时候实盘往往会在两周内教会你做人。问题出在哪在于交易数据跟普通机器学习数据集有本质差别。你在 Kaggle 上做泰坦尼克号生存预测训练集和测试集都是来自同一个人群分布、同一套统计规律的数据而行情数据是典型的时间序列它的统计规律不仅随时间漂移还会因为市场参与者结构变化、政策环境变化、情绪周期变化而整体换一副面孔。你用 2015 年到 2020 年的数据训练出来的规律拿到 2021 年可能就是反向指标。决策树这种“把特征空间切成一个个小格子每格里统计样本多数决定输出”的模型对特征的泛化能力依赖极强——但这些特征在训练期里建立的相关性到了样本外可能完全不存在甚至反向。更要命的是决策树本身是高方差模型。它有多容易记住训练集如果你不限制深度它会一直分裂到每个叶子节点只剩一个样本把所有噪声都背下来。历史行情里的噪声含量又比其他领域高出一截于是这棵树学到的“规律”里相当一部分是随机波动的回声。这就是为什么同样一棵树换个时间段滚样本参数就全失效了。所以本文所有实操第一条纪律就是限制模型复杂度比追求回测收益更重要。2. 核心细节解析与难点拆解四个真正卡住你的关键环节2.1 特征工程市场不是马尔可夫过程光喂“历史价格”远远不够第一个难点特征到底怎么造。常见的新手做法是拿 OHLCV 数据直接开算用close.pct_change()得到每日收益率滚动 5 日均值、20 日均值、布林带位置、RSI、MACD再加成交量变化率十几个特征一股脑塞给模型。这样做不是不行但很多人忽略了两个关键问题。第一个问题是特征的信息量有限。决策树本质上只能学习“当前特征组合 → 未来结果”的条件概率它没有任何记忆机制。如果特征里只有“今天的涨跌幅”而没有“过去一周的累计状态”那模型学到的顶多是“今天涨了明天继续涨的概率略高”这种短视统计。市场不是马尔可夫过程——今天的行情并不能完全决定明天的走势至少还要看趋势的斜率、动能强度、所处的位置等等。所以特征设计不能只做一阶差分要把“状态”类特征一起放进去比如均线相对关系MA5-MA20 的差值、价格在近 20 日区间的位置、波动率所处的分位水平。这些特征告诉模型一件事当前市场处于什么状态。第二个问题是特征不是越多越好。决策树的特征选择是局部的、贪心的它每次只找一个“当下划分最纯”的特征并不考虑特征组合的全局效应。当特征里混入大量噪声特征时树分裂时很容易选中那些恰好能把当前样本分开、但毫无泛化能力的特征——这就是过拟合的源头之一。我自己的经验是起始特征控制在 812 个以内宁缺毋滥并且要用滚动窗口验证特征在样本外是否依然有区分度。相关性太高的特征也要去重比如 MA5 和 MA10 在短期趋势里高度相关同时放进去会让分裂时选择不稳定造成树的规则集在相近的时间窗口里反复横跳。2.2 标签设计你让模型学的“涨跌”可能根本不适合交易第二个难点可能很多人压根没当回事标签怎么定义。如果是分类任务最常见的是把 t1 或 t5 的收益率取符号作为标签收益为正标 1收益为负标 0。这个设计本身没错但它隐藏着几个问题。一是分类任务会让模型牺牲收益幅度它只关心方向对不对不关心涨 1% 和涨 8% 的区别。决策树分裂时用的是基尼系数或熵算的是“这个分支里正负样本更纯了没有”于是模型很可能倾向预测“大概率涨一点点”而对极端行情完全没有捕捉能力。实际操作中我会建议用回归树预测未来收益的数值再在决策层把预测值转成信号——预测收益大于某个阈值才开仓这样既能过滤低质量信号又能保留幅度信息。二是预测周期太短会导致交易成本过高。如果你用 t1 收益做标签模型天天给你信号扣掉手续费和滑点胜率就算 55% 也未必能赚钱。我踩过的坑就是这样跑出来的回测看起来胜率 53%年化收益 40%但把双边万三手续费、千一滑点一加收益直接打了个三折。所以标签的预测周期要跟持仓周期匹配——你想做隔日波段标签至少用未来 35 日收益想做趋势跟踪标签可能是未来 10 日或 20 日收益。预测周期拉长信号频率降下来每笔交易能吃的波动更大成本占比自然被摊薄。还有一个容易被忽略的细节是标签的类别平衡度。A 股、美股指数这类数据长期来看上涨的天数略多于下跌但差异不大基本在 50%55% 范围内但如果你加了一个“横盘”类标签比如 |收益| 0.5% 记为 0样本分布往往会严重偏向横盘模型学出来就是个“永远预测横盘”的废物。处理方式要么去掉横盘样本要么用class_weightbalanced给少数类加权。总之标签设计直接决定模型在学什么这一步想清楚了后面所有环节才有意义。2.3 过拟合与样本外失效回测曲线越漂亮越要警惕第三个难点也是最核心的难点过拟合。决策树在交易数据上的过拟合严重程度远超一般人的预期。我举一个实际例子某次我用同样的特征、同样的标签只改了max_depth从 4 调到 6回测年化从 28% 直接跳到 67%最大回撤从 12% 变成 18%。懂行的人一看就明白深度加大之后树开始记细节了——它学的不再是“均线多头排列时上涨概率大”而是“2020 年 7 月 3 日前后那段特征的精确组合曾经大涨过”。这种记忆没有任何泛化价值换个时间窗口立刻失效。处理过拟合我的经验是三条线同时收紧。第一条是限制模型复杂度max_depth控制在 35min_samples_leaf至少 50max_features可以用sqrt或者手动限制每次分裂只考虑一部分特征。这个组合会让模型更“钝”回测曲线没那么性感但至少是在学规律而不是背答案。第二条是样本外验证时必须做时间序列分割。普通的train_test_split随机打乱数据在时间序列场景下是禁区——它会把 2023 年的数据泄漏到训练集里模型等于提前看了“未来”。正确做法是训练集用前 70% 的时间段测试集用后 30%甚至更严谨一点用TimeSeriesSplit做滚动验证每一折都保证训练集时间在测试集之前。第三条是观察参数敏感性如果max_depth从 3 调到 4回测结果发生剧烈波动说明模型已经处于记忆状态赶紧把复杂度压回去。过拟合还有个隐蔽变种叫“前视偏差”。我见过最典型的例子是用当天的收盘价计算信号却在当天开盘价就买入/卖出回测系统里看起来每天都有信号、每天都能吃到当天的波动实盘根本不可能复现。任何用到“当日”数据的特征最早只能在次日开盘执行。这类问题回测软件不会提醒你全凭自己心里那根弦绷着。2.4 市场状态切换与样本不均衡为什么模型会突然“失灵”第四个难点来自市场本身的非平稳性。金融市场的规律在不同阶段完全不同单边牛市里“回调就买”是王道震荡市里“涨多了就卖”才能活命熊市里最好的策略可能是不交易。决策树训练时面对的是整段历史的混合分布它学出来的规则是“所有时期规律的加权平均”。问题是如果训练期里牛市占了 70%模型会严重偏向“乐观”等到震荡市一来它的高置信度信号大概率是错的。这个问题的解法一种是用滚动窗口训练固定训练集长度为最近 12 年每季度或每月重新训练一次让模型始终在“最近的市场语言”里学习。另一种是做市场状态标记把“均线多头排列 波动率中等”之类的状态作为特征喂进去让树自己去学不同状态下的差异。我实操下来滚动训练比静态训练稳健得多但代价是代码复杂度上来了还要处理每次训练后规则变化带来的信号不一致问题。样本不均衡在交易里的具体表现是“趋势段样本稀少”。拿 A 股的主要指数来看真正走出流畅趋势的时间可能只占全部交易日的 30%剩下 70% 都是震荡。如果你用“未来 20 日涨幅 5%”作为多头标签正样本比例可能不到 15%。决策树面对极度不均衡的数据会倾向于把所有样本都归到多数类。这时候光靠class_weight不够我更推荐直接按市场状态分层采样或者干脆把震荡段数据剔除一部分让模型集中学习有区分度的样本。不过这招要慎用——剔除太狠等于你在教模型“只会在特定行情里玩”。3. 实操过程与核心环节实现从零到一回测一棵能用的决策树3.1 数据准备与特征计算实操部分我直接用 Python 给你走一遍完整流程。数据源自己准备我用的是日线级别的行情数据字段至少包含date, open, high, low, close, volume指数或个股都能跑。先导入必要的库并读取数据import pandas as pd import numpy as np from sklearn.tree import DecisionTreeClassifier from sklearn.model_selection import TimeSeriesSplit from sklearn.metrics import accuracy_score import warnings warnings.filterwarnings(ignore) df pd.read_csv(daily_data.csv, parse_dates[date]) df df.sort_values(date).reset_index(dropTrue)特征计算是关键。我按前面说的思路构造四类特征动量类、均线类、波动类、量能类外加一组时间哑变量。具体的计算逻辑如下# 动量类 df[ret_1] df[close].pct_change(1) df[ret_5] df[close].pct_change(5) df[ret_10] df[close].pct_change(10) df[ret_20] df[close].pct_change(20) # 均线类短期均线相对长期均线的偏离度量化“多空排列” df[ma5] df[close].rolling(5).mean() df[ma20] df[close].rolling(20).mean() df[ma_gap] (df[ma5] - df[ma20]) / df[ma20] # 波动类20日滚动标准差波动率 df[vol_20] df[close].pct_change(20).rolling(20).std() # 量能类当日成交量相对5日均量的变化 df[volume_ratio] df[volume] / df[volume].rolling(5).mean() # 价格位置当前收盘价在近20日最高最低区间中的位置 df[pos_20] (df[close] - df[low].rolling(20).min()) / ( df[high].rolling(20).max() - df[low].rolling(20).min() 1e-9 ) # 时间特征星期几周一至周五 df[weekday] df[date].dt.weekday这里要特别解释一下pos_20这个特征。它代表当前价格在最近 20 日波动区间里的相对位置取值 0 到 1 之间数值越接近 0 说明价格越贴近区间底部越接近 1 说明越接近顶部。这个特征对决策树有独特价值树可以很容易地学出“位置大于 0.8 时短期回调概率高”这类规则而且这类规则在不同的震荡行情中都能复用。相比之下纯价格类特征在不同标的上绝对值差很多反而不好用。标签我采用两手方案一手是分类标签label_cls定义成未来 5 日收益大于 0 为 1否则为 0另一手是回归标签label_reg直接用未来 5 日收益率。先用分类做信号再用回归预测值过滤低质量信号。构造方式如下# 未来5日收益率 df[future_ret_5] df[close].shift(-5) / df[close] - 1 # 分类标签未来5日收益 0 为1否则为0 df[label_cls] (df[future_ret_5] 0).astype(int) # 回归标签 df[label_reg] df[future_ret_5] # 去掉末尾没有未来数据的行和NaN行 df df.replace([np.inf, -np.inf], np.nan).dropna().reset_index(dropTrue)3.2 模型训练与核心参数选择特征和标签准备好之后选择特征列初始化决策树模型。参数这块我有固定的起步配置大多数行情数据上都能直接跑出相对稳健的结果feature_cols [ret_1, ret_5, ret_10, ret_20, ma_gap, vol_20, volume_ratio, pos_20, weekday] X df[feature_cols] y_cls df[label_cls] y_reg df[label_reg] # 分类树限制深度和叶子样本量这是防过拟合的第一道防线 clf DecisionTreeClassifier( max_depth4, min_samples_leaf50, max_features0.7, class_weightbalanced, random_state42 ) # 回归树用同样限制辅助预测收益幅度 reg DecisionTreeRegressor( max_depth4, min_samples_leaf50, max_features0.7, random_state42 )这几个参数值得逐个说清楚。max_depth4意味着树最多只有 4 层分裂最多产生 16 个叶子节点对应最多 16 条“规则”。这个上限是刻意压低的——深度 3 到 5 之间树学的是相对稳健的条件概率超过 6就开始逐条记忆训练集了。min_samples_leaf50表示每个叶子节点至少要有 50 个训练样本才能成立这保证了叶子节点上的统计结论不是靠一两个样本撑起来的能显著提升样本外稳定性。max_features0.7让每次分裂只随机考虑 70% 的特征这是给树加随机性、降低方差的手段借鉴了随机森林的思路。class_weightbalanced则在样本不均衡时自动给少数类加权防止树把全体样本都判成多数类。回归树在这里扮演的角色是“置信度过滤器”。训练完成后我让分类树先判断方向再用回归树输出未来收益的预测值只有两个模型都给出正向结论、且回归树预测收益超过阈值比如 1%视持仓周期而定时才生成做多信号。这样能过滤掉那些“方向可能对但幅度太小、扣完成本不赚钱”的鸡肋信号。3.3 回测框架与评估方法先别急着看收益训练和信号生成只是第一步关键是回测怎么设计和评估。用时间序列分割做样本外验证避免数据泄漏# 时间序列分割训练集在前测试集在后且测试集严格晚于训练集 tscv TimeSeriesSplit(n_splits4) for fold, (train_idx, test_idx) in enumerate(tscv.split(X)): X_train, X_test X.iloc[train_idx], X.iloc[test_idx] y_train, y_test y_cls.iloc[train_idx], y_cls.iloc[test_idx] clf.fit(X_train, y_train) pred clf.predict(X_test) acc accuracy_score(y_test, pred) print(fFold {fold1}: acc{acc:.4f})回测策略逻辑我用最简单的“择时”方式所有可用现金信号为 1 时持有标的信号为 0 时空仓。每天按信号调仓次日开盘执行。这里有个关键点必须守住当天的特征值只有在收盘后才能全部确认所以信号只能用于次日开盘的交易绝不能当天收盘买入。回测代码里要把信号向后平移一天# 用滚动训练方式生成样本外信号并做次日开盘执行 signals [] for fold, (train_idx, test_idx) in enumerate(tscv.split(X)): clf.fit(X.iloc[train_idx], y_cls.iloc[train_idx]) reg.fit(X.iloc[train_idx], y_reg.iloc[train_idx]) X_test X.iloc[test_idx] cls_prob clf.predict_proba(X_test)[:, 1] reg_pred reg.predict(X_test) # 只有当分类概率 0.55 且回归预测收益 0.5% 时才出多头信号 signal ((cls_prob 0.55) (reg_pred 0.005)).astype(int) signals.extend(signal) df[signal_raw] pd.Series(signals, indexX.index) # 信号后移一天模拟次日开盘执行 df[signal] df[signal_raw].shift(1).fillna(0)这段代码里有两个阈值值得解释。cls_prob 0.55意味着模型预测上涨的概率必须明显高于 50%——如果模型输出 51%说明它自己都没多大把握这种信号实盘里噪声极大。reg_pred 0.005即预测未来 5 日收益要超过 0.5%扣掉双边交易成本和滑点后还能剩一点。这两个阈值不能拍脑袋定最好用训练集上的预测分布做分位数参考但起步阶段用这两个经验值跑通流程没问题。接着算策略净值曲线和关键指标df[strategy_ret] df[signal] * df[ret_1] # 持有标的时获得次日收益 df[strategy_ret] df[strategy_ret] - 0.0006 * df[signal].diff().abs() # 扣除换仓成本 df[cum_strategy] (1 df[strategy_ret]).cumprod() df[cum_benchmark] (1 df[ret_1]).cumprod() # 计算基础指标 total_return df[cum_strategy].iloc[-1] - 1 annual_return (1 total_return) ** (252 / len(df)) - 1 # 最大回撤 rolling_max df[cum_strategy].cummax() max_drawdown (df[cum_strategy] / rolling_max - 1).min() # 胜率 trade_days df[df[signal] 1] win_rate (trade_days[ret_1] 0).mean() print(f策略累计收益: {total_return:.2%}, 年化: {annual_return:.2%}, 最大回撤: {max_drawdown:.2%}, 胜率: {win_rate:.2%})这段代码已经是能直接跑通的雏形但我要再三提醒跑出来的回测结果不代表未来能赚这么多。我用这个流程实测过多个标的和时间段得出的结论是决策树策略的样本外表现普遍比训练期内要差一截年化收益打个五折到七折都是正常现象。更稳的做法是把样本外结果分年度去看如果某一年策略明显失效别急着否定模型先看看那一年是不是震荡市——这往往是模型适用范围的自然边界而不是代码 bug。3.4 策略稳定性和参数敏感性检查回测能跑通之后别急着上实盘先做一件事参数敏感性检查。具体做法是把max_depth从 3 调到 6min_samples_leaf从 30 调到 100观察策略的年化收益、最大回撤、胜率三个指标的变化幅度。如果收益曲线剧烈波动比如深度 4 年化 30%、深度 5 年化 80%说明模型在记忆历史噪声这个策略的真实泛化能力存疑。如果指标在一个合理区间内小幅波动比如年化始终在 20%35% 之间徘徊那至少说明策略核心逻辑对参数不那么敏感是个相对健康的信号。另外一定要对比两个基准买入持有和随机信号。拿买入持有做对比是为了回答“模型真的比躺平强吗”拿随机信号做对比是为了检验交易成本和信号频率是否侵蚀了收益。有个小技巧把信号列df[signal]随机洗牌 100 次跑 100 遍回测看随机策略的收益分布。如果真实策略的收益落在随机分布的下半区那这模型还不如扔硬币。这个检查我每次都会做能过滤掉大量“看着厉害、实则运气”的假策略。4. 实测踩坑记录与排查方法把最常见的坑一次性列给你4.1 实盘和回测不一致的三大隐形杀手决策树交易策略从回测到实盘最常见的“魔鬼”有三个。第一个就是前视偏差。之前提到过用当日收盘价计算特征、当日执行交易回测里感觉每天都赚钱实盘里每笔都是“收盘后看到信号第二天开盘追进去价格已经跳空”。排查方法很简单把信号列shift(1)之后再算一次回测如果收益差距巨大说明原策略严重依赖当日不可执行的信号。第二个是滑点估计不足。回测里用收盘价成交实盘集合竞价、大单冲击、停牌复牌等因素都会让实际成交价偏离理想价。我一般按成交额的千分之一到千分之二估算滑点即便这样在流动性差的标的上还是有偏差。第三个是真假交易成本的混淆。很多回测框架默认手续费为零或者只算单边实际来回一次的成本会让高频信号策略直接亏穿。排查方式是设置“生死线”把单边成本调到 0.15% 再跑一遍回测如果策略从盈利变亏损说明它赚的其实是幻想出来的价差。4.2 六大高频问题速查表我在训练决策树做交易的过程中积累了下面这张排查表。遇到问题先对着表格查一遍能省下大量盲目调参的时间。问题现象可能原因排查与对策回测年化极高换段时间就失效模型过拟合记住了训练期噪声降低max_depth提高min_samples_leaf用时间序列分割重新验证准确率 60% 但交易不赚钱忽略了收益幅度和交易成本改用回归树过滤信号要求预测收益超过阈值才开仓训练集和测试集收益差异巨大训练/测试随机分割导致数据泄漏改用TimeSeriesSplit训练集必须时间上在前信号过于频繁手续费吞噬收益标签预测周期太短把标签从 t1 改成 t5 或 t10降低换仓频率模型长期预测“横盘”或“不动”样本不均衡多数类占主导设置class_weightbalanced或剔除过度震荡样本跑的结果每次都不太一样决策树分裂的随机性固定random_state或者用随机森林做集成降低方差4.3 我踩过的三个具体坑第一个坑是特征泄漏而且非常隐蔽。我当时做了一个“当日涨跌幅”的特征又在同一天用close计算持仓收益回测系统里“今天上涨 → 今天买入 → 吃到今天的涨幅”收益曲线完美得让我一度怀疑人生。后来把信号shift(1)之后曲线直接从年化 60% 变成 15%。那一次给我的教训是回测代码里所有信号和收益的计算时间点必须分得清清楚楚信号只允许用当日收盘前可得的数据交易最早在次日开盘执行。第二个坑是max_depth从 5 加到 7回测收益翻了一倍我差点以为自己发现了圣杯。后来用滚动样本外验证一看深度 7 的模型在样本外的表现反而比深度 5 还要差。原因很简单深度越深树的规则越细碎每条规则覆盖的样本越少统计显著性越低跨时间窗口的稳定性自然越差。所以我现在一律先从max_depth3开始确认样本外稳定再加到 4 或 5绝不拍脑袋追求高深度高收益。第三个坑跟时间特征有关。我把weekday作为数值特征放进去树学会了“周三大概率涨”这种规则。一开始我觉得挺神奇直到我意识到这可能只是历史某段时间的巧合换标的基本就失效了。时间特征不是不能用但要用周期编码比如sin(2π * weekday / 5)和cos(...)或者做哑变量更重要的是要验证它在滚动样本外是否保持有效。否则树学到的可能是一堆没有逻辑支撑的统计巧合。5. 更深一层的思考决策树在交易里真正的定位走到这一步你可能已经意识到用决策树直接预测价格方向本质上是个胜率游戏——特征选得好、参数限制严、成本算得清能做出一个勉强跑赢基准的策略但天花板非常明显。交易市场是零和博弈参与者都在进化任何静态规则都会被市场反噬。那么决策树做交易真的没有价值了吗我个人看法不是这样。我在实操中得出的体会是决策树最大的价值不在于“作为主策略预测员”而在于“作为规则解释器和过滤器”。它训练完后可以直接导出完整的 if-else 规则集这些规则能帮你理解到底什么样的市场状态下什么样的特征组合历史上更可能产生好的交易机会。比如我的某棵树训练完后最重要的规则有三条20 日波动率处于历史低位 均线多头排列 价格在 20 日区间高位时未来 5 日上涨概率明显偏高而波动率剧烈放大时无论方向如何模型输出都趋于 50% 以下——这从数据层面验证了“高波动期不该贸然开仓”的交易常识。这类规则拿来复盘自己的手工交易系统或者拿来做风控过滤器比如模型对当前行情的“不确定性”高时主动降低仓位比直接拿它做买卖信号要实用得多。用回归树的预测分布做仓位管理也是好思路。真金白银的教训是别指望决策树给你一个“圣杯式”买卖点把它的输出当作一个“打分器”或“状态分类器”叠加在自己原本的交易逻辑之上才是它最合适的归宿。这个思路后来帮我规避了好几次不该开的仓——当树的预测概率长期低于 50% 时说明当前行情根本不是它擅长的那种空仓等待反而是最优解。最后分享一个我后来一直在用的小技巧训练完树之后把clf.feature_importances_打印出来按重要性做月度监控。如果某个月开始重要性的排序剧烈变动或者某个特征的重要性突然从 0.3 掉到 0.02通常意味着市场风格在切换。这个时候别急着加仓先静下来重新评估策略逻辑是不是还适应当前环境。这个习惯帮我少踩了很多震荡市的坑也让我对“模型什么时候会失效”有了更具体的感知。
返回列表