【Quant(1)】- Backtesting

Using 0050.TW as the main Underlying asset to do the dollar-cost averaging backtesting

* What is Backtesting and how to do it?

Assumption:As long as the company's ROE exceeds 15%, then we buy it's stock, rebalance once a year, and sell when its ROE falls below 15%.

* 0050.TW dollar-cost averaging(DCA) method backtesting

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import matplotlib.transforms as transformsimport datetimeimport tejapi
tejapi.ApiConfig.api_key = "your key"
TW0050 = tejapi.get(
'TWN/EWPRCD',
coid = '0050',
mdate={'gte':'2016-01-01', 'lte':'2020-12-31'},
opts={'columns': ['mdate','close_adj']},
paginate=True
)
TW0050['mdate'] = TW0050.loc[:,'mdate'].astype('datetime64[ns]')
TW0050 = TW0050.set_index('mdate')
##change the frequency of the data
TW0050_monthly = TW0050.resample('MS').first()
##add the last day of our historical data
TW0050_monthly = TW0050_monthly.append(TW0050.iloc[-1])
TW0050_monthly
Monthly Data(0050.TW)
##Shares to buy in each month(chop off)
TW0050_monthly['每月購買股數']=
np.floor(10000 / TW0050_monthly['close_adj'])
TW0050_monthly['每月購買股數'][-1] = 0##Cumulative Shares
TW0050_monthly['累積股數'] = TW0050_monthly['每月購買股數'].cumsum()
##Cumulative Shares Value
TW0050_monthly['累積價值(月)'] =
  round(TW0050_monthly['累積股數'] * TW0050_monthly['close_adj'],2)
##Original Asset Value
TW0050_monthly['原始價值(月)'] =
  [10000*i for i in range(len(TW0050_monthly.index))]
TW0050_monthly['原始價值(月)'] =
  TW0050_monthly['原始價值(月)'].shift(-1)
TW0050_monthly['原始價值(月)'][-1] = TW0050_monthly['原始價值(月)'][-2]##Cumulative Return
TW0050_monthly['累積報酬(月)'] =
  round((TW0050_monthly['累積價值(月)']-TW0050_monthly['原始價值(月)'])/TW0050_monthly['原始價值(月)'], 6) +1
0050.TW Cumulative Return
plt.figure(figsize = (10, 6))
plt.plot(TW0050_monthly['累積價值(月)'], lw=1.5, label = '0050')
plt.plot(TW0050_monthly['原始價值(月)'], lw=1.5, label = 'Original Asset')
plt.xlabel('Time(Year)')
plt.ylabel('Value')
plt.legend(loc = 0)
plt.grid()
0050.TW DCA Method VS Original Asset
##Monthly return
ret =
  np.log(TW0050_monthly['累積報酬(月)']/TW0050_monthly['累積報酬(月)'].shift(1))
fig, ax = plt.subplots()
ret.plot(kind="bar", figsize=(12,6), stacked=True, ax=ax)
##Build an empty array with the length of total data
ticklabels = ['']*len(TW0050_monthly.index)
##Show the month and the date every 6 months
ticklabels[::6] =
  [item.strftime('%b %d') for item in TW0050_monthly.index[::6]]
##Show the year every 12 months
ticklabels[::12] =
  [item.strftime('%b %d\n%Y') for item in TW0050_monthly.index[::12]]
ax.xaxis.set_major_formatter(ticker.FixedFormatter(ticklabels))
plt.gcf().autofmt_xdate()
##Add the horizontal line of average monthly return
ax.axhline(ret.mean(), c='r')
plt.xlabel('Month')
plt.ylabel('Return')
plt.title('0050 Monthly return')
plt.show()
0050.TW Monthly Return
##CAGR
cagr = (TW0050_monthly['累積報酬(月)'][-1]) ** (1/5) -1
##Annually Standard Deviation
std = ret.std()*np.sqrt(12)
##Sharpe Ratio(Assume that Rf is 1%)
shapre_ratio = (cagr-0.01)/std
##MDD
roll_max = TW0050_monthly['累積價值(月)'].cummax()
monthly_dd =TW0050_monthly['累積價值(月)']/roll_Max - 1.0
max_dd = monthly_dd.cummin()
##Table
pd.DataFrame(columns=['0050'],
  index=['年化報酬率(%)', '年化標準差(%)', '夏普比率', '期間最大回撤(%)'],
  data = np.round(np.array([100*cagr, 100*std, sharpe_ratio, 100*max_dd[-1]]),2))
Indicators

* Conclusion

* Links related to this article again!💪💪

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
TEJ 台灣經濟新報

TEJ 為台灣本土第一大財經資訊公司,成立於 1990 年,提供金融市場基本分析所需資訊,以及信用風險、法遵科技、資產評價、量化分析及 ESG 等解決方案及顧問服務。鑒於財務金融領域日趨多元與複雜,TEJ 結合實務與學術界的精英人才,致力於開發機器學習、人工智慧 AI 及自然語言處理 NLP 等新技術,持續提供創新服務