noteのタイトル画像

[Puppeteer] 地味に痛い「funding手数料」が今幾らになるかを取得してみる

手数料が地味に痛い

bitmexは8時間置き(日本時間の5:00, 13:00, 21:00の3回)に”funding手数料”というものが徴収されます。

呼び方は「funding手数料」「資金調達率」「スワップポイント手数料」だったりしているようですが、ここでは「funding手数料」と呼ぶことにしましょう。

これが何者であるかは、

をご覧いただくとして。

今回のお題は先日作成した「bitmex_websocket」を組み込んだPuppeteerで、このfunding手数料をプログラムから取得したいと思います。

プログラム

funding.py

# -*- coding: utf-8 -*-
# ==========================================
# サンプル Puppet (websocket)
# ==========================================
from datetime import datetime as dt, timezone as tz, timedelta as delta
import dateutil

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._ws = Puppeteer._ws                # websocket
        self._bitmex = Puppeteer._bitmex        # ccxt.bimexラッパーオブジェクト
        
    # ==========================================================
    # 売買実行
    #   param:
    #       ticker: Tick情報
    #       orderbook: 板情報
    #       position: ポジション情報
    #       balance: 資産情報
    #       candle: ローソク足
    # ==========================================================
    def run(self, ticker, orderbook, position, balance, candle):
        
        # Socketの接続が活きている限り処理を続けます
        if not self._ws.ws.sock.connected:
            self._logger.warning('websocket not running')
            return

        # --------------------------
        # ここに処理を記述します
        # --------------------------
        pos_qty, avg_price = self.position()
        
        fundingInterval, fundingRate, fundingCost, fundingCost_xbt = self.funding(pos_qty)
        
        # ----------------------------------------------
        # ログ出力
        # ----------------------------------------------
        self._logger.info('■ pos={}, fundingRate={}, 手数料={}(xbt) [{}分後]'
            .format(
                    pos_qty,                        # 現在ポジション
                    fundingRate,                    # レート
                    round(fundingCost_xbt,4),       # スワップポイント手数料(xbt)
                    round(fundingInterval/60,1)     # 手数料徴収・付与までの時間(分)
                ))

    # ==========================================================
    # ポジション、参入価格
    #   return:
    #       pos_qty, avg_price
    # ==========================================================
    def position(self):
        position = self._ws.position()
        if position is {}:
            return 0,0
        pos_qty = position['currentQty'] if position['currentQty'] is not None else 0           # ポジション
        avg_price = position['avgEntryPrice'] if position['avgEntryPrice'] is not None else 0   # 参入価格
        return pos_qty, avg_price

    # ==========================================================
    # スワップポイント手数料がいくらになるか
    #     資金調達率の範囲は -0.375% ≦ -0.001% 0.001% ≦ 0.375% です。(XBT/USD)
    #  資金調達率について参考にしたサイト
    #    https://bitcoin-talk.info/hisshouhou/#toc1
    #
    #   param:
    #       pos_qty
    #   return:
    #       fundingInterval:    手数料発生までの秒数
    #       fundingRate:        レート
    #       fundingCost:        手数料(単位:ドル) プラスなら払う、マイナスならもらう
    #       fundingCost_xbt:    手数料(単位:BTC) プラスなら払う、マイナスならもらう
    # ==========================================================
    def funding(self, pos_qty):
        instrument = self._ws.instrument()
        if instrument is {}:
            return 0,0,0,0
        # for DEBUG
        #print(instrument)
        fundingFire_dt = dateutil.parser.parse(instrument['fundingTimestamp'])
        now_dt = dt.now(tz(delta(hours=0), name='UTC'))
        # スワップポイント手数料計算
        fundingInterval = int((fundingFire_dt - now_dt).total_seconds())    # 秒
        fundingRate  = instrument['fundingRate']                            # 
        fundingCost = pos_qty * instrument['fundingRate']                   # ドル
        fundingCost_xbt = fundingCost / instrument['lastPrice']             # BTC
        # 
        return fundingInterval, fundingRate, fundingCost, fundingCost_xbt

funding.json (apikey, secretはご自分のを設定ください)

{
    "//" : "===============================================",
    "//" : " システムで利用",
    "//" : "===============================================",
    "//" : "取引所の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
    },

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

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

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

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

    "//" : "===============================================",
    "//" : " ユーザで自由に定義",
    "//" : "===============================================",
    "//" : "コメント",
    "XXXXX" : 100
}

配置

上記のファイルを「Puppeteer」の「Puppets」フォルダの下に以下のように配置します。

- puppets/
  - funding/
    - funding.py
    - funding.json

起動

puppeteerのフォルダに移動して、そこで次のコマンドを実行します。

python3 puppeteer.py puppets/funding/funding.py puppets/funding/funding.json

実行結果

すると以下のような実行結果が表示されると思います。
(数値はその時保有しているポジションやRateによって変わります)

2019-05-11 18:00:28, INFO    , [傀儡師] 起動しました。Puppet=puppets/funding/funding.py, Config=puppets/funding/funding.json, 対象通貨ペア=BTC/USD, RUN周期=5(秒)
2019-05-11 18:00:28, INFO    , ■ pos=2555, fundingRate=-0.00375, 手数料=-0.0014(xbt) [179.5分後]
2019-05-11 18:00:33, INFO    , ■ pos=2555, fundingRate=-0.00375, 手数料=-0.0014(xbt) [179.4分後]
2019-05-11 18:00:38, INFO    , ■ pos=2555, fundingRate=-0.00375, 手数料=-0.0014(xbt) [179.3分後]
2019-05-11 18:00:43, INFO    , ■ pos=2555, fundingRate=-0.00375, 手数料=-0.0014(xbt) [179.3分後]
・・・・

いかがでしょうか。
いつ、どれだけの手数料が徴収されるかわかりますね。
上記の例では179分後に0.0014XBTが貰えることがわかります。

プラス表示なら「徴収」され、マイナス表示なら「付与」されます。

がっぽり稼いでいる時はほとんど気にならないし、付与される側にいる時は嬉しい手数料ですが、徴収される方にいる時には地味に痛いものです。

最新版はこちらから

楽しいbotライフを!


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