Pythonを使って詳細なバックテストエンジンを作成


tradingviewのストラテジーバックテスターは素晴らしく、少ないコードで簡単にバックテストプログラムを
書くことが出来て、あらゆるデータを提供してくれます。

ただ、システムを作成してあらゆるパラメータ値を試して損益の統計量を取り、そのシステムの堅牢性
や優位性を測定する機能はありません。
これはMT4やトレードステーションにはウォークフォワードオプティマイザーがあるようですが、
tradingviewには無いのでPythonのseleniumを使って実装しました。

seleniumのchrome.driverを使うとwebブラウザを自動操作できるのでdriverでチャート画面を開き、
設定画面から仕掛けのパラメータ値の最小値から最大値まで自動入力し、損益や勝率、平均利益などの数値をcssセレクタで
スクレイピングして取得していきます。

取得したデータはpandasやnumpyで整形し、平均値や標準偏差などのデータを表示しました。
試しにインサイドデイストラテジーを作成し、インサイドデイの発生したバーの数を1~3、終値が1~3
本前の高値より高ければロング、低ければショートのロジックでバックテストをした結果、全体で利益がでたのは
全てのパラメータセットで22%しかありませんでした。
一見良さそうなパラメータで最適化しても、少しパラメータが変わっただけで使い物にならなくなるという
ガラクタのシステムだったということがよくわかります。

良いシステムとはパラメータが変わっても利益を出せる堅牢性が備わっているシステムですね。

戦略名= インサイド・デイ
↓ 行= インサイド・デイ = 1 ~ 3
→ 列= バーバック = 1 ~ 3
1 2 3
1 158420 130880 -87310
2 -4820 -39700 -12580
3 -22030 -26490 -14650

利益率= 22 %
平均勝率= 38 %
平均AVGトレード= -960
平均値= 9080
中央値= -14650
標準偏差= 76206
--------------------
最高値= 158420
インサイド・デイ = 1
バーバック = 1

import numpy as np
import pandas as pd
from mpl_toolkits.mplot3d import axes3d
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import cm
import csv
import matplotlib as mpl
import matplotlib.pyplot as plt

stType = int(input('パラメータ数を入力 :'))

if stType == 1:
with open(CSVファイル\パラメータ1.csv",encoding='utf8') as f:
reader = csv.reader(f)
l = [row for row in reader]

p = l.pop(0)

#平均勝率と平均AVGトレードを求める式
l_len = len(l)
jlist = []
klist = []
for j in range(l_len):
wins = int(l[j].pop(2))
avgW = int(l[j].pop(2))
jlist.append(wins)
klist.append(avgW)
j_avg = round(sum(jlist)/l_len)
k_avg = round(sum(klist)/l_len)

param = p[1]
stname = p[0]
print("\n","戦略名=",stname)

A = np.array(l, dtype=np.int)
B = A.transpose()
y = B[0]
x = B[1]
df =pd.DataFrame(x,index=y,columns=[param])

print("\n",df)
ave = np.mean(df)
mid = np.median(df)
std = np.std(df)

count = (df.count()).sum()
success = (x>0).sum()
result = int(success/count*100)
print("")
print('利益率=',result,'%')
print('平均勝率=',j_avg,'%')
print('平均AVGトレード=',k_avg)
print('平均値=',int(ave))
print('中央値=',int(mid))
print('標準偏差=',int(std))
print("--------------------")

maxlist = []
A = (df.max())
idM = int(df.idxmax())
B = (int(A))

maxlist.append(B)
maxlist.append(idM)
print("最高値=",int(A))
print(param,"=",int(maxlist[1]))

plt.figure(figsize=(12,6))
plt.rcParams["figure.subplot.bottom"] = 0.2
plt.style.use('seaborn')
plt.plot(y,x,'-')
plt.plot(y,x,'ro')
plt.xlabel(param,fontname="MS Gothic")
plt.ylabel('損益',fontname="MS Gothic")
plt.title(stname,fontname="MS Gothic")
plt.show()

CV = open(CSVファイル\ウォークフォワード1.csv','a',newline='',encoding='utf8')
csvWriter = csv.writer(CV)
csvWriter.writerow(maxlist)
CV.close()

elif stType == 2:
with open(CSVファイル\パラメータ2.csv",encoding='utf8') as f:
reader = csv.reader(f)
l = [row for row in reader]

p2 = l.pop(0)

#平均勝率と平均AVGトレードを求める式
l_len = len(l)
jlist = []
klist = []
for j in range(l_len):
wins = int(l[j].pop(3))
avgW = int(l[j].pop(3))
jlist.append(wins)
klist.append(avgW)
j_avg = round(sum(jlist)/l_len)
k_avg = round(sum(klist)/l_len)

stname = p2[0]
param1 = p2[1]
param2 = p2[2]
print("\n","戦略名=",stname)

A = np.array(l, dtype=np.int)
B = A.transpose()

y = B[0]
x = B[1]
z = B[2]
Ymax = y.max()
Ymin = y.min()
Ylen1 = np.unique(y)
Ydata = len(Ylen1)

Xmax = x.max()
Xmin = x.min()
Xlen1 = np.unique(x)
Xdata = len(Xlen1)
print("")
print("↓ 行=",param1,'=',Ymin,'~',Ymax)
print("→ 列=",param2,'=',Xmin,'~',Xmax)

xx = np.linspace(Xmin,Xmax,Xdata)
yy = np.linspace(Ymin,Ymax,Ydata)

z2 = z.reshape(Ydata,Xdata)
df =pd.DataFrame(z2,index=Ylen1,columns=Xlen1)
print(df)

count = (df.count()).sum()
success = (z>0).sum()
result = int(success/count*100)
print("")
print('利益率=',result,'%')
print('平均勝率=',j_avg,'%')
print('平均AVGトレード=',k_avg)

ave = np.mean(z)
mid = np.median(z)
std = np.std(z)
print('平均値=',int(ave))
print('中央値=',int(mid))
print('標準偏差=',int(std))
print("--------------------")
maxlist2 = []
A = (df.max())
B = (A.max())
C = (A.idxmax())
idm = (df[C].idxmax())

maxlist2.append(B)
maxlist2.append(idm)
maxlist2.append(C)
print("最高値=",B)
print(param1,"=",idm)
print(param2,"=",C)

xx,yy = np.meshgrid(xx,yy)
zs = np.array(z)
zz = zs.reshape((Ydata,Xdata))


zero = np.linspace(0,0,num=count)
zero_z = zero.reshape((Ydata,Xdata))

fig = plt.figure(figsize=(12,6))
ax = fig.gca(projection='3d')

ax.plot_wireframe(xx,yy,zero_z, color = "w", alpha = 0.0)
surf = ax.plot_surface(xx,yy,zz,cstride=1,rstride=1,cmap='coolwarm',edgecolor="k",alpha=0.9)
ax.set_ylabel(param1,fontname="MS Gothic")
ax.set_xlabel(param2,fontname="MS Gothic")
ax.set_zlabel('損益',fontname="MS Gothic")
ax.set_title(stname,fontname="MS Gothic")
fig.colorbar(surf, shrink=1, aspect=6)
plt.show()

CV = open(CSVファイル\ウォークフォワード2.csv','a',newline='',encoding='utf8')
csvWriter = csv.writer(CV)
csvWriter.writerow(maxlist2)
CV.close()
else:
print('パラメータ数が正しくありません')
Chart PatternsTechnical IndicatorsTrend Analysis

Penafian