Photo by Isaac Smith on Unsplash
Table of Contents
首先,時間序列是按照時間軸排序,呈現歷史數據發展過程的資料結構;而時間序列模型,則是依照上述資料結構分析其規律性以及趨勢,並且透過找到概似的軌跡建立模型,用以預測未來的動向。
本系列所運用的模型:
整合移動平均自迴歸模型(Autoregressive Integrated Moving Average model, ARIMA model)
ARIMA是一個基礎的時間序列模型,參數項目包括自我迴歸(AR)、差分次數(Differencing)以及移動平均數(MA)。
廣義自迴歸條件異方差模型(General Autoregressive Conditional Heteroskedasticity model, GARCH model)
GARCH為分析時間序誤差項目的模型,在金融領域的應用則是衡量資產或股價的波動度,本文會藉由此模型檢定ARIMA模型的殘差項目,進行誤差項目的修正。GARCH的參數項目與ARIMA的AR及MA不完全相同,GARCH是針對誤差項以及變異數的模型,而在取用幾個過往值這方面,本文會利用ACF/PACF圖搭配GARCH模型本身特點決定(內文會再詳細說明)。
本文流程:
本文使用 MacOS 並以 Jupyter Notebook作為編輯器
# 基本功能
import numpy as np
import pandas as pd# 繪圖
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
sns.set()# TEJ API
import tejapi
tejapi.ApiConfig.api_key = 'Your Key'
tejapi.ApiConfig.ignoretz = True
證券交易資料表:上市(櫃)未調整股價(日),資料代碼為(TWN/EWPRCD)。
報酬率資訊表:上市(櫃)股價報酬(日)-資料代碼為(TWN/EWPRCD2)。
本文以元大台灣50指數作為標的。
data_price = tejapi.get('TWN/EWPRCD', # 公司交易資料-收盤價
coid= '0050', # 台灣50
mdate={'gte': '2003-01-01', 'lte':'2021-12-24'},
opts={'columns': ['coid', 'mdate', 'close_d', ]},
chinese_column_name=True,
paginate=True)
data_price = data_price.set_index('日期')# 導入中文
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']# 繪製0050價格走勢圖
fig, ax = plt.subplots(figsize = (10, 5))
plt.plot(data_price['收盤價'], label = '0050-price')
plt.title('0050收盤價')
plt.legend()
根據上圖可以發現,0050的價格隨著時間推移,有明顯的波動,而這樣的情形有可能源於該數據為非定態,所以這邊會操作Augmented Dickey-Fuller(ADF)檢定數列是否存在單位根,若數列存在單位根通常代表其為非平穩數列,可以透過取差分的方式轉換成平穩數列。本文將透過P-value驗證其定態與否。
# 從statsmodels數據包導入ADF套件
from statsmodels.tsa.stattools import adfuller# 從產出的ADF報表擷取P-value項目
price_p_value = adfuller(data_price['收盤價'])[1]# 設定判別式以及0.05的P-value標準
if price_p_value > 0.05:
print('Nonstationary')
else:
print('Stationary')
H0:非定態資料
H1:定態資料
透過ADF檢定可以知道股價數據確實是非定態的資料,所以並不能夠以此為模型的數據來源。
此處需說明定態的重要性是因為當資料為非定態時,則其波動走勢為隨機漫步,因此,即便後續模型能夠有很好的配適,那也只是剛好的結果,並不能說明模型的強度,畢竟隨機波動沒辦法用模型來解釋。
在說明無法運用價格資料作為模型的依據後,本文導入報酬率資料。(繪圖與ADF檢定過程詳見完整程式碼)
data_ret = tejapi.get('TWN/EWPRCD2', # 公司交易資料-報酬率
coid= '0050', # 台灣50
mdate={'gte': '2003-01-01', 'lte':'2021-12-24'},
opts={'col umns': ['coid', 'mdate', 'roia', ]},
chinese_column_name=True,
paginate=True)
data_ret = data_ret.set_index('日期')
透過ADF檢定可以知道報酬率數據是定態的資料,所以能夠以此為模型的數據來源。
train_date = data.index.get_level_values('日期') <= '2020-12-31'
train_data = data[train_date]
test_data = data[~train_date]
以train_data的期間建立模型,並以test_data的期間作為模型的測試,並與實際資料做比對,而本文為數據前處理以及模型基本建置的說明,所以並不會運用到test_data的資料。
本文用pmdarima套件找出最佳的參數組合。
import pmdarima as pmdpmd_mdl = pmd.auto_arima(train_data['日報酬率(%)'], stationary = True)
pmd_mdl.summary()
通過報表,得知pmdarima所提供的最佳參數組合為(2, 0, 2);此外,也可以從參數估計報表中得知每項P-value皆小於0.01的最嚴格標準,所以各參數的顯著水準也沒有問題。(讀者若注意到左上報表中的模型名稱是SARIMAX而非ARIMA,可以不用擔心,這是套件預設的名稱,若仍不放心可以導入另一個套件檢查各項數值。)
from statsmodels.tsa.arima.model import ARIMAmodel = ARIMA(train_data['日報酬率(%)'], order = (2, 0, 2))
stats_mdl = model.fit()
print(stats_mdl.summary())
觀察新的套件產出的ARIMA模型報表,可以看到在模型配適標準值(AIC或BIC)上與先前的報表相差不遠;並且在參數估計值報表的部分,儘管估計值以及標準差有些許不同,但也不影響P-value在顯著性上的結果,所以不必太糾結於此。
stats_mdl.plot_diagnostics(figsize = (15, 10))
plt.show()
從上圖殘差診斷可以目測殘差(左上)無明顯的趨勢,但是觀察殘差直方圖(右上)卻發現具有窄峰厚尾的現象,代表不符合迴歸常態假設;並且從常態機率圖(左下)來看,模型殘差的常態性不足,所以ARIMA模型的殘差項應該還有潛在的解釋變量,以下將進行白噪音檢定進一步確認。
藉由Ljung-Box檢定觀察ARIMA模型的殘差項是否為隨機變動,若檢定結果呈現白噪音(隨機),則可以知道ARIMA模型的配適程度良好,便直接做預測;然而,若檢定結果呈現誤差項目並非白噪音,則需要用GARCH模型找出誤差項中的變異數解釋變量。
from statsmodels.stats.diagnostic import acorr_ljungboxwhite_noise = acorr_ljungbox(pmd_residual, lags = [10], return_df=True)
H0:誤差項為白噪音
H1:誤差項非白噪音
檢定結果讓我們能夠以P-value判斷,此誤差項並不是白噪音(P-value < 0.05),所以本文後續會執行GARCH模型適配ARIMA的殘差項目。
首先,儘管本文已經透過白噪音檢定了解ARIMA模型在誤差的問題,然而若要證明該項目有變異數異質性,還須進行ARCH Effect Test確認。
from statsmodels.stats.diagnostic import het_archLM_pvalue = het_arch(arima_resid, ddof = 4)[1]
print('LM-test-Pvalue:', '{:.5f}'.format(LM_pvalue))
H0:不具有ARCH Effect
H1:具有ARCH Effect
透過檢定結果的P-value可以拒絕虛無假設,也就說明ARIMA的誤差項可以進行GARCH模型修正。
透過觀察殘差ACF/PACF圖,了解殘差平方項目的滯後情形,並將觀察到的結果帶入GARCH模型中,決定GARCH模型的參數組合,檢定波動度。
fig, ax = plt.subplots(1, 2, figsize = (18,5))pmd_residual = pmd_mdl.arima_res_.resid
sgt.plot_acf(pmd_residual**2, zero = False, lags = 40, ax=ax[0])
sgt.plot_pacf(pmd_residual**2, zero = False, lags = 40, ax=ax[1])plt.show()
從圖中了解殘差平方的自迴歸程度很大,而綜合考量PACF圖(右上)中第一、二期的滯後較明顯以及GARCH模型數學式結構,本文假設參數組合(p,q)為(1,1)、(2,1)、(1,2)、(2,2),並互相比較配適程度以及各參數項係數的顯著水準,然後才決定使用哪個組合。本文因應篇幅考量,所以只展示最適組合(1,1)。
Note: GARCH模型數學式結構會直接包含過往各期值,而距離時間越遠係數權重越低。
from arch import arch_modelmdl_garch = arch_model(pmd_residual, vol = 'GARCH', p = 1, q = 1)
res_fit = mdl_garch.fit()
res_fit.summary()
藉由觀察上表,了解各項參數估計值皆具備顯著水準,以下將進行模型診斷,驗證GARCH模型的殘差項為隨機變量。
從上圖殘差診斷目測殘差無明顯的趨勢,而從殘差直方圖(右下)也可以發現其概似常態分配;此外,觀察常態機率圖(左下),模型殘差的常態性也足夠,所以GARCH模型的殘差項應該沒有潛在的解釋變量,以下將進行白噪音檢定進一步確認。
檢定結果讓我們能夠以P-value判斷,此誤差項是白噪音(P-value > 0.05),代表殘差項目中沒有其他解釋變量可以提取,已經是隨機過程。
至此,本文已經將模型建置的整體流程展示一遍,從最初的數據定態分析,接著導入ARIMA模型找出需要套用的歷史資料組合(AR與MA項目),最後將ARIMA項目的殘差套入GARCH模型進行誤差修正。此外,讀者應該也發現統計學在處理數據上是非常嚴謹的,而本文為了提高易讀性,亦省略檢定背後的數學過程,讓讀者快速了解整個流程。
以上就是本文想要讓讀者了解的時間序列模型建置,續篇文章將說明如何運用本文得到的模型,進行走勢預測。最後要提醒讀者,本文在處理數據上較方便是因為TEJ數據庫的資料齊全,所以歡迎對金融數據分析有興趣的讀者,至TEJ E-Shop選購符合自身需求的資料包組合。
電子報訂閱