
簡介這份基于LSTM的股票價格預測項目源碼主要面向計算機相關專業學生或從業者可作為期末大作業、課程設計的完整參考解決金融時序數據建模與預測的實戰需求。壓縮包共包含89個文件核心為24個Python腳本與19個編譯緩存文件涵蓋數據預處理、模型構建、訓練評估等環節另有13個txt說明文檔、4個HTML頁面及配套CSS/JS前端資源以及xls、xlsx、sqlite3等數據文件整體僅8.89MB結構清晰便于快速提取使用。項目由個人大作業打磨而成評審分達到95分以上并經過嚴格調試下載后即可運行。學習該源碼可掌握LSTM在股票價格預測中的完整流程包括數據清洗、特征構造、模型調參與結果可視化同時可參考作者在項目組織、文件劃分和問題排查方面的思路對完成同類課設或提升實戰能力具有較高價值。目前已有200人學習下載適合中高級Python學習者深入研讀。 股票價格預測是深度學習期末作業里出現頻率最高的課題之一但也是“看起來在跑、實際上沒學對”的重災區。用LSTM做這題時最典型的現象是loss持續下降打開預測圖卻發現藍色預測線總比紅色真實線慢半拍——這不是調大epoch能解決的根因在于滑動窗口的構造方式、歸一化的作用邊界和模型輸出目標三處沒對齊。這里不打算用某份現成源碼的說明書糊弄過去而是按期末大作業的驗收標準數據可查、代碼可跑、答案可解釋展開一套結構完整的LSTM股票價格預測源碼方案從序列樣本怎么切、特征怎么歸一化到Keras模型怎么搭、訓練完怎么評估每個步驟都有對應代碼和參數解釋。適合要交課設作業的在校學生也適合快速套用一個LSTM回歸任務模板的工程師。2. 時間序列預測的選型邏輯LSTM的門控機制與滑動窗口構造2.1 為什么股票序列預測優先LSTM而不是普通RNN股票的收盤價、成交量本質上是一個長依賴時間序列今天是否站上均線、近20個交易日的趨勢是否延續都會對明天的價格產生作用。普通RNN在反向傳播時梯度經過多個時間步連乘序列長度只要超過20步就會出現明顯的梯度消失隱狀態里留存的主要是最近一步的信息模型退化成“拿昨天的價格當預測結果”。這也是很多用SimpleRNN做股價預測的同學發現數據擬合尚可、但測試集上幾乎無泛化能力的原因。LSTM是在RNN基礎上引入細胞狀態Ct的改進結構。細胞狀態沿時間軸穿過整個序列門控只做乘性修改梯度因此擁有一條直通的“高速公路”信息可以在幾十個時間步內保持。你可以在Keras里做一個5分鐘能跑完的對照實驗同樣的數據與相同的unitsLSTM與SimpleRNN各訓練50輪留意驗證集loss的下降速度差異。這個對照組寫進期末作業報告里比空談“LSTM優勢”更有說服力。2.2 LSTM遺忘門的輸入是哪些數據h(t-1)與x(t)的拼接網上經常有人搜“lstm遺忘門的輸入是什么數據”背后的坑是維度理解。遺忘門計算式為f_t sigmoid(W_f * concat(h(t-1), x(t)) b_f)輸入由兩個部分拼接而成上一時刻的隱藏狀態h(t-1)和當前時刻的特征向量x(t)。在股票數據里h(t-1)不是收盤價本身而是模型對“截至上一個交易日”市場信息的壓縮隱藏向量x(t)則是當日輸入特征比如收盤價歸一化值、成交量、5日漲幅這些原始觀測。兩者列維度不同必須用tf.concat或numpy的concatenate拼在一起再經過線性變換和sigmoid得到0到1之間的向量逐元素乘到細胞狀態上決定哪些歷史信息要保留。門控名稱輸入作用股票預測中的直覺理解遺忘門h(t-1), x(t)決定細胞狀態哪一位要被歸零是否丟棄昨天積累的平臺支撐或趨勢信號輸入門h(t-1), x(t)決定候選值哪些寫入細胞狀態當前價格與成交量是否構成新的上漲結構輸出門h(t-1), x(t)過濾后的細胞狀態映射為隱藏狀態h(t)模型對外表達的“綜合判斷”過濾后輸出2.3 數據準備的第一個雷區歸一化、滑動窗口與訓練集切分數據準備階段最常見的錯誤是把亂序樣本直接喂進LSTM。股票序列一旦隨機打亂模型會“偷看未來”訓練時指標非常漂亮一到真實滾動預測就徹底失靈。正確做法是保留時間順序并在窗口內組織樣本。import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler def prepare_data(csv_path, feature_colsNone, target_colclose, seq_len20): # 讀取本地CSV按日期升序排好 df pd.read_csv(csv_path, parse_dates[date]).sort_values(date) if feature_cols is None: feature_cols [target_col] target_idx feature_cols.index(target_col) data df[feature_cols].values.astype(np.float32) # 按時間順序取前80%訓練后20%測試 train_size int(len(data) * 0.8) train_raw, test_raw data[:train_size], data[train_size:] # 只對訓練區擬合scaler測試區僅transform避免歸一化泄漏 scaler MinMaxScaler(feature_range(0, 1)) train_norm scaler.fit_transform(train_raw) test_norm scaler.transform(test_raw) def make_samples(seq): X, y [], [] for i in range(len(seq) - seq_len): X.append(seq[i:i seq_len]) y.append(seq[i seq_len, target_idx]) return np.array(X), np.array(y) X_train, y_train make_samples(train_norm) # 用訓練集尾部seq_len個點接上測試區保證窗口不斷檔 test_seq np.concatenate([train_norm[-seq_len:], test_norm], axis0) X_test, y_test make_samples(test_seq) return X_train, y_train, X_test, y_test, scaler, target_idx這段代碼有幾個關鍵約定。seq_len20表示用過去20個交易日預測第21天的收盤價周期上對應A股一個月的交易日數量。scaler只對訓練區調用fit_transform測試區只能調用transform如果對全量數據fit測試集信息會經歸一化參數泄漏進訓練過程答辯時一問一個準。make_samples里的滑動窗口會產生重疊樣本這是時間序列增廣的常見做法但注意重疊帶來的自相關性會影響誤差分布評估時要有心理預期。3. 用Keras搭建LSTM模型源碼結構與必調參數3.1 構建模型Sequential接口下的LSTM層參數用Python做LSTM時間序列預測時最常出錯的環節不是模型結構而是樣本維度沒對齊。下面先給一個可運行的Keras模型定義import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping seq_len 20 n_features 1 # 演示場景只用收盤價單特征多特征改這里 model Sequential([ LSTM(units64, return_sequencesTrue, input_shape(seq_len, n_features)), Dropout(0.2), LSTM(units32, return_sequencesFalse), Dropout(0.2), Dense(units1) ]) model.compile( optimizertf.keras.optimizers.Adam(learning_rate0.001), lossmse, metrics[mae] )參數這里要說明清楚。第一層units64是隱狀態維度可以理解為模型同時維護64個獨立的“記憶單元”并不是越大大越好股票數據噪聲多隱維度過大會在訓練集上記住具體價位而非規律。return_sequencesTrue是堆疊兩層LSTM時的必需品它讓第一層把每個時間步的隱藏狀態都傳給下一層最后一層LSTM取最后一個時間步輸出經過Dense(1)壓縮成下一日收盤價預測值。input_shape里的(seq_len, n_features)必須與第2章prepare_data的返回值保持一致否則跑數據時會直接報維度不匹配錯誤。參數示例值影響與調整方向units64/32增大則容量提升但股票數據容易過擬合首選32~128return_sequencesTrue/False堆疊LSTM時首層要True末層要Falsedropout0.2抑制過擬合期末作業建議0.2~0.4之間學習率0.001Adam默認可用loss震蕩時降到0.00053.2 訓練與早停epoch、batch_size與驗證集訓練LSTM回歸模型要盡量讓epoch上限設大同時用早停兜底因為不同股票序列的收斂速度差別很大固定epochs50要么欠擬合要么過擬合。early_stop EarlyStopping( monitorval_loss, patience10, restore_best_weightsTrue ) history model.fit( X_train, y_train, validation_split0.1, epochs100, batch_size32, callbacks[early_stop], verbose1 )這里使用validation_split0.1會從訓練序列尾部自動切出最近10%數據作為驗證集天然符合時間順序。不要額外設置shuffleTrueKeras的fit默認會在訓練時洗牌但這個洗牌發生在樣本層面對序列值本身沒有影響驗證集仍然按尾部截取所以不必擔心樣本順序被打亂導致數據泄漏。batch_size32在幾千個滑窗樣本量級下是穩定選擇顯存緊張時改成16收斂更慢但更穩。3.3 預測與價格還原從歸一化空間回到真實股價模型的輸出是歸一化后的數值要畫對比圖或計算誤差指標必須把預測值和真實值同時還原到原始價格區間。單特征場景下直接逆變換即可import matplotlib.pyplot as plt y_pred model.predict(X_test) # shape: (樣本數, 1) pred_close scaler.inverse_transform(y_pred) true_close scaler.inverse_transform(y_test.reshape(-1, 1)) plt.figure(figsize(10, 4)) plt.plot(true_close, labelreal) plt.plot(pred_close, labellstm predict) plt.legend() plt.title(stock close price prediction) plt.show()這段代碼只有一個注意點y_test在生成時是(n,)的一維數組inverse_transform要求二維輸入所以要用reshape(-1, 1)。如果第2章里把feature_cols擴展成包含成交量在內的多個特征就不能再這樣逆變換需要把預測結果拼接成完整特征行、逆變換后再取目標列我在第5章會展開這個細節。4. 訓練完成后的評估與排錯時間切分、評估指標與三個高頻翻車點4.1 時間序列驗證必須遵守的順序邊界train_test_split這類隨機切分工具不能用于股票預測。序列樣本之間高度自相關隨機切分會讓訓練集和測試集出現大量時間交疊模型相當于“開卷考試”在答辯演示時經不起推敲。推薦做法是按時間點切分前80%訓練、后20%測試第2章代碼已經按這個思路實現。要檢查自己的切分是否靠譜可以把X_test里每個樣本的窗口起點和終點打出來確認最小起點時間大于訓練集最大時間。實際做的時候我還建議把train_norm[-seq_len:]這一段當作跨邊界銜接單獨說明因為很多同學在構造測試集時直接對test_raw做滑窗丟掉了前面seq_len個樣本的上下文導致測試預測前20個點斷檔。4.2 評估指標選哪個RMSE、MAPE與方向準確率期末作業不能只貼一張下降的loss曲線評估指標要能解釋模型在真實數據上的水平。from sklearn.metrics import mean_squared_error, mean_absolute_error def evaluate_metrics(y_true, y_pred): y_true y_true.flatten() y_pred y_pred.flatten() rmse np.sqrt(mean_squared_error(y_true, y_pred)) mae mean_absolute_error(y_true, y_pred) # MAPE對低價股異常敏感價格無限接近0時數值會爆炸 mape np.mean(np.abs((y_true - y_pred) / y_true)) * 100 # 方向準確率比較相鄰兩日價格差的方向是否相同 diff_true np.diff(y_true) diff_pred np.diff(y_pred) direction_acc np.mean(np.sign(diff_true) np.sign(diff_pred)) return rmse, mae, mape, direction_acc rmse, mae, mape, direction_acc evaluate_metrics(true_close, pred_close) print(fRMSE{rmse:.4f}, MAE{mae:.4f}, MAPE{mape:.4f}%, direction_acc{direction_acc:.2%})指標關注點局限RMSE大誤差的懲罰更重受價格絕對值影響不同股票間不可直接對比MAE平均絕對偏差更容易理解對極端行情不敏感MAPE相對誤差百分比便于橫向比較股價接近0時失效方向準確率漲跌方向是否判斷正確忽略漲跌幅度但適合展示LSTM的實用價值4.3 高頻翻車點與其背后的低層原因第一個翻車點是預測曲線滯后一拍。模型輸出幾乎等于上一個真實收盤價肉眼看著擬合很好實際上它學的不是趨勢規律而是“復制前值”。檢測方法很簡單把diff(true_close)和diff(pred_close)畫在同一個坐標系里如果預測值的diff基本貼近0說明模型退化了。緩解手段是縮短seq_len并加入成交量、漲跌幅等額外特征迫使模型依賴更多信息。第二個翻車點是歸一化泄漏。一定要確保scaler.fit()只見過訓練集否則測試區間的最小最大值提前被模型通過數據管線“學過”測試指標虛高。第三個翻車點是滑窗時序列補位錯誤。很多源碼在測試階段不拼接train_norm[-seq_len:]導致X_test[0]不是訓練集尾巴后緊接著的那一天語義上形成了一個跳躍窗口。提示期末作業答辯時老師最愛問“為什么你的訓練loss一直在降測試曲線還是滯后”。回復的起點就是這三個翻車點而不是“再訓練50輪”。5. 從源碼包到期末作業多步預測、特征增強與答辯交付技巧5.1 從單步預測升級為多步遞歸預測單步預測在答辯里容易被追問“你只能預測明天能預測未來一周嗎”。多步預測有遞歸法、直接法和seq2seq三種路線期末作業性價比最高的是遞歸法用模型預測次日再把預測值拼進窗口末尾滾動預測后續天數。def recursive_forecast(model, last_window, steps5, target_idx0): 輸入最后一個歷史窗口遞歸預測未來steps天 cur last_window.reshape(1, seq_len, n_features) # 保證三維 results [] for _ in range(steps): next_val model.predict(cur, verbose0)[0, 0] results.append(next_val) # 構造新窗口丟棄窗口最舊一天加入預測值 new_last cur[0, -1, :].copy() new_last[target_idx] next_val cur np.concatenate([cur[:, 1:, :], new_last.reshape(1, 1, -1)], axis1) return np.array(results)注意這里的n_features是在模型定義時就固定了的如果只有close單特征target_idx0沒問題如果后續加了volume就要把被預測的列替換為next_val其余列可以沿用昨天數值也可以分別遞歸預測。誤差會隨著預測步數累積這是LSTM自身無法消除的展示結果時要誠實說明“第五天預測明顯劣于第一天”。5.2 加入成交量與漲跌幅特征時的收益與邊界把feature_cols擴展成[close, volume]或加上5日漲跌幅模型能從量價配合中捕捉到更多狀態。但要注意兩個問題不同特征的量綱差異大統一進MinMaxScaler是可行的而歸一化后的inverse_transform必須基于完整特征矩陣才能還原價格列不能只對單列操作。特征數量從1加到3時樣本量不變而輸入維度變大模型參數量隨之上升幾百條股票數據很容易過擬合建議同時把units降到32并提高dropout到0.3。5.3 源碼包結構與README交付清單期末大作業的源碼包要讓人拿到手里就能復現一份合格的目錄結構是lstm_stock/ ├── data/ # 原始CSV列名包含date/close/volume ├── prepare.py # 歸一化、滑動窗口、時間切分 ├── train.py # LSTM模型定義、訓練、早停 ├── evaluate.py # RMSE/MAE/MAPE/方向準確率與繪圖 └── README.md # 運行步驟、依賴、結果圖與結論README里要把運行命令寫到可直接復制的程度python train.py python evaluate.py。結果圖命名要帶指標比如prediction_rmse_12.34.png評審打開目錄一眼就能看到效果。答辯時把單步預測圖和多步遞歸預測誤差累積圖畫在一張A4報告里左邊真實vs預測右邊誤差隨步數變化曲線這組圖比任何調參論述都有說服力。本文還有配套的精品資源點擊獲取