クリプトHFTとか競プロとか

競技プログラミングや仮想通貨に関することを中心にブログを書いていきます.

BitMEXの秒足を約定履歴から30秒で自動生成するプログラム✨

BitMEXという荒野を駆け抜けるBotterの皆さんこんにちは.

そんなBotterの皆さんは日々バックテストを重ねて,新しい戦略を構築していることと思います.

mmbotなどのバックテストには高い解像度の情報が必要で,皆さんそのようなことに頭を悩ませているでしょう.

ほとんどの高頻度Botterは秒足などに対してバックテストをしていると思いますが,なにせ秒足を用意するのは意外と面倒くさいものです.

約定履歴を収集するプログラムを書いても,24時間稼働させなければいけないため,管理コストがかかります.

というわけで今回の記事では,BitMEXに公開されてる約定履歴から特定のシンボル(XBTUSDなど)の任意の秒足を作るプログラムを公開します.

f:id:KabukiMining:20200320120142j:plain
チャートの画像

今回使うデータ供給元

意外と知られていませんが,BitMEXは日々の約定履歴を集めたファイルをここで公開しています. ですが,このデータは様々なシンボルでの約定が一緒くたにされているために,特定のシンボルだけを抽出する加工が必要になります.

今回のプログラムではその作業も行います.

プログラム

import gzip
import pandas as pd
from urllib import request

#参考: https://qiita.com/yuukiclass/items/88e9ac6c5a3b5ab56cc4


def main():
    date, symbol, sec= input('yyyymmdd symbol sec\n').split()    
    date, sec = int(date), int(sec)
    baseurl = 'https://s3-eu-west-1.amazonaws.com/public.bitmex.com/data/trade/'
    print('Downloading...')
    filepath = '{}.csv.gz'.format(date)
    request.urlretrieve(baseurl + '{}.csv.gz'.format(date), filepath)
    print('Making candles...')
    df = unzip(filepath)
    df_ohlcv = makeCandles(df, symbol, sec,date)
    print('Done!')
    file_title = 'ohlc_bitmex-{}.csv'.format(date)
    df_ohlcv.to_csv(file_title)    
    
    return

def makeCandles(df, symbol, sec, date):
    # 参考: https://note.com/nagi7692/n/ne674d117d1b6?magazine_key=m0b2a506bf904
    df = df.query('symbol == "{}"'.format(symbol))

    df.drop(['tickDirection', 'trdMatchID', 'grossValue', 'homeNotional', 'foreignNotional'], axis=1, inplace=True)
    #86400本の秒足ができるように0秒に約定を入れる
    year = str(date)[:4]
    month = str(date)[4:6]
    day = str(date)[6:]
    side = df.iloc[0]['side']
    price = df.iloc[0]['price']
    ser = pd.Series(['{}-{}-{}D00:00:00.000000000'.format(year,month,day), symbol, side, 0,price], index=df.columns, name=0)
    df = df.append(ser)
    df = df.sort_index()
    df['timestamp'] = pd.to_datetime(df['timestamp'], format="%Y-%m-%dD%H:%M:%S.%f")
    df = df.rename(columns={'timestamp': 'exec_date'})
    df = df.set_index('exec_date')
    
    df['buy_size'] = df['size'].where(df['side'] == 'Buy', 0)
    df['buy_flag'] = df['side'] == 'Buy'
    df['sell_size'] = df['size'].where(df['side'] == 'Sell', 0)
    df['sell_flag'] = df['side'] == 'Sell'

    df_ohlcv = df.resample('{}S'.format(sec)).agg({"price": "ohlc", "size": "sum", "buy_size": "sum", "buy_flag": "sum",
                                      "sell_size": "sum", "sell_flag": "sum", })
    df_ohlcv.columns = ['open', 'high', 'low', 'close', 'volume', 'buy_vol', 'buy_num', 'sell_vol', 'sell_num']
    df_ohlcv['buy_num'] = df_ohlcv['buy_num'].astype(int)
    df_ohlcv['sell_num'] = df_ohlcv['sell_num'].astype(int)
    df_ohlcv.ffill(inplace=True)

    return df_ohlcv

def unzip(filepath):
    with gzip.open(filepath, 'rt') as f:
        df = pd.read_csv(f)
    return df

if __name__ == "__main__":
    main()

使い方

Pythonなどでプログラムを開くと

yyyymmdd symbol sec

と出るので 20200301 XBTUSD 1 とすることで,2020年3月1日のXBTUSDの1秒足が生成されます.

最後に

なにかプログラムのエラーやわからないこと等ありましたら気軽にコメントお願いします.