A股时序建模实战:LSTM工作流与频域特征工程

发布时间:2026/9/11 23:28:07
A股时序建模实战:LSTM工作流与频域特征工程
简介本资源是一套面向金融数据分析初学者与机器学习实践者的A股股票走势预测系统融合金融逻辑、时间序列建模与Python工程实现旨在辅助投资者建立数据驱动的决策能力。压缩包共12个文件含6个Jupyter Notebook涵盖LSTM时序建模、单票回测、特征工程与FFT滤波等核心实验、3个CSV格式A股个股历史行情数据如600256、002475等、2个Python脚本用于数据获取与新特征生成及1份Markdown运行说明整体2.41MB结构清晰、开箱即用。已有516人学习下载适合掌握基础Pandas/Scikit-learn后进阶实践时间序列预测的学习者。读者可直接复现从数据清洗、多算法对比线性回归、随机森林、LSTM、模型评估到实盘回测的完整流程并获得适配A股T1与涨跌停机制的特征设计思路与代码级实现细节。1. 这不是“涨停预测器”而是一套可验证、可调试、可复现的A股时序建模工作流你打开这个压缩包第一眼看到singlelstm.ipynb和600256.csv可能下意识觉得“又一个喊单式AI炒股工具”。但实际拆开后会发现它不封装模型、不隐藏特征构造逻辑、不打包成exe骗点击——所有.ipynb文件都保留完整执行单元getstockcsv.py显式调用 Tushare 接口需用户自行配置 tokenfft-filter.ipynb甚至把频域去噪过程拆成四步可视化。它解决的不是“明天涨不涨”而是“如何在A股T1、涨跌停、非正态分布、低信噪比的现实约束下构建一个有明确输入输出边界、误差可归因、参数可调节的机器学习预测管道”。适合三类人金融工程初学者想理解时序特征工程怎么落地量化爱好者需要可修改的LSTM基线模板Python数据科学从业者想练手真实金融场景下的数据清洗与模型诊断。它不承诺收益但承诺每一步都能print(df.head())、每一行代码都能debug进去。2. 为什么选LSTM而非XGBoost从A股K线数据特性倒推模型选型逻辑2.1 A股K线数据的四大反直觉特性决定算法边界A股日线数据表面是标准时间序列实则暗藏四重陷阱第一非平稳性极强。以002475.csv立讯精密为例2020年疫情后PE从25倍飙升至68倍2022年又回落至18倍传统差分难以完全消除趋势项第二跳跃式结构断点频发。2021年9月“双减”政策导致教育股单日-20%跌停这种外生冲击在训练集里表现为孤立异常点但SVM或随机森林会将其误判为高权重特征第三多尺度周期混叠。周线级别有资金调仓节奏约5-8日月线级别有财报季效应30±3日而LSTM的门控机制天然支持对不同时间尺度记忆权重的动态分配第四特征维度稀疏且非独立。开盘价、收盘价、最高价高度共线直接喂入线性模型会导致系数震荡但LSTM通过隐藏层非线性映射可缓解该问题。提示sklearn机器学习单票回测.ipynb中对比了RandomForestRegressor与LSTM在600256.csv广汇能源上的MAE——前者为1.82元后者为1.37元差距看似微小但当应用于高频信号生成时LSTM的残差序列自相关系数ACF在滞后5阶内衰减至0.1以下而RF残差ACF在滞后10阶仍高于0.4说明LSTM更有效捕获了时序依赖。2.2 LSTM实现细节从singlelstm.ipynb看三层关键设计2.2.1 输入张量构造为何必须用滑动窗口而非原始序列def create_dataset(data, lookback60, predict_step1): X, y [], [] for i in range(lookback, len(data) - predict_step 1): X.append(data[i-lookback:i, 0]) # 取前60天收盘价 y.append(data[i predict_step - 1, 0]) # 预测第61天收盘价 return np.array(X), np.array(y) # 关键参数说明 # lookback60对应A股约3个月交易周期覆盖完整财报季资金轮动周期 # predict_step1严格遵循T1交易规则不预测跨日走势 # data[:, 0]强制只用收盘价作为主特征避免多变量引入共线性干扰这段代码拒绝使用pandas.DataFrame.shift()的向量化操作坚持用显式循环构造样本。原因在于当lookback60时若某日数据缺失如停牌向量化shift会导致整行错位而显式循环可通过try/except捕获并跳过该样本保证每个(X,y)元组的时间连续性。2.2.2 模型架构两层LSTMDropout的物理意义model Sequential([ LSTM(50, return_sequencesTrue, input_shape(60, 1)), # 第一层50个记忆单元保留时序维度 Dropout(0.2), # 在timestep间随机屏蔽20%连接抑制过拟合 LSTM(50, return_sequencesFalse), # 第二层压缩时序维度输出单向量 Dense(1) # 线性输出层 ]) model.compile(optimizeradam, lossmse)此处return_sequencesTrue不是技术炫技——它让第一层LSTM的每个timestep输出都参与第二层计算相当于构建了“时间维度上的残差连接”。当处理xmm.csv新媒股份这类波动剧烈的小市值股票时该设计使验证集loss下降速度比单层LSTM快37%见singlelstm2.ipynb的训练曲线对比图。2.2.3 归一化策略Min-Max vs StandardScaler在金融数据中的实证差异方法训练集MAE验证集MAE对异常值敏感度是否需逆变换Min-Max (0,1)1.291.41高涨停板导致max突变必须否则预测值失真StandardScaler1.331.37低均值/方差鲁棒必须否则价格量纲错误singlelstm.ipynb采用StandardScaler但关键在fit_transform()仅作用于训练集验证集和测试集严格使用训练集的mean_和scale_参数。这避免了未来信息泄露——若用全量数据标准化验证集的std会包含未来波动率信息导致评估虚高。3. 特征工程实战从原始K线到可训练张量的七步清洗链3.1 数据加载与基础校验getstockcsv.py的防御式编程def fetch_stock_data(ts_code, start_date, end_date): try: df pro.daily(ts_codets_code, trade_date, start_datestart_date, end_dateend_date) if df.empty: raise ValueError(fNo data for {ts_code}) # 强制按日期升序排列Tushare返回顺序不稳定 df df.sort_values(trade_date).reset_index(dropTrue) # 检查日期连续性A股休市日不补数但需确认无意外断点 date_diff pd.to_datetime(df[trade_date]).diff().dt.days if (date_diff 10).any(): # 超过10日断点视为异常 print(fWarning: Large gap detected in {ts_code}) return df except Exception as e: print(fFetch failed for {ts_code}: {e}) return pd.DataFrame()该函数不信任任何外部API的稳定性。date_diff 10的阈值来自A股最长连续休市记录春节国庆叠加超过即触发人工核查。sort_values操作虽增加0.3秒耗时但避免了LSTM输入时序错乱导致的梯度爆炸。3.2 K线特征衍生newfeature.py中的三个关键指标3.2.1 量能饱和度圆圈指标适配A股特性def calc_volume_saturation(df, window20): 量能饱和度 当日成交量 / 近window日平均成交量 圆圈1.00含义当日量能达20日均值水平突破此阈值常伴随趋势启动 df[vol_mean] df[vol].rolling(windowwindow).mean() df[vol_saturation] df[vol] / df[vol_mean] return df # 应用示例在002475.csv中 df calc_volume_saturation(df) df[saturation_signal] (df[vol_saturation] 1.00).astype(int) # 生成二值信号注意window20对应A股月度交易日均值而非自然月。vol_saturation 1.00的阈值非经验设定而是通过validation_small_cap_filter.ipynb中的网格搜索确定——在小市值股票池中该阈值使信号准确率Precision达63.2%显著高于1.2或0.8等备选值。3.2.2 市盈率动态平滑解决财报季数据断点def smooth_pe_ratio(df, pe_colpe): 对PE列进行前向填充指数加权移动平均 解决财报发布后PE突变问题如从30→亏损→NaN→80 df[pe_col] df[pe_col].fillna(methodffill) # 前向填充空值 df[pe_col] df[pe_col].ewm(span5, adjustFalse).mean() # 5日EMA平滑 return dfspan5的选择依据A股财报披露后市场通常用5个交易日消化信息过长span10会延迟信号过短span2则无法过滤噪声。3.3 频域滤波fft-filter.ipynb中的噪声分离实践def fft_denoise(signal, threshold0.1): 对收盘价序列做FFT去噪 threshold0.1保留能量占比前10%的频谱分量 fft_result np.fft.fft(signal) magnitude np.abs(fft_result) threshold_val np.percentile(magnitude, 100*(1-threshold)) # 取前10%分量 filtered_fft fft_result * (magnitude threshold_val) return np.real(np.fft.ifft(filtered_fft)) # 在600256.csv上应用效果 # 原始序列标准差2.17 # 滤波后序列标准差1.43降低34% # 但关键滤波后序列的ACF在滞后1阶相关性提升12%说明保留了核心趋势成分该方法不用于最终预测而是作为特征增强手段——将fft_denoise(close)与原始close拼接为双通道输入使LSTM能同时学习原始波动与平滑趋势singlelstm2.ipynb中该设计使方向准确率Directional Accuracy从52.1%提升至56.7%。4. 模型验证与生产就绪如何避免“回测完美实盘失效”的陷阱4.1 时间序列交叉验证的正确姿势sklearn机器学习单票回测.ipynb中未使用TimeSeriesSplit而是实现自定义滚动验证def rolling_validation(model, X, y, train_size1000, test_size200): 滚动验证每次取前train_size样本训练后test_size样本测试 避免未来信息泄露符合A股实盘迭代逻辑 results [] for i in range(0, len(X) - train_size - test_size 1, test_size): X_train X[i:itrain_size] y_train y[i:itrain_size] X_test X[itrain_size:itrain_sizetest_size] y_test y[itrain_size:itrain_sizetest_size] model.fit(X_train, y_train) pred model.predict(X_test) mae mean_absolute_error(y_test, pred) results.append(mae) return np.mean(results), np.std(results) # 在002475.csv上运行结果 # 平均MAE1.39 ± 0.21标准差反映模型稳定性 # 若用普通KFoldMAE为1.12 ± 0.45低估误差且高估稳定性滚动验证的steptest_size设计模拟实盘每周更新模型的节奏std0.21表明模型在不同时间段表现稳定而KFold的std0.45暴露了其对特定时间切片的过拟合。4.2 涨跌停约束下的预测后处理A股存在±10%涨跌停限制但LSTM原始输出无边界。singlelstm.ipynb中的修正逻辑def apply_limit_constraint(pred_close, prev_close, limit_rate0.10): 根据前一日收盘价和涨跌停规则约束预测值 upper_limit prev_close * (1 limit_rate) lower_limit prev_close * (1 - limit_rate) # 注意A股ST股涨跌幅为5%此处需扩展判断逻辑 return np.clip(pred_close, lower_limit, upper_limit) # 关键细节prev_close取自验证集y_true的前一日值 # 避免用预测值链式约束如pred_t1→pred_t2防止误差累积该约束使600256.csv的预测方向准确率提升2.3个百分点——因为涨停日往往伴随次日惯性上涨模型原始输出易低估该效应。4.3 回测框架README.md中被忽略的关键参数表参数名默认值修改建议影响说明LOOKBACK_DAYS60小市值股可降至40大盘股增至90控制模型记忆长度过短丢失周期信息过长引入噪声PREDICT_STEP1严禁设为1违反T1规则多步预测在A股无效因中间日价格不可交易TRAIN_TEST_SPLIT0.8波动剧烈期如2022年建议0.7确保验证集覆盖足够多的极端行情FEATURE_COLS[close]可添加[close,vol_saturation]多特征需同步归一化否则LSTM梯度失衡注意TRAIN_TEST_SPLIT0.8指按时间顺序划分非随机打乱。README.md中强调“必须保持时间连续性”否则验证集会包含未来数据。5. 进阶技巧用fft-filter.ipynb定位A股主力资金介入时点5.1 从频谱能量分布识别资金行为模式A股主力资金操作具有典型周期性建仓期20-30日、拉升期5-10日、派发期15-25日。fft-filter.ipynb中的频谱分析可量化这些周期def analyze_main_force_cycles(df, price_colclose): signal df[price_col].values fft_result np.fft.fft(signal) freqs np.fft.fftfreq(len(signal), d1) # 单位交易日 magnitude np.abs(fft_result[:len(signal)//2]) # 取正频率部分 freqs freqs[:len(signal)//2] # 查找能量峰值对应的周期单位日 peaks, _ find_peaks(magnitude, heightnp.max(magnitude)*0.3) dominant_periods [1/freqs[i] for i in peaks if freqs[i] 0] return dominant_periods # 在xmm.csv新媒股份2023年数据上运行 # 输出[23.5, 8.2, 17.9] → 对应建仓期23日、拉升期8日、派发期18日 # 与龙虎榜数据比对23.5日周期匹配度达76%该分析不用于直接预测而是作为特征工程的输入——将dominant_periods中的23.5日周期强度作为新特征加入LSTM输入使模型在002475.csv上的方向准确率再提升1.8%。5.2 构建“周期强度”特征将频域结果转化为时序特征def add_cycle_strength_feature(df, period_days23.5, window60): 计算指定周期在滑动窗口内的能量强度 signal df[close].values strength_series [] for i in range(window, len(signal)): window_signal signal[i-window:i] fft_win np.fft.fft(window_signal) freqs_win np.fft.fftfreq(window, d1) # 找到最接近period_days的频率索引 target_freq 1 / period_days idx np.argmin(np.abs(freqs_win[:window//2] - target_freq)) strength np.abs(fft_win[idx]) strength_series.append(strength) # 归一化到0-1区间 strength_arr np.array(strength_series) strength_norm (strength_arr - np.min(strength_arr)) / (np.max(strength_arr) - np.min(strength_arr) 1e-8) df.loc[window:, cycle_23d_strength] strength_norm return df # 应用后LSTM输入维度从1变为2close cycle_23d_strength # 在singlelstm2.ipynb中该特征使验证集MSE降低0.08相对降幅6.2%此技巧将频域洞察落地为可训练特征避免了“分析很精彩模型用不上”的常见陷阱。它要求使用者理解target_freq 1 / period_days是傅里叶变换的基本原理而非魔法参数。本文还有配套的精品资源点击获取