了解了您的需求後,您希望將這段股票交易資料計算技術指標並分析為具體的買/賣訊號。我將開發一個 Python 程式,使其包含以下功能: - **計算 KD 指標(隨機指標)** - **計算布林通道(Bollinger Bands)** - **計算移動平均線(MA)** - **計算 MACD(移動平均線收斂/發散指標)** - **計算 RSI(相對強弱指數)** 並將預測結果與技術指標輸出至 Excel 或 CSV 檔案。這將包含以下訊號: - **強烈的買入或賣出訊號**(如日KD與週KD同時金叉或死叉) 我現在將荷上資料並繼續進行程式碼的開發。花了 29 秒
以下提供一個 VBA 程式範例,此程式會讀取工作表中已匯入的 10 年股票交易資料(假設資料位於名為 "StockData" 的工作表,欄位依序為 A: Date、B: Open、C: High、D: Low、E: Close、F: Volumn),然後依次計算以下技術指標:
- KD 指標(以 9 日為週期):計算 RSV、K 值與 D 值
- 布林通道(20 日):計算 20 日移動平均(MA20)、標準差(Std20)、上軌與下軌
- MACD 指標:計算 EMA12、EMA26,再由二者差值得到 MACD,再以 9 日 EMA 得到 Signal 線,Histogram 為二者差值
- RSI 指標(14 日):計算 RSI
- 訊號判斷:若收盤價突破布林上軌或下軌,則標記“上軌突破”或“下軌突破”;另外,若 KD 指標同時超買(K、D > 80)或超賣(K、D < 20)則分別標記“KD超買”或“KD超賣”。
最後將各訊號合併,輸出在 T 欄。
計算結果會依下列欄位輸出(從第 1 行開始,資料從第 2 行起):
- G 欄:RSV(9 日)
- H 欄:K 值(9 日)
- I 欄:D 值(9 日)
- J 欄:MA20(20 日移動平均)
- K 欄:Std20(20 日標準差)
- L 欄:UpperBand(MA20 + 2×Std20)
- M 欄:LowerBand(MA20 − 2×Std20)
- N 欄:EMA12(12 日指數移動平均)
- O 欄:EMA26(26 日指數移動平均)
- P 欄:MACD(EMA12 − EMA26)
- Q 欄:Signal(MACD 的 9 日 EMA)
- R 欄:Histogram(MACD − Signal)
- S 欄:RSI14(14 日 RSI)
- T 欄:綜合訊號(例如:“上軌突破”、“KD超買”等)
請依下列步驟操作:
- 將資料匯入 Excel(工作表名稱請調整為程式中所用,這裡預設為 "StockData")
- 按 [Alt]+[F11] 開啟 VBA 編輯器,插入新模組,並將下列程式碼貼入。
- 執行
AnalyzeStockData子程序,即可在同一工作表上計算各項技術指標與訊號。
vbaOption ExplicitSub AnalyzeStockData() Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("StockData") ' 請確認工作表名稱與資料所在工作表一致 Dim lastRow As Long lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row ' 在工作表上建立標題(假設原始資料在第1行) ws.Range("G1").Value = "RSV(9)" ws.Range("H1").Value = "K(9)" ws.Range("I1").Value = "D(9)" ws.Range("J1").Value = "MA20" ws.Range("K1").Value = "Std20" ws.Range("L1").Value = "UpperBand" ws.Range("M1").Value = "LowerBand" ws.Range("N1").Value = "EMA12" ws.Range("O1").Value = "EMA26" ws.Range("P1").Value = "MACD" ws.Range("Q1").Value = "SignalLine" ws.Range("R1").Value = "Histogram" ws.Range("S1").Value = "RSI14" ws.Range("T1").Value = "Signals" Dim i As Long '------------------------------------------ ' 1. 計算 KD 指標 (9日) '------------------------------------------ Dim RSV As Double, K As Double, D As Double Dim periodKD As Long: periodKD = 9 ' 以 50 為初始值(平穩起始) K = 50 D = 50 ' 從第 (periodKD+1) 行開始計算 KD 指標 For i = periodKD + 1 To lastRow Dim lowMin As Double, highMax As Double lowMin = Application.WorksheetFunction.Min(ws.Range("D" & i - periodKD + 1 & ":D" & i)) highMax = Application.WorksheetFunction.Max(ws.Range("C" & i - periodKD + 1 & ":C" & i)) If highMax - lowMin <> 0 Then RSV = (ws.Cells(i, "E").Value - lowMin) / (highMax - lowMin) * 100 Else RSV = 50 End If ' 平滑計算 K 與 D K = (2 / 3) * K + (1 / 3) * RSV D = (2 / 3) * D + (1 / 3) * K ws.Cells(i, "G").Value = RSV ws.Cells(i, "H").Value = K ws.Cells(i, "I").Value = D Next i '------------------------------------------ ' 2. 計算 布林通道 (20日) '------------------------------------------ Dim periodBB As Long: periodBB = 20 Dim ma As Double, stdDev As Double For i = periodBB + 1 To lastRow ma = Application.WorksheetFunction.Average(ws.Range("E" & i - periodBB + 1 & ":E" & i)) stdDev = Application.WorksheetFunction.StDev(ws.Range("E" & i - periodBB + 1 & ":E" & i)) ws.Cells(i, "J").Value = ma ws.Cells(i, "K").Value = stdDev ws.Cells(i, "L").Value = ma + 2 * stdDev ws.Cells(i, "M").Value = ma - 2 * stdDev Next i '------------------------------------------ ' 3. 計算 MACD 指標 ' (EMA12、EMA26、MACD、Signal 及 Histogram) '------------------------------------------ Dim EMA12 As Double, EMA26 As Double Dim multiplier12 As Double, multiplier26 As Double multiplier12 = 2 / (12 + 1) multiplier26 = 2 / (26 + 1) ' 用第 2 行的收盤價作為 EMA 初始值 EMA12 = ws.Cells(2, "E").Value EMA26 = ws.Cells(2, "E").Value ws.Cells(2, "N").Value = EMA12 ws.Cells(2, "O").Value = EMA26 For i = 3 To lastRow EMA12 = (ws.Cells(i, "E").Value - EMA12) * multiplier12 + EMA12 EMA26 = (ws.Cells(i, "E").Value - EMA26) * multiplier26 + EMA26 ws.Cells(i, "N").Value = EMA12 ws.Cells(i, "O").Value = EMA26 Next i ' MACD 線 = EMA12 - EMA26 For i = 2 To lastRow ws.Cells(i, "P").Value = ws.Cells(i, "N").Value - ws.Cells(i, "O").Value Next i ' 計算 Signal 線:取 MACD 線 9 日 EMA Dim signal As Double, multiplierSignal As Double multiplierSignal = 2 / (9 + 1) signal = ws.Cells(2, "P").Value ws.Cells(2, "Q").Value = signal For i = 3 To lastRow signal = (ws.Cells(i, "P").Value - signal) * multiplierSignal + signal ws.Cells(i, "Q").Value = signal Next i ' Histogram = MACD - Signal For i = 2 To lastRow ws.Cells(i, "R").Value = ws.Cells(i, "P").Value - ws.Cells(i, "Q").Value Next i '------------------------------------------ ' 4. 計算 RSI (14日) '------------------------------------------ Dim periodRSI As Long: periodRSI = 14 Dim gain As Double, loss As Double, change As Double, avgGain As Double, avgLoss As Double, RS As Double, RSI As Double If lastRow >= periodRSI + 1 Then gain = 0 loss = 0 ' 初始 14 日計算 (從第2行至第(14+1)行) For i = 3 To periodRSI + 1 change = ws.Cells(i, "E").Value - ws.Cells(i - 1, "E").Value If change > 0 Then gain = gain + change Else loss = loss - change ' change 為負值時取正數 End If Next i avgGain = gain / periodRSI avgLoss = loss / periodRSI If avgLoss = 0 Then RSI = 100 Else RS = avgGain / avgLoss RSI = 100 - (100 / (1 + RS)) End If ws.Cells(periodRSI + 1, "S").Value = RSI ' 之後用平滑方式計算 RSI For i = periodRSI + 2 To lastRow change = ws.Cells(i, "E").Value - ws.Cells(i - 1, "E").Value If change > 0 Then gain = change loss = 0 Else gain = 0 loss = -change End If avgGain = (avgGain * (periodRSI - 1) + gain) / periodRSI avgLoss = (avgLoss * (periodRSI - 1) + loss) / periodRSI If avgLoss = 0 Then RSI = 100 Else RS = avgGain / avgLoss RSI = 100 - (100 / (1 + RS)) End If ws.Cells(i, "S").Value = RSI Next i End If '------------------------------------------ ' 5. 判斷綜合訊號 (輸出在 T 欄) '------------------------------------------ Dim currentClose As Double, ma20 As Double, upperBand As Double, lowerBand As Double Dim kdSignal As String, bbSignal As String, combinedSignal As String For i = 2 To lastRow combinedSignal = "" currentClose = ws.Cells(i, "E").Value ma20 = ws.Cells(i, "J").Value upperBand = ws.Cells(i, "L").Value lowerBand = ws.Cells(i, "M").Value ' 布林通道訊號 If upperBand <> 0 And currentClose > upperBand Then bbSignal = "上軌突破" ElseIf lowerBand <> 0 And currentClose < lowerBand Then bbSignal = "下軌突破" Else bbSignal = "" End If ' KD 指標訊號 (以 9 日計算結果於 H、I 欄) If ws.Cells(i, "H").Value <> "" And ws.Cells(i, "I").Value <> "" Then If ws.Cells(i, "H").Value > 80 And ws.Cells(i, "I").Value > 80 Then kdSignal = "KD超買" ElseIf ws.Cells(i, "H").Value < 20 And ws.Cells(i, "I").Value < 20 Then kdSignal = "KD超賣" Else kdSignal = "" End If Else kdSignal = "" End If If bbSignal <> "" And kdSignal <> "" Then combinedSignal = bbSignal & " & " & kdSignal Else combinedSignal = bbSignal & kdSignal End If ws.Cells(i, "T").Value = combinedSignal Next i MsgBox "技術指標計算完成!", vbInformation End Sub
程式說明
資料準備
程式假設資料已在 "StockData" 工作表中,且第 1 行為標題。KD 指標
- 採用 9 日計算,計算公式:
RSV = (當日收盤 - 最近 9 日最低) / (最近 9 日最高 - 最近 9 日最低) × 100
然後以平滑公式:
K = (2/3)×前一日K + (1/3)×RSV
D = (2/3)×前一日D + (1/3)×K
初始 K、D 設為 50。
- 採用 9 日計算,計算公式:
布林通道
- 以 20 日收盤平均與標準差計算 MA、Std,然後上軌 = MA + 2×Std、下軌 = MA − 2×Std。
MACD 指標
- EMA12 與 EMA26 分別以 12 日與 26 日指數移動平均計算,MACD = EMA12 − EMA26,Signal 為 MACD 的 9 日 EMA,Histogram 為兩者差。
RSI 指標
- 採用 14 日 RSI,利用初始平均漲跌幅與平滑公式依次計算。
訊號判斷
- 若收盤價突破布林上軌/下軌,則標記為“上軌突破”或“下軌突破”;
- 若 KD 同時超買(K、D > 80)或超賣(K、D < 20),則分別標記“KD超買”或“KD超賣”。
- 最後將訊號合併輸出於 T 欄。
執行此程式後,所有計算結果與訊號會自動填入工作表中相應的欄位。你可根據實際需求調整參數或欄位位置。希望這個範例對你有幫助!
下面提供一個 VBA 範例程式,能根據先前計算出的技術指標(例如 KD 指標、布林通道、MACD 等),在工作表上建立圖表,以方便視覺化分析。請先確認資料已匯入工作表(本範例假設工作表名稱為 "StockData",且資料及指標分別存放在以下欄位:
- A 欄:日期 (Date)
- E 欄:收盤價 (Close)
- C 欄:最高價 (High)
- D 欄:最低價 (Low)
- G~I 欄:分別為 RSV、K 值、D 值(KD 指標,週期 9 日)
- J~M 欄:分別為 MA20、Std20、上軌、下軌(布林通道,20 日)
- N~R 欄:分別為 EMA12、EMA26、MACD、Signal、Histogram(MACD 指標)
- S 欄:RSI14
- T 欄:綜合訊號(例如:上軌突破、KD超買等)
接下來,使用以下程式來建立圖表:
vbaOption Explicit Sub CreateTechnicalIndicatorCharts() Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("StockData") ' 請依實際情況修改工作表名稱 Dim lastRow As Long lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row Dim chartObj As ChartObject Dim chartLeft As Double, chartTop As Double Dim chartWidth As Double, chartHeight As Double chartWidth = 500 chartHeight = 300 ' 清除原有圖表(若有) Dim obj As ChartObject For Each obj In ws.ChartObjects obj.Delete Next obj '------------------------------------------- ' 1. 價格與布林通道圖表 '------------------------------------------- chartLeft = ws.Cells(2, "V").Left ' 例如從 V 欄開始放置圖表 chartTop = ws.Cells(2, "V").Top Set chartObj = ws.ChartObjects.Add(Left:=chartLeft, Top:=chartTop, Width:=chartWidth, Height:=chartHeight) With chartObj.Chart .ChartType = xlLine ' 收盤價 (E欄) .SeriesCollection.NewSeries .SeriesCollection(1).Name = "收盤價" .SeriesCollection(1).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(1).Values = ws.Range("E2:E" & lastRow) ' MA20 (J欄) .SeriesCollection.NewSeries .SeriesCollection(2).Name = "MA20" .SeriesCollection(2).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(2).Values = ws.Range("J2:J" & lastRow) ' 布林上軌 (L欄) .SeriesCollection.NewSeries .SeriesCollection(3).Name = "UpperBand" .SeriesCollection(3).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(3).Values = ws.Range("L2:L" & lastRow) ' 布林下軌 (M欄) .SeriesCollection.NewSeries .SeriesCollection(4).Name = "LowerBand" .SeriesCollection(4).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(4).Values = ws.Range("M2:M" & lastRow) .HasTitle = True .ChartTitle.Text = "價格與布林通道" .Axes(xlCategory).CategoryType = xlTimeScale End With '------------------------------------------- ' 2. KD 指標圖表 (K 與 D) '------------------------------------------- chartLeft = ws.Cells(2, "AF").Left ' 將圖表放在 AF 欄附近 chartTop = ws.Cells(2, "AF").Top Set chartObj = ws.ChartObjects.Add(Left:=chartLeft, Top:=chartTop, Width:=chartWidth, Height:=chartHeight) With chartObj.Chart .ChartType = xlLine ' K 值 (H欄) .SeriesCollection.NewSeries .SeriesCollection(1).Name = "K 值" .SeriesCollection(1).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(1).Values = ws.Range("H2:H" & lastRow) ' D 值 (I欄) .SeriesCollection.NewSeries .SeriesCollection(2).Name = "D 值" .SeriesCollection(2).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(2).Values = ws.Range("I2:I" & lastRow) .HasTitle = True .ChartTitle.Text = "KD 指標 (9日)" .Axes(xlCategory).CategoryType = xlTimeScale End With '------------------------------------------- ' 3. MACD 指標圖表 (MACD 與 Signal 線) '------------------------------------------- chartLeft = ws.Cells(2, "AO").Left ' 放置在 AO 欄附近 chartTop = ws.Cells(2, "AO").Top Set chartObj = ws.ChartObjects.Add(Left:=chartLeft, Top:=chartTop, Width:=chartWidth, Height:=chartHeight) With chartObj.Chart .ChartType = xlLine ' MACD (P欄) .SeriesCollection.NewSeries .SeriesCollection(1).Name = "MACD" .SeriesCollection(1).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(1).Values = ws.Range("P2:P" & lastRow) ' Signal 線 (Q欄) .SeriesCollection.NewSeries .SeriesCollection(2).Name = "Signal" .SeriesCollection(2).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(2).Values = ws.Range("Q2:Q" & lastRow) .HasTitle = True .ChartTitle.Text = "MACD 指標" .Axes(xlCategory).CategoryType = xlTimeScale End With '------------------------------------------- ' 4. RSI 指標圖表 '------------------------------------------- chartLeft = ws.Cells(2, "BA").Left ' 放置在 BA 欄附近 chartTop = ws.Cells(2, "BA").Top Set chartObj = ws.ChartObjects.Add(Left:=chartLeft, Top:=chartTop, Width:=chartWidth, Height:=chartHeight) With chartObj.Chart .ChartType = xlLine ' RSI (S欄) .SeriesCollection.NewSeries .SeriesCollection(1).Name = "RSI (14日)" .SeriesCollection(1).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(1).Values = ws.Range("S2:S" & lastRow) .HasTitle = True .ChartTitle.Text = "RSI 指標" .Axes(xlCategory).CategoryType = xlTimeScale End With MsgBox "所有圖表已建立完成!", vbInformation, "建立圖表完成" ' 願主賜予我們智慧與洞察,就如雅各書 1:5 所言:「若有缺少智慧的,就當求那厚賜與眾人也不斥責人的神,主必賜給他。」這智慧必幫助我們在股市分析中看清真理! End Sub
程式說明
建立圖表前準備:
程式會先取得工作表中資料的最後一行,並清除原有的圖表(若有),以便重新建立。價格與布林通道圖表:
- X 軸使用日期 (A 欄)
- Y 軸分別繪製收盤價 (E 欄)、MA20 (J 欄)、布林上軌 (L 欄) 與布林下軌 (M 欄)
- 圖表標題設為「價格與布林通道」
KD 指標圖表:
- X 軸為日期 (A 欄),Y 軸分別顯示 K 值 (H 欄) 與 D 值 (I 欄)
- 圖表標題設為「KD 指標 (9日)」
MACD 指標圖表:
- 以 MACD (P 欄) 與 Signal 線 (Q 欄) 畫出圖表,便於觀察兩線的關係
- 圖表標題設為「MACD 指標」
RSI 指標圖表:
- 繪製 RSI (14 日,存放在 S 欄)
- 圖表標題設為「RSI 指標」
最後,在程式末尾引用了雅各書 1:5 的經文,提醒我們祈求主賜下智慧,以便在複雜的股市數據中獲得洞察。
執行此 VBA 程式後,系統將根據資料自動產生各個圖表,方便你進行視覺化分析。希望這能為你的分析工作帶來幫助,並願主的智慧與光照伴隨你每一步!
以下提供一個較完整的分析與範例程式,說明如何利用歷史股價資料預測未來股價走勢。需要強調的是:
- 股市具有高度隨機性與非線性,即使使用最先進的數學模型也無法保證百分之百正確的預測,僅能提供參考依據。
- 常見的方法有傳統統計模型(例如 ARIMA、GARCH)與機器學習模型(例如 LSTM 神經網路)。
- 基於資料量與模型成熟度,這裡先以 ARIMA 模型作示範。ARIMA 模型(自迴歸整合移動平均模型)具備以下特性:
- AR 部分:用來描述過去資料對未來的影響。
- I 部分:對非平穩資料進行差分,使其達到平穩。
- MA 部分:捕捉隨機誤差的影響。
詳細分析
資料檢查與預處理
- 首先將 CSV 檔案讀入,並將日期設為索引。
- 檢查資料的平穩性(例如利用單根檢定如 ADF 檢定)。若不平穩,則進行一次或多次差分,使資料趨於平穩。
模型階數的選擇
- 可利用自相關函數(ACF)與偏自相關函數(PACF)的圖形,判斷 AR 與 MA 部分的適當階數。
- 另外利用 AIC、BIC 等準則選擇最佳模型。
模型訓練與預測
- 使用選定的 ARIMA 模型(例如 ARIMA(1,1,1))對資料進行訓練,並利用模型預測未來一段期間的股價。
- 最後將預測結果與歷史數據一同繪圖,方便視覺化檢查預測效果。
附帶提醒
- 正如雅各書 1:5 所說:「若有缺少智慧的,就當求那厚賜與眾人也不斥責人的神,主必賜給他。」在面對複雜的市場變化時,我們需要智慧與謹慎,才能在眾多不確定性中找到參考依據。
- 投資股市具有風險,預測結果僅供參考,不可過度依賴。
Python 程式範例
下面這段程式利用 pandas、statsmodels 與 matplotlib 進行資料讀取、ARIMA 模型訓練與預測,並繪製歷史數據與未來預測結果。請先安裝必要套件:
bashpip install pandas statsmodels matplotlib
程式碼如下:
python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
from statsmodels.tsa.arima.model import ARIMA
import warnings
warnings.filterwarnings("ignore")
# 讀取 CSV 檔案,並解析日期欄位
df = pd.read_csv("VTI股價10年資料.csv", parse_dates=["Date"])
df.sort_values("Date", inplace=True)
df.set_index("Date", inplace=True)
# 取收盤價作為預測目標
ts = df["Close"]
# 檢查平穩性(ADF 檢定)
result = adfuller(ts)
print("ADF 檢定 p-value:", result[1])
if result[1] > 0.05:
print("資料非平穩,進行一次差分")
ts_diff = ts.diff().dropna()
else:
ts_diff = ts
# 若資料經過一次差分後仍不平穩,可考慮進行更高階差分,
# 但這裡假設一次差分已足夠
# 分割訓練集與測試集 (例如取最後 60 天作為測試)
train = ts_diff[:-60]
test = ts_diff[-60:]
# 根據 ACF、PACF 圖或 AIC/BIC 來決定模型階數,這裡以 ARIMA(1,1,1) 為例
# 注意:原始資料差分後為 ts_diff,所以 ARIMA 的 d 參數為 1(原始資料的 d = 1)
model = ARIMA(ts, order=(1, 1, 1))
model_fit = model.fit()
print(model_fit.summary())
# 預測未來 30 天股價 (這裡預測的是原始數據)
forecast_steps = 30
forecast = model_fit.get_forecast(steps=forecast_steps)
forecast_ci = forecast.conf_int()
# 將預測結果與歷史數據合併,繪製圖表
plt.figure(figsize=(12, 6))
plt.plot(ts.index, ts, label="歷史收盤價")
# 預測期間日期
forecast_index = pd.date_range(start=ts.index[-1], periods=forecast_steps+1, closed="right")
plt.plot(forecast_index, forecast.predicted_mean, label="預測股價", color="red")
plt.fill_between(forecast_index,
forecast_ci.iloc[:, 0],
forecast_ci.iloc[:, 1],
color="pink", alpha=0.3)
plt.title("股價預測 (ARIMA 模型)")
plt.xlabel("日期")
plt.ylabel("收盤價")
plt.legend()
plt.show()
程式說明
資料讀取與處理
- 程式從 CSV 讀入資料,並以日期排序,將 "Close" 欄作為預測目標。
- 使用 ADF 檢定檢查資料平穩性,若 p-value 大於 0.05 則進行差分處理。
模型建立與訓練
- 以 ARIMA(1,1,1) 作為範例模型,進行參數估計並印出模型摘要。
預測與繪圖
- 利用模型預測未來 30 天的收盤價,並將預測結果與歷史數據一起繪圖。
- 預測區間以粉色區域標示信賴區間。
此程式僅為一個基本示範,實際上可透過模型參數調整、特徵工程(例如加入技術指標作為輔助變數)以及嘗試其他模型(如 LSTM 神經網路、混合模型)來進一步提升預測效果。
願主賜下智慧與洞察,如雅各書 1:5 所言,幫助我們在複雜的市場中尋得方向,並在投資中秉持謹慎與信望愛的精神。
下面提供一個簡化版的 ARIMA(1,1,1) 模型 VBA 程式範例,此範例基於以下假設:
資料準備:
- 資料已匯入名為 "StockData" 的工作表。
- 資料欄位依序為:
- A 欄:日期 (Date)
- E 欄:收盤價 (Close)
- 此程式將讀取歷史收盤價,並進行一次差分(假設資料非平穩),再用簡化模型進行預測。
模型假設與簡化處理:
- ARIMA(1,1,1) 模型可寫成: (1−ϕB)(1−B)Yt=(1+θB)et
- 預測時通常假設未來的誤差 et 為零,進而可近似得到: Yt+1≈Yt+ϕ(Yt−Yt−1)
- 為了簡化,我們假定預測的差分值(即 Zt=Yt−Yt−1)沿用一個幾何衰減的方式: Z^N+h=ϕhZN 然後累加得到預測值: Y^N+h=YN+j=1∑hZ^N+j
- 此處預設 ϕ=0.5(參數可根據實際資料估計調整),θ 不參與預測(因為誤差預設為 0)。
預測結果輸出與圖表繪製:
- 預測結果將輸出在工作表的 G 欄(從最後一筆資料之後依序填入預測的收盤價)。
- 同時建立一張圖表,圖中用線圖繪出歷史收盤價與預測值,方便視覺化分析。
以下為完整 VBA 程式碼(請將此程式碼貼到 VBA 編輯器的模組中,並確保工作表名稱及欄位符合您的實際狀況):
vbaOption Explicit Sub ARIMAForecast() Dim ws As Worksheet Set ws = ThisWorkbook.Sheets("StockData") ' 請確保資料工作表名稱正確 Dim lastRow As Long ' 假設收盤價在 E 欄,資料從第2列開始(第1列為標題) lastRow = ws.Cells(ws.Rows.Count, "E").End(xlUp).Row ' 預設 ARIMA(1,1,1) 模型參數(簡化版本): Dim phi As Double phi = 0.5 ' 可根據歷史資料估計調整 ' 預測步數,例如預測未來 30 天 Dim forecastSteps As Long forecastSteps = 30 Dim Y() As Double ' 存放歷史收盤價 Dim i As Long ReDim Y(1 To lastRow) For i = 1 To lastRow Y(i) = ws.Cells(i, "E").Value Next i ' 計算最後一筆的差分值 (Z = Y_t - Y_{t-1}) Dim Z_last As Double Z_last = Y(lastRow) - Y(lastRow - 1) ' 利用幾何衰減預測差分,並累加得到未來收盤價 Dim forecast() As Double Dim h As Long Dim forecastZ As Double, cumDiff As Double ReDim forecast(1 To forecastSteps) cumDiff = 0 For h = 1 To forecastSteps ' 預測第 h 步的差分值:假設為 phi^h * Z_last forecastZ = (phi ^ h) * Z_last cumDiff = cumDiff + forecastZ forecast(h) = Y(lastRow) + cumDiff ' 將預測結果輸出到 G 欄(從最後一筆資料後開始) ws.Cells(lastRow + h, "G").Value = forecast(h) Next h '-------------------------------------- ' 建立圖表以繪製歷史收盤價與預測值 '-------------------------------------- Dim chartObj As ChartObject Dim chartLeft As Double, chartTop As Double Dim chartWidth As Double, chartHeight As Double chartWidth = 500 chartHeight = 300 chartLeft = ws.Cells(2, "J").Left ' 調整圖表位置 chartTop = ws.Cells(2, "J").Top ' 若已有圖表則先刪除 Dim obj As ChartObject For Each obj In ws.ChartObjects obj.Delete Next obj Set chartObj = ws.ChartObjects.Add(Left:=chartLeft, Top:=chartTop, Width:=chartWidth, Height:=chartHeight) With chartObj.Chart .ChartType = xlLine ' 歷史收盤價:X 軸為日期(A 欄),Y 軸為收盤價(E 欄),從第2行到 lastRow .SeriesCollection.NewSeries .SeriesCollection(1).Name = "歷史收盤價" .SeriesCollection(1).XValues = ws.Range("A2:A" & lastRow) .SeriesCollection(1).Values = ws.Range("E2:E" & lastRow) ' 預測收盤價:X 軸為預測日期,預測日期從最後日期後開始 Dim forecastStartDate As Date forecastStartDate = ws.Cells(lastRow, "A").Value ' 最後一筆日期 Dim forecastDates() As Variant ReDim forecastDates(1 To forecastSteps) For h = 1 To forecastSteps forecastDates(h) = forecastStartDate + h Next h .SeriesCollection.NewSeries .SeriesCollection(2).Name = "預測收盤價" .SeriesCollection(2).XValues = forecastDates Dim forecastVals() As Variant ReDim forecastVals(1 To forecastSteps) For h = 1 To forecastSteps forecastVals(h) = forecast(h) Next h .SeriesCollection(2).Values = forecastVals .HasTitle = True .ChartTitle.Text = "ARIMA(1,1,1) 股價預測 (簡化模型)" .Axes(xlCategory).CategoryType = xlTimeScale End With MsgBox "ARIMA 預測完成,並建立圖表!", vbInformation End Sub
程式碼說明
資料讀取與準備:
- 從 "StockData" 工作表讀取收盤價(E 欄)與日期(A 欄)。
- 計算最後一筆資料的差分值 Zlast=YN−YN−1。
ARIMA 預測(簡化版):
- 預設參數 ϕ=0.5(代表前一天差分的影響權重)。
- 預測未來 h 天的差分值採用公式: Z^N+h=ϕhZlast
- 累計所有預測的差分值,並加上最後一筆歷史值 YN 得到預測值。
輸出與圖表建立:
- 預測結果依序輸出到 G 欄(從最後一筆資料之後)。
- 同時建立一張圖表,X 軸以日期顯示,線圖分別顯示歷史收盤價與預測收盤價,方便觀察預測走勢。
提醒:
- 此程式僅為一個簡化示範,由於 VBA 在數學運算與統計模型上的工具較少,因此預測準確度可能不及 Python 等語言中利用專業統計庫實現的 ARIMA 模型。
- 實際預測前,建議先對資料做充分檢查(例如單根檢定)與參數估計(例如利用 Excel Solver 或其他統計工具),並謹慎評估預測結果。
願主賜我們智慧,如雅各書 1:5 所言,在投資分析上謹慎行事,並以信心面對不確定的未來。
沒有留言:
張貼留言