noteのタイトル画像

[Puppeteer] <初めてのPuppeteer> マルチタイムフレーム機能を標準機能に組み込みました

以前のnoteにてマルチタイムフレームを扱いました。

マルチタイムフレーム

bitmexが公開しているpublic APIで取得可能なローソク足のタイムフレームは、
 1分、5分、1時間、1日
の4種類に限られます。
それ以外のタイムフレームを扱う場合には自分で他の時間足を作成しなくてはなりません。

いちいち、その他のタイムフレームを作成するのは面倒なので、Puppeteer本体の標準機能に組み込んでしまいました。

定義方法

Puppeteerの定義ファイル(JSONファイル)に次のパラメータを追加します。

   "//" : "マルチタイムフレームのローソク足を使用するかどうかを指定",
   "//" : "設定値: 1m, 3m, 5m, 10m, 15m, 30m, 1h, 2h, 3h, 4h, 6h, 12h, 1d",
   "MULTI_TIMEFRAME_CANDLE_SPAN_LIST" : [],

上記に欲しいローソク足の値を設定します。複数設定可能です。
例えば15分足と2時間足が欲しいとします。
定義は次のようになります。

   "//" : "マルチタイムフレームのローソク足を使用するかどうかを指定",
   "//" : "設定値: 1m, 3m, 5m, 10m, 15m, 30m, 1h, 2h, 3h, 4h, 6h, 12h, 1d",
   "MULTI_TIMEFRAME_CANDLE_SPAN_LIST" : ["15m", "2h"],

これを実行すると、

2019-07-16 21:22:29, INFO    ,                               open     high      low    close  volume
timestamp                                                            
2019-07-16 11:15:00+00:00  10804.0  10804.0  10794.5  10798.0  126054
2019-07-16 11:30:00+00:00  10798.0  10800.0  10797.5  10798.0  129604
2019-07-16 11:45:00+00:00  10798.0  10800.0  10798.0  10798.5  103742
2019-07-16 12:00:00+00:00  10798.5  10799.0  10791.5  10795.5  101384
2019-07-16 12:15:00+00:00  10795.5  10795.5  10787.0  10795.5   80403
2019-07-16 21:22:29, INFO    ,                               open     high      low    close   volume
timestamp                                                             
2019-07-16 02:00:00+00:00  10953.5  10954.0  10600.0  10730.0  4594153
2019-07-16 04:00:00+00:00  10730.0  10900.0  10600.0  10899.5  3181474
2019-07-16 06:00:00+00:00  10899.5  10900.0  10600.0  10891.0  2927910
2019-07-16 08:00:00+00:00  10891.0  10900.0  10770.0  10776.5  2823361
2019-07-16 10:00:00+00:00  10776.5  10865.0  10770.0  10798.5  2194266

のように15分足と2時間足が取得できました。

この2つのローソク足データを取得するためのコードは次の2行だけです。

       # 15m
       self._logger.info(self._candle.candle(self._config['MULTI_TIMEFRAME_CANDLE_SPAN_LIST'][-2]).tail(5))
       # 2h
       self._logger.info(self._candle.candle(self._config['MULTI_TIMEFRAME_CANDLE_SPAN_LIST'][-1]).tail(5))

self._candleにマルチタイムフレームを取得するクラスのインスタンスが格納されています。
そのクラスに対して

self._candle.candle(欲しいローソク足の期間)

を指定することで指定したローソク足のDataFrameが取得できます。

お家の事情から

でも、きっと鋭いあなたは「あれ?変だな?」と思われると思います。

MULTI_TIMEFRAME_CANDLE_SPAN_LIST というパラメータには

["15m", "2h"]

と定義したので、本来なら配列の0番目と1番目を指定すれば

       # 15m
       self._logger.info(self._candle.candle(self._config['MULTI_TIMEFRAME_CANDLE_SPAN_LIST'][0]).tail(5))
       # 2h
       self._logger.info(self._candle.candle(self._config['MULTI_TIMEFRAME_CANDLE_SPAN_LIST'][1]).tail(5))

で値が取得できるはずです。
なぜわざわざ配列の「後ろ」からパラメータを取得しているのでしょうか?

これはPuppeteerの内部の事情なのです。
bitmexのサイトからはローソク足として

1分、5分、1時間、1日

の4種類のローソク足情報しか取得できません。
その他の時間足はPuppeteerが内部で合成しているのです。

15分足が欲しい場合は一番近い足(この場合は5分足)の情報から15分足を生成しています。
15分足を生成するために、5分足の情報も取得しておかなければならないのです。

そのため、Puppeteerはパラメータに「15分足」見つけたら、パラメータの先頭に「5分足」の定義を追加します。
そして15分足は、5分足情報を取得したのちに内部で生成しているのです。

よって、

       # 5m
       self._logger.info(self._candle.candle(self._config['MULTI_TIMEFRAME_CANDLE_SPAN_LIST'][0]).tail(5))
       # 1h
       self._logger.info(self._candle.candle(self._config['MULTI_TIMEFRAME_CANDLE_SPAN_LIST'][1]).tail(5))

とした場合には、次のデータが取得されていることが確認できます。

timestamp                                                            
2019-07-16 12:05:00+00:00  10798.5  10798.5  10798.0  10798.0    6865
2019-07-16 12:10:00+00:00  10798.0  10799.0  10791.5  10795.5   68832
2019-07-16 12:15:00+00:00  10795.5  10795.5  10787.0  10795.5   80403
2019-07-16 12:20:00+00:00  10795.5  10800.0  10787.5  10797.5  170964
2019-07-16 12:25:00+00:00  10797.5  10798.0  10781.5  10781.5  571999
2019-07-16 21:33:29, INFO    ,                               open     high      low    close   volume
timestamp                                                             
2019-07-16 07:00:00+00:00  10843.0  10900.0  10600.0  10891.0  2381276
2019-07-16 08:00:00+00:00  10891.0  10900.0  10816.5  10886.0   959334
2019-07-16 09:00:00+00:00  10886.0  10900.0  10770.0  10776.5  1864027
2019-07-16 10:00:00+00:00  10776.5  10865.0  10770.0  10800.5  1398370
2019-07-16 11:00:00+00:00  10800.5  10804.5  10794.0  10798.5   795896

以上のデータは5分足と1時間足になっていますね。

ソースコード全体

マルチタイムフレームの時間足として「15分」「2時間」の2つを取得するサンプルソースを以下に載せます。
PuppeteerのPuppetsフォルダの下に

 - Puppets/
  - sample/
    - sample.py
    - sample.json

というフォルダとファイルを作成し、

sample.py

# -*- coding: utf-8 -*-
# ==========================================
# サンプル Puppet
# ==========================================
import datetime

from puppeteer import Puppeteer

# ==========================================
# Puppet(傀儡) クラス
#   param:
#       puppeteer: Puppeteerオブジェクト
# ==========================================
class Puppet(Puppeteer):

   # ==========================================================
   # 初期化
   #   param:
   #       puppeteer: Puppeteerオブジェクト
   # ==========================================================
   def __init__(self, Puppeteer):
       self._exchange = Puppeteer._exchange    # 取引所オブジェクト(ccxt.bitmex)
       self._logger = Puppeteer._logger        # logger
       self._config = Puppeteer._config        # 定義ファイル
       self._candle = Puppeteer._candle        # マルチタイムフレーム
       
   # ==========================================================
   # 売買実行
   #   param:
   #       ticker: Tick情報
   #       orderbook: 板情報
   #       position: ポジション情報
   #       balance: 資産情報
   #       candle: ローソク足
   # ==========================================================
   def run(self, ticker, orderbook, position, balance, candle):
       # --------------------------
       # ここに処理を記述します
       # --------------------------
       # 15m
       self._logger.info(self._candle.candle(self._config['MULTI_TIMEFRAME_CANDLE_SPAN_LIST'][-2]).tail(5))
       # 2h
       self._logger.info(self._candle.candle(self._config['MULTI_TIMEFRAME_CANDLE_SPAN_LIST'][-1]).tail(5))

sample.json

{
   "//" : "===============================================",
   "//" : " システムで利用",
   "//" : "===============================================",
   "//" : "取引所のapiKey, secretを設定します",
   "APIKEY" : "YOUR_APIKEY",
   "SECRET" : "YOUR_SECRET",

   "//" : "bitmex取引所で対応する通貨ペア等を記述",
   "SYMBOL" : "BTC/USD",
   "INFO_SYMBOL" : "XBTUSD",
   "COIN_BASE" : "BTC",
   "COIN_QUOTE" : "USD",
   "//" : "bitmex取引所の価格の最小幅(0.5ドル)",
   "PRICE_UNIT" : 0.5,

   "//" : "TestNetを使うか?(使う: true, 使わない: false)",
   "USE_TESTNET" : true,

   "//" : "ticker, orderbook, position, balance, candle のどれを利用するかを指定する。Falseを指定した場合はそのデータは取得しない",
   "USE" : {
       "TICKER" : false,
       "ORDERBOOK" : false,
       "POSITION" : false,
       "BALANCE" : false,
       "CANDLE" : false
   },

   "//" : "ローソク足の収集定義。",
   "CANDLE" : {
       "//" : "ローソク足の足幅を設定する。設定値= 1m, 5m, 1h, 1d",
       "TIMEFRAME" : "1m",
       "//" : "データ取得開始時刻(UNIXTIME:1ミリ秒)、使用しない場合 もしくは自動の場合は null(None) を指定",
       "SINCE" : null,
       "//" : "取得件数(未指定:100、MAX:500)",
       "LIMIT" : null,
       "//" : "True(New->Old)、False(Old->New) 未指定時はFlase",
       "REVERSE" : false,
       "//" : "True(最新の未確定足を含む)、False(含まない) 未指定はTrue",
       "PARTIAL" : false
   },

   "//" : "板情報の収集定義。",
   "ORDERBOOK" : {
       "//" : "取得件数(未指定:25、MAX:取引所による?)",
       "LIMIT" : null
   },

   "//" : "マルチタイムフレームのローソク足を使用するかどうかを指定",
   "//" : "設定値: 1m, 3m, 5m, 10m, 15m, 30m, 1h, 2h, 3h, 4h, 6h, 12h, 1d",
   "MULTI_TIMEFRAME_CANDLE_SPAN_LIST" : ["15m", "2h"],

   "//" : "websocketを使用するかどうかを指定",
   "USE_WEBSOCKET" : false,

   "//" : "ログレベルを指定。('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG')",
   "LOG_LEVEL" : "INFO",

   "//" : "インターバル(botの実行周期)を秒で設定",
   "INTERVAL" :30,

   "//" : "discord通知用URL",
   "DISCORD_WEBHOOK_URL" : "",

   "//" : "資産状況通知をするか",
   "USE_SEND_BALANCE" : false,

   "//" : "===============================================",
   "//" : " ユーザで自由に定義",
   "//" : "===============================================",
   "//" : "xxx",
   "XXX" :0
}

とします。
(sample.jsonファイルのAPIKEY,SECRETはご自身のものを設定してください)

今回はrunメソッドの引数のcandle引数は使用していません。

実行結果

上記を配置して、Puppeteerフォルダから

python3 puppeteer.py puppets/sample/sample.py puppets/sample/sample.json

を実行します。

実行結果は以下のようになると思います。

2019-07-16 21:38:08, INFO    , class BitMEX initialized
2019-07-16 21:38:12, INFO    , [傀儡師] 起動しました。Puppet=puppets/sample/sample.py, Config=puppets/sample/sample.json, 対象通貨ペア=BTC/USD, RUN周期=30(秒)
2019-07-16 21:38:12, INFO    ,                               open     high      low    close  volume
timestamp                                                            
2019-07-16 11:30:00+00:00  10798.0  10800.0  10797.5  10798.0  129604
2019-07-16 11:45:00+00:00  10798.0  10800.0  10798.0  10798.5  103742
2019-07-16 12:00:00+00:00  10798.5  10799.0  10791.5  10795.5  101384
2019-07-16 12:15:00+00:00  10795.5  10800.0  10781.5  10781.5  823366
2019-07-16 12:30:00+00:00  10781.5  10790.5  10781.5  10790.0   72088
2019-07-16 21:38:12, INFO    ,                               open     high      low    close   volume
timestamp                                                             
2019-07-16 02:00:00+00:00  10953.5  10954.0  10600.0  10730.0  4594153
2019-07-16 04:00:00+00:00  10730.0  10900.0  10600.0  10899.5  3181474
2019-07-16 06:00:00+00:00  10899.5  10900.0  10600.0  10891.0  2927910
2019-07-16 08:00:00+00:00  10891.0  10900.0  10770.0  10776.5  2823361
2019-07-16 10:00:00+00:00  10776.5  10865.0  10770.0  10798.5  2194266

これで定期的に複数のタイムフレームを取得することができるようになります。
未確定足を取得するかどうかや、いくつのデータを取得するかについてはJSONファイルの

   "//" : "ローソク足の収集定義。",
   "CANDLE" : {
       "//" : "ローソク足の足幅を設定する。設定値= 1m, 5m, 1h, 1d",
       "TIMEFRAME" : "1m",
       "//" : "データ取得開始時刻(UNIXTIME:1ミリ秒)、使用しない場合 もしくは自動の場合は null(None) を指定",
       "SINCE" : null,
       "//" : "取得件数(未指定:100、MAX:500)",
       "LIMIT" : null,
       "//" : "True(New->Old)、False(Old->New) 未指定時はFlase",
       "REVERSE" : false,
       "//" : "True(最新の未確定足を含む)、False(含まない) 未指定はTrue",
       "PARTIAL" : false
   },

の定義が使われます。

runメソッドのcandle引数とは違い、Puppetを呼び出す周期(Interval)をいくつに設定しても、マルチタイムフレームで指定したローソク足を無駄に取得したり、逆に取りそこねることはありません。
Puppeteer内部でマルチタイムフレームに指定したローソク足を別の実行周期で取得しているからです。

注意事項

一つ注意しなくてはならないのは、bitmexが提供している時間足以外の足を取得する場合、もともとはbitmexが提供している1分、5分、1時間、1日のデータから指定時間足のデータを生成しているので、15分足は5分足データの1/3個の個数しか取得できません。(5分足データを元にして15分足データを作成しているので)

よって、12時間足を作ろうと思った場合は1時間足データの1/12個しか作成されません。
現在、Puppeteerで取得できる個々の足の個数は最大で500個なので、その比率よりも多い数のデータは取れないことになります。

とは言え、よく使われるであろう2時間足や4時間足を使ってテクニカル分析をする上でそれほど問題なることは”当面はない”と考えています。

もし、ご要望があれば更に改善したいと思います。

楽しいbotライフを!






ソフトウェア・エンジニアを40年以上やってます。 「Botを作りたいけど敷居が高い」と思われている方にも「わかる」「できる」を感じてもらえるように頑張ります。 よろしくお願い致します。