ARTICLE DETAIL

资讯详情

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

HMM-LSTM股票趋势分析:四类模型分层拆解

HMM-LSTM股票趋势分析:四类模型分层拆解 简介基于HMM-LSTM的股票市场趋势分析项目提供了四种模型融合实验方案适合金融量化初学者及有Python基础的算法工程师用于理解隐马尔可夫模型与长短期记忆网络在行情预测中的实际结合。资源共61个文件包含28个Python脚本、26个pyc编译文件、4张结果图、1篇参考论文PDF、1个Markdown项目说明及1张示意图片压缩包仅2.54MB轻量易部署。整体代码覆盖数据清洗、特征工程、模型训练、预测评估、结果可视化等关键环节四种模型包括HMM-LSTM、GMM-HMM、XGB-HMM及独立LSTM便于横向对比不同建模思路。目前已有327人学习下载。读者可借此掌握HMM对市场状态的识别、LSTM对趋势序列的拟合并通过图表与论文辅助理解算法原理项目说明提供了清晰的运行指引适合在此基础上扩展自己的量化策略或完成课程设计。1. 从HMM到LSTM这四类模型是怎么把股市趋势“分层拆解”的做量化的人都清楚一个尴尬的事实单纯靠均线、MACD这类技术指标做趋势判断震荡行情里会被来回打脸单纯靠深度学习模型又容易被市场噪声带偏。这套基于HMM-LSTM的股票市场趋势分析源码核心思路是把“市场状态识别”和“时序趋势预测”拆成两个层次来处理隐马尔可夫模型HMM负责从价格、成交量、技术因子中识别隐含的牛熊和震荡状态LSTM再基于状态信息与原始特征序列预测后续趋势。源码里一共实现了HMM、GMM-HMM、XGB-HMM和LSTM四类模型并且提供了训练、预测、评估、绘图全流程。适合两类人一是正在做量化选股或择时研究、想用状态空间模型做市场阶段划分的工程师二是想在同一个数据集上对比“传统概率模型 vs 集成学习 vs 深度学习”效果的算法学习者。文章后面会带你逐个拆解源码中的核心文件包括HMM多因子建模、XGBoost输出概率参与构建HMM观测矩阵、LSTM时序预测以及最后的模型组合与样本平衡处理。2. HMM状态建模多因子观测序列与GMM-HMM的实现细节2.1 为什么用HMM描述股票市场状态股票价格走势不是一个平稳随机过程它会在趋势、反转、震荡之间切换。这种“切换”看不见摸不着但我们能观察到价格涨跌幅、成交量、波动率等指标。HMM正好匹配这个结构隐藏状态表示市场当前处于什么阶段观测序列是我们可以拿到的行情因子状态转移矩阵描述从牛市到震荡、再到熊市的概率。源码中的HMM_duoyinzi.py就是按这个思路写的多因子HMM。相较于直接用收益率阈值划分牛熊HMM的优势在于状态是概率性的每个时刻都会输出处于各个状态的后验概率而不是硬切一刀。这个概率序列后续既可以单独做择时信号也可以作为LSTM或XGBoost的输入特征。源码中HMM_hangqing.py处理行情数据、process_on_raw_data.py做原始数据清洗都是为了给HMM准备干净的多因子观测序列。2.2 多因子观测构造与数据对齐HMM的观测序列要保证所有因子在同一时间轴对齐并且尽量平稳。源码中form_df_all.py和process_on_raw_data.py完成这步工作。常见因子的构造方式如下表因子名称计算方式用途对数收益率ln(close_t / close_{t-1})消除价格水平影响满足平稳性成交量变化率volume_t / volume_{t-1} - 1反映资金活跃度波动率过去N日收益率标准差区分高波动与低波动状态振幅(high - low) / close日内多空博弈强度源码中把这些因子拼接成一个DataFrame对齐后按日期排序。需要注意因子数据不能混入未来信息比如计算波动率只能用截至当天的历史窗口。HMM_duoyinzi.py里对每个因子做z-score标准化这步很关键因为不同因子的量纲差异会影响观测概率密度函数的估计结果。2.3 GMM-HMM用高斯混合替代单高斯观测分布标准的HMM如果假设观测概率服从单高斯分布对股票这种尖峰厚尾的收益率分布拟合效果有限。GMM_HMM.py实现了用高斯混合模型GMM作为HMM的观测概率密度函数即每个隐藏状态下观测向量由多个高斯成分加权组合而成。这样做的好处是一个“震荡市”状态内部可能包含窄幅整理和宽幅波动两种子模式单高斯只能描述一种均值-方差结构而GMM可以表达更复杂的观测分布。2.3.1 训练脚本核心逻辑train_HMM_model.py中会调用GMM_HMM.py完成训练关键流程如下import numpy as np from hmmlearn.hmm import GaussianHMM # 或使用带GMM的扩展版本 from hmmlearn.hmm import GMMHMM # n_components为隐藏状态数n_mix为每个状态下的高斯成分数 model GMMHMM(n_components4, n_mix3, covariance_typediag, n_iter200, random_state42) # obs为多因子序列shape: (n_samples, n_features) model.fit(obs) # 解码最优状态序列Viterbi算法 states model.predict(obs) # 计算每个时刻的状态后验概率 posterior model.predict_proba(obs)n_components4表示预设4种市场状态实际可根据AIC或BIC调整n_mix3表示每个隐藏状态下用3个高斯成分拟合观测分布成分越多拟合能力越强但越容易过拟合covariance_typediag假设因子之间条件独立计算量小且对多维因子更稳健。训练完成后states就是每个交易日对应的市场状态标签posterior则给出每一天处于各状态的概率。注意HMM的状态序号本身没有语义0号不一定代表熊市。需要训练完后对照每个状态的均值向量来人工标注状态含义比如某个状态下收益率均值显著为负、波动率偏高就对应熊市状态。2.4 状态转移矩阵与初始状态的可解释性训练完成后可以从model.transmat_拿到状态转移矩阵每一行表示从状态i转移到状态j的概率。实际经验中牛市和熊市的自转移概率通常在0.9以上说明趋势有惯性而震荡市向牛熊市的转移概率相对均衡符合“震荡是趋势的蓄势阶段”这一市场规律。源码中的evaluate_plot.py会把状态序列画在价格图上你可以直观看到HMM识别的牛熊分界点是否和肉眼判断一致。如果状态切换过于频繁说明因子噪声太大或状态数偏多需要减少n_components或对因子做平滑。3. XGB-HMM特征融合把XGBoost概率输出变成HMM的观测矩阵3.1 XGBoost和HMM能怎么结合HMM的观测概率B矩阵描述的是“在某个隐藏状态下观测到某个特征值的概率”。传统做法是用高斯分布或GMM去拟合这个概率但XGBoost在表格数据上有更强的非线性拟合能力。XGB_HMM.py的思路是先用XGBoost对历史行情样本做分类或回归输出每个样本属于某种市场状态的概率然后把这个概率作为HMM观测似然的一部分或者直接用来重新估计B矩阵。这样HMM的状态转移部分保留时序结构的建模能力而观测部分则引入XGBoost的特征交互能力。3.2 源码中的B矩阵重估流程pred_proba_XGB.py训练XGBoost分类器输入特征包括滞后N期的收益率、成交量变化、RSI、布林带位置等标签来自HMM解码出的状态序列或者人工标注的牛熊标签。训练完成后对全部样本做交叉验证预测得到每个样本属于各状态的概率向量。form_B_matrix_by_XGB.py利用这些概率重新构建HMM的B矩阵import numpy as np import xgboost as xgb # 训练XGB分类器num_class对应状态数 model xgb.XGBClassifier( n_estimators300, max_depth5, learning_rate0.05, objectivemulti:softprob, num_class4, subsample0.8, colsample_bytree0.8, ) model.fit(X_train, y_hmm_states) # 对训练集全量样本输出状态概率 train_proba model.predict_proba(X_train) # 用概率重新估计B矩阵每个状态下特征的条件概率 # 这里简化展示按状态聚合特征均值结合XGB概率加权 B_matrix np.zeros((n_states, n_features)) for s in range(n_states): weight train_proba[:, s].reshape(-1, 1) B_matrix[s] np.average(X_train_features, axis0, weightsweight.ravel())multi:softprob是XGBoost的多分类目标函数输出每个类别的概率colsample_bytree0.8在每棵树构建时随机采样80%的特征降低过拟合。通过这种方式HMM的观测概率不再局限于参数化的高斯分布而是由XGBoost的叶节点输出决定理论上可以捕获因子之间的高阶交互关系。3.3 这种融合方式的适用边界XGB-HMM的优势在特征数量较多比如20个以上且因子间存在复杂非线性关系时体现得比较明显如果只用收益率和成交量两三个因子反而可能不如GMM-HMM稳定。源码中XGB_HMM.py会把XGBoost的概率输出和HMM的转移概率相乘得到每个时刻的联合状态概率这个概率序列既可以直接作为择时信号也可以拼接到LSTM的输入特征中。另外一个容易踩坑的地方是XGBoost训练时使用的标签如果来自HMM解码结果那么HMM的训练数据必须和XGBoost的训练数据在时间上严格错开否则会有标签泄漏。源码中random_cut.py的作用就是随机切分训练集和验证集确保HMM和XGBoost都在各自的区间上训练避免未来函数进入特征。4. LSTM序列预测与四模型完整训练流程4.1 HMM状态已经建模了为什么还要LSTMHMM是一阶马尔可夫模型它假设当前状态只依赖前一个状态而且观测序列内部的条件独立。这在股票市场里过于简化因为趋势的形成往往依赖更长周期的上下文信息比如连续五天的放量上涨和单日放量上涨对未来走势的影响完全不同。LSTM通过门控机制可以学习这种长距离依赖因此源码中LSTM.py的输入不仅包含原始行情因子还拼接了HMM输出的状态后验概率。4.2 random_cut.py时序数据切分与防泄漏时序预测最忌讳随机打乱数据后切分训练集和测试集因为相邻日期的样本高度相关。random_cut.py做了两件事一是按时间顺序保留连续性二是在训练集和验证集之间留出间隔窗口。常见的做法是训练集占70%、验证集占15%、测试集占15%切分点按时间比例而不是随机索引。源码中还提供了sample的滑动窗口构造逻辑用过去60个交易日的数据预测未来5日的趋势方向。import numpy as np def create_sequences(features, states, seq_len60, pred_len5): X, y [], [] for i in range(len(features) - seq_len - pred_len): # 输入窗口原始因子 HMM状态概率 x_seq np.hstack([ features[i : i seq_len], states[i : i seq_len] ]) # 预测目标未来pred_len日收益率均值方向 future_ret features[i seq_len : i seq_len pred_len, 0] y_label 1 if np.mean(future_ret) 0 else 0 X.append(x_seq) y.append(y_label) return np.array(X), np.array(y)seq_len60对应大约一个季度的交易日数量覆盖中期趋势周期pred_len5是预测未来一周的方向避免过短的预测周期被噪声主导。hstack操作把HMM状态概率作为额外的特征列拼在原始因子后面这样LSTM在每个时间步都能感知当前市场状态。4.3 train_LSTM_model.py的训练配置源码中LSTM模型用Keras实现核心参数比较常规但有几处容易影响效果的地方。一个典型的配置是from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.optimizers import Adam model Sequential([ LSTM(units128, return_sequencesTrue, input_shape(60, n_features)), Dropout(0.3), LSTM(units64, return_sequencesFalse), Dropout(0.3), Dense(units32, activationrelu), Dense(units1, activationsigmoid), ]) model.compile( optimizerAdam(learning_rate0.001), lossbinary_crossentropy, metrics[accuracy], ) # 设置早停避免过拟合 from tensorflow.keras.callbacks import EarlyStopping early_stop EarlyStopping(monitorval_loss, patience10, restore_best_weightsTrue)return_sequencesTrue的第一层LSTM输出完整时间步序列给第二层让第二层能捕捉更高层的时间模式Dropout(0.3)在LSTM层之后生效对循环层内部权重也有内置的dropout参数可以在构建时另设两个位置要区分开。EarlyStopping的patience10表示验证损失连续10轮不下降就停止训练restore_best_weightsTrue保证回到验证损失最低的权重防止后段训练过拟合。4.4 四类模型的训练脚本分工与评估整个训练流程分布在几个脚本中下面是它们的分工脚本名功能输出train_HMM_model.py训练标准和GMM-HMM状态序列、转移矩阵xgb.py / XGB_HMM.py训练XGBoost分类器构建B矩阵状态概率、B矩阵train_LSTM_model.py训练LSTM分类器预测概率、准确率evaluate_plot.py汇总预测结果绘制对比图混淆矩阵、收益曲线predict.py和main_single_score.py负责单只股票的独立预测流程。train_LSTM_model.py跑完后FIGURE目录下的train1.jpg、train2.jpg、best_iter.png分别是训练曲线、验证曲线和最优迭代步的预测效果图。源码中test1.jpg和test2.jpg则展示了测试集上的状态划分和趋势预测结果。4.5 类别不平衡处理bagging_balance_weight.py股票趋势预测中“上涨”和“下跌”样本通常不均衡尤其在震荡市里“横盘”样本占比很高。bagging_balance_weight.py实现了两种处理一是给少数类样本分配更高的损失权重二是在每个bagging子模型上做下采样让每个子模型看到的类别比例接近均衡最后集成多个子模型的预测结果。from sklearn.utils.class_weight import compute_class_weight from sklearn.ensemble import BaggingClassifier # 计算类别权重用于模型训练 classes np.array([0, 1]) weights compute_class_weight(class_weightbalanced, classesclasses, yy_train) # 构建bagging LSTM评估器示意 base_model create_lstm_model() bagging_model BaggingClassifier( estimatorbase_model, n_estimators5, max_samples0.8, bootstrapTrue, )compute_class_weight会按样本总数和类别频次自动计算权重少数类的权重会高于多数类max_samples0.8让每个子模型只用80%的样本增加子模型间差异。在股票数据这种信噪比很低的任务里bagging对提升稳定性比单模型调参更有效。5. 组合预测与模型部署中的几个关键细节5.1 combine.py的投票与加权策略四个模型各有侧重HMM擅长状态识别但预测收益方向较粗GMM-HMM在波动率大的市场段表现更好XGB-HMM在特征关系复杂时有优势LSTM擅长捕捉短期动量。combine.py默认采用加权投票方式权重由验证集上的每类模型的F1分数决定。一个可用的权重分配逻辑是from sklearn.metrics import f1_score # 四个模型在验证集上的预测概率示意变量 model_probs [hmm_prob, gmm_prob, xgb_hmm_prob, lstm_prob] model_names [HMM, GMM-HMM, XGB-HMM, LSTM] # 计算每个模型的F1分数作为权重 weights [] for prob in model_probs: pred (prob 0.5).astype(int) weights.append(f1_score(y_val, pred)) # 加权平均预测概率 final_prob np.average(model_probs, axis0, weightsweights) final_pred (final_prob 0.5).astype(int)combine_allow_flag.py的作用是对组合结果做合规过滤比如当HMM判断当前处于高波动状态时即使LSTM给出强买入信号也降权处理。这个逻辑在实际交易中是必要的因为LSTM在极端行情下的预测往往外推过度。5.2 数据泄漏与随机种子这个项目中比较隐蔽的问题是HMM和LSTM共用同一段行情数据时HMM的观测序列如果包含了未来区间的数据信息后续LSTM的输入就存在泄漏。源码中random_cut.py和combine_allow_flag.py设计了一套时间窗口切分机制HMM只在训练集前半段拟合LSTM使用后半段两者之间的状态概率在验证集上重新计算。修改代码时要注意保持这个切分逻辑不要在全数据集上一次性训练所有模型否则测试结果会偏乐观。5.3 参数调整速查表在实际复现时按下面参数起步再根据标的和周期微调参数位置推荐值调整方向n_componentstrain_HMM_model.py4状态切换频繁则减小到3长期趋势则增加到5n_mixGMM_HMM.py3因子波动大时可增到5但要防止过拟合seq_lenrandom_cut.py60短周期交易可减到20中长线可增到120n_estimatorsxgb.py300特征多时增加同时配合early stoppingLSTM unitstrain_LSTM_model.py128数据量大可增到256小数据集建议64learning_ratetrain_LSTM_model.py0.001训练不稳时降至0.0005如果训练HMM后状态序列几乎不切换大概率是因子平滑过度检查process_on_raw_data.py中是否用了过大的移动平均窗口或者把n_components减小到3。反之如果状态切换过于频繁可以增加交易日级别的平滑处理比如对后验概率做3日滑动平均后再取argmax。5.4 运行过程中常见的三个报错第一个是hmmlearn版本差异导致的参数名变化旧版本中GaussianHMM的covariance_type参数是必填的新版本改为可选但默认值不同建议固定hmmlearn0.2.7。第二个是LSTM训练时维度不匹配检查input_shape的第二个维度是否等于因子数加上HMM状态概率列数。第三个是form_B_matrix_by_XGB.py中使用了XGBoost模型当前环境不支持的tree_method参数换成hist即可兼容CPU环境。建议在运行main_train_model.py之前先按顺序执行各模块的单元测试确定数据对齐后再跑全流程。本文还有配套的精品资源点击获取
返回列表