見出し画像

Bybitの約定履歴から一秒足をつくる

Photo by moren hsu

黒枝といいます。

Bybitでダウンロードできる一日分の約定履歴から、一秒ローソク足を作るコードを書きました。

せっかく約定履歴から作っているので、ついでにvolume_bとvolume_sというキーで、売りと買いのvolumeを分けて保存しています。何か簡単なフットプリント的なことが出来るかもしれません。

Bybitの約定履歴はこちらから。

使い方は、以下のコードと約定履歴を同じディレクトリに配置して、次のように引数を与えて起動してください。

通貨ペアと日付のフォーマットは、Bybitでダウンロートできるcsvのファイル名と同じです。

ファイル名の例:BTCUSD2021-05-01.csv

 one_sec_candles_gen.py BTCUSD 2021-05-24

あるいは、コード内で定数になっているPAIRとDATEの値を直接書き換えて頂いても大丈夫です。

出来上がるファイル名の例:1s-candles-2021-05-24-BTCUSD.csv

#!/usr/bin/python3
# coding: utf-8

from datetime import timedelta
from datetime import date
from datetime import datetime

import pathlib
import csv
import sys

current_dir = str(pathlib.Path(__file__).parent.absolute())
field_names = ['time', 'open', 'high', 'low', 'close', 'volume_b', 'volume_s']

PAIR = "BTCUSD"
DATE = "2021-05-24"

if len(sys.argv) >= 2:
   PAIR = sys.argv[1]
   DATE = sys.argv[2]


def init_file(_date):
   with open(current_dir + "/1s-candles-{}-{}.csv".format(DATE, PAIR), mode='w', newline="") as csv_file:
       csv_file.write('')
       writer = csv.DictWriter(csv_file, fieldnames=field_names)
       writer.writeheader()


def append_data(data, _date):
   with open(current_dir + "/1s-candles-{}-{}.csv".format(DATE, PAIR), mode='a', newline="") as csv_file:
       writer = csv.DictWriter(csv_file, fieldnames=field_names)
       writer.writerows([row for row in data])


def filling_row(start_time, close_price):
   return {
       'time': start_time.isoformat(),
       'open': close_price,
       'high': close_price,
       'low': close_price,
       'close': close_price,
       'volume_b': 0,
       'volume_s': 0
   }


def within_a_sec(start_time, item_timestamp):
   return start_time + timedelta(seconds=1) > datetime.fromtimestamp(item_timestamp)


def no_trade_for_a_sec(start_time, item_timestamp):
   return start_time + timedelta(seconds=2) < datetime.fromtimestamp(item_timestamp)


def create_ohlcv(pair="BTCUSD", _date="2021-05-21"):
   with open("{}/{}{}.csv".format(current_dir, pair, _date), mode='r', newline="") as f:
       reader = csv.reader(f)

       # 0-time 2-side 3-size 4-price.
       items = list(reader)[::-1]  # reverse items since the raw items are from new to old.
       items = items[:-1]  # exclude the header line.

       start = date.fromisoformat(_date) - timedelta(days=1)  # say data of 5th is from 4th to 5th, thus deduct 1 day.
       start = datetime(start.year, start.month, start.day) + timedelta(hours=20)  # data is from 20:00.

       results = list()

       prices = list()
       row = dict()
       volume_b = 0
       volume_s = 0

       close_price = float(items[0][4])
       if not within_a_sec(start, float(items[0][0])):
           # no trade within the first 1 sec of the day.
           close_price = 0

       for item in items:
           if within_a_sec(start, float(item[0])):
               prices.append(float(item[4]))
               if item[2] == "Buy":
                   volume_b += float(item[3])
               else:
                   volume_s += float(item[3])
           else:
               # 1 sec period breaks.

               if no_trade_for_a_sec(start, float(item[0])):
                   # fill in no trade period.
                   start += timedelta(seconds=1)
                   end = datetime.fromtimestamp(float(item[0]))
                   while True:
                       _row = filling_row(start, close_price)
                       results.append(_row)
                       if start >= end:
                           break
                       start += timedelta(seconds=1)

               start += timedelta(seconds=1)
               row['time'] = start.isoformat()
               row['volume_b'] = volume_b
               row['volume_s'] = volume_s
               if len(prices) > 0:
                   row['open'] = prices[0]
                   row['high'] = max(prices)
                   row['low'] = min(prices)
                   row['close'] = prices[-1]
                   close_price = prices[-1]  # keep the closed price in case no trade done in the next 1 seco.
               else:
                   # nobody traded.
                   row['open'] = close_price
                   row['high'] = close_price
                   row['low'] = close_price
                   row['close'] = close_price

               results.append(row)

               # reset for the next row.
               prices = list()
               row = dict()
               volume_b = 0
               volume_s = 0
       return results


def main():
   data = create_ohlcv(pair=PAIR, _date=DATE)
   init_file(DATE)
   append_data(data, DATE)
   return print("1s-candles-{}-{}.csv is generated.".format(DATE, PAIR))


if __name__ == '__main__':
   main()


いいなと思ったら応援しよう!