[Python Websocket JSON-RPC OHLCV] bitFlyer の約定情報からオレオレOHLCデータを作成する

関連note

最新版


やったこと

bitFlyer の Realtime API(JSON-RPC over websocket)で配信される約定情報から、オレオレOHLCデータを作成。


動機

Cryptowatch と TradingView の OHLCデータに結構誤差があり、bot の動作に影響したため。オレオレOHLCで誤差が少なくなれば嬉しいなと思い。


コード

たぶんもっと上手いやり方あると思う。

import json
import websocket
from datetime import datetime, timedelta
import dateutil.parser
from time import sleep
from logging import getLogger,INFO,StreamHandler
logger = getLogger(__name__)
handler = StreamHandler()
handler.setLevel(INFO)
logger.setLevel(INFO)
logger.addHandler(handler)

def get_exec_date(d):
  exec_date = d["exec_date"].replace('T', ' ')[:-1]
  return dateutil.parser(exec_date) + timedelta(hours=9)

"""
This program calls Bitflyer real time API JSON-RPC2.0 over Websocket
"""
class RealtimeAPI(object):
  def __init__(self, url, channel):
    self.url = url
    self.channel = channel
    self.ohlc = {}
    self.ohlc["date"] = ""

    #Define Websocket
    self.ws = websocket.WebSocketApp(self.url, header=None, on_open=self.on_open, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close)
    websocket.enableTrace(True)

  def run(self):
    #ws has loop. To break this press ctrl + c to occur Keyboard Interruption Exception.
    self.ws.run_forever()
    logger.info('Web Socket process ended.')

  """
  Below are callback functions of websocket.
  """
  # when we get message
  def on_message(self, ws, message):
    output = json.loads(message)['params']
    now = datetime.now()
    for d in output["message"]:
      exec_date = get_exec_date(d)
      # 約定データが現在時刻より過去の場合は捨てる
      if(datetime(exec_date.year, exec_date.month, exec_date.day, exec_date.hour, exec_date.minute) < datetime(now.year, now.month, now.day, now.hour, now.minute)):
        continue

      price = float(d["price"])
      # OHLC データの時刻が更新された場合
      if(self.ohlc["date"] != exec_date.strftime("%Y-%m-%d %H:%M:00")):
        # 起動直後でなければ OHLC データを出力
        if(self.ohlc["date"] != ""):
          logger.info("{}, {}, {}, {}, {}, {}".format(now, self.ohlc["date"], self.ohlc["open"], self.ohlc["high"], self.ohlc["low"], self.ohlc["close"]))
        self.ohlc["date"] = exec_date.strftime("%Y-%m-%d %H:%M:00")
        self.ohlc["open"] = price
        self.ohlc["high"] = price
        self.ohlc["low"] = price
        self.ohlc["close"] = price
      # OHLC データの時刻が同じ場合
      else:
        self.ohlc["high"] = max(self.ohlc["high"], price)
        self.ohlc["low"] = min(self.ohlc["low"], price)
        self.ohlc["close"] = price

  # when error occurs
  def on_error(self, ws, error):
    logger.error(error)

  # when websocket closed.
  def on_close(self, ws):
    logger.info('disconnected streaming server')

  # when websocket opened.
  def on_open(self, ws):
    logger.info('connected streaming server')
    output_json = json.dumps(
      {'method' : 'subscribe',
      'params' : {'channel' : self.channel}
      }
    )
    ws.send(output_json)

if __name__ == '__main__':
  #API endpoint
  url = 'wss://ws.lightstream.bitflyer.com/json-rpc'
  channel = 'lightning_executions_FX_BTC_JPY' # 約定
  json_rpc = RealtimeAPI(url=url, channel=channel)
  #ctrl + cで終了
  json_rpc.run()

注意点

1分足限定になってるので、5分足とか15分足とかやるなら、もう少しコードいじる必要あり。トリガー時刻みたいなのを設定すればいいんじゃないかな。

最新OHLCデータ(1件)しか保持しない作りになっているので、過去n本分のOHLCデータをインジケータに食わせたい場合は、list 使ってください。n を変数にして、insert/append/pop/del などで対応すればいけるはず。

↑の注意点は最新版で対処済


実行結果

初回データは起動時刻からローソク足更新タイミングまでの中途半端なデータになるので注意。(※ 22:07:30 に起動したら、22:07:30〜22:07:59 までのデータ)

出力内容は [データ出力時刻, 対象ローソク足時刻, Open, High, Low, Close]

$ python create_ohlc_realtime_api.py
(中略)
2018-07-09 22:07:00.281850, 2018-07-09 22:06:00, 758284.0, 758314.0, 758261.0, 758314.0
2018-07-09 22:08:00.816771, 2018-07-09 22:07:00, 758311.0, 758873.0, 758246.0, 758677.0
2018-07-09 22:09:00.575687, 2018-07-09 22:08:00, 758640.0, 758679.0, 758351.0, 758447.0
2018-07-09 22:10:00.448579, 2018-07-09 22:09:00, 758426.0, 758887.0, 758300.0, 758587.0
...


TradingView、Cryptowatch との誤差比較

それぞれ TradingView と重ね合わせた画像を載せておく。ざっと見た感じ、オレオレOHLCの方が TradingView に近い(気がする)。
計測期間:2018/07/09 22:06〜23:32


TradinvView vs オレオレOHLC


TradingView vs Cryptowatch


個別の画像はこちらのツイートから辿っていってください。


API ドキュメント


おわりに

有料(¥100)にしてるけど、これで内容は全部です。募金してくれる人がいれば、ジュース代としていただけると嬉しい。コードは、インデントくずれが起きたりするようなので、コピペ時には注意してください。


マガジン


コメント用note(未購入者向け)


干し芋


ここから先は

0字

¥ 100

サポート頂けると励みになります BTC,BCH: 39kcicufyycWVf8gcGxgsFn2B8Nd7reNUA LTC: LUFGHgdx1qqashDw4WxDcSYQPzd9w9f3iL MONA: MJXExiB7T7FFXKYf9SLqykrtGYDFn3gnaM