01 引言
金融數據主要分為時間序列(時間維度)、橫截面(個體維度)和面板數據(時間+截面)。比如上證綜指2019年1月至今的日收盤價數據就是時間序列,而2019年8月12日所有A股收盤價數據則是橫截面數據,2018-2019年3000多只個股收盤價數據便是面板數據。金融時間序列分析是量化投資建模的重要基礎,今天給大家分享時間序列的一些基礎概念,包括自相關性、偏自相關性、白噪聲和平穩性,以及Python的簡單實現,為后續關於時間序列建模專題做一個鋪墊。Python中的statsmodels包提供了強大的統計和計量建模函數,其中子模塊tsa(time series analysis)專門用於時間序列分析。
02 自相關性
相關性一般是指兩個變量之間的統計關聯性,那么自相關性則是指一個時間序列的兩個不同時間點的變量是否相關聯。時間序列具有自相關性是我們能夠進行分析的前提,若時間序列的自相關性為0,也就是說各個時點的變量不相互關聯,那么未來與現在和過去就沒有聯系,根據過去信息來推測未來就變得毫無根據。時間序列的自相關性一般用時間序列的自協方差函數、自相關系數函數和偏自相關系數函數等統計量來衡量。
自協方差函數
自協方差(Autocovariance,簡稱AF)是時間序列與其滯后項的協方差,假設X為隨機變量(即隨着時間變化取值隨機的變量,比如股票價格),則k階自協方差使用數學公式表示為:
其中,E表示求數學期望,u是隨機變量X的均值,當k=0時,可得
即為隨機變量X的方差。
自相關函數
自協方差跟變量的單位有很大關系,比如X放大10倍,則自協方差將放大100倍,因此其值大小並不能反映相關性的大小。為了消除量綱(單位)的影響,使用自相關系數來刻畫變量與其滯后項的相關性。自相關系數(Autocorrelation Coefficient,簡稱ACF)本質是相關系數,等於自協方差除以方差,k階自相關系數數可以表示為:
上過高中數學的都知道協方差和相關系數的含義,從統計上描述兩個不同變量的相互影響關系(非因果),那么自協方差和自相關系數則是刻畫同一個變量在不同時期取值的相關程度,比如描述上證綜指過去價格對今天價格的影響。
偏自相關函數
假設對於上證綜指價格序列,一階自相關系數大於0,說明今天的價格與昨天的價格相關,而昨天價格又與前一日價格相關,依次類推,可見當你計算今天與昨天價格之間的自相關系數時,同時包含了更早之前所有各期的信息對今天的間接影響,度量的是過去所有信息加總的影響效果。為了剔除其他各期的影響,單純考察過去某一單期對今天的影響,引入偏自相關函數(Partial Autocorrelation Coefficient,簡稱PACF),即條件自相關系數,使用數學公式表示為:
偏自相關函數可以通過自回歸模型(后續關於時間序列建模會進一步分析)來表述和求解,用表示k階自回歸式中第j個回歸系數,則k階自回歸模型表示為
其中是最后一個系數。若把
看作滯后期k的函數,則稱
,k = 1,2… 為偏自相關函數。
自相關系數和偏自相關系數越大,說明過去對現在的影響越
Python計算自相關和偏自相關系數
Python的pandas庫提供了計算基本統計量的函數,包括均值df.mean(),協方差df.cov(),相關系數df.corr(),方差df.var()(或標准差df.std())等,其中df為數據列表;而自相關系數和偏自相關系數的計算則要用到statsmodels庫(acf()和pacf())。statsmodels這是一個很強大的統計數理模型庫,在后面的時間序列分析與建模會進一步介紹相關函數及其運用。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
%matplotlib inline
#正常顯示畫圖時出現的中文和負號
from pylab import mpl
mpl.rcParams['font.sans-serif']=['SimHei']
mpl.rcParams['axes.unicode_minus']=False
#獲取數據,從tushare上獲取滬深300指數為例
import tushare as ts
token='輸入你的token'
pro=ts.pro_api(token)
def get_data(code,n=250*3):
df=pro.index_daily(ts_code=code)
#將日期設置為索引
df.index=pd.to_datetime(df.trade_date)
#最近n日價格走勢
df=df.sort_index()[-n:]
#只保留收盤價數據
del df.index.name
return df.close
df=get_data('000300.SH')
計算自相關和偏自相關系數
import statsmodels.tsa.api as smt
#tsa是Time Series analysis縮寫
#tsa的stattools(統計工具)提供了計算acf和pacf以及后面要用到的adfuller單位根檢驗函數
#使用help(smt.stattools.acf)可以查看相關參數設置
#計算自相關系數,這里設置滯后項為5期,默認是40期滯后
acf=smt.stattools.acf(df,nlags=5)
#計算偏自相關系數
pacf=smt.stattools.pacf(df,nlags=5)
print(f'自相關系數為:{acf};\n偏自相關系數為:{pacf}')
自相關系數為:[1. 0.99098764 0.98189466 0.97312885 0.96252012 0.95335064];
偏自相關系數為:[ 1. 0.99231072 -0.01047826 0.01620047 -0.12635305 0.09200772]
自相關系數和偏自相關系數可視化
def acf_pacf_plot(data, lags=None):
#判斷是否為pandas的Series格式數據
if not isinstance(data, pd.Series):
data = pd.Series(data)
#設定畫面風格,這里設置為'bmh', colspan=2
with plt.style.context('bmh'):
fig = plt.figure(figsize=(10, 8))
#設置子圖
layout = (3,1)
ts_ax = plt.subplot2grid(layout, (0, 0))
acf_ax = plt.subplot2grid(layout, (1, 0))
pacf_ax = plt.subplot2grid(layout, (2, 0))
data.plot(ax=ts_ax)
ts_ax.set_title('時間序列圖')
smt.graphics.plot_acf(data, lags=lags, ax=acf_ax, alpha=0.5)
acf_ax.set_title('自相關系數')
smt.graphics.plot_pacf(data, lags=lags, ax=pacf_ax, alpha=0.5)
pacf_ax.set_title('偏自相關系數')
plt.tight_layout()
return
#設置20階滯后期
acf_pacf_plot(df,lags=20)
03 平穩性
時間序列分析的主要目的是利用事物特征變量的歷史和現狀來推測未來可能出現的狀況,即假設時間序列的基本特性必須能從過去維持到我們推測的時期,否則,基於歷史和現狀來預測未來將變得不可靠。時間序列的平穩性,簡單理解是時間序列的基本特性維持不變,換句話說,所謂平穩性就是要求由樣本時間序列所得到的曲線在未來的一段時期內仍能沿着現有的形態持續下去。金融領域很多變量之所以難以估計,是因為這些變量經常發生突變,不是平穩的時間序列。時間序列的平穩性是經典時間序列分析的基本假設前提,只有基於平穩的時間序列進行的預測才是有效的。平穩性有強平穩和若平穩之分,一般所說的平穩時間序列指的是若平穩時間序列。
強平穩(Strictly Stationary)
強平穩要求時間序列隨着時間的推移,其統計性質保持不變,對於任意的τ,其聯合概率密度函數滿足:
,則時間序列是強平穩的。
強平穩是一個很強的條件,要求該時間序列的任何統計性質都不會隨着時間發生變化。強平穩由於條件苛刻,理論和實證上都難以檢驗,因此現實中幾乎無法運用。
弱平穩(Weakly Stationary)
弱平穩放寬了平穩性條件,只要求低階矩平穩,即數學期望(均值)和方差不隨時間和位置變化。弱平穩過程的條件是:
(1)均值函數在所有時間上恆為常數;
(2)存在二階矩;
(3)對於所有時間t和和時滯k,自協方差相同。
值得注意的是,強平穩和弱平穩時間序列二者並沒有包含關系。換句話說,強平穩時間序列不一定是弱平穩的,因為強平穩過程不一定存在二階距;弱平穩時間序列也不一定是強平穩過程,因為弱平穩只能保證一階矩和二階距不隨時間變化,但不能保證其有窮維分布不隨時間變化。弱平穩的正態分布時間序列必定是強平穩的。因為正態分布的概率密度是由均值函數和自相關函數完全確定的,即如果均值函數和自相關函數不隨時間變化,則概率密度函數也不隨時間變化。
時間序列平穩性的判斷方法
通過時序圖的圖形觀察和單位根檢驗可以判斷時間序列是否平穩,具體如下:
(1)觀察時間序列圖的形狀來初步判斷其平穩性
根據弱平穩的定義,時間序列的均值和方差為常數,因此其時序圖應該圍繞某一水平線上下以大致相同的幅度波動。如果該時序圖存在明顯遞增、遞減或周期性波動,則該時間序列很可能是不平穩的。
(2)觀察序列的自相關和偏自相關函數圖對於平穩時間序列而言,其自相關或偏自相關系數一般會快速減小至0附近或者在某一階后變為0,而非平穩的時間序列的自相關系數一般是緩慢下降而不是快速減小。
(3)單位根檢驗。通過觀察時序圖、自相關和偏自相關圖來判斷時間序列平穩性,可能出現因觀察者對圖形的判斷不同而得出不同的結論,為了更加客觀的考察時間序列的平穩性,引入統計檢驗方法,即單位根檢驗。常見的單位根檢驗方法有DF檢驗(Dickey-Fuller Test)、ADF檢驗(AuGMENTED Dickey-Fuller Test)和PP檢驗(Phillips-Perron Test)。關於單位根檢驗和DF、ADF、PP檢驗的公式原理此處不詳細展開,可參考本科計量經濟學教材的時間序列分析部分。
04 白噪聲和隨機游走
白噪聲過程也叫純隨機序列,是指隨機過程在任意時點t的變的均值和協方差均為0,而方差為一常數,即滿足下面的數學條件:
白噪聲序列的均值和方差為常數,間隔大於0的自協方差都恆等於0,因此是平穩的時間序列。如果白噪聲過程中各變量獨立並且都服從正態分布,則該序列為高斯白噪聲過程(Gussian White Noise)。高斯白噪聲序列是強平穩的時間序列,並且各期之間不僅不相關還相互獨立。
如果一個時間序列滿足高斯白噪音過程,則無法根據過去信息來預測未來。比如非平穩時間序列:
這里的隨機擾動是服從正態分布的純隨機序列,即為純隨機變量的加總,所以被成為隨機游走過程(Random Walk)。根據有效市場假說原理,股票價格是隨機游走的,因此是無法被預測的。
白噪聲檢驗(Ljung-Box檢驗)
如果一個時間序列是純隨機游走的,意味着它的每一次新的變化都無跡可尋,無法從中捕捉對預測有用的信息。換句話說,純隨機時間序列是沒有分析和預測的價值的。那么如何檢驗和判斷一個時間序列是否為純隨機序列呢?一般可用Ljung-Box檢驗方法(簡稱LB檢驗)進行統計檢驗,檢驗的統計量為Q統計量:
其中,是序列的k階自相關系數,n是整個序列中的觀測值個數,m是滯后階數。當序列存在自相關時,其自相關系數較大,對應的
也較大,相反,當序列為隨機序列、無自相關時,序列的自相關系數不會顯著地異於0,則
會很小。檢驗一個時間序列在m階內是否為白噪聲,只有當
m個Q統計量均小於對應的
分布的臨界值時,才能說明該序列在所檢驗的m階內是純隨機的。在實際應用中,LB檢驗的原假設為所檢驗序列是純隨機序列,當LB檢驗統計量對應的p值大於所設定的顯著性水平(如5%,1%,0.5%等)時,接受原假設,認為所檢驗序列為白噪聲序列,反之拒絕原假設,認為序列是非白噪聲序列。
05 Python模擬白噪音和平穩性檢驗
#引入statsmodels和scipy.stats用於畫QQ和PP圖
import scipy.stats as scs
import statsmodels.api as sm
def ts_plot(data, lags=None,title=''):
if not isinstance(data, pd.Series):
data = pd.Series(data)
with plt.style.context('bmh'):
fig = plt.figure(figsize=(10, 8))
layout = (3, 2)
ts_ax = plt.subplot2grid(layout, (0, 0))
acf_ax = plt.subplot2grid(layout, (1, 0))
pacf_ax = plt.subplot2grid(layout, (1, 1))
qq_ax = plt.subplot2grid(layout, (2, 0))
pp_ax = plt.subplot2grid(layout, (2, 1))
data.plot(ax=ts_ax)
ts_ax.set_title(title+'時序圖')
smt.graphics.plot_acf(data, lags=lags, ax=acf_ax, alpha=0.5)
acf_ax.set_title('自相關系數')
smt.graphics.plot_pacf(data, lags=lags, ax=pacf_ax, alpha=0.5)
pacf_ax.set_title('偏自相關系數')
sm.qqplot(data, line='s', ax=qq_ax)
qq_ax.set_title('QQ 圖')
scs.probplot(data, sparams=(data.mean(), data.std()), plot=pp_ax)
pp_ax.set_title('PP 圖')
plt.tight_layout()
return
#Q-Q圖的結果與P-P圖非常相似,只是P-P圖是用分布的累計比,而Q-Q圖用的是分布的分位數來做檢驗
#和P-P圖一樣,如果數據為正態分布,則在Q-Q正態分布圖中,數據點應基本在圖中對角線上
模擬白噪聲過程
#使用numpy簡單模擬白噪聲過程
np.random.seed(1)
# plot of discrete white noise
randser = np.random.normal(size=500)
ts_plot(randser, lags=30,title='白噪聲')
可以看到過程是隨機且在0附近波動。ACF和PACF顯示沒有明顯的序列相關。要記住,由於是正態分布采樣的結果,我們應該在自相關圖中看到大約5%的顯著性。最下面,QQ圖和概率圖是比較數據的概率分布和其他理論的分布。在這里,理論分布是標准正態分布,因此我們的數據是正態分布,符合高斯白噪聲。隨機游走:隨機游走是時間序列 ?? 的模型:??=??−1+??,?? 是離散的白噪聲序列。隨機游走是不平穩的,因為協方差是和時間相關的。如果我們建模的時間序列是隨機游走的,那么它是不可預測的。
模擬隨機游走過程
#從標准正態分布采樣模擬一個隨機游走
np.random.seed(2)
n_samples = 1000
x = w = np.random.normal(size=n_samples)
for t in range(1,n_samples):
x[t] = x[t-1] + w[t]
ts_plot(x, lags=30,title='隨機游走')
明顯看出序列是不平穩的。隨機游走模型是 ??=??−1+??,移項可以得到??−??−1=?? 。因此,隨機游走的一階差分應該等於白噪聲,可以對時間序列使用 np.diff() 函數看它是否成立。
# First difference of simulated Random Walk series
ts_plot(np.diff(x), lags=30)
應用實例:對滬深300近三年來數據進行平穩性檢驗分析
#滬深300近三年價格數據
data=pd.DataFrame(df,columns=['close'])
#對數收益率
data['logret']=np.log(data.close/data.close.shift(1))
#普通收益率
data['ret']=data.close/data.close.shift(1)-1
data=data.dropna()
圖形觀察判斷平穩性
#滬深300股價的平穩性
#觀察時序圖
ts_plot(data.close,lags=30,title='滬深300股價')
上圖顯示,滬深300近三年股價走勢存在明顯遞增、遞減或周期性波動,該時間序列很可能是不平穩的;自相關系數呈現緩慢減小過程, 而偏自相關系數一階等於1,然后迅速減小,由此可以初步判斷其價格不符合平穩性時間序列特征。此外,從QQ圖和PP圖(二者類似)上不難看出,滬深300價格時間序列不符合正態分布
#滬深300收益率,對數收益率與算術收益率差異不是很大
ts_plot(data.logret,lags=30,title='滬深300收益率')
滬深300對數收益率時序圖圍繞某一水平線上下以大致相同的幅度波動,比較像白噪聲過程,而自相關與偏自相關系數快速減小至0附近或在某一階后變為0,從圖形上觀察應該是平穩過程。從QQ圖和概率圖上看,該過程很像標准正態分布但是存在厚尾,並且在ACF和PACF圖上有一些重要的序列相關性,這意味着應該有更好的模型去描述真實的價格變化過程,為后面時間序列建模設下鋪墊。
單位根檢驗
圖形觀察方式很直觀,但也很主觀,不同的人對相同的圖形,可能得出不同的結論。因此需要一個更加客觀的統計方法來檢驗時間序列的平穩性,即單位根檢驗,常見的單位根檢驗方法有DF檢驗、ADF檢驗和PP檢驗,下面主要介紹如何使用Python進行ADF單位根檢驗。
#statsmodel和arch包都提供了adf檢驗的函數
#statsmodel也提供了多種方式使用adfulle單位根檢驗函數
#這些方法得到的結果是一致的
#使用stats子模塊中diagnostic(模型診斷)單位根檢驗unitroot_adf
from statsmodels.stats.diagnostic import unitroot_adf
unitroot_adf(data.close)
(-2.050712363785268,
0.26478930749812246,
9,
739,
{'1%': -3.439229783394421,
'5%': -2.86545894814762,
'10%': -2.5688568756191392},
7444.231922186031)
輸出結果依次為檢驗的統計量值、p-value、滯后階數、自由度等信息,其中檢驗統計量為-2.05,遠大於10%的臨界值-2.56,實際上p值為0.2648,遠大於0.1,因此我們無法拒絕原假設(原假設是存在單位根),認為該時間序列是非平穩的。
#模塊一樣,只是引用方式使用了api
import statsmodels.api as sm
sm.stats.diagnostic.unitroot_adf(data.close)
(-2.050712363785268,
0.26478930749812246,
9,
739,
{'1%': -3.439229783394421,
'5%': -2.86545894814762,
'10%': -2.5688568756191392},
7444.231922186031)
#從時間序列分析tsa子模塊api中導入adfuller
import statsmodels.tsa.api as smt
smt.adfuller(data.close)
(-2.050712363785268,
0.26478930749812246,
9,
739,
{'1%': -3.439229783394421,
'5%': -2.86545894814762,
'10%': -2.5688568756191392},
7444.231922186031)
#直接從時間序列分析tsa子模塊的stattools統計工具中導入adfuller
from statsmodels.tsa.stattools import adfuller
adfuller(data.close)
(-2.050712363785268,
0.26478930749812246,
9,
739,
{'1%': -3.439229783394421,
'5%': -2.86545894814762,
'10%': -2.5688568756191392},
7444.231922186031)
#使用arch包中的單位根檢驗unitroot導入ADF
#arch包在后續建模中將會運用到
from arch.unitroot import ADF
ADF(data.close)
Trend: Constant
Critical Values: -3.44 (1%), -2.87 (5%), -2.57 (10%)
Null Hypothesis: The process contains a unit root.
Alternative Hypothesis: The process is weakly stationary.
結果與上述導入方法是一致的,不過arch包的輸出結果比較直觀。
#下面沿用arch包的單位根檢驗函數對滬深300收益率進行單位根檢驗
ADF(data.logret)
Trend: Constant
Critical Values: -3.44 (1%), -2.87 (5%), -2.57 (10%)
Null Hypothesis: The process contains a unit root.
Alternative Hypothesis: The process is weakly stationary.
結果顯示,滬深300對數收益率ADF單位根檢驗得到的p值約等於0,因此拒絕原假設(原假設是存在單位根),即認為該時間序列是平穩的。一般而言,股票價格時間序列是不平穩的,而收益率數據是平穩的,因此一般使用股票收益進行時間序列建模而不是直接使用股價,這將在后續推文中進一步分析。
參考文獻:
1. statsmodels官方文檔
2. Time Series Analysis (TSA) in Python - Linear Models to GARCH
3. 蔡立耑.《量化投資以Python為工具》.電子工業出版社.2017.
(公眾號后台回復:812 可下載高清pdf資料)
————————————————
版權聲明:本文為CSDN博主「Python金融量化」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/ndhtou222/article/details/100148319