今回もビットコインの自動売買プログラムを Python で実装していきます。
これまではボリンジャーバンドやMACDなどのメジャーなテクニカル指標を使って実装してきました。
が、それだけだとPython を使うことのメリットをあまり感じられなかったという方も多かったと思います。
(別に MT 4とかでもできるやん的な)
そこで今回は、基本的な統計モデルである線形回帰モデルを使った自動売買を実装していきます。
統計や機械学習といった分野は Python の得意分野であり、驚くほど簡単にコードをかけるということをわかってもらえると思います。
この記事の目標
線形回帰トレンドから相場が上昇局面にあると判断された時に、自動でビットコインを購入するコードを書く目次
線形回帰分析とは?
まずはじめに線形回帰分析について簡単におさらいしておきましょう。線形回帰モデルは大学で統計の授業を取ると、とりあえずやらされるやつですね。 上の図は、ある店のアイスクリームの販売数量とその日の気温の関係を表したものです(数字は適当に考えました)。
(軸に単位がなくてすみません。縦軸が(個)、横軸が(℃)だと思ってください)
なんとなく気温が高いほどアイスクリームが売れている傾向にありますね。
この図をずっと眺めていると、このデータの全体的な傾向を単純な直線の式で表したいという願望が生じてきますよね。
(つまり下の図のような直線を引きたいということです) そこで、 アイスクリームの販売数量をy 気温をx としてyとxの関係を
y = ax + b
としてみましょう 。ここでaとbの値を上手く決められれば、非常にありがたいです。
例えば
y = 1.3x – 21
という風に決まれば気温が34℃の日は23個ぐらいアイスクリームが売れるんじゃね
このように目的変数(アイスクリーム販売個数)と説明変数(気温)に直線的な関係を仮定して分析することを線形回帰分析と呼びます。
ちなみに
目的変数yに対し説明変数xは必ずしも一つではなく複数ある場合もありえます(重回帰)。
しかし、あまり話がややこしくなるのもアレなので今回は X が一つだけ(単回帰)の場合しか考えません。
目的変数yに対し説明変数xは必ずしも一つではなく複数ある場合もありえます(重回帰)。
しかし、あまり話がややこしくなるのもアレなので今回は X が一つだけ(単回帰)の場合しか考えません。
先にネタバレをしておくと、
ビットコインの価格をy
時間経過をx
とした線形回帰の式を最終的に立てていきます。
この場合に例えば
時間が経つほど(つまりxが大きくなるほど)ビットコインの価格が上がるんじゃね?(つまりyが大きくなる)
と判断するということです。
ビットコインの価格をy
時間経過をx
とした線形回帰の式を最終的に立てていきます。
この場合に例えば
y = 3x + 40
という予測の式が立てられた場合、時間が経つほど(つまりxが大きくなるほど)ビットコインの価格が上がるんじゃね?(つまりyが大きくなる)
と判断するということです。
単回帰の場合の線型回帰分析のやり方
ここで、実際に線形回帰分析を行う(要はaとbを求める)方法を解説しておきます。最もメジャーな方法は、直線から予測されるyと実際のyの誤差の2乗和を最小化するようなaとbを計算することです(最小二乗法)。
具体的な計算手法は下のサイトが分かりやすかったので興味がある方はぜひ見てみると良いでしょう。
(普通の二変数関数の最小化問題を偏微分を駆使して解く流れです)
https://www.randpy.tokyo/entry/2017/06/16/153435
大学の統計の授業だと、手計算で線形回帰の式を計算させられることもあるかと思いますが、実践ではそんなことをする必要は全くありません。
特に Python を使う場合は非常に簡単に非常に簡単にかけます。
必要なコードはたったのこれだけです。
from sklearn.linear_model import LinearRegression
linearModel = LinearRegression()
linearModel.fit(説明変数のデータ(つまりx),目的変数のデータ(つまりy))
手動で面倒な計算をしなくても、linearModel.fit()と書くだけで勝手に計算を行ってくれます。
回帰係数(さっきでいうa)と切片(さっきでいうb)を取得したい場合はそれぞれ以下のように書けば OK です。
#回帰係数
a = linearModel.coef_
#切片
b = linearModel.intercept_
さてそれでは、この線形回帰分析を仮想通貨投資に応用していきましょう。
線型回帰の投資への応用(線形回帰トレンド)
まず、線形回帰分析を自動売買に応用するというのは何となく僕の頭に浮かんだことですが、調べてみるとテクニカル指標として昔から存在していたようです。線型回帰トレンドというテクニカル指標がちゃんとあるんですね。
(参考)https://www.sevendata.co.jp/shihyou/technical/senkei.html
まさに、ここまで説明した線形回帰を投資に応用した例だと言えます。
今回は最初に何回かビットコイン価格を観察し、
yを仮想通貨価格、 xを時間経過として
y = ax +b
の式をつくりaが正であれば、自動で買い注文を出すという仕様にしてみようと思います。作成するコードの動き
改めてこれから作成するコードの動作を日本語で説明しておきます。今回のコードの動作
①初めは相場のデータがないので、まず何もせずBTC価格をしばらく観測②観測したデータに対して線型回帰分析を行い(=線型回帰トレンドのラインを作成し)相場が強いのか弱いのか判断する
③相場が上昇局面にあると判断したら、買い注文を入れる
プログラムの下準備
まずはプログラムを動かすための下準備です。今回はコインチェックで動かします。
やることはいつもの通り、口座開設とAPIキーの発行、必要ライブラリのインストールの3つです。
これらがまだの人は下の記事の手順に従って2種類の API キーを発行しておいてください。 まだ入っていない人は上記記事で紹介しているライブラリもpipでインストールしておく必要があります。
それに加えて今回はscikit-learnを使うのでこちらもインストールしておきます。
pip3 install scikit-learn
こちらはあってもなくても良いです。
pip3 install matplotlib
コード本体
以下がコードの本体です。import pandas as pd
from sklearn.linear_model import LinearRegression
# import matplotlib.pyplot as plt
from coincheck import market,order,account
import time
access_key=input("APIのアクセスキーを入力してください")
secret_key=input("APIのシークレットキーを入力してください")
#何秒ごとに価格データを確認するか
interval_sec=7
#今回は回帰係数(回帰直線の傾き)が0以上で買い判断とする
target_tangent = 0
#初めの何回か(デフォルトでは25回)は取引をせずに価格データをただ集める
def price_data_collecting(how_many_samples=25):
print("まずは今から"+str(how_many_samples*interval_sec)+"秒間、価格データを収集します。")
price_list=[]
for i in range(how_many_samples):
price_list.append(m1.ticker()["last"])
time.sleep(interval_sec)
print("収集が完了しました。")
return price_list
#coincheckのAPIラッパーインスタンス
m1=market.Market()
o1 = order.Order(secret_key=secret_key,access_key=access_key)
price_data = price_data_collecting()
x = [i for i in range(len(price_data))]
#先程取得したデータをpandasのデータフレームに格納しておく(今後の発展性のため)
#今回の目的を達成するだけなら、リストのまま処理しても良かった
df= pd.DataFrame()
df["x"]=x
df["y"]=price_data
#線形回帰を行う
linearModel = LinearRegression()
linearModel.fit(df[["x"]],df[["y"]])
#回帰係数
coef = linearModel.coef_
#切片
intercept = linearModel.intercept_
#決定係数
score = linearModel.score(df[["x"]],df[["y"]])
if intercept > target_tangent:
print("買い注文を実行します。")
print(o1.buy_btc_jpy(rate=str(df["y"].iloc[-1]),amount=0.005))
else:
print("トレンドが発生していると判断できなかったので、購入注文を行いません。")
print("回帰係数、切片、決定係数の値はそれぞれ以下です。")
print(coef,intercept,score)
#データの散布図を表示する
# plt.scatter(df["x"],df["y"])
# plt.show()
これで他のデータ分析手法と組み合わせるときもやりやすいのではないかと思います(あまり変わらないという説もある)。
forループでコードをまわし、何回も線形回帰トレンドを使って売買を繰り返したい人は、forループ毎にデータの数が増えていかないように注意する必要があるでしょう。
今回はこんな感じで終わりにします。
バグ報告や質問ご要望などは適宜受け付けております。
(返信できない場合もあります。ご了承ください。)
こんばんは。
いつも参考にさせていただいております。
以下文章に関して質問です。
「forループでコードをまわし、何回も線形回帰トレンドを使って売買を繰り返したい人は、forループ毎にデータの数が増えていかないように注意する必要があるでしょう。」
何十時間も稼働させる際にデータ数が増えないようにするためにはどのようにすればよろしいでしょうか?
よろしくお願い申し上げます。
forループの最後でdfの先頭行を削除するのが一つの手です。
df=df.drop(df.index[0])
などと書いておけばOKです。
ありがとうございます。