AKAGAMI式 トレードシリーズ botトレーダー養成講座 第1回 PythonによるBitMEXヒストリカルデータ(OHLCV)取得からトレードbotの基本形作成まで
はじめに
あなたの意図した通りにコンピュータが自動的にお金を稼いでくれたら何よりも嬉しいし、それはエキサイティングなことでしょう。
予告で書いた通り、これから全10回に渡って、GAMIZAPと題し、ビットコインをbotプログラムで自動売買し、トレード収益を上げるために必要なノウハウを講座形式でお届けして参ります。
開発・実行環境としてはCloud9を推奨・前提としていますので、もしまだ登録・設定がお済みでない場合は、こちらのnoteを参考にしながらセットアップを完了させてください。
第1回の内容はbot作成経験者の方にとっては至極基本的な内容です。ただし、第2回以降は今回の内容を前提として進めていきます。
土台となる考え方や手の動かし方はこの初回でしっかりと吸収していただきます。せっかくですので、脱落者は生み出したくないです。
そのため、丁寧に分かりやすく説明していきます。
Pythonプログラミングやbot作成のエッセンスの楽しさを少しでも多くの方に味わっていただきたいです。
最後まで読んで手を動かしていただければ、BitMEXで自動売買を行う完結した一つのbotを作ることができます(初めてのサンプルなので収益性はひとまず置いておきましょう。
それらは次回以降のトピックです)。経験者の方も、振り返り・再確認の意味で読んでいただければ幸いです。
目次
・裁量トレードとシステムトレード (Plan)
・BitMEXヒストリカルデータ(OHLCV)取得 (Python) (Do)
・トレードbotの基本形 (Python) (Do)
裁量トレードとシステムトレード (Plan)
まずは「Plan」の何よりの土台となる、裁量トレード・システムトレードの区別について説明します。
この講座はbotトレードを学んでいただくためのものです。以後、基本的にはbotトレード≒システムトレードと考えていただいて差し支えないのですが、では、システムトレードとは一体何でしょう?
システムトレード=相場に向き合う中での「ひらめき」「直感」「嗅覚」に頼ることなく、予め定めた一定のルールに従い機械的に売買を行うトレード
と思っていただければ良いです。ここで大切なのは、「システムトレード=自動売買」というわけではないということです。
「価格が10%下がったら買い(ロング)、価格が10%上がったら売る(ショート)を手動売買でひたすら繰り返す」といった行動も(広義の意味での)立派なシステムトレードになります。
ルールはトレーダーの頭の中にあるものだったり、手書き・Excelのような形式だったりするかもしれません。
これらのルールに忠実に従い、手動売買をこなしていくのは、時間効率の点で生活に占める負荷が非常に高いです。
また、収益を上げやすいルールは人間の本能に逆らうものであったりするため、遵守するのが(本能的に)難しかったります。
ルールを事前に定めているのに、ついついメンタル(欲望・恐怖)が悪い方向に作用して、ルールを無視した闇雲でギャンブルに近いトレードをしてしまう。相場に触れた方であれば一度はそういった経験があるでしょう。
規律に反した行動を避けることが、一貫性を持ったトレード(行動)には重要です。まぐれ当たりではなく、適切な振り返りのできる期待値が高い行動へと落とし込む。
そして、一定の明確なルールがあるならそれをコンピュータの自動処理に任せてしまう。これが狭義の意味でのシステムトレード(=自動売買)です。
今や、IT技術・プログラミング環境・取引所APIの整備により、個人でも簡単に自動売買ができる時代です。
売買ルールがプログラムとして表現できるほどに明快であれば、自分の手でなく、コンピュータに任せるほうが得策です。
その上、プログラムが正しく組まれていれば、誤発注のような人為的なミスを防ぐこともできるため、これもメリットとなります。
続いて、botトレードとは何でしょう?
botという言葉は、個人的な感覚を含めてしまうのですが、自動的にTwitterでツイートを行ったり、チャット・メッセンジャーの応答を自動化したりなど、小回りが利くシンプルなプログラムを指して使われることが多いように思います。
金融の世界から来た言葉というより、IT技術の世界で自動化を行うプログラムを指した言葉であり、暗号通貨のように、IT技術が先行・牽引して成り立つ世界でよく使われる呼称です。
暗号通貨の自動売買では「自動売買システムを構築する」という重厚な表現より、「自動売買用のbotを作る」というようなライト(軽量)な言い回しが多いです。
本講座ではbotトレードという言葉を使っていきます。
そして、システムトレードの対義語が裁量トレードです。
裁量トレード=相場に向き合う中での「ひらめき」「直感」「嗅覚」を重視しながら、その場その場の判断で臨機応変に売買を行うトレード
裁量トレードの場合にも売買ルールはあるかもしれませんが、あくまで目安としての利用になります。
裁量トレードでは自ずと相場に張り付く時間が長くなり、冷静に判断を行うメンタルの強さが求められます。
体力も必要でしょう。また、トレードの記録や振り返りが難しかったりします。
一方で、システムトレード(botトレード)であれば、そういった事態は避けられ、定めた売買ルールを客観的な視点から検証し、改善点を見つけ出し、ブラッシュアップしていくことができます。
また、売買ルールを過去の値動きに当てはめてルールの検証を行う、バックテストという手法も有効になります。
出典:使える売買システム判別法 ─確率統計で考えるシステムトレード入門
さらに、自動売買であれば、時間的な制約から解放されることができます。
仕事中や就寝中もbotが勝手にあなたの代わりにトレードを行ってくれます。
仮に、裁量で平日の仕事明けの3時間しかトレードできない人がいたとします。
ルールが明確であれば、それを24時間稼働のbot化することで、時間比で考えて8倍の売買機会を獲得することができます。
その場合はもちろん、(単純計算で)収益(利回り)が8倍になる可能性だってあります。
寝ポジの「おはぎゃー」ではなく、寝トレードでの「おは893」を繰り出す可能性がそこにはあるのです。
また、人間の手動取引ではスピードの点で追いつかずに真似できないような高速な取引ができるのもbotの強みです。
良いことづくめのように思いますが、ルールが明確になっていなければbot化することはできないため、裁量とシステムを行き来する場面があると思いますし、それは正しいステップです。
裁量でルールを確立し、bot化する。
botでの取引結果・ルールを振り返り、かつ、意識しながら裁量での試行錯誤・ルール遵守に活かしてみる。
どちらか一本ではなく、両方を使い分けてこそ、より優れたトレーダーになることができるでしょう。
BitMEXヒストリカルデータ(OHLCV)取得 (Python) (Do)
では、話は変わり、続いて「Do」を強化していただきます。
まず、Python3を利用し、BitMEXでのビットコイン価格をCryptowatchから取得します。
Cryptowatchは暗号通貨のリアルタイム価格配信・チャート表示サービスで、bitFlyerのチャート表示にも利用されています。
様々な取引所に対応しており、BitMEXも含まれています。
ヒストリカルデータ(過去価格情報)は、
https://api.cryptowat.ch/markets/bitmex/btcusd-perpetual-futures/ohlc?periods=60
を開くことで、ブラウザからも簡単にアクセスすることができます。
要素はそれぞれ
・タイムスタンプ(UNIXタイム)
・始値(OPEN)
・高値(HIGH)
・安値(LOW)
・終値(CLOSE)
・BTC建ての出来高(VOLUME)
・USD建ての出来高(VOLUME)
です。このデータを頭文字を取って、OHLCデータ、もしくは、OHLCVデータと呼ぶことがあります。情報取得はCPU allowanceという考え方で制限されており、毎時8,000,000,000ナノ秒(=8秒)が割り当てられています。costが消費した分、remainingが残りの分を表します。(remainingは https://api.cryptowat.ch/ で低costで確認することができます。) 負荷の高い、レスポンスデータ量の多い頻繁なリクエストは控えるようにしましょう。ただ、トレードbotで利用する範囲では問題にならないことが多いので、そこまで気にする必要はありません。「どうも結果が返ってこないな」と問題に遭遇した際に一つの原因候補として疑ってみる、くらいの気に留め方で良いです。
関連:
Cryptowatch > Documentation > Public Market REST API
bitFlyerの過去チャートを取得するAPI
トレードbotの基本形 (Python) (Do)
引き続き、取得した価格データ・Python3・CCXT・Cloud9を利用してBitMEXで自動売買を行う一つの完結したトレードbotを作成します。読んでいる方の中には、これが初めてのトレードbot作成になる人もいるかと思います。一歩ずつ成功体験を積んでいただきます。ここではbot作りの基礎を理解していただくのが目的ですので、売買ロジックとしては、単純移動平均を用いたシンプルなゴールデンクロス・デッドクロスルールを採用し、発注は全て成行で行うことにします。
前回のnoteであるPython3・CCXT・Cloud9を用いたBitMEX裁量トレード補助ツール作成講座では、タイトルどおり、裁量トレードを補助するためのスクリプトを実装しました。エントリのタイミングを自分で判断し、スクリプトを実行することで、エントリ・利確・損切りを行う処理でした。そこでは一回のトレードを想定しており、トレードの度にスクリプトを実行することが必要でした。
一方、botトレードは、この「エントリ=>利確・損切り」というプロセスを繰り返し行います。指定した売買ロジックに基づき、このサイクルを自動的に行わせます。繰り返しには、前回のnoteで損切り注文を入れる際に用いた「ループ処理と待ち処理」を使います。
#!/usr/bin/python3
import time
#前処理
while True:
#メイン処理
print('test')
time.sleep(5) #一定時間(秒)待つ
これが基本構造です。前処理として、
・最初に一度だけ実行すれば良い処理
・メイン処理で利用するための様々な変数や関数
を記述しておき、その後、無限ループの中でメイン処理を実行させます。そのままではループが必要以上に速く回ってしまうため、一定時間待ちます。上記の例では、実行すると'test'という文字列が5秒ごとに表示されます。終了にはCtrl-cを押します。
続いて、先ほどの価格取得をループに組み込みます。JSON (JavaScript Object Notation)データを標準で扱うことができるrequestsライブラリを使用します。PythonでGETリクエストにてデータを取得するのに非常に人気のあるライブラリです。「sudo pip-3.6 install requests」でインストールを行い、ご利用ください。
#!/usr/bin/python3
import time
import requests
#前処理
CLOSE = 4
while True:
#メイン処理
r = requests.get('https://api.cryptowat.ch/markets/bitmex/btcusd-perpetual-futures/ohlc?periods=60') #価格データの取得
json = r.json()['result']['60'] #結果から1分足データを抜き出し
print(json[-1][CLOSE]) #直近の終値の表示
time.sleep(5) #一定時間(秒)待つ
実行すると、5秒ごとに終値が表示されます。json[0]はBitMEXの無期限契約のマーケットの取得した中で一番古い(500分前の)1分足データを、json[-1]は(まだ終値の確定していない)最新の1分足データを意味します。上の例では最新の終値を表示しています。
続いて、価格データから終値ベースで単純移動平均(SMA)を計算する関数をwhile True:の直前に定義します。
def sma(ohlcv, n):
result = 0
for i in range(n):
result += ohlcv[-i-1][CLOSE] #終値[-1]から終値[-n]までを足し合わせる
result = result / n
return result
例えば期間nに5を与えることで、終値[-1]、終値[-2]、終値[-3]、終値[-4]、終値[-5]を足し合わせて5で割った平均値を算出します。確定した足から遡りたい場合は[-2]から始めます。
def sma(ohlcv, n):
result = 0
for i in range(n):
result += ohlcv[-i-2][CLOSE] #終値[-2]から終値[-n-1]までを足し合わせる
result = result / n
return result
とすると良いでしょう。では、続いてゴールデンクロス・デッドクロスを検知して発注を行う処理を記述します。
※これ以降は、有料パートとなります。bot作成に興味を持っていただけた方は是非とも最後まで読み進めていただけると幸いです。
ここからは有料パートです。まずはご購入いただき、どうもありがとうございます!今後、さらに高度で、実体験を活かした生の情報を発信していくための励みになります。bot作成経験者の方も、ご厚意でのサポートに感謝します。引き続きよろしくお願いします!
では、ゴールデンクロス・デッドクロスの説明に移ります。以後、単純移動平均線をSMA (Simple Moving Average)と表記します。売買ルールは簡単です。
ゴールデンクロス:短期SMAが長期SMAを上抜けたら買い
デッドクロス:短期SMAが長期SMAを下抜けたら売り
短期SMAには期間13、長期26を使うのが一般的です(週足の場合)。ここでは1分足で同様の期間設定を使いましょう。
#!/usr/bin/python3
import time
import requests
#前処理
CLOSE = 4
def sma(ohlcv, n):
result = 0
for i in range(n):
result += ohlcv[-i-2][CLOSE] #終値[-2]から終値[-n-1]までを足し合わせる
result = result / n
return result
while True:
#メイン処理
r = requests.get('https://api.cryptowat.ch/markets/bitmex/btcusd-perpetual-futures/ohlc?periods=60') #価格データの取得
json = r.json()['result']['60'] #結果から1分足データを抜き出し
close = json[-1][CLOSE]
sma13 = sma(json, 13)
sma26 = sma(json, 26)
print('CLOSE: ' + str(close)) #直近の終値の表示
print('SMA13: ' + str(sma13)) #短期SMAの表示
print('SMA26: ' + str(sma26)) #長期SMAの表示
time.sleep(5) #一定時間(秒)待つ
このように書けます。print文の中で、表示が見やすいように文字列を連結しています。文字列連結に際には、str()を忘れないようにしましょう。それでは実行してみましょう。
SMAの小数点以下の桁数が多く、見辛いですね。四捨五入の丸めをround()関数で行ってあげましょう。sma関数のreturn文を次のように書き換えます。
return round(result)
かなり見やすくなりましたね。続いて、ccxtをimportし、API KeyとAPI Secretの設定を行い、成行発注用の関数marketを定義しておきましょう。
#!/usr/bin/python3
import time
import requests
import ccxt
#前処理
CLOSE = 4
LOT = 100
bitmex = ccxt.bitmex({
'apiKey': 'API_KEY',
'secret': 'API_SECRET',
})
bitmex.urls['api'] = bitmex.urls['test'] #Testnetへ接続
def market(side, size):
return bitmex.create_order('BTC/USD',
type='market', side=side, amount=size)
#def sma(ohlcv, n):以降は省略
上のコードはBitMEXのTestnetを前提に書いています。売買LOTは100ドルに設定しています。続いて、保有ポジションを取得する処理をwhile True:ループの前に追記します。
# return round(result) 以前は省略
pos = bitmex.private_get_position()[0]['currentQty']
print('POS: ' + str(pos))
#while True:以降は省略
いったんBitMEXの画面から成行で50ドルの買いを入れておきましょう。上記コードはポジションを保有していない時は0番目の要素が無い、と怒られてしまうので要注意です。
POS: 50が表示されましたね。では、続いてコアロジックの追記に移ります。time.sleep(5)の前に、売買の判断となるif文を記述します。
if sma13 > sma26 and pos < 0:
print('Market Buy!')
market('buy', LOT)
pos = LOT / 2
if sma13 < sma26 and pos > 0:
print('Market Sell!')
market('sell', LOT)
pos = -LOT / 2
time.sleep(5) #一定時間(秒)待つ
ショートポジション(pos < 0):ゴールデンクロス(sma13 > sma26)待ち
ロングポジション(pos > 0):デッドクロス(sma13 < sma26)待ち
であり、成行売買を行うとともに、pos変数を売買に応じて書き換えています。売買LOTを100ドルとしたため、手動で50ドル分の買い、または、売りを事前に入れておいてください。そうすることで、
保有ポジション+50ドル=>100ドル売り=>保有ポジション-50ドル
保有ポジション-50ドル=>100ドル買い=>保有ポジション+50ドル
という形でひたすらにドテンロング・ショートをルールに従って実行することができます。
反映されているか、BitMEXの画面で見てみましょう。
正常に動いてますね!約定価格(参入価格)はTestnetの板の都合上、botの表示のCLOSEとはずれていますが、09:01:43という時刻は完全に一致しています。
最後に、可読性向上のため、時刻を表示するようにしましょう。TIME = 0とfrom datetime import datetimeを冒頭に記述します。
from datetime import datetime
#前処理
TIME = 0
その後、次のprint文の中身を書き換えます。
print('CLOSE: ' + str(close)) #直近の終値の表示
print('SMA13: ' + str(sma13)) #短期SMAの表示
print('SMA26: ' + str(sma26)) #長期SMAの表示
次のように、str()で括られた部分を+で連結してください。
print(str(datetime.fromtimestamp(round(time.time()) + 60 * 60 * 9)) + ' CLOSE: ' + str(close)) #直近の終値の表示
print(str(datetime.fromtimestamp(json[-2][TIME] + 60 * 60 * 9 - 60)) + ' SMA13: ' + str(sma13)) #短期SMAの表示
print(str(datetime.fromtimestamp(json[-2][TIME] + 60 * 60 * 9 - 60)) + ' SMA26: ' + str(sma26)) #長期SMAの表示
time.time()ではUNIXタイムでの現在時刻を取得し、round()関数で整数に変換しています。+ 60 * 60 * 9という形で数字で演算している部分は、Cloud9の場合、標準の時刻がUTC (世界協定時)であるものを、JST (日本時間)に変換するための調整処理です。datetime.fromtimestamp()を使って、UNIXタイムから、人間が読みやすい'%Y-%m-%d %H:%M:%S'という形へと変換しています。
では、締め括りにコードの全文を振り返ってみましょう。ちょうど50行になりました。
#!/usr/bin/python3
import time
import requests
import ccxt
from datetime import datetime
#前処理
TIME = 0
CLOSE = 4
LOT = 100
bitmex = ccxt.bitmex({
'apiKey': 'API_KEY',
'secret': 'API_SECRET',
})
bitmex.urls['api'] = bitmex.urls['test'] #Testnetへ接続
def market(side, size):
return bitmex.create_order('BTC/USD',
type='market', side=side, amount=size)
def sma(ohlcv, n):
result = 0
for i in range(n):
result += ohlcv[-i-2][CLOSE] #終値[-2]から終値[-n-1]までを足し合わせる
result = result / n
return round(result)
pos = bitmex.private_get_position()[0]['currentQty']
print('POS: ' + str(pos))
while True:
#メイン処理
r = requests.get('https://api.cryptowat.ch/markets/bitmex/btcusd-perpetual-futures/ohlc?periods=60') #価格データの取得
json = r.json()['result']['60'] #結果から1分足データを抜き出し
close = json[-1][CLOSE]
sma13 = sma(json, 13)
sma26 = sma(json, 26)
print(str(datetime.fromtimestamp(round(time.time()) + 60 * 60 * 9)) + ' CLOSE: ' + str(close)) #直近の終値の表示
print(str(datetime.fromtimestamp(json[-2][TIME] + 60 * 60 * 9 - 60)) + ' SMA13: ' + str(sma13)) #短期SMAの表示
print(str(datetime.fromtimestamp(json[-2][TIME] + 60 * 60 * 9 - 60)) + ' SMA26: ' + str(sma26)) #長期SMAの表示
if sma13 > sma26 and pos < 0:
print('Market Buy!')
market('buy', LOT)
pos = LOT / 2
if sma13 < sma26 and pos > 0:
print('Market Sell!')
market('sell', LOT)
pos = -LOT / 2
time.sleep(5) #一定時間(秒)待つ
例によって、画像でも貼っておきます。
最後に
今回はシステムトレード(botトレード)の説明と、
・while True:によるループ
・ヒストリカルデータの取得
・単純移動平均の算出
・タイムスタンプの変換
・if文分岐による注文
・time.sleep(second)による待ち処理
を利用したトレードbotの基本形を解説しました。ヒストリカルデータであるOHLCVデータは、バックテストを行ってストラテジーの検証をしたり、テクニカル指標の実装に使えたりするので、重要事項として覚えておいてください。他の取引所のBTC価格取得にも使えるため、今回はCryptowatchからの取得を説明しました。しかし、時折不安定なことがあるため、より安定的な稼働を求めるのであれば、BitMEXのAPIから取得するのがベターかもしれません。
参考:
https://www.bitmex.com/api/udf/history?symbol=XBTUSD&resolution=1&from=1521500502&to=1521506502
https://www.bitmex.com/api/v1/trade/bucketed?symbol=XBTUSD&binSize=1m&partial=true&count=20&reverse=true
次回は私が2016年にbotトレーダーを志したきっかけとなった、生のエピソードをお伝えするとともに、Plan(着想)のプロセスをどのようにDo(実装・稼働)へとつなげていくか、3週間で+100万円の利益を上げた実績のあるbotを題材にして解説していきます。ご期待ください!では、第2回でまたお会いしましょう!最後まで読んでいただき、ありがとうございました!
【宣伝・告知】
AKAGAMI3年半ぶりの新トレード教材。
年間6000万円を稼いだ自動売買手法とは?
「シン・アービトラージ」公開中。