【BitFlyer】特定日時のトレードID(exec_id)を自動で取得する
# python # 仮想通貨
環境
Python: 3.6.3 ccxt: 1.18.466
やりたかったこと
BitFlyerのAPIでは、日時を指定して約定履歴を取得することができない仕様になっています。 なんでやねんと言いたくなる気持ちは抑えつつ、手動で地道に探すのは大変すぎるので2分探索で指定日時のIDを取得するスクリプトを簡易的ですが書きました。 これで約定履歴を地道に管理せずとも、ある程度簡単にIDは取得できるはず。 (rate limit 部分を書いては見たものの、実際に引っかかってはいないです。他も軽く動かした程度なのでバグがあればコメント等頂けると助かります。)
コード
# get target date's id
import re
import ccxt
from datetime import datetime
from time import sleep
TRADE_PAIR = 'FX_BTC_JPY'
BIT_FLYER = ccxt.bitflyer()
INVALID_ID_MESSAGE = r'.*Execution history is limited to the most recent 31 days..*'
def check_finish(target_date: datetime, trade_date: datetime):
if trade_date is None:
return False
if trade_date > target_date:
return False
delta = trade_date - target_date
if delta.seconds < 60 * 5:
return True
else:
return False
def get_datetime(trade_info) -> datetime:
return datetime.fromtimestamp(int(str(trade_info['timestamp'])[0:10]))
def main():
exist_rate_limit = 480
rate_limit_time = None
target_date = datetime(2019, 5, 28, 0, 0, 0)
trade_info = None
trade_date = None
# bitflyerは1ヶ月前までの履歴しか取得できないので、idがわかれば入れる。
# わからなければなしでok
min_id = None
max_id = None
# ----
if min_id is None:
min_id = 0
while not check_finish(target_date, trade_date):
if exist_rate_limit < 0:
delta = datetime.now() - rate_limit_time
if delta.seconds > 60 * 5:
rate_limit_time = datetime.now()
else:
print(f'wait for rate limits, {delta.seconds} seconds is passed.')
sleep(60 * 5 - delta.seconds)
continue
if max_id is None:
trade_info = BIT_FLYER.fetch_trades(TRADE_PAIR, limit=1)[0]
exist_rate_limit -= 1
trade_date = get_datetime(trade_info)
max_id = int(trade_info['id'])
else:
check_id = int((max_id + min_id) / 2) if trade_info else check_id
try:
trade_info = BIT_FLYER.fetch_trades(TRADE_PAIR, limit=1, params={'before': check_id})[0]
exist_rate_limit -= 1
trade_date = get_datetime(trade_info)
if trade_date > target_date:
max_id = check_id
else:
min_id = check_id
print('-------')
print(f'max_id: {max_id}')
print(f'min_id: {min_id}')
print(f'check_id: {check_id}')
print(f'check_date: {trade_date}')
except ccxt.ExchangeNotAvailable as e:
if re.match(INVALID_ID_MESSAGE, e.args[0]):
# trade履歴が古すぎて参照できない時用の処理
print('-------')
print('order id is too old.')
print(f'check_id: {check_id}')
min_id = check_id
else:
raise ccxt.ExchangeNotAvailable(e)
print(f'------')
print(f'finish binary search. final id is {trade_info["id"]}')
if __name__ == '__main__':
main()