目次
GMOコイン - KLine情報の取得
GMOコインで2021年4月からKLineの取得apiが追加されました。
意外とKLineを配信してくれる取引所は無くて、それ以前は自作していました。
私はスイングトレードでの自動売買を行っているので、あまりスピード感は重要視しておらず、配信してくれたら楽なのにな~と思っていたら、いつの間にやら実装されてました。
というわけで、取り込んでみたのでそのご紹介。
概要
銘柄名・チャート足の種類・検索日は色々なパターンがあるので、KLine情報の取得 | GMOコインからご確認ください。
1分足から取得できますが、API制限上1秒間に1回なので、あまり回転の速いbotには向いていないかもしれないですね。
取得例
一番需要が高いであろうビットコイン/円(レバレッジ取引)で、指定可能な検索日2パターンをそれぞれ試してみます。
検索日YYYYMMDD
検索日を日付まで指定するパターンで、1時間足以下の短いチャート足でのみ指定可能です。
- 銘柄名:BTC_JPY
- 検索日:20210702
- チャート足:1分足
結果は見やすいように加工してます。
2021年7月2日06:00を起点に、2021年7月3日05:59まで1日分の1分足が取得されました。
- 銘柄名:BTC_JPY
- 検索日:20210702
- チャート足:1時間足
2021年7月2日06:00を起点に、2021年7月3日05:59まで1日分の1時間足が取得されました。
ポイント
YYYYMMDDで検索日を指定するとam6:00から1日分のOHLCVが取得される。
検索日YYYY
検索日を年だけ指定するパターンで、4時間足~1ヵ月までの長めのチャート足でのみ指定可能です。
- 銘柄名:BTC_JPY
- 検索日:2019
- チャート足:4時間足
2019年1月1日09:00を起点に、2020年1月1日05:00まで1年分の4時間足が取得されました。
- 銘柄名:BTC_JPY
- 検索日:2019
- チャート足:1ヵ月
2019年1月1日06:00を起点に、2020年1月1日06:00まで1年分の1ヶ月足が取得されました。
ポイント
YYYYで検索日を指定すると1年分のOHLCVが取得される。
自動売買botへの実装
私のbotでは時間足と日足をそれぞれ過去30足分程度は必要だったので、次のように実装しました。
時間足はYYYYMMDD、日足はYYYYの検索日で取得します。
プログラミング独学者なので誤りや改善点が多々あることをお含み置きください
まずは必要な変数を準備。
klines_short = "1hour" # チャート足指定(1時間足) klines_long = "1day" # チャート足指定(日足) timescale_short = 3600 # 更新用秒数指定 timescale_long = 86400 # 更新用秒数指定 price_list_short = [] # 1時間足格納リスト price_list_long = [] # 日足格納リスト
次にGMOコインと接続する関数を設定。
時間足・日足もこの関数1つで対応しています。
len(price_list)の条件分岐を挟んで、初回取得時は単純にappendで追加。
稼働中の更新は差分のみを追加する仕様にしました。
また、response_statusにリターンコードを格納してます。
後で触れますが、日付の関係で正常終了(200)以外が返ってくるときの条件分岐に使用します。
# ローソク足取得関数 def get_klines(interval, date_get, price_list): failed = 0 symbol = "BTC_JPY" interval = str(interval) date = date_get response_status = 0 while True: try: endPoint = 'https://api.coin.z.com/public' path = '/v1/klines?symbol={0}&interval={1}&date={2}'.format(symbol, interval, date) response = requests.get(endPoint + path) response_status = response.status_code response.raise_for_status() try: if "json" in response.headers.get("Content-Type"): data = response.json() if data["status"] == 0: # 更新用 if ( len(price_list) ) > 0: for i in data["data"]: # openTimeはミリ秒なので1000で割っている。 if ( int(int(i['openTime']) / 1000) > price_list[-1]["close_time"] ): price_list.append({ "close_time" : int( int(i['openTime']) / 1000 ), "close_time_dt" : datetime.fromtimestamp(int(i['openTime']) / 1000).strftime('%Y/%m/%d %H:%M'), "open_price" : int(i['open']), "high_price" : int(i['high']), "low_price" : int(i['low']), "close_price" : int(i['close']), "volume" : float(i['volume']) }) else: pass time.sleep(1) return price_list, response_status # 新規取得用 else: for i in data["data"]: price_list.append({ "close_time" : int(int(i['openTime']) / 1000), "close_time_dt" : datetime.fromtimestamp(int(i['openTime']) / 1000).strftime('%Y/%m/%d %H:%M'), "open_price" : int(i['open']), "high_price" : int(i['high']), "low_price" : int(i['low']), "close_price" : int(i['close']), "volume" : float(i['volume']) }) time.sleep(1) return price_list, response_status except: time.sleep(1) pass except: time.sleep(1) return price_list, response_status
上の関数をベースに新規取得時は次の感じ。
# 日付を取得 nt_unix = int(time.time()) # 1日分しか取得できないため、検索日として今日・昨日・一昨日までを準備(UNIX時間) today = datetime.today() yesterday = today - timedelta(days=1) day_before_yesterday = today - timedelta(days=2) # 今日・昨日・一昨日までをYYYYMMDD・YYYY形式に変換 date_get_before_yesterday = datetime.strftime(day_before_yesterday, '%Y%m%d') date_get_yesterday = datetime.strftime(yesterday, '%Y%m%d') date_get_today = datetime.strftime(today, '%Y%m%d') date_get_today_long = datetime.strftime(today, '%Y') # 初回ローソク足を取得 price_list_short, response_status = get_klines(klines_short, date_get_before_yesterday, price_list_short) price_list_short, response_status = get_klines(klines_short, date_get_yesterday, price_list_short) price_list_short, response_status = get_klines(klines_short, date_get_today, price_list_short) price_list_long, response_status = get_klines(klines_long, date_get_today_long, price_list_long)
稼働中の更新は次の感じ。
検索日を今日(YYYYMMDD)で指定している場合、24時の日付が変わったタイミングでエラーになってしまうので、200以外のエラーコードが出たら、日付を昨日に変えて再度取得する仕様にしています。
# 時間足を取得 if nt_unix >= ( price_list_short[-1]["close_time"] + timescale_short ): price_list_short, response_status = get_klines(klines_short, date_get_today, price_list_short) if response_status != 200: yesterday = today - timedelta(days=1) date_get_yesterday = datetime.strftime(yesterday, '%Y%m%d') price_list_short, response_status = get_klines(klines_short, date_get_yesterday, price_list_short) # 日足を取得 if nt_unix > ( price_list_long[-1]["close_time"] + timescale_long ): price_list_long, response_status = get_klines(klines_long, date_get_today_long, price_list_long) if response_status != 200: yesterday = today - timedelta(days=1) date_get_yesterday_long = datetime.strftime(yesterday, '%Y') price_list_long, response_status = get_klines(klines_long, date_get_yesterday_long, price_list_long)
ご参考まで。