Pythonでアービトラージ自動売買に挑戦⑤~発注条件検討~
前回はこちら→bitFlyerでアービトラージ自動売買に挑戦④
Pythonを使ってビットコインのアービトラージに挑戦する記録の第5弾です。
前回は、取引所間の差額をcsv出力する処理に挑戦しました。その出力結果をもとにグラフ化してみたのがこちらになります。
2000円以上差額が開いているときもありますね。取引所によっては手数料で1000円近く取られてしまうので、最低2000円は開いてほしいところです。
(手数料0.001BTCだとすると90万円x0.001=900円)
今回は、アービトラージの成功率を上げるために、差額以外に発注条件を設けてその条件が成立したときのみ発注をできるような条件判別処理を入れたいと思います。今回設けた条件が下記の3つです。
①取引所間の差額が○円以上(実装済)
②直近○時間の値幅(高値-安値)が○円以内
③下げ局面でないこと
早速ですが作成したソースコードを下記に紹介します。
import ccxt
import time
import datetime
import csv
from pprint import pprint
import requests
import json
max = 500 #cryptowatchで取得できる足の数
before = 5 #さかのぼる足の数
periods = 1800 #3600秒=1時間足
range_th = 15000 #値動きの最大幅
range_flag = 0 #値動きの最大幅が許容内の時のフラグ
arbi_th = 2000 #裁定取引開始差額
arbi_flag = 0 #裁定取引開始差額の時のフラグ
sage_flag = 0 #下げ局面でないことを確認する時のフラグ
delay = 10 #指定秒数待って繰り返し
def get_price(min,i):
data = response.json()
last_data = data["result"][str(min)][i]
return { "close_time" : last_data[0],
"open_price" : last_data[1],
"high_price" : last_data[2],
"low_price" : last_data[3],
"close_price":last_data[4] }
def check_candle( data ):
if data["close_price"]-data["open_price"] > 0 : return True
else : return False
def check_ascend( data,last_data ):
if data["open_price"] > last_data["open_price"] and data["close_price"] > last_data["close_price"]:
return True
else:
return False
while 1:
dt = datetime.datetime.now()
print(dt)
exchange_list = ['bitflyer', 'coincheck', 'bitbank', 'liquid', 'btcbox']
ask_exchange = ''
ask_price = 99999999
bid_exchange = ''
bid_price = 0
for exchange_id in exchange_list:
exchange = eval('ccxt.' + exchange_id + '()')
orderbook = exchange.fetch_order_book ('BTC/JPY')
bid = orderbook['bids'][0][0] if len (orderbook['bids']) > 0 else None
ask = orderbook['asks'][0][0] if len (orderbook['asks']) > 0 else None
if ask < ask_price:
ask_exchange = exchange_id
ask_price = ask
if bid > bid_price:
bid_exchange = exchange_id
bid_price = bid
#アービトラージ計算結果を出力
arbi = bid_price - ask_price
print (ask_exchange, 'で', ask_price, '円で買って')
print (bid_exchange, 'で', bid_price, '円で売れば')
print (arbi, '円の利益!')
if arbi > arbi_th:
arbi_flag = 1
print('①',arbi_th,'円以上の差額なのでフラグ立てます')
else:
arbi_flag = 0
print('①',arbi_th,'円以下の差額なのでフラグ立てません')
#②過去のボラティリティを確認
response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcjpy/ohlc",params = { "periods" : periods })
json_data = response.json()
i = max - before
max_range = 0
while i in range(max):
data = get_price(periods, i)
price_range = data["high_price"] - data["low_price"]
print((max-i)*periods/3600,'時間前の値幅',price_range)
if max_range < price_range:
max_range = price_range
i = i+1
print('直近',before*periods/3600,'時間の値幅は',max_range,'円です')
if max_range < range_th:
range_flag = 1
print('②',range_th,'円以内の値幅なのでフラグ立てます')
else:
range_flag = 0
print('②',range_th,'円以上の値幅なのでフラグ立てません')
#③売り局面でないことを確認
data1 = check_candle(get_price(periods, max-3))
data2 = check_candle(get_price(periods, max-2))
data3 = check_candle(get_price(periods, max-1))
data4 = check_ascend(get_price(periods, max-2),get_price(periods, max-3))
data5 = check_ascend(get_price(periods, max-1),get_price(periods, max-2))
if data1 or data2 or data3 or data4 or data5:
sage_flag = 1
print('③','下げ局面ではないのでフラグ立てます')
else:
sage_flag = 0
print('③','下げ局面なのでフラグ立てません')
if arbi_flag * range_flag * sage_flag == 1:
print('発注条件成立しました\n')
else:
print('発注条件成立せず\n')
time.sleep(delay)
①は実装済なので、②から説明します。アービトラージをする上で差額が大きくても相場がそれ以上に大きく動いてしまうと高く買って安く売ってしまう可能性も大きくなると思うので、指定時間内の値動きが一定値に収まっているかをチェックします。該当箇所は下記の部分です。
cryptowatchにアクセスして過去の価格情報を取得し、JSONデータとして保存します。そして各種パラメータは調整がしやすいように変数として定義しました。指定時間中の値幅が指定値に収まっていればrange_flagを1にします。
次に③「下げ局面でないこと」 のブロックは下記の部分になります。
ここではcheck_candle関数とcheck_ascend関数を別で定義して呼び出しています。
check_candleでは陽線か陰線か(始値と終値の大小を比較)を確認しています。陽線ならTrueを返します。check_ascendでは前後の足の始値の増減、終値の増減をそれぞれ確認しています。両者とも増加していればTrueを返します。
簡易なロジックではありますが、直近3本の足がいずれも陰線、かつ始値、終値が前の足よりも減少していれば売り局面と今回は判断することにしました。売り局面でなければsage_flagを1にします。
最後に、取引所間差額が指定値以上の場合に1とするarbi_flagと上記②,③のrange_flag,sage_flagの3つのフラグが全て1であればアービトラージの発注条件成立としました。出力結果はこちらのようになります。
発注を含めた完全自動化はまだ先になりそうですが、しばらくはこちらのプログラムを発注サインとして活用して手動アービトラージに挑戦しようと思います。
ディスカッション
コメント一覧
まだ、コメントがありません