春節期間台股績效表現

本文重點概要

  • 文章難度:★★☆☆☆
  • 整理自2008年起台股封關前後的報酬&利用事件研究法討論具有異常報酬之標的
  • 閱讀建議:本文會先討論台股大盤在封關前後的漲跌,再藉由事件研究法選出這段期間具有異常報酬之標的,若讀者對於事件研究法感到陌生,可以先行閱讀現金增資宣告效果,以事件研究法為例,了解事件研究法的基礎原理。

前言

農曆春節是華人社會中最重要的節日,傳統來說這段期間才是年末與新年的開始,證券市場參與者也會在此時對過去的市況進行總結並於年節後表態對於未來的展望。因此內文會以農曆年節為主題,討論這段期間台股市場的行情;此外也會對個股進行事件研究,以正負5日為事件期間,討論封關前後的異常報酬情形。

Note: 本文提及之個股標的僅供說明使用,不代表任何金融商品之推薦或建議。

編輯環境及模組需求

本文使用MacOS 並以 Jupyter Notebook 作為編輯器。

import pandas as pd import numpy as np from sklearn.linear_model import LinearRegression from scipy import stats from datetime import datetime import tejapi tejapi.ApiConfig.api_key = 'Your Key' tejapi.ApiConfig.ignoretz = True

資料庫使用

大盤行情

Step 1. 資料撈取

twn = tejapi.get('TWN/APRCD',                 coid = 'Y9997',                 mdate = {'gte': '2008-01-01', 'lte':'2021-03-30'},                 opts = {'columns':['mdate', 'roia']},                 paginate = True,                 chinese_column_name = True)

撈取報酬指數(Y9997),並以2008–01–01至2021–03–30為區間,確保涵蓋各年度農曆年節前後的範圍。

資料表(一)

Step 2. 輸入封關最後交易日&對比大盤資料日期

# 歷年春節前最後交易日 last_day = ['2008-02-01', '2009-01-21', '2010-02-10', '2011-01-28', '2012-01-18', '2013-02-06', '2014-01-27', '2015-02-13', '2016-02-03', '2017-01-24', '2018-02-12', '2019-01-30', '2020-01-20', '2021-02-05'] # 確保可以使用last_day為日資料型態,將其轉換成時間物件 last_day = [datetime.fromisoformat(i) for i in last_day] date = [] for i in last_day:     date.append(int(twn[twn['年月日'] == i].index.values))

Step 3. 計算封關前後15日、5日以及當日報酬率

market = pd.DataFrame(columns = ['前十五日累計報酬', '前五日累計報酬', '封關日報酬', '後五日累計報酬', '後十五日累計報酬' ]) for i in date:     # 封關前十五日累計報酬     market.loc[i, '前十五日累計報酬'] = ((twn.loc[i, '收盤價(元)'] / twn.loc[i-15, '收盤價(元)']) - 1) * 100     # 封關前五日累計報酬     market.loc[i, '前五日累計報酬'] = ((twn.loc[i, '收盤價(元)'] / twn.loc[i-5, '收盤價(元)']) - 1) * 100     # 封關當天報酬     market.loc[i, '封關日報酬'] = ((twn.loc[i, '收盤價(元)'] / twn.loc[i-1, '收盤價(元)']) - 1) * 100     # 封關後五日累計報酬     market.loc[i, '後五日累計報酬'] = ((twn.loc[i+5, '收盤價(元)'] / twn.loc[i, '收盤價(元)']) - 1) * 100     # 封關後十五日累計報酬     market.loc[i, '後十五日累計報酬'] = ((twn.loc[i+15, '收盤價(元)'] / twn.loc[i, '收盤價(元)']) - 1) * 100 market = market.reset_index().drop(columns = 'index')
資料表(二)

Step 4. 計算平均漲跌幅&漲跌幅情況

for i in range(0,5):     data['平均漲幅'][i] = market.iloc[:, i].mean()        pos = list(filter(lambda x: (x > 0), market.iloc[:,i]))     data['上漲次數'][i] = len(pos)     data['上漲機率'][i] = len(pos) / len(last_day)     data['上漲平均漲幅'][i] = np.mean(pos)     neg = list(filter(lambda x: (x < 0), market.iloc[:,i]))         data['下跌次數'][i] = len(neg)     data['下跌機率'][i] = len(neg) / len(last_day)     data['下跌平均跌幅'][i] = np.mean(neg)
資料表(三)

從表中可以發現年節前三個禮拜的交易日出現跌大於漲的情形,並且在年節後有漲大於跌的趨勢。這應該是源於年節前市場參與者會傾向出場,以避免接下來休市期間可能發生意外事件所導致的衝擊;而年後往往也會展開新年的計劃,進場佈局,因此以多頭為主。

個股事件研究 — 封關前

Note:再次提醒,若是對事件研究法不熟悉的讀者,可以先行閱讀現金增資宣告效果,以事件研究法為例

Step 1. 取得普通股代碼

security = tejapi.get('TWN/ANPRCSTD',               mkt = 'TSE',               stypenm = '普通股',               opts = {'columns':['coid','mdate','stypenm','mkt']},               paginate = True,               chinese_column_name = True) tse_stocks = security['證券碼'].tolist()

Step 2. 事件研究過程(詳見完整程式碼)

  1. 通過估計期間(每年度各251期)的資料建置Fama-French五因子模型。
  2. 應用五因子模型對事件期間(封關前後5日與當天,共11期)進行股價報酬預測。
  3. 將實際報酬減去預期報酬,得到異常報酬率,並計算每日累計異常報酬率。
資料表(四)

Step 3. 檢定封關前的異常報酬顯著性

通過t值、P-value檢定個股的異常報酬顯著水準。

pre_close = pd.DataFrame() for stock in tse_stocks:     #以封關當天累計異常報酬進行檢定      df = test[test['證券代碼'] == stock].reset_index(drop=True)     df = df[df['相對天數'] == 0]     #刪除樣本過少公司     if len(df) < 4:         print(stock, 'has no enough data')         continue     sample = df['累計異常報酬率'].values     #檢定     t, p_value = stats.ttest_1samp(sample, 0)     if p_value <= 0.01:         significance = '***'     elif 0.01 < p_value <= 0.05:         significance = '**'     elif 0.05 < p_value <= 0.1:         significance = '*'     else:         significance = ''       pre_close = pre_close.append(pd.DataFrame(np.array([stock,t,p_value, significance]).reshape((1,4)), columns = ['證券代碼','T檢定值', 'P-value','顯著水準'],)).reset_index(drop=True)
資料表(五)

以最嚴格的檢定水準(P-value < 0.01),挑選異常報酬具有顯著性之個股標的。

result = pre_close[(pre_close['T檢定值'] > 0) & (pre_close['P-value'] < 0.01) ].reset_index(drop=True)
資料表(六)

Step 4. 計算異常報酬

首先,計算各年度遞延n期的平均報酬,例如:各年度封關前5日的平均異常報酬;接著,計算期間的累計平均報酬,也就是封關前五日到當天的平均累計報酬。

# 各期平均報酬 for i in range(-5, 1):     result['第' + str(i) + '天平均異常報酬'] = test[test['證券代碼'].isin(positive_list) & (test['相對天數'] == i)].groupby('證券代碼')['異常報酬率'].mean().reset_index(drop=True) # 加總累計各平均報酬 result['期間累計平均異常報酬率'] = test[test['證券代碼'].isin(positive_list) & (test['相對天數'] == 0)].groupby('證券代碼')['累計異常報酬率'].mean().reset_index(drop=True)
資料表(七)

Step 5. 合併公司資料表

result['公司中文簡稱'] = '' result['TEJ產業名'] = '' result['TEJ子產業名'] = '' for i in range(len(positive_list)):     firm_info = tejapi.get('TWN/AIND',                           coid = positive_list[i],                           opts = {'columns':['coid', 'inamec', 'tejind2_c', 'tejind3_c']},                           chinese_column_name = True,                           paginate = True)     result.loc[i, '公司中文簡稱'] = firm_info.loc[0, '公司中文簡稱']     result.loc[i, 'TEJ產業名'] = firm_info.loc[0, 'TEJ產業名']     result.loc[i, 'TEJ子產業名'] = firm_info.loc[0, 'TEJ子產業名']
資料表(八)
資料表(九)

透過公司產業屬性可以發現,三家在農曆年封關前異常報酬最具顯著性的公司為工業類股或加工品製造類股。

個股事件研究 — 封關後

封關前後的處理過程基本上大同小異,只需要更改事件期間進行計算即可,本文因篇幅考量,此處直接呈現最終結果,供讀者參考。(詳見完整程式碼)。

資料表(十)
資料表(十一)

透過公司產業屬性了解,工業類股在年節封關後依然還是相對台股其他族群具有顯著異常報酬的個股。

Note: 本文所提及之個股標的僅供說明使用,不代表任何金融商品之推薦或建議。

結論

首先,本文藉由台股報酬指數的封關前後表現,分析市場參與者對於休市期間的態度,發現休市前一段時間市場會出現些微空頭趨勢,並且在新年開始會有多頭的行情出現。

其次,本文第二部分的主題為事件研究法討論個股異常報酬,通過封關前後的結果,讀者應該可以發現工業類股的異常報酬較有顯著性,而本文認為這是綜合考量年度初期基礎工業加工品訂單開始增加且國際金屬價格經常在二月底會呈現滑落的狀態,所以市場預期工業類股公司的未來營收成長且成本下降而進場該類型個股。

最後,還是要再次提醒本文所提及之標的僅供說明使用,不代表任何金融商品之推薦或建議。因此,若讀者對於事件研究等議題有興趣,歡迎選購 TEJ E Shop中的方案,具有齊全的資料庫,就能輕易的完成各種檢定。

完整程式碼

延伸閱讀

相關連結

返回總覽頁
Procesing