システムトレードをするうえでどのパラメータが最適か総当たりで探索する方法について記載します。使用するシステムは前回同様単純移動平均線のゴールデンクロス・デッドクロスとします。
1.データ前処理
まずはデータの前処理をします。今回は2012年から2018年までの日足を使用します。移動平均線の出力は関数にしておきます。
import numpy as np
import pandas as pd
import matplotlib as mpl
df = pd.read_csv('^N225m.csv',
sep=',',
names=('Date','Open','High','Low','Close'),
usecols=range(5),
index_col=0,
parse_dates=True,
header=0)
def SMA(data,period):
sma = data['Close'].rolling(period).mean()
return sma
df1=df['2012':'2018']
2.バックテスト・テスト結果出力
バックテストは前回の記事のBacktest_rev()を使用します。テスト結果出力をEquityから総損益、最大ドローダウン、プロフィットファクターに変更します。
def BacktestReport_list(Trade, PL):
LongPL = PL['Long']
LongTrades = np.count_nonzero(Trade['Long'])//2
LongWinTrades = np.count_nonzero(LongPL.clip(lower=0))
LongLoseTrades = np.count_nonzero(LongPL.clip(upper=0))
ShortPL = PL['Short']
ShortTrades = np.count_nonzero(Trade['Short'])//2
ShortWinTrades = np.count_nonzero(ShortPL.clip(lower=0))
ShortLoseTrades = np.count_nonzero(ShortPL.clip(upper=0))
Trades = LongTrades + ShortTrades
WinTrades = LongWinTrades+ShortWinTrades
LoseTrades = LongLoseTrades+ShortLoseTrades
GrossProfit = LongPL.clip(lower=0).sum()+ShortPL.clip(lower=0).sum()
GrossLoss = LongPL.clip(upper=0).sum()+ShortPL.clip(upper=0).sum()
Profit = GrossProfit+GrossLoss
PF=-GrossProfit/GrossLoss
Equity = (LongPL+ShortPL).cumsum()
MDD = (Equity.cummax()-Equity).max()
return [round(Profit,2),round(MDD,2),round(PF,2)]
3.パラメータ変更して総当たりバックテスト
移動平均線のパラメータを変更してどの組み合わせが最も総損益が大きいかを確認します。短期線をparamA,長期線をparamBで定義してすべての組み合わせでテストします。listAとしてリスト形式で出力します。
i=0
listA=[]
paramA = [ 5,7,9,15,25 ]
paramB = [ 30,45,60,120,200 ]
combinations = [(a, b)
for a in paramA
for b in paramB]
for a,b in combinations:
BuyEntry,SellEntry,BuyExit,SellExit=GCDCsignal(SMA(df1,a),SMA(df1,b))
Trade, PL = Backtest_rev(df1, BuyEntry, SellEntry, BuyExit, SellExit, TP=20, SL=1, Limit=0.5)
Profit,MDD,PF=BacktestReport_list(Trade, PL)
listA.append([a,b,Profit,MDD,PF])
listA
[[5, 30, -610492.6, 813337.0, 0.4],
[5, 45, -447328.18, 559521.53, 0.38],
[5, 60, 442512.13, 226842.83, 1.89],
[5, 120, -304356.3, 452784.13, 0.38],
[5, 200, -32845.69, 227811.4, 0.91],
[7, 30, -498700.19, 748292.98, 0.42],
[7, 45, -648605.63, 648605.63, 0.09],
[7, 60, -283779.42, 383539.29, 0.44],
[7, 120, 26119.84, 365404.17, 1.06],
[7, 200, -97533.48, 284018.96, 0.67],
[9, 30, -624753.92, 630809.67, 0.26],
[9, 45, -450860.13, 492051.18, 0.36],
[9, 60, 416118.56, 212903.85, 1.9],
[9, 120, -173304.79, 320918.2, 0.57],
[9, 200, -104120.46, 290692.52, 0.64],
[15, 30, -252234.99, 446860.35, 0.67],
[15, 45, 144473.25, 268956.45, 1.26],
[15, 60, -206251.45, 429728.97, 0.58],
[15, 120, -153878.36, 197697.89, 0.5],
[15, 200, -46835.93, 235571.52, 0.8],
[25, 30, 296951.36, 277971.02, 1.28],
[25, 45, 480664.06, 234067.24, 1.88],
[25, 60, -303508.68, 478101.74, 0.38],
[25, 120, -82306.63, 157451.49, 0.65],
[25, 200, 83234.35, 106525.88, 1.78]]
最後にpandasデータフレームに変換します。
df2=pd.DataFrame(listA,
columns=['FastSMA','SlowSMA','Profit','MDD','PF'])
df2
FastSMA SlowSMA Profit MDD PF
0 5 30 -610492.60 813337.00 0.40
1 5 45 -447328.18 559521.53 0.38
2 5 60 442512.13 226842.83 1.89
3 5 120 -304356.30 452784.13 0.38
4 5 200 -32845.69 227811.40 0.91
5 7 30 -498700.19 748292.98 0.42
6 7 45 -648605.63 648605.63 0.09
7 7 60 -283779.42 383539.29 0.44
8 7 120 26119.84 365404.17 1.06
9 7 200 -97533.48 284018.96 0.67
10 9 30 -624753.92 630809.67 0.26
11 9 45 -450860.13 492051.18 0.36
12 9 60 416118.56 212903.85 1.90
13 9 120 -173304.79 320918.20 0.57
14 9 200 -104120.46 290692.52 0.64
15 15 30 -252234.99 446860.35 0.67
16 15 45 144473.25 268956.45 1.26
17 15 60 -206251.45 429728.97 0.58
18 15 120 -153878.36 197697.89 0.50
19 15 200 -46835.93 235571.52 0.80
20 25 30 296951.36 277971.02 1.28
21 25 45 480664.06 234067.24 1.88
22 25 60 -303508.68 478101.74 0.38
23 25 120 -82306.63 157451.49 0.65
24 25 200 83234.35 106525.88 1.78
最後に総損益を降順で表示させます。sort_valueメソッドでascending=falseで降順に、Trueで昇順になります。
df2.sort_values('Profit', ascending=False)
FastSMA SlowSMA Profit MDD PF
21 25 45 480664.06 234067.24 1.88
2 5 60 442512.13 226842.83 1.89
12 9 60 416118.56 212903.85 1.90
20 25 30 296951.36 277971.02 1.28
16 15 45 144473.25 268956.45 1.26
24 25 200 83234.35 106525.88 1.78
8 7 120 26119.84 365404.17 1.06
4 5 200 -32845.69 227811.40 0.91
19 15 200 -46835.93 235571.52 0.80
23 25 120 -82306.63 157451.49 0.65
9 7 200 -97533.48 284018.96 0.67
14 9 200 -104120.46 290692.52 0.64
18 15 120 -153878.36 197697.89 0.50
13 9 120 -173304.79 320918.20 0.57
17 15 60 -206251.45 429728.97 0.58
15 15 30 -252234.99 446860.35 0.67
7 7 60 -283779.42 383539.29 0.44
22 25 60 -303508.68 478101.74 0.38
3 5 120 -304356.30 452784.13 0.38
1 5 45 -447328.18 559521.53 0.38
11 9 45 -450860.13 492051.18 0.36
5 7 30 -498700.19 748292.98 0.42
0 5 30 -610492.60 813337.00 0.40
10 9 30 -624753.92 630809.67 0.26
6 7 45 -648605.63 648605.63 0.09
短期が25日、長期が45日の組み合わせが最大で総損益が480664円という結果が得られました。システムトレードでよく議論されるカーブフィッティングという考えがありますが。パラメータをさらに細かくして増やして最適な組み合わせを見たとしても将来もそのパラメータが最適といえる保証はありませんので参考程度にとどめておくのでいいと思います。
コメント