Last active
December 7, 2016 11:18
-
-
Save darden1/15e4924fc12ff4e32f0ec51436a07dd7 to your computer and use it in GitHub Desktop.
BackTestOptimization.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import poloniex | |
import time | |
import datetime | |
from sklearn import tree | |
import numpy as np | |
import matplotlib.pyplot as plt | |
from mpl_toolkits.mplot3d import Axes3D | |
import pickle | |
def main(): | |
# --トレーニング用パラメータ | |
#トレーニングデータ数 | |
theNumberOfTrainData_Min=20 | |
theNumberOfTrainData_Max = 40 | |
# トレーニングデータと教師データのセット数 | |
theNumberOfTrainAndKyoushiSet_Min=20 | |
theNumberOfTrainAndKyoushiSet_Max = 40 | |
studyTrialTimes = 200 #予測のトライアル数(予測結果がばらつくので1回の予測結果を出すために実施する試行回数(取りあえずこのままにしておいてください。) | |
# --バックテストパラメータ | |
plotGraphFlag = 0 # バックテスト結果の資金グラフをプロットしますか?yes:1。no:0 (最適化時実行は0にしてください。) | |
initialFund = 1000 # 初期資金 | |
spread = 0 # 取引スプレット(手数料) | |
backTestDays = 30*2 # バックテスト期間(日) | |
dateBTC, dataBTC = getDataPoloniex() | |
dateBTC.reverse() | |
dataBTC.reverse() | |
data = changeData(dataBTC) | |
X = np.arange(theNumberOfTrainData_Min,theNumberOfTrainData_Max+1,1) | |
Y = np.arange(theNumberOfTrainAndKyoushiSet_Min,theNumberOfTrainAndKyoushiSet_Max+1,1) | |
X, Y = np.meshgrid(X, Y) | |
Z = np.zeros([len(Y[:]), len(X[0])]) | |
for i in range(0, len(X[0])): | |
for j in range(0, len(Y[:])): | |
theNumberOfTrainData=X[j][i] | |
theNumberOfTrainAndKyoushiSet=Y[j][i] | |
seitouritsuUp, seitouritsuDown, increasedFundRatio, increasedBTCPriceRatio, simOutputStr = backTest(data, dateBTC, dataBTC, theNumberOfTrainData,theNumberOfTrainAndKyoushiSet, studyTrialTimes, initialFund, spread, backTestDays, plotGraphFlag) | |
Z[j][i]=increasedFundRatio | |
print(simOutputStr) | |
print('---------------------------------------') | |
maxZRow = np.where(Z == np.max(Z))[0][0] | |
maxZCol = np.where(Z == np.max(Z))[1][0] | |
theNumberOfTrainData_Opt=X[maxZRow][maxZCol] | |
theNumberOfTrainAndKyoushiSet_Opt=Y[maxZRow][maxZCol] | |
theDateOpt=datetime.datetime.now() | |
backTestOptResult={"X":X,"Y":Y,"Z":Z,"theNumberOfTrainData_Opt":theNumberOfTrainData_Opt,"theNumberOfTrainAndKyoushiSet_Opt":theNumberOfTrainAndKyoushiSet_Opt,"theDateOpt":theDateOpt} | |
with open('backTestOptResult.pickle', mode='wb') as f: | |
pickle.dump(backTestOptResult, f) | |
print('最適解(資金上昇率): ' + str(round(Z[maxZRow][maxZCol]*100,1)) + '%') | |
print('最適トレーニングデータ数: ' + str(theNumberOfTrainData_Opt)) | |
print('最適トレーニングデータと教師データのセット数: ' + str(theNumberOfTrainAndKyoushiSet_Opt)) | |
fig = plt.figure() | |
ax = Axes3D(fig) | |
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.cm.hot) | |
ax.contourf(X, Y, Z, zdir='z', offset=-2, cmap=plt.cm.hot) | |
ax.set_xlabel('theNumberOfTrainData') | |
ax.set_ylabel('theNumberOfTrainAndKyoushiSet') | |
ax.set_zlabel('increasedFundRatio') | |
plt.show() | |
def backTest(data, dateBTC, dataBTC, theNumberOfTrainData,theNumberOfTrainAndKyoushiSet, studyTrialTimes, initialFund, spread, backTestDays, plotGraphFlag): | |
realValue = [] | |
predictionValue = [] | |
fund = [initialFund] | |
pastDay = 0 | |
seitouUp = 0 | |
seitouDown = 0 | |
for trainStartDay in range(backTestDays, 0, -1): | |
y_Prediction, y = predictionTommorowBTCForBackTest(data, trainStartDay, theNumberOfTrainData, theNumberOfTrainAndKyoushiSet, studyTrialTimes) | |
realValue.append(y) | |
predictionValue.append(y_Prediction) | |
pastDay += 1 | |
if y_Prediction == y: | |
if y_Prediction == 1: | |
seitouUp += 1 | |
fund.append(fund[pastDay - 1] * (1 + abs(data[trainStartDay - 1]) - spread)) | |
else: | |
seitouDown += 1 | |
#---fund.append(fund[pastDay - 1] * (1 + abs(data[trainStartDay - 1]) - spread)) | |
fund.append(fund[pastDay - 1]) | |
else: | |
if y_Prediction == 1: | |
fund.append(fund[pastDay - 1] * (1 - abs(data[trainStartDay - 1]) - spread)) | |
else: | |
#---fund.append(fund[pastDay - 1] * (1 - abs(data[trainStartDay - 1]) - spread)) | |
fund.append(fund[pastDay - 1]) | |
# ----バックテスト結果出力 | |
outputStr = '・トレーニングデータ数: ' + str(theNumberOfTrainData) +'\n' | |
outputStr += '・トレーニングデータと教師データのセット数: ' + str(theNumberOfTrainAndKyoushiSet)+'\n' | |
outputStr += '・バックテスト期間: 過去' + str(backTestDays) + '日\n' | |
seitouritsuUp = float(seitouUp) / sum(predictionValue) | |
seitouritsuDown = float(seitouDown) / (backTestDays - sum(predictionValue)) | |
outputStr += '・正答率(上昇時): ' + str(round(seitouritsuUp * 100,1)) + '%' + '\n' | |
outputStr += '・正答率(下降時): ' + str(round(seitouritsuDown * 100,1)) + '%' + '\n' | |
trainStartDay=0 | |
dataBTCOnBackTest = dataBTC[trainStartDay:trainStartDay+backTestDays+1] | |
dataBTCOnBackTest.reverse() | |
increasedFundRatio=(fund[-1]-fund[0])/fund[0] | |
increasedBTCPriceRatio=(dataBTCOnBackTest[-1]-dataBTCOnBackTest[0])/dataBTCOnBackTest[0] | |
outputStr += '・資金上昇率: ' + str(round(increasedFundRatio*100,1)) + '% (初期資金は$' +str(fund[0])+'。最終資金は$' +str(fund[-1])+'。)' + '\n' | |
outputStr += '・BTC価格上昇率: ' + str(round(increasedBTCPriceRatio*100,1)) + '% (初期BTC価格は$' +str(dataBTCOnBackTest[0])+'。最終BTC価格は$' +str(dataBTCOnBackTest[-1])+'。)' + '\n' | |
# ----資金推移グラフ | |
if(plotGraphFlag): | |
# ----Plot Fund | |
dateBTCOnBackTest = dateBTC[trainStartDay:trainStartDay + backTestDays + 1] | |
dateBTCOnBackTest.reverse() | |
fig1, ax1 = plt.subplots() | |
p1, = ax1.plot(dateBTCOnBackTest, fund, '-ob') | |
ax1.set_title("Simulation with past data") | |
ax1.set_xlabel("Day") | |
ax1.set_ylabel("Fund[$]") | |
plt.grid(fig1) | |
# ----Plot BTC Price | |
ax2 = ax1.twinx() | |
p2, = ax2.plot(dateBTCOnBackTest, dataBTCOnBackTest, '-or') | |
ax2.set_ylabel('BTC price[$]') | |
ax1.legend([p1, p2], ["Fund", "BTC price"], loc="upper left") | |
plt.show(fig1) | |
return seitouritsuUp, seitouritsuDown, increasedFundRatio, increasedBTCPriceRatio, outputStr | |
def getDataPoloniex(): | |
polo = poloniex.Poloniex() | |
polo.timeout = 2 | |
chartUSDT_BTC = polo.returnChartData('USDT_BTC', period=polo.DAY, start=time.time() - polo.DAY * 500, end=time.time()) | |
tmpDate = [chartUSDT_BTC[i]['date'] for i in range(len(chartUSDT_BTC))] | |
date = [datetime.datetime.fromtimestamp(tmpDate[i]).date() for i in range(len(tmpDate))] | |
data = [float(chartUSDT_BTC[i]['open']) for i in range(len(chartUSDT_BTC))] | |
return date ,data | |
def changeData(data): | |
newData=[] | |
for i in range(0, len(data) - 1): | |
newData.append(float(data[i] - data[i + 1]) / data[i + 1]) | |
newData.append(0) | |
return newData | |
def preparationTrainAndKyoushiSets(data,trainStartDay,theNumberOfTrainData,theNumberOfTrainAndKyoushiSet): | |
train_X = [] | |
train_y = [] | |
for i in range(0,theNumberOfTrainAndKyoushiSet): | |
train_X.append(data[trainStartDay+1+i:trainStartDay+theNumberOfTrainData+1+i]) | |
train_y.append([int(0 < data[trainStartDay+i])]) | |
return train_X, train_y | |
def predictionTommorowBTCForBackTest(data, trainStartDay, theNumberOfTrainData,theNumberOfTrainAndKyoushiSet, studyTrialTimes): | |
train_X, train_y = preparationTrainAndKyoushiSets(data, trainStartDay, theNumberOfTrainData,theNumberOfTrainAndKyoushiSet) | |
X=data[trainStartDay:trainStartDay+theNumberOfTrainData] | |
y = int(0 < data[trainStartDay-1]) | |
y_PredictionTommorow=[] | |
for i in range(0, theNumberOfTrainAndKyoushiSet): | |
clf = tree.DecisionTreeClassifier() | |
clf.fit(train_X, train_y) | |
y_PredictionTommorow.append(clf.predict([X])[0]) | |
upOrDownRatio = sum(y_PredictionTommorow) * 1.0 / len(y_PredictionTommorow) | |
return int(upOrDownRatio>0.5),y | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment