Table of Contents
當市場資金過度氾濫時,投資人為了規避系統性風險,常透過資產配置的方式同時建立多空部位,來消除大部份市場風險,獲得穩定報酬。而本文挑選長榮與陽明做為配對交易的股票對,並以單根檢定確定兩檔價差存在定態性,即確認長榮與陽明具有共整合關係,從而在價差偏離時,買進被低估的股票,賣出被高估的股票,並在價差修正時,反向平倉,賺取價差。
本文使用 Windows OS 並以 Jupyter Notebook 作為編輯器
# 基本功能
import pandas as pd
import numpy as np
from arch.unitroot import ADF
import statsmodels.api as sm
# 繪圖
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
plt.rcParams['axes.unicode_minus'] = False
# TEJ API
import tejapi
tejapi.ApiConfig.api_key = 'Your Key'
從 TEJ資料庫匯入長榮與陽明的股價報酬率。
# 匯入資料
stock = tejapi.get('TWN/EWPRCD2',
coid = ['2603','2609'],
mdate= {'gte': '2019-06-01','lte':'2021-06-30'},
opts={'columns':['coid','mdate','roia']},
chinese_column_name=True,paginate=True)
stock = stock.pivot(index='日期', columns='證券碼', values='日報酬率(%)')
stock.columns = ['2603 長榮','2609 陽明']
stock = stock * 0.01
stock.tail(6)
Step 1. 股票日報酬率序列有定態性
從下圖看出兩檔日報酬率都在0附近上下波動,可以確定兩檔日報酬率序列存在定態性。
# 長榮與陽明 日報酬率的時序圖
fig = plt.figure(figsize = (15,8))
ax = fig.add_subplot()
ax.plot(stock['2603 長榮'] ,linewidth=2, alpha=1)
ax.plot(stock['2609 陽明'] ,linewidth=2, alpha=0.7)
ax.axhline(0,color = 'black')
ax.set_title('長榮與陽明 日報酬率的時序圖' ,fontsize=20 ,fontweight='bold')
ax.legend(['2603 長榮','2609 陽明'],loc='best')
ax.set_ylabel('報酬率', fontsize=12,rotation=0)
ax.grid(axis='y')
Step 2. 股票對的價差
先將回測期間分成形成期與交易期,我們在計算交易期的價差序列時,為了避免前視偏誤,我們使用形成期價差序列的線性迴歸而得的 alpha係數值與 beta係數值,計算交易期的價差序列。
# 價差
def CointegrationSpread(df,formStart,formEnd,tradeStart,tradeEnd):
formX = df[(df.index >= formStart) & (df.index <= formEnd)]['2603 長榮']
formY = df[(df.index >= formStart) & (df.index <= formEnd)]['2609 陽明']
tradeX = df[(df.index >= tradeStart) & (df.index <= tradeEnd)]['2603 長榮']
tradeY = df[(df.index >= tradeStart) & (df.index <= tradeEnd)]['2609 陽明']
results = sm.OLS(formY,sm.add_constant(formX)).fit()
spread = tradeY - results.params[0] - results.params[1] * tradeX
return spread
Spread_2020_10_12 = CointegrationSpread(stock,'2019-06-01','2020-06-30','2020-10-01','2020-12-31')
Spread_2021_01_03 = CointegrationSpread(stock,'2020-01-01','2020-12-31','2021-01-01','2021-03-30')
# 對兩檔股價的價差序列做定態性檢定
adfSpread = ADF(Spread_2021_10_12, trend='n')
print(adfSpread.summary().as_text())
由下圖可知在1%顯著性水平下,我們可以拒絕虛無假設,說明 2021_10_12價差序列是定態的,即長榮與陽明的日報酬率序列具有共整合關係。
mu = np.mean(Spread_2020_10_12)
sd = np.std(Spread_20201012)
我們計算形成期價差序列的 μ均值與 σ標準差,獲得交易期進出場的條件門檻值。設定 μ±1.5σ和 μ±0.2σ為開倉與平倉的臨界值,而 μ±2.5σ.
。同時我們可以發現形成期價差序列都沒有觸及 μ±2.5σ臨界值。
我們根據開倉平倉點制定交易策略,
Spread_2021_01_03 = Spread_2021_01_03.to_frame()
Spread_2021_01_03.columns = ['價差']Spread_2021_01_03['開倉平倉區間'] = \
pd.cut(Spread_2021_01_03['價差'] ,
(float('-inf') ,mu-2.5*sd ,mu-1.5*sd ,mu-0.2*sd ,
mu+0.2*sd ,mu+1.5*sd ,mu+2.5*sd ,float('inf')) ,labels=False)-3Spread_2021_01_03['交易訊號'] = \
np.select([(Spread_2021_01_03['開倉平倉區間'].shift() == 1) &
(Spread_2021_01_03['開倉平倉區間'] == 2),
(Spread_2021_01_03['開倉平倉區間'].shift() == 1) &
(Spread_2021_01_03['開倉平倉區間'] == 0),
(Spread_2021_01_03['開倉平倉區間'].shift() == 2) &
(Spread_2021_01_03['開倉平倉區間'] == 3),
(Spread_2021_01_03['開倉平倉區間'].shift() == -1) &
(Spread_2021_01_03['開倉平倉區間'] == -2),
(Spread_2021_01_03['開倉平倉區間'].shift() == -1) &
(Spread_2021_01_03['開倉平倉區間'] == 0),
(Spread_2021_01_03['開倉平倉區間'].shift() == -2) &
(Spread_2021_01_03['開倉平倉區間'] == -3)],
[-2,2,3,1,-1,-3],default = 0)position = [Spread_2021_01_03['交易訊號'][0]]
ns = len(Spread_2021_01_03['交易訊號'])Spread_2021_01_03['倉位情況'] = pd.Series(position,index=Spread_2021_01_03.index)
Spread_2021_01_03['倉位情況'] = Spread_2021_01_03['倉位情況'].shift() # 隔天開盤才進場Spread_2021_01_03 = Spread_2021_01_03.join(stock)
Spread_2021_01_03['策略報酬率'] = \
np.select([Spread_2021_01_03['倉位情況'] == 1,
Spread_2021_01_03['倉位情況'] == 0,
Spread_2021_01_03['倉位情況'] == -1],
[Spread_2021_01_03['2609 陽明'] * -1 + Spread_2021_01_03['2603 長榮'] * 1,
0,
Spread_2021_01_03['2609 陽明'] * 1 + Spread_2021_01_03['2603 長榮'] * -1], default=np.nan)Spread_2021_01_03['累積報酬率'] = (Spread_2021_01_03['策略報酬率'] + 1).cumprod() -1
Spread_2021_01_03.head(10)
我們完成上述策略,並將策略的累積報酬率與最大回檔呈現在下圖。
由最大回檔圖可以發現有兩次的配對交易最大回檔都連續跌破8%,代表策略的停損機制做的不是太好,或是 μ均值與 σ標準差參數失靈。未來可以試著調降2.5σ的標準,或是以rolling
的方式計算形成期價差序列的 μ均值與 σ標準差,因為海運股在2021年上半年的波動性極大,而交易期剛好落在2021年1月至3月,形成期則是2020年1月至12月。
本文僅供參考之用,並不構成要約、招攬或邀請、誘使、任何不論種類或形式之申述或訂立任何建議及推薦,讀者務請運用個人獨立思考能力,自行作出投資決定,如因相關建議招致損失,概與作者無涉。
電子報訂閱