這篇文章將會按照上一篇【程式交易系列】#3 回測(Backtesting)的架構來實作,讓大家可以透過Python程式碼能又更具體的感受。
抓取資料
先利用我們在【網路爬蟲】臺灣證券交易所歷史資料教學(2)的爬蟲方法將股價資料抓下來,並存成Excel檔案,前面均不變僅在最後一行加上了將DataFrame產出為Excel的指令。
import pandas as pd
import numpy as np
import json
import requests
import datetime
import time
def Get_StockPrice(Symbol, Date):
url = f'https://www.twse.com.tw/exchangeReport/STOCK_DAY?response=json&date={Date}&stockNo={Symbol}'
print(url)
data = requests.get(url).text
json_data = json.loads(data)
Stock_data = json_data['data']
StockPrice = pd.DataFrame(Stock_data, columns = ['Date','Volume','Volume_Cash','Open','High','Low','Close','Change','Order'])
StockPrice['Date'] = StockPrice['Date'].str.replace('/','').astype(int) + 19110000
StockPrice['Date'] = pd.to_datetime(StockPrice['Date'].astype(str))
StockPrice['Volume'] = StockPrice['Volume'].str.replace(',','').astype(float)/1000
StockPrice['Volume_Cash'] = StockPrice['Volume_Cash'].str.replace(',','').astype(float)
StockPrice['Order'] = StockPrice['Order'].str.replace(',','').astype(float)
StockPrice['Open'] = StockPrice['Open'].str.replace(',','').astype(float)
StockPrice['High'] = StockPrice['High'].str.replace(',','').astype(float)
StockPrice['Low'] = StockPrice['Low'].str.replace(',','').astype(float)
StockPrice['Close'] = StockPrice['Close'].str.replace(',','').astype(float)
StockPrice = StockPrice.set_index('Date', drop = True)
StockPrice = StockPrice[['Open','High','Low','Close','Volume']]
print(StockPrice)
return StockPrice
if __name__ == '__main__':
Symbol = '00631L'
Dates = pd.date_range(start = '2010-01-01', end = '2020-09-01', freq = 'MS').astype(str)
data = Get_StockPrice(Symbol, Dates[0].replace('-',''))
for Date in Dates[1:]:
try:
data = pd.concat([data,Get_StockPrice(Symbol, Date.replace('-',''))], axis = 0)
time.sleep(5)
except:
pass
data.to_excel(Symbol + '.xlsx')
分析資料與交易策略發想
首先我們將剛剛生成的Excel檔案讀入,先將歷史資料暫存的目的就是要讓每次測試執行時,不用一直去交易所爬蟲,爬蟲比較耗時間,例如每次爬取一個月後,就必須要sleep幾秒,所以我們這個簡單的範例就先用Excel來暫存,我自己在ㄧ些比較大的專案比較喜歡建立SQL的資料庫。
讀入歷史資料:
import pandas as pd
import numpy as np
df = pd.read_excel('2330.xlsx')
df.info()
確認格式均為可計算的浮點位數
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2539 entries, 0 to 2538
Data columns (total 6 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Date 2539 non-null datetime64[ns]
1 Open 2539 non-null float64
2 High 2539 non-null float64
3 Low 2539 non-null float64
4 Close 2539 non-null float64
5 Volume 2539 non-null float64
dtypes: datetime64[ns](1), float64(5)
memory usage: 119.1 KB
我們先來用一個相當簡單的範例來說明回測的流程,這篇的目的是教大家怎麼樣做回測,不是要告訴你會賺錢的策略,大家別誤會啊!所以我們先用一個老少咸宜的均線交叉策略來說明,我們在這邊假設以短中期均線作為我們的交易策略,當短期均線由下往上穿越中期均線時,則進場買進,當短期均線由上往下穿越中期均線時,則出清持股。
df['MA1'] = df['Close'].rolling(20).mean() #計算短期均線
df['MA2'] = df['Close'].rolling(60).mean() #計算中期均線
df[['Close','MA1','MA2']].plot() #將收盤價、短期均線、中期均線進行作圖
交易訊號轉換
我們可以利用np.where的函數來操作,np.where就是矩陣式計算if-else的意思,可以看到下面程式碼中np.where有三個參數,第一個為判斷的條件,我們的條件式短期均線大於中期均線,第二個參數就是符合條件時,df[‘Signal’]將產生出哪個值,如果不符合條件時,產生出的值則放在第三個參數。
df['Signal'] = np.where(df['MA1'] > df['MA2'], 1, 0)
df['Signal'].plot(kind = 'area')
回測
進行回測也有幾個動作要處理,第一個是我們要先計算股票的日報酬率,這樣才能在回測時知道每一天的報酬率狀況,計算完股價日報酬率後,另外需建立交易策略下的報酬率,而且我們並假設邏輯如下:當天收盤確認訊號出現,在隔天的收盤價進場。
df['Return'] = df['Close'].pct_change() #計算股價日報酬率
df['Strategy_Return'] = df['Return'] * df['Signal'].shift(1) #計算交易策略日報酬率
先就兩個策略間的日報酬率進行分析
df[['Return','Strategy_Return']].describe()
Return Strategy_Return
count 2538.000000 2538.000000
mean 0.000858 0.000567
std 0.014856 0.011117
min -0.069194 -0.067623
25% -0.007973 -0.002658
50% 0.000000 -0.000000
75% 0.009343 0.004320
max 0.099741 0.099741
可以發現整體績效狀況不大明顯的差異,僅有在最低的第25百分位數日報酬有比較少的狀況。
績效評估
我們第一件事就是去產生權益曲線(Equity Curve),由於是使用報酬率來去進行估計報酬率,所以就會有所謂的單利與複利狀況,我們分別假設兩種狀況。
df['EquityCurve(Simple)'] = df['Strategy_Return'].cumsum() #單利
df['EquityCurve(Compound)'] = ( 1 + df['Strategy_Return']).cumprod() -1 #複利
df[['EquityCurve(Simple)','EquityCurve(Compound)']].plot()
由於是一個長期向上的曲線,所以橘色線(複利)一定會比藍色線(單利)來得高,而複利其實是比較符合實際金融市場交易的狀況,買進一張股票或一口期貨的市值將會隨著市價的變動而變動,所以投資部位的市值是不斷在改變的,而單利的假設為每天的投資部位市值是不變的!
在產生出交易訊號、策略報酬率及權益曲線後,要計算出完整的策略報酬就只是資料處理的技巧了,就留給大家自己做了,有任何問題都可以留言或在粉專私訊我。
結論
最基本的回測操作就是由上面所教學的內容,大家可以自行去延伸,包含交易策略的設計與績效衡量,甚至是最佳化,在能夠自己完成回測程式後,再回去看上一篇【程式交易系列】#3 回測(Backtesting)的內容,相信大家就能夠對這塊有更深一層的瞭解。
Python x 股票、期貨、選擇權|客製自動化交易平台
雷大的Python投資筆記電子報
歡迎訂閱雷大的Python投資筆記電子報,每週將會發布定期市場分析文章與不定期的專案研究文章:
- 國際金融市場分析
- 量化交易策略分享
- Python程式撰寫教學
立即訂閱最新文章