環境
Python: 3.6.3
ccxt: 1.18.466
やりたかったこと
BitFlyerのAPIでは、日時を指定して約定履歴を取得することができない仕様になっています。
なんでやねんと言いたくなる気持ちは抑えつつ、手動で地道に探すのは大変すぎるので2分探索で指定日時のIDを取得するスクリプトを簡易的ですが書きました。
これで約定履歴を地道に管理せずとも、ある程度簡単にIDは取得できるはず。
(rate limit 部分を書いては見たものの、実際に引っかかってはいないです。他も軽く動かした程度なのでバグがあればコメント等頂けると助かります。)
コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# 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() |