Skip to content

Instantly share code, notes, and snippets.

@akkijp
Created August 28, 2016 18:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akkijp/9ff3bfcc2b9b724a5aed0766e729cc63 to your computer and use it in GitHub Desktop.
Save akkijp/9ff3bfcc2b9b724a5aed0766e729cc63 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
from sklearn import tree
from sklearn.svm import SVC
import matplotlib.pyplot as plt
import datetime
#--メール送信用
import os.path
import smtplib
from email import Encoders
from email.Utils import formatdate
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
def sendMail(l_subject,l_body,l_yourGmailAddress,l_yourGmailAddressPassword):
#---Parameters
l_SMTP = "smtp.gmail.com"
l_PORT = 587
l_from_addr=l_yourGmailAddress
l_to_addr = l_yourGmailAddress
#---Create message
l_msg = MIMEMultipart()
l_msg["From"] = l_from_addr
l_msg["To"] = l_to_addr
l_msg["Date"] = formatdate()
l_msg["Subject"] = l_subject
l_body = MIMEText(l_body)
l_msg.attach(l_body)
#---Send mail
l_smtpobj = smtplib.SMTP(l_SMTP, l_PORT)
l_smtpobj.ehlo()
l_smtpobj.starttls()
l_smtpobj.login(l_yourGmailAddress, l_yourGmailAddressPassword)
l_smtpobj.sendmail(l_from_addr, l_to_addr, l_msg.as_string())
l_smtpobj.close()
def importData(l_csvfile):
l_rawData = pd.read_csv(l_csvfile)
l_date = np.array(l_rawData['Date'])
l_data = np.array(l_rawData['Close'])
nanIndex = np.where(np.isnan(l_data))[0].tolist() #---find 'nan'
l_date = np.delete(l_date, nanIndex) # ---Remove 'nan'
l_data = np.delete(l_data, nanIndex) # ---Remove 'nan'
return np.array(l_date[::-1]) ,np.array(l_data[::-1])
def changeData(l_data):
l_newData=[]
for i in range(0, len(l_data) - 1):
l_newData.append((l_data[i] - l_data[i + 1]) / l_data[i + 1])
l_newData.append(0)
return np.array(l_newData)
def trainData(l_data,l_trainStartDay,l_trainDataLength,l_kyoushiDataNumber):
l_train_X = []
l_train_y = []
for i in range(0,l_kyoushiDataNumber):
l_values=l_data[l_trainStartDay+1+i:l_trainStartDay+l_trainDataLength+1+i]
l_train_y.append(int(0 < l_data[l_trainStartDay+i]))
l_train_X.append(l_values)
return np.array(l_train_X), np.array(l_train_y)
def prediction(l_data, l_trainStartDay, l_trainDataLength, l_kyoushiDataNumber, l_predictionTrialTimes):
l_train_X, l_train_y = trainData(l_data, l_trainStartDay, l_trainDataLength, l_kyoushiDataNumber)
l_X=l_data[l_trainStartDay:l_trainStartDay+l_trainDataLength]
l_y = int(0 0.5),l_y
def predictionTommorow(l_data, l_trainDataLength, l_kyoushiDataNumber, l_predictionTrialTimes):
l_trainStartDay=0
l_train_X, l_train_y = trainData(l_data, l_trainStartDay, l_trainDataLength, l_kyoushiDataNumber)
l_X=l_data[l_trainStartDay:l_trainStartDay+l_trainDataLength]
l_y_PredictionTommorow=[]
for i in range(0, l_predictionTrialTimes):
l_clf = tree.DecisionTreeClassifier()
l_clf.fit(l_train_X, l_train_y)
l_y_PredictionTommorow.append(l_clf.predict(l_X.reshape(1, -1))[0])
l_upOrDownRatio = sum(l_y_PredictionTommorow) * 1.0 / len(l_y_PredictionTommorow)
return l_upOrDownRatio
def backTest(l_data, l_btcPriceData, l_trainStartDay, l_trainDataLength, l_kyoushiDataNumber, l_predictionTrialTimes, l_initialFund, l_spread, l_trialDays, l_plotGraphFlag):
l_realValue = []
l_predictionValue = []
l_fund = [l_initialFund]
l_pastDay = 0
l_seitouUp = 0
l_seitouDown = 0
for l_trainStartDay in range(l_trialDays, 0, -1):
y_Prediction, y = prediction(l_data, l_trainStartDay, l_trainDataLength, l_kyoushiDataNumber, l_predictionTrialTimes)
l_realValue.append(y)
l_predictionValue.append(y_Prediction)
l_pastDay += 1
if y_Prediction == y:
if y_Prediction == 1:
l_seitouUp += 1
l_fund.append(l_fund[l_pastDay - 1] * (1 + abs(l_data[l_trainStartDay - 1]) - l_spread))
else:
l_seitouDown += 1
#--l_fund.append(l_fund[l_pastDay - 1] * (1 + abs(l_data[l_trainStartDay - 1]) - l_spread))
l_fund.append(l_fund[l_pastDay - 1])
else:
if y_Prediction == 1:
l_fund.append(l_fund[l_pastDay - 1] * (1 - abs(l_data[l_trainStartDay - 1]) - l_spread))
else:
#---fund.append(fund[pastDay - 1] * (1 - abs(l_data[l_trainStartDay - 1]) - l_spread))
l_fund.append(l_fund[l_pastDay - 1])
l_outputStr = '・トレーニングデータ数: ' + str(l_trainDataLength) +'\n'
l_outputStr += '・教師データ数: ' + str(l_kyoushiDataNumber)+'\n'
l_outputStr += '・バックテスト期間: 過去' + str(l_trialDays) + '日\n'
l_seitouritsuUp = float(l_seitouUp) / sum(l_predictionValue)
l_seitouritsuDown = float(l_seitouDown) / (l_trialDays - sum(l_predictionValue))
# ----Print simulation result
l_outputStr += '・正答率(上昇時): ' + str(round(l_seitouritsuUp * 100,1)) + '%' + '\n'
l_outputStr += '・正答率(下降時): ' + str(round(l_seitouritsuDown * 100,1)) + '%' + '\n'
l_btcPrice = l_btcPriceData[l_trainStartDay-1:l_trainStartDay-1+l_trialDays+1]
l_btcPrice = l_btcPrice[::-1]
l_increasedFundRatio=(l_fund[-1]-l_fund[0])/l_fund[0]
l_increasedBTCPriceRatio=(l_btcPrice[-1]-l_btcPrice[0])/l_btcPrice[0]
l_outputStr += '・資金上昇率: ' + str(round(l_increasedFundRatio*100,1)) + '% (初期資金は$' +str(l_fund[0])+'。最終資金は$' +str(l_fund[-1])+'。)' + '\n'
l_outputStr += '・BTC価格上昇率: ' + str(round(l_increasedBTCPriceRatio*100,1)) + '% (初期BTC価格は$' +str(l_btcPrice[0])+'。最終BTC価格は$' +str(l_btcPrice[-1])+'。)' + '\n'
if(l_plotGraphFlag):
# ----Plot Fund
day1 = range(0, l_trialDays + 1)
fig1, ax1 = plt.subplots()
p1, = ax1.plot(day1, l_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(day1, l_btcPrice, '-or')
ax2.set_ylabel('BTC price[$]')
ax1.legend([p1, p2], ["Fund", "BTC price"], loc="upper left")
plt.show(fig1)
plt.close(1)
return l_seitouritsuUp,l_seitouritsuDown,l_increasedFundRatio,l_increasedBTCPriceRatio,l_outputStr
if __name__ == "__main__":
# --トレーニング用パラメータ
trainDataLength=28 #トレーニングデータ数
kyoushiDataNumber=26 #教師データ数
predictionTrialTimes = 200 #予測のトライアル数(予測結果がばらつくので1回の予測結果を出すために実施する試行回数(取りあえずこのままにしておいてください。)
#--バックテストパラメータ
plotGraphFlag=0 #バックテスト結果の資金グラフをプロットしますか?yes:1。no:0 (スケジューラで自動実行させる時は0にしてください。)
initialFund=100000 #初期資金
spread=0 #---0.006 #取引スプレット(手数料)
trialDays=30*2 #バックテスト期間(日)
#--メール送信パラメータ
sendMailFlag=1 #明日のBTC価格の予想結果をメール送信しますか? yes:1。no:0
yourGmailAddress = "**********@gmail.com" #---送信時のメールアドレス(自分のGメールアドレス。自分自身に送信します。)
yourGmailAddressPassword = "**********" #---Gメールのログインパスワード
outputStr = '-----------------------------------------' + '\n'
outputStr += 'BTC価格データダウンロード' + '\n'
outputStr += '-----------------------------------------' + '\n'
#--- 日本時間の 09:10 a.m.過ぎにCoindeskのデータが更新されるので、その辺りで実行してください。
todayStr = str(datetime.datetime.today())[0:10]
tommorrowStr = str(datetime.datetime.today() + datetime.timedelta(1))[0:10]
csvfile = 'http://api.coindesk.com/v1/bpi/historical/close.csv?start=2010-07-18&end=' + todayStr + '&index=USD'
outputStr += '今日は' +todayStr +'です。\n'
outputStr += 'Coindesk(http://www.coindesk.com/price/)からBTC価格データをダウンロードします。' + '\n'
outputStr += '(URL: ' + csvfile + ')\n'
dateData, btcPriceData = importData(csvfile)
data = changeData(btcPriceData)
outputStr += '取得データファイル中にある最後の日付は' + dateData[0] + 'でその時のBTCクローズ価格は$' + str(btcPriceData[0]) + 'です。\n'
outputStr += '-----------------------------------------' + '\n'
outputStr += 'バックテストの実施' + '\n'
outputStr += '-----------------------------------------' + '\n'
outputStr += '※過去のデータから資金上昇率を算出します。上昇シグナル時に現物で買い。下降シグナル時は何もしません。ポジションは1日ごとに決裁します。' + '\n'
trainStartDay=1
seitouritsuUp, seitouritsuDown,increasedFundRatio,increasedBTCPriceRatio, simOutputStr=backTest(data, btcPriceData, trainStartDay, trainDataLength, kyoushiDataNumber, predictionTrialTimes, initialFund, spread, trialDays, plotGraphFlag)
outputStr +=simOutputStr
outputStr += '-----------------------------------------' + '\n'
outputStr += '明日のBTC価格予想' + '\n'
outputStr += '-----------------------------------------' + '\n'
outputStr += '※' + dateData[0] + 'までのデータから' + todayStr + 'のBTCクローズ価格を予測します。' + '\n'
upOrDownRatio=predictionTommorow(data, trainDataLength, kyoushiDataNumber, predictionTrialTimes)
if upOrDownRatio>0.5:
outputStr += '\n明日のBTC価格は'+ str(round(upOrDownRatio*100,1)) +'%の確率で上昇します。' + '\n'
else:
outputStr += '\n明日のBTC価格は' + str(round((1-upOrDownRatio) * 100,1)) + '%の確率で下落します。' + '\n'
print(outputStr)
if(sendMailFlag):
subject='明日のBTC価格予想'
body=outputStr
sendMail(subject, body,yourGmailAddress,yourGmailAddressPassword)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment