炒股必看的時序預測基本方法 —— 移動平均(SMA、EMA、WMA)

時間序列預測
移動平均就是用當前時刻前期的觀測值預測下一期的取值。
給定一個時間序列,觀測值序列為。
可預測為前項的平均值,即:
其中,為滑動窗口大小表示需要往前推多少期。

根據(jù)計算平均數(shù)的方法劃分,移動平均可分為簡單移動平均、指數(shù)移動平均、加權移動平均等。
移動平均是根據(jù)前若干個觀測值,預測下期的取值。那下下期、下下下期該如何預測呢?可以考慮使用二次移動平均,也叫二項移動,即在一次移動平均的基礎上再移動平均。
注意:移動平均用于預測場景時,尤其是多步預測,有個前提假設條件,序列相對平穩(wěn),沒有趨勢、季節(jié)性的情況。
描述趨勢特征
移動平均能夠去除時間序列的短期波動,使得數(shù)據(jù)變得平滑,從而可以方便看出序列的趨勢特征。尤其在金融領域,移動平均線作為一種計算簡單、易于解釋的趨勢性指標,可以從中看出市場的趨勢和傾向。
下圖顯示了五糧液股票價格數(shù)據(jù)以及30日簡單移動平均值。移動平均線平滑了股價的波動,從而顯示了長期的波動趨勢。
從上圖可以看出,原序列波動較大,經(jīng)移動平均后,隨機波動明顯減少;窗口大小越大,平滑后波動越小,滯后越明顯。
移動平均有兩種方法:中心移動平均,尾部移動平均。中心移動平均,計算t時刻的移動平均值時同時使用t時刻之前的觀測值及t時刻之后的觀測值,牽扯到時間穿越問題,無法做預測,通常用來可視化;尾部移動平均,計算t時刻的移動平均值時僅使用t時刻之前的觀測值,通常用來預測,也是本文學習的目標。
簡單移動平均
簡單移動平均(Simple Moving Average),是最容易使用的一種,也是最容易理解的。
其中,為窗口大小,表示t時刻的移動平均值。
以下為“五糧液”今年十一后七個交易日的收盤價移動平均線的實現(xiàn)代碼:
import?pandas?as?pd
import?akshare?as?ak
df?=?ak.stock_zh_a_hist(symbol="000858",?start_date="20211008",?end_date='20211018')
df?=?df.set_index('日期')
df.index?=?pd.to_datetime(df.index)
df?=?df[['收盤']]
df['SMA_3']?=?df['收盤'].rolling(window=3).mean()
df['SMA_5']?=?df['收盤'].rolling(window=5).mean()
print(df)

加權移動平均
加權移動平均(Weighted Moving Average)與SMA類似,但是在計算平均數(shù)時并不是等量齊觀,可以給最近的觀測值相對歷史觀測值更大的權重。比如股票價格,最近的價格最有影響力,歷史價格隨著時間拉長影響力越小。
技術分析中,權重系數(shù)為n~0,即最近一個數(shù)值的權重為n,次近的為n-1,如此類推,直到0。
import?numpy?as?np
import?pandas?as?pd
import?akshare?as?ak
df?=?ak.stock_zh_a_hist(symbol="000858",?start_date="20211008",?end_date='20211018')
df?=?df.set_index('日期')
df.index?=?pd.to_datetime(df.index)
df?=?df[['收盤']]
def?WMA(close,?n):
????weights?=?np.array(range(1,?n+1))
????sum_weights?=?np.sum(weights)
????res?=?close.rolling(window=n).apply(lambda?x:?np.sum(weights*x)?/?sum_weights,?raw=False)
????return?res
df['WMA_3']?=?WMA(df['收盤'],?3)
df['WMA_5']?=?WMA(df['收盤'],?5)
print(df)

這里再分享一個功能相同輸出結果一樣另一種比較有意思的實現(xiàn)方式:
def?WMA(close,?n):
????return?close.rolling(n).apply(lambda?x:?x[::-1].cumsum().sum()?*?2?/?n?/?(n?+?1))
分母的實現(xiàn):x[::-1].cumsum().sum()
說明:逆序累加,最后一個元素會參與n遍計算,第一個元素只會參與1次計算
:分子的實現(xiàn):(n+1)*n/2
說明:(首項+尾項)*項數(shù)/2,熟悉的口號
指數(shù)移動平均

import?pandas?as?pd
import?akshare?as?ak
df?=?ak.stock_zh_a_hist(symbol="000858",?start_date="20211008",?end_date='20211018')
df?=?df.set_index('日期')
df.index?=?pd.to_datetime(df.index)
df?=?df[['收盤']]
df['SMA_3']?=?df['收盤'].rolling(window=3).mean()
df['EMA_3']?=?df['收盤'].ewm(span=3,min_periods=3).mean()
df['EMA_5']?=?df['收盤'].ewm(span=5,min_periods=5).mean()
print(df)

ewm()方法中可通過四選一[com or span or halflife or alpha]調整衰減系數(shù)。根據(jù)質心指定衰減,則;根據(jù)跨度指定衰減,則;根據(jù)半衰期指定衰減,則;
也可直接指定衰減系數(shù)alpha。adjust參數(shù)控制指數(shù)移動平均函數(shù)的計算方式。
adjust=False時,
adjust=True時(默認), ?
方法對比分析
從權重思維來看,三種方法都可以認為是加權平均。SMA:權重系數(shù)一致;WMA:權重系數(shù)隨時間間隔線性遞減;EMA:權重系數(shù)隨時間間隔指數(shù)遞減。
import?numpy?as?np
import?pandas?as?pd
from?matplotlib?import?pyplot?as?plt
#?窗口大小指定為30(30日均線時)
n?=?30
#?簡單移動平均-權重系數(shù)
weights_sma?=?np.ones(n)
#?加權移動平均-權重系數(shù)
weights_wma?=?range(1,?n+1)
weights_wma?/=?np.sum(weights_wma)
weights_wma?=?weights_wma[::-1]??#?按時間倒序
#?指數(shù)移動平均-加權系數(shù)(對應pandas.ewm(span=n))
alpha?=?2?/?(n+1)
dived?=?1*(1-(1-alpha)**n)/(1-(1-alpha))??#?等比數(shù)列:a1*(1-q**n)/(1-q)
weights_ema?=?list(map(lambda?i:?(1-alpha)**i?/?dived,?range(n)))
df?=?pd.DataFrame({'SMA(30)-Weights':?weights_sma,?'WMA(30)-Weights':?weights_wma,?'EMA(30)-Weights':?weights_ema})
ticks?=?['t']?+?list(map(lambda?i:?'t-{}'.format(i),?range(1,n)))
ax?=?df.plot.bar(subplots=True,?figsize=(16,?6),?title=['',?'',?''])
ax[-1].set_xticklabels(ticks)
plt.show()
從上圖中的權重系數(shù)隨時間間隔衰減情況可以看出,指數(shù)移動平均系數(shù)衰減較快,也因此一般也能更快的發(fā)現(xiàn)趨勢的變化。
從實際股票分析場景看,先上圖:
import?numpy?as?np
import?pandas?as?pd
import?akshare?as?ak
from?matplotlib?import?pyplot?as?plt
def?SMA(close,?n):
????return?close.rolling(window=n).mean()
def?WMA(close,?n):
????return?close.rolling(window=n).apply(lambda?x:?x[::-1].cumsum().sum()?*?2?/?n?/?(n?+?1))
def?EMA(close,?n):
????return?close.ewm(span=n,?min_periods=n).mean()
df?=?ak.stock_zh_a_hist(symbol="000858",?start_date="20210101",?end_date='20211018')
df?=?df.set_index('日期')
df.index?=?pd.to_datetime(df.index)
df?=?df[['收盤']]
df.columns?=?['close']
df['SMA_30']?=?SMA(df['close'],?30)
df['WMA_30']?=?WMA(df['close'],?30)
df['EMA_30']?=?EMA(df['close'],?30)
df.plot(figsize=(16,?6))
ax?=?plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
plt.xlabel('')
plt.show()
可以看出,三種方法均有一定的滯后性,所以在使用時用作判斷長期趨勢,短期股價分析還應結合更多指標。當然也可以互相組合使用,比如SMA+WMA,SMA+EMA;同時也可以通過設置窗口大小進行交叉分析,比如5日均線向上突破10日、30日均線股市中稱之為“金叉”,利好。
言而總之,移動平均雖預測能力有限,但仍有很多優(yōu)點,計算簡單,支持海量數(shù)據(jù)在線/實時計算,易于理解,可以描述序列長期趨勢,也可當成一種最為簡單的濾波器使用。作為時間序列預測的基本方法,了解其特性,在使用其他方法時若能靈活與之搭配或許也能產(chǎn)出意想不到的效果。
[1]https://www.math.pku.edu.cn/teachers/lidf/course/fts/ftsnotes/html/_ftsnotes/fts-mamod.html#ma-frcst
[2]https://forex-indicators.net/trend-indicators/moving-averages-ema-sma-wma
[3]https://blog.csdn.net/the_time_runner/article/details/101071591
[4]https://zhuanlan.zhihu.com/p/377045460
[5]https://www.cnblogs.com/xiaobajiu/p/7066490.html
