【Application(5)】Modular Backtesting System

Use TEJ API to construct our own backtest system.

--

Photo Creds: Unsplash

Preface

Trade Backtest is a more scientific approach to test strategy nowadays. Although the past cannot represent the future. The result of backtest can provide us some information about the strategy. However, if we have to run different strategy, we need to build a new system. This way will waste our much time and it is inefficient. Therefore, we try to modular the system and focus on developing the strategy.

The Editing Environment and Modules Required

We use Windows OS and Jupyter Notebook in this article.

import tejapi
import pandas as pd
import numpy as np
tejapi.ApiConfig.api_key = 'Your Key'
tejapi.ApiConfig.ignoretz = True

Note: Remember to replace ‘Your key’ with the one you applied for. The last line indicates that we ignore the time zone.

The highlights of the article

  • Pre-planning of Building System
  • Modular System

Building System

Step 1. Thinking about what tables or variables we might need.

  • Stock Pool
  • Raw Data
  • Trade Strategy
  • Trade Signal
  • Backtesting
  • Sell Variable
  • Buy Variable

Consider the columns required for the process.

Step 2. Creating class name backtest

class backtest():

Step 3. All of the def is created under this class.

def __init__(self, target_list):
# 設定初始值

# 股票池
self.target_list = target_list
# 訊號表
self.signal_data = pd.DataFrame()

# 交易表
self.action_data = pd.DataFrame()

# 獲利數
self.protfolio_profit = []

# 成本數
self.protfolio_cost = []

Raw also need to put it into this class. target_list is our stock pool.

# 資料庫
self.data = tejapi.get('TWN/APRCD',
coid = target_list,
mdate={'gte':'2020-01-01', 'lte':'2020-12-31'},
opts={'columns':['coid','mdate','close_d',
'volume']},
chinese_column_name=True,
paginate=True).reset_index(drop=True)

Step 4. Making Strategy, here we choose common strategies. We only explain specific point. To see full code, you can click this link.

  • Price and Volume Strategy

We will buy the stock if the price and volume break through the highest price and volume in the past 20 days.

def price_volume(self, specific=None):
# 策略更新
self.signal_data = pd.DataFrame()
self.action_data = pd.DataFrame()

Generate transaction signals for each stock.

# 股票池每一檔股票都跑一次訊號產生
for i in self.target_list:
target_data = self.data[self.data['證券代碼'] == i]

Calculate the highest and lowest price and volume in past 10 and 20 days.

rolling_max = target_data[['收盤價(元)', '成交量(千股)']].rolling(20).max()rolling_min = target_data[['收盤價(元)', '成交量(千股)']].rolling(10).min()

Buy

stock_data['買入訊號判斷'] = np.where((stock_data['收盤價(元)'] == stock_data['收盤價(max)']) & (stock_data['成交量(千股)'] == stock_data['成交量(max)']), -1, 0)

Sell

stock_data['賣出訊號判斷'] = np.where((stock_data['收盤價(元)'] == stock_data['收盤價(min)']) & (stock_data['成交量(千股)'] == stock_data['成交量(min)']), 1, 0)

Offset on last day

remain_stock = self.signal_data.iloc[:-1,8:10].sum().sum()self.signal_data.iloc[-1,9] = 0
self.signal_data.iloc[-1,8] = 0
if remain_stock < 0:
self.signal_data.iloc[-1,9] = -remain_stock
else:
self.signal_data.iloc[-1,8] = -remain_stock
  • Buy and Hold strategy
def buy_hold(self, specific=None):
# 策略更新
self.signal_data = pd.DataFrame()
self.action_data = pd.DataFrame()

Generate transaction signals for each stock.

# 股票池每一檔股票都跑一次訊號產生
for i in self.target_list:
target_data = self.data[self.data['證券代碼'] == i]

Buy on first day and Sell on last day

target_data['買入訊號判斷'] = 0
target_data['賣出訊號判斷'] = 0

# 第一天買入,最後一天賣出
target_data.iloc[0, 4] = -1
target_data.iloc[-1,5] = 1

Step 5. Processing Backtest

def run(self, specific=None):
# 做出交易紀錄表
trade_data = pd.DataFrame(index= self.data['年月日'], columns=self.target_list).fillna(0.0)

action_data = self.signal_data[(self.signal_data['買入訊號判斷'] != 0) | (self.signal_data['賣出訊號判斷'] != 0)]

Calculate Profit

# 計算個股總獲利
self.protfolio_profit.append(sum(action_data['交易'].tolist()))

Calculate Cost

# 計算個股總成本
self.protfolio_cost.append(-action_data[action_data['買入訊號判斷'] < 0]['交易'].sum())

Step 6. Calculate Return on Investment

def ROI(self):
# 報酬率
return_profit = sum(self.protfolio_profit) /
sum(self.protfolio_cost)
return return_profit

Review the performance of the market

We usually compare our strategy to market return. That is because we want beat the market to obtain excess profits.

Step 1. Creating class name market, here we use ‘Y9997’ to represent market index.

market = backtest(['Y9997'])

Step 2. Chooses the strategy

market.buy_hold()

Step 2. Backtesting

market.run()

Step 3. Review the performance

market.ROI()

Custom our own portfolio

Now we want to use MSCI to be our portfolio. MSCI is an acronym for Morgan Stanley Capital International. It is an investment research firm that provides stock indexes, portfolio risk and performance analytics. Code of Database is TWN/AIDXS , and we can find MSCI portfolio in 2020.

data_MSCI = tejapi.get('TWN/AIDXS',
coid = 'MSCI',
mdate= '2019-12-31',
opts={'columns':['coid','mdate','key3']},
chinese_column_name=True)

Filter the data and save it to the list.

MSCI_list = data_MSCI['成份股'].unique().tolist()

Delete the Chinese name.

MSCI_list = [coid[:4] for coid in MSCI_list]

Due to the effect of module, we do not need to rewrite the process of backtest. Just need to change target_list to get the result we want.

Step 1. Creating class name msci , target_list is MSCI_list.

msci = backtest(MSCI_list)

Step 2. Chooses the strategy

msci.price_volume()

Step 3. Backtesting

msci.run()

Step 4. Review the performance

msci.ROI()

Conclusion

There will be a strong bull market in Taiwan’s stock market in 2020. It seems like buy and hold is better than price_volume strategy. But the period just only one year, we cannot jump to conclusion that which is better one. Today’s article describes how to build a simple backtest system. Reader can try to adjust the structure. For example, turn rolling days 1020 into adjustable parameters, in order to compare the compact of date change on the rate of return.

Quantitative Analysis is the trend of investment. Worldwide famous hedge fund adopt this method to make trade strategy. If you have interest on this topic, you can go to our official website. It provides various financial data to help you make better strategy.

Source Code

Extended Reading

Related Link

You could give us encouragement by …
We will share financial database applications every week.
If you think today’s article is good, you can click on the
applause icononce.
If you think it is awesome, you can hold the
applause icon until 50 times.
If you have any feedback, please feel free to leave a comment below.

--

--

TEJ 台灣經濟新報
TEJ-API Financial Data Analysis

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