こんにちは、はやたす(@hayatasuuu )です。
第13回目の本記事では、自動売買で必要なロジックを作成していきます。
前回の記事 : #12 Python×ビットコイン自動売買 | クラスを作成してコードを読みやすくしよう!
まずは「どのような自動売買ロジックを組んでいくのか」を紹介します。
そのあと、プログラムでビットコイン価格を取得して、「買い」か「売り」を判定する方法まで解説していきます。
この記事で売買注文するための準備をしていきましょう!
なおコードを作成するにあたり、前回の記事で作成したmain.py
を使っていきます。
自動売買ロジックの確認
今回は以下の条件になったとき、「買い」と「売り」を入れるプログラムを作成します。
- 買い : 観測地点のビットコイン価格が[latex]-2\sigma[/latex]を下回ったとき
- 売り : 観測地点のビットコイン価格が[latex]+2\sigma[/latex]を上回ったとき
ここで登場する[latex]+2\sigma[/latex]と[latex]-2\sigma[/latex]を理解するには、ボリンジャーバンドについて知る必要があります。
とはいえ、ボリンジャーバンドをしっかり理解しようとすると、大学で習う統計学の知識が必要です。
そこで今回は、直感的に理解できるようチャートを確認しながらボリンジャーバンドについて紹介していきます。
ボリンジャーバンドとは?
以下は1時間足のBTC/JPYチャートです。
緑と赤でスティックになっているのが、ビットコインの価格推移です。そして今回は価格推移だけでなく、BB:UpperとBB:Lowerも描かれています。
このBBがボリンジャーバンドです。
同じ色の線で上下セットになっていて、内側からそれぞれ[latex]1\sigma[/latex]、[latex]2\sigma[/latex]、[latex]3\sigma[/latex]と呼びます。
だから最も内側に存在する青い線は[latex]1\sigma[/latex]です。
さらに上側の線を[latex]+1\sigma[/latex]、下側の線を[latex]-1\sigma[/latex]と呼びます。
ボリンジャーバンドが意味するもの
ボリンジャーバンドを使うと、価格が各ライン内におさまる理論的な確率が分かります。
少し分かりにくいので、具体的に見ていきましょう。
[latex]1\sigma[/latex]〜[latex]3\sigma[/latex]ごとに、価格がライン内におさまる確率は以下のとおりです。
- [latex]\pm1\sigma[/latex]内におさまる確率 : 約68.3%
- [latex]\pm2\sigma[/latex]内におさまる確率 : 約95.4%
- [latex]\pm3\sigma[/latex]内におさまる確率 : 約99.7%
つまり以下のグラフで言えば、価格が最も内側の青いラインにおさまる確率は約68.3%ということになります。
ボリンジャーバンドを使うと、値動きの上限と下限をある程度は把握できるようになります。
今回のロジックの狙い
ここまでおさえた上で、今回プログラムで組んでいきたいロジックを振り返ってみます。
- 買い : 観測地点のビットコイン価格が[latex]-2\sigma[/latex]を下回ったとき
- 売り : 観測地点のビットコイン価格が[latex]+2\sigma[/latex]を上回ったとき
要するに、今回使っていきたいのは[latex]\pm2\sigma[/latex]です。
図で表すと、以下の紫の線になります。
ここで描かれている紫線の内側におさまる確率は約95.4%でした。
今回はそれを下回ったときに「買い」を入れて、上回ったときに「売り」を入れます。
図で確認すると、以下のようになります。
つまり、ほとんどの場合は約95.4%の確率で[latex]\pm2\sigma[/latex]におさまるけど、もし例外が発生したら売買をおこなうということです。
これくらいシンプルなロジックだと、プログラムの作成もそこまで難しくありません。
自動売買に必要なロジックの作成
それでは自動売買で必要なロジックを作成していきましょう。
自動売買プログラムの作成にあたり、以下のステップが必要になります。
- STEP① : Pandasをインストールする
- STEP② : 最新価格を取得し続ける
- STEP③ : ボリンジャーバンドを計算する
- STEP④ : 「買い」または「売り」の条件を書く
順を追って解説していきます!
STEP① : Pandasをインストールする
今回は追加でPandasというライブラリをインストールします。
Pandasを使う理由は、自動売買で必要になる移動平均や標準偏差をラクに計算できるからです。
というわけでPandasをインストールするために、以下のコマンドを実行しましょう。
$ pip install pandas
インストールが完了したら、Pandasをインポートします。
import configparser
import pandas as pd
from coincheck import Coincheck
conf = configparser.ConfigParser()
conf.read('config.ini')
ACCEES_KEY = conf['coincheck']['access_key']
SECRET_KEY = conf['coincheck']['secret_key']
coincheck = Coincheck(access_key=ACCEES_KEY, secret_key=SECRET_KEY)
print(coincheck.last)
これでPandasを使う準備が完了しました。
STEP② : 最新価格を取得し続ける
ライブラリのインポートが完了したら、さっそくコードを書いていきます。
まず今回必要になるのは、ビットコインの最新価格を取得するcoincheck.last
です。
そして取得したビットコイン価格を、PandasのDataFrame(データフレーム)に格納していきます。
このDataFrameを活用することで、簡単に[latex]\pm2\sigma[/latex]の計算をおこなえます。
というわけで、DataFrameにビットコインの最新価格を入れるためにコードを編集しましょう。
import configparser
import pandas as pd
from coincheck import Coincheck
conf = configparser.ConfigParser()
conf.read('config.ini')
ACCEES_KEY = conf['coincheck']['access_key']
SECRET_KEY = conf['coincheck']['secret_key']
coincheck = Coincheck(access_key=ACCEES_KEY, secret_key=SECRET_KEY)
df = pd.DataFrame()
df = df.append(
{'price': coincheck.last}, ignore_index=True
)
print(df)
これでmain.py
を実行すると、以下のような出力になるはずです。
price
0 6503280.0
これがprice
というカラムを持ったDataFrameです。
データが1つだと分かりづらいので、for
ループでAPIに5回アクセスして価格を追加しましょう。
このとき各回ごとに1秒間の休止状態を入れます。その理由は、繰り返しアクセスすることで、コインチェックのサーバーに負荷がかかってしまうからです。
Pythonで1秒間の休止状態を入れるには、time
ライブラリをインポートしてtime.sleep(1)
を使います。
import configparser
import time
import pandas as pd
from coincheck import Coincheck
conf = configparser.ConfigParser()
conf.read('config.ini')
ACCEES_KEY = conf['coincheck']['access_key']
SECRET_KEY = conf['coincheck']['secret_key']
coincheck = Coincheck(access_key=ACCEES_KEY, secret_key=SECRET_KEY)
interval = 1
df = pd.DataFrame()
for _ in range(5):
time.sleep(interval)
df = df.append(
{'price': coincheck.last}, ignore_index=True
)
print(df)
ここではinterval
という変数を準備してから、1秒間の休止を設定しました。
上記のコードを実行すると、以下の出力になるはずです。
price
0 6500985.0
1 6500985.0
2 6500985.0
3 6503649.0
4 6503649.0
これで1秒おきにビットコイン価格を取得できるようになりました。
今回は「ビットコインの最新価格を取得し続ける」ので、以下のようにWhile
文を使ったコードに修正します。
import configparser
import time
import pandas as pd
from coincheck import Coincheck
conf = configparser.ConfigParser()
conf.read('config.ini')
ACCEES_KEY = conf['coincheck']['access_key']
SECRET_KEY = conf['coincheck']['secret_key']
coincheck = Coincheck(access_key=ACCEES_KEY, secret_key=SECRET_KEY)
interval = 1
df = pd.DataFrame()
while True:
time.sleep(interval)
df = df.append(
{'price': coincheck.last}, ignore_index=True
)
print(df)
これで最新価格を取得し続けるコードを作成できました!
STEP③ : ボリンジャーバンドを計算する
次にやるべきことは、取得した価格を使ったボリンジャーバンドの計算です。
ボリンジャーバンドを計算するには、「過去どれくらい遡って価格情報を使うのか」を指定する必要があります。
もし1日ごとに価格を取得しているのであれば、「どれくらいの日足を使って計算するのか」ということです。
今回は過去20回の価格情報を使って、ボリンジャーバンドを計算していきたいと思います。
[latex]\pm2\sigma[/latex]の値は、以下の計算式で求められます。
$$\begin{eqnarray} +2\sigma &=& SMA + 2\sigma \\ -2\sigma &=& SMA – 2\sigma \end{eqnarray}$$
SMAというのは、単純に過去20回分の価格平均です。
また、[latex]\sigma[/latex]は標準偏差のことで、要するに価格のバラツキを表します。[latex]\sigma[/latex]が大きければ、バラツキも大きいということですね。
[latex]\sigma[/latex]は数学が分からないと少し難しいですが、Pandasを使えば簡単に計算できます。
それではコードで書いてみましょう。
"""
中略
"""
interval = 1
duration = 20
df = pd.DataFrame()
while True:
time.sleep(interval)
df = df.append(
{'price': coincheck.last}, ignore_index=True
)
if len(df) < duration:
continue
df['SMA'] = df['price'].rolling(window=duration).mean()
df['std'] = df['price'].rolling(window=duration).std()
df['-2σ'] = df['SMA'] - 2*df['std']
df['+2σ'] = df['SMA'] + 2*df['std']
print(df)
これでビットコイン価格の取得と、[latex]\pm2\sigma[/latex]の計算までおこなえます。
ポイントはSMA
とstd
の計算です。
Pandasを使うことで、それぞれ1行のコードで簡単に記述できます。
引数のwindow=duration
では、あらかじめ先に決めておいた変数duration=20
が入ります。
duration
に20を選択している理由は、過去20回分の価格を元に「平均と標準偏差を計算したいから」です。
言い方を換えると、過去20回分の価格データが必要なので、それまでは価格取得に注力しています。
過去20回分の価格を使った平均と標準偏差の計算結果は、df['SMA']
とdf['std']
として新しいカラムに格納しています。
それではコードを実行して、出力を確認してみましょう。
price SMA std -2σ +2σ
0 6559000.0 NaN NaN NaN NaN
1 6562420.0 NaN NaN NaN NaN
2 6562420.0 NaN NaN NaN NaN
"""
中略
"""
17 6560002.0 NaN NaN NaN NaN
18 6560002.0 NaN NaN NaN NaN
19 6560002.0 6561444.75 1771.380814 6.557902e+06 6.564988e+06
このように、20行目では過去の価格データを使った[latex]\pm2\sigma[/latex]の計算ができていますね。
これでボリンジャーバンドを計算するコードも作成できました!
STEP④ : 「買い」または「売り」の条件を書く
あとは計算したボリンジャーバンドを元に、「買い」と「売り」の条件を書くだけです。
「買い」と「売り」の条件を書くには、直近で取得した価格と[latex]\pm2\sigma[/latex]の値を比較する必要があります。
DataFrameで最後の値を参照するにはdf['カラム名']iloc[-1]
を使います。
このことを応用すれば、作成したいコードは以下のようになります。
"""
中略
"""
df = pd.DataFrame()
while True:
time.sleep(interval)
df = df.append(
{'price': coincheck.last}, ignore_index=True
)
if len(df) < duration:
continue
df['SMA'] = df['price'].rolling(window=duration).mean()
df['std'] = df['price'].rolling(window=duration).std()
df['-2σ'] = df['SMA'] - 2*df['std']
df['+2σ'] = df['SMA'] + 2*df['std']
# もし-2σを割ったら買いを入れる
if df['price'].iloc[-1] < df['-2σ'].iloc[-1]:
print('buy!!!')
# もし+2σを超えたら売りを入れる
if df['+2σ'].iloc[-1] < df['price'].iloc[-1]:
print('sell!!!')
これで直近の価格と[latex]\pm2\sigma[/latex]を比較できます。
条件判定の中身はprint()
で補っていますが、次のレクチャーで売買注文のコードを作成します。
今回は、最新価格の取得とボリンジャーバンドの計算、またそれらを比較する部分まで作っておけば大丈夫です!
まとめ : 自動売買に必要なロジックを作成してみよう!
というわけで、この記事では自動売買に必要なロジックを作成しました。
おそらく、想像していたよりも簡単にコードを書けたのではないでしょうか。
次回の記事では、売買の部分もコードを書いていき、自動売買ロジックを完成させたいと思います。
完成に近づいているので、最後まで頑張っていきましょう!