見出し画像

Bot初心者にもおすすめ!pybitflyerを徹底強化したはみ式APIClient「BFFXClient」

はじめに

はじめまして、はみと申します。Twitterでは @hami__cc で活動しています。よろしくおねがいします。

さて、私は今年の7月からPythonでbitFlyerのBot制作をしているのですが、pybitflyerやCCXTでは少し痒いところに手が届かないなと日頃感じていました。そこで、個人用にAPI Clientを作り、それを使っています。

このAPI Client、つい先日Bot制作仲間の数名(初心者の方を含む)に渡してみたところ「とても使いやすい!」と好評でした。そこで「折角なら公開してしまおう!」と思い立ちこのNoteを書いています。

というわけで

bitFlyerのPython製API Client「BFFXClient」を公開します!

まずは、作ろうと思った経緯について簡単に説明したいと思います。

pybitflyerやCCXTといったAPI Clientを利用するメリットはたくさんあります

・APIを叩くための面倒な認証作業を気にする必要がない
・リクエスト周りの実装をしなくてよい
・叩きたいAPIに対応するmethodを呼ぶだけで良い
・etc.

とにかく自分で書くと面倒なことをいろいろやってくれるので便利です。でも、実際に使ってみて私が感じたのは、

・ほとんどのmethodで、必要なParameterが何かを具体的には教えてくれない
・引数名や型、フォーマットを間違えるとエラー沼にハマりやすい

・特殊注文(特にIFD, OCO, IFDOCO)が複雑で面倒
・実は用意されていないmethodがある

などなど。この辺が地味に効いてきて、頻繁に手が止まってはAPI Documentを確認し…、と作業効率が落ちてしまっていました。

そこで、これらの問題点を解消し「もう二度とAPI Documentを見に行かなくてよくなる」を目標に、pybitflyerを更にWrapする形で今回のライブラリ BFFXClient を制作しました。

このBFFXClient、ドキュメントを確認する手間が省ける分劇的に作業効率がアップします。また、後述するこちらで用意した一覧サンプルコードを見ることで、やりたいことから具体的なコードを見つけることもできます。Bot初心者の方が最初に躓きやすい「そもそも注文したくてもエラーが出て動かない」のような問題を回避できるので、これからBotを作るという初心者の方にもおすすめです。ぜひ話題のあんなストラテジーやこんなストラテジーの実現に役立ててもらえればと思います。

目次

・使い方について
  ・シンプル編
  ・応用編

・発注方法
  ・子注文 [ Limit / Market ]
  ・親注文(特殊注文) [ Stop / Stop Limit / Trail ]
  ・親注文(特殊注文) [ IFD / OCO / IFDOCO ]
  ・細かい条件を指定する

・注文のキャンセル
・各種情報の取得
・それ以外も含めた全ての利用例サンプル

・熟練者向けQ & A

=========== ↓ 有料パート ↓ ===========

・BFFXClientの実装コード
・簡単な導入方法(Cloud 9 の例)
・Tips
・その他
・おわりに
・BFFXClient 更新履歴

BFFXClientの特徴

まずはBFFXClientの特徴を簡単にまとめてみました。

bitFlyerのAPI Documentに載っている全てのREST APIを網羅
APIを叩く(注文やデータ取得)際に必要なパラメータは、全て引数名で分かるよう設計 → IDEなどで補完が出る(超大事!)
全てのクエリパラメータにも対応 → default値があるものはmethodのdefault引数で吸収
・Python3.6に対応し、引数の型も明示することでミスを軽減
特殊注文の記述方法が直感的かつシンプル
・利用頻度の高そうな注文やデータ取得に関する便利methodを複数用意
・各methodに簡易的な日本語コメントを記述
・既存ライブラリと差し替えやすいよう、エラーハンドリングは無し
・利用環境
  ・Python 3.6 以上
  ・pybitflyer インストール済み

pybitflyerやCCXTで少し不便に感じていた箇所を、なるべく解消するような設計・実装になっています。とにかく、IDE(PyCharm等)などで補完が出てくれることによる作業効率アップが顕著です。いちいち迷わなくて済みます。

例えば、Stop Limit買いの注文をしたい場合。

下の画像のように必須なパラメータ(size, price, trigger_price)が型とともに補完で分かるようになります。更に、Optional型になっているものやデフォルト値が設定されているものはオプションなので、なくても良いということが一目瞭然です。

使い方について

では実際どうやって使うのか、シンプルな例と応用例の2つを挙げて説明していきます。

シンプル編

例えば

・現在のbest_bid(最高買い価格)の1円上に 0.01 BTC の買い指値

という注文を出すコードを書くと、こんな感じになります。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from bffx_client import BFFXClient

# BFFXClient のインスタンスを生成
client = BFFXClient(
    api_key="API_KEY",  # bitFlyerのAPI Key
    api_secret="API_SECRET"  # bitFlyerのAPI Secret
)

# best_bid を取得 (BFFXClientが用意している便利methodの1つ)
best_bid = client.best_bid()

# best_bidの1円上に買い指値
client.limit_buy(size=0.01, price=best_bid + 1)

もちろんIDEなら入力補完もあるので楽ちんです。

応用編

今度はちょっと複雑な注文をしてみます。

1. もし現在のポジションがあれば、全て成行で決済
2. 800000円に 0.01 BTC の買い指値
3. もし上の注文が約定したら、トレーリングストップを 5000円幅 で注文

2. と 3. の組み合わせはIFDという特殊注文で実現することができます。

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from bffx_client import BFFXClient, Order

client = BFFXClient(
    api_key="API_KEY",  # bitFlyerのAPI Key
    api_secret="API_SECRET"  # bitFlyerのAPI Secret
)

# もし現在のポジションがあれば、全て成行で決済
client.close_all_positions()

# IFD注文(firstの注文が約定したらsecondの注文を出すといった特殊注文)
client.ifd(
    first=Order.limit_buy(size=0.01, price=800000),  # 800000円に 0.01 BTC の買い指値
    second=Order.trail_sell(size=0.01, offset=5000)  # トレーリングストップを 5000円幅 で注文
)

close_all_positions というmethodがありますが、これはBFFXClientにある便利methodの1つで、勝手にポジション数を計算した後、ポジションを0にするような成行注文を投げてくれます。こういった便利methodは他にもいくつか用意しています。

IFD注文についても、firstとsecondに好きな Order を設定する形になっており、かなり直感的な記述で発注できていることが分かると思います。

=================

それでは、大まかな使い方を見たところで、具体的な発注方法について簡単に説明していきたいと思います。

発注方法

子注文 [ Limit / Market ]

子注文とは、指値と成行の売買を行う注文のことを指します。発注の仕方は簡単で、以下のように書くだけです。

# 買い指値
client.limit_buy(size=0.1, price=700000)

# 売り指値
client.limit_sell(size=0.1, price=700000)

# 成り買い
client.market_buy(size=0.1)

# 成り売り
client.market_sell(size=0.1)

ちなみに、成行注文に本来必要のない price を指定するなど誤ったパラメータを指定すると、以下のようにエラーが発生します。

TypeError: market_buy() got an unexpected keyword argument 'price'

一方pybitflyerやCCXTでは、実際にリクエストを送り、APIからのResponseにエラーが入っていることを確認するまでミスに気づくことはできません

● 親注文(特殊注文) [ Stop / Stop Limit / Trail ]

親注文(特殊注文)とは、子注文以外の少し複雑な注文のことを指します。

↓ 親注文(特殊注文)の詳細についてはこちら

まず Stop / Stop Limit / Trail 注文の出し方はこちらになります。

# Stop 買い
client.stop_buy(size=0.1, trigger_price=700000)

# Stop 売り
client.stop_sell(size=0.1, trigger_price=700000)

# Stop Limit 買い
client.stop_limit_buy(size=0.1, price=701000, trigger_price=700000)

# Stop Limit 売り
client.stop_limit_sell(size=0.1, price=699000, trigger_price=700000)

# Trail 買い
client.trail_buy(size=0.1, offset=5000)

# Trail 売り
client.trail_sell(size=0.1, offset=5000)

もちろんこれらの引数はmethodの引数として定義されているものなので、補完で教えてくれます。

親注文(特殊注文) [ IFD / OCO / IFDOCO ]

そして、親注文(特殊注文)の中でも複雑な IFD / OCO / IFDOCO についても、直感的に記述することができます。この3つの注文では、記述を簡潔にするために用意した Order というものを使うため、import文に Order を追加する必要があります。

from bffx_client import BFFXClient, Order

そして、以下のように記述することで簡単に発注することができます。

# IFD
client.ifd(
    first=Order.limit_sell(size=0.01, price=800000),  # 売り指値
    second=Order.limit_buy(size=0.01, price=700000)  # 買い指値
)

# OCO
client.oco(
    first=Order.stop_sell(size=0.01, trigger_price=700000),  # Stop売り
    second=Order.limit_sell(size=0.01, price=800000)  # 売り指値
)

# IFDOCO
client.ifdoco(
    ifd=Order.limit_buy(size=0.01, price=700000),  # 買い指値
    oco1=Order.trail_sell(size=0.01, offset=5000),  # Trail売り
    oco2=Order.stop_sell(size=0.01, trigger_price=699000)  # Stop売り
)

IFD / OCO / IFDOCO のmethodに対して、設定したい Order(注文) をそれぞれ作って組み合わせていくイメージです。

ちなみにこれらを実際に発注すると、bitFlyer上では以下のような状態になり、意図したとおりに発注できていることが分かると思います(拡大して見てください)。

細かい条件を指定する(慣れてきた人向け)

あまり使用頻度は高くないかもしれませんが、注文に対して更に細かい条件を設定することもできます。条件には以下の2つがあり、BFFXClientではもちろんこれらにも対応しています。

minute_to_expire: 期限切れまでの時間を分で指定
time_in_force執行数量条件 を "GTC", "IOC", "FOK" のいずれかで指定

例えば 

・minute_to_expire を 10 とする買い指値
・time_in_force を "FOK" とする買い指値

を発注したい場合、それぞれ以下のように書きます。

# minute_to_expire を 10 とする買い指値
client.limit_buy(size=0.01, price=800000, minute_to_expire=10)

# time_in_force を "FOK" とする買い指値
client.limit_buy(size=0.01, price=800000, time_in_force=TimeInForce.FOK)

ここで ​time_in_force の設定をする場合は TimeInForce というものが必要になるため、import文に TimeInForce を追加する必要があります。

from bffx_client import BFFXClient, TimeInForce

文字列ではなく Enum での指定なので、タイポなどの不要なミスの心配がありません。

注文のキャンセル

キャンセル時に指定する注文IDには order_id と order_acceptance_id の2種類ありますが、好きな方を設定することができます。

# 指定した Order ID に対応する子注文をキャンセル
client.cancel_child_order(child_order_id="CHILD_ORDER_ID")
client.cancel_child_order(child_order_acceptance_id="CHILD_ORDER_ACCEPTANCE_ID")

# 指定した Order ID に対応する親注文(特殊注文)をキャンセル
client.cancel_parent_order(parent_order_id="PARENT_ORDER_ID")
client.cancel_parent_order(parent_order_acceptance_id="PARENT_ORDER_ACCEPTANCE_ID")

# 全ての注文をキャンセル
client.cancel_all_child_orders()

各種情報の取得

Bot制作に欠かせない、マーケットの状態や取引に関する情報の取得も楽に行なえます。シンプルなので、以下に実際のコードをコメントとともに載せました。

# 板情報
board = client.board()

# Ticker
ticker = client.ticker()

# 約定履歴
executions = client.executions()

# 板の状態
board_state = client.board_state()

# 取引所の状態
# (板の状態の内 NORMAL, BUSY, VERY BUSY, SUPER BUSY, NO ORDER, STOP の情報のみ)
health = client.health()

# チャット
chat = client.chat()

それ以外も含めた全ての利用例サンプル

トレードには直接関係しないものの、bitFlyerのAPIには他にもいろんなものがあります。そしてBFFXClientではそれら全てに対応するmethodと、加えて便利methodも複数用意してあります。一覧できるサンプルコードを用意しましたので、詳細を見てみたい方、または実際の利用時に参考にする時などはこちらのGitLabスニペットコードを見ていただければと思います。

↓ BFFXClient method一覧

熟練者向けQ & A

ここまでの紹介・説明だけでは、Bot制作熟練者の方の中に「実際のコードを見てないからこことかどうなってるの?」といった疑問を持っている方もいらっしゃるかと思います。そこで、そういった疑問をなるべく解消していただくためにQ & Aを用意しました。

Q. リクエストのタイムアウトは設定できるの?
A. できます。BFFXClient初期化時の引数に timeout を用意してあります。
Q. 現物とか先物でも使えるの?
A. 使えます。
BFFXClient初期化時の引数に product_code を指定できます。デフォルト値が "FX_BTC_JPY" になっているので、他のマーケットで使いたい場合はここに別の product_code を指定してください。先物であれば先物が対応しているAPI、現物であれば現物が対応したAPIであれば動作します。

※ 2018/09/04現在 bitFlyerの不具合について
先物をalias名で指定すると、親注文の発注時にbitFlyerからエラー(Invalid product)が返却されるようです。bitFlyer側の不具合が修正されるまではalias名での指定はお控えください。
Q. ログの出力はできるの?
A. できます。こちらもBFFXClient初期化時の引数に logger を用意してあります。logging module の logger を設定することで任意のフォーマットで出力させることが可能です。 → logger作成例
上記作成例で作成したloggerを設定した場合は以下のようにログが出力されます(IFDOCOの例)。

Q. 各APIに対するデフォルト値ってどうなってんの?
A. BFFXClientのmethodを呼び出す際 None もしくは引数自体を指定しないことで、リクエスト時のパラメータに乗せません。そのためbitFlyer側が決めているデフォルト値が適用されるようになっています。BFFXClientでデフォルト値を決め打ちでは持っていません。
Q. ページ形式にもちゃんと対応してる?
A. 対応しています!
ページ形式でのリクエストができるAPIについては全て対応しています。使用例はこちらを参照してください。
約定履歴でページ形式を利用した例
Q. 実装見させてもらうけど、まさかコーディング規約守ってないとかないよね?
A.  Pythonのコーディング規約 PEP8 に準拠しています!
Q. API Reqeust時に特定の処理を走らせるためのcallbackとか登録できる?
A. できます!v1.1.0からBFFXClient classの初期化時に request_callback へcallbackを渡すことで登録できるようになりました。API Request直後にcallbackが呼び出されます。API Requestの制限に引っかからないようRequest回数をカウントアップするときなどに便利です。具体的な利用方法についてはサンプルコードをご参照ください。
サンプルコード

=================

ここから先は有料パートになります。有料パートでは

・BFFXClientの実装コード全て
・簡単な導入方法(Cloud 9 の例)
・Tips
・その他
・おわりに

・BFFXClient 更新履歴

を記載していきます。もし機能追加やその他改善、修正等がある場合は本Noteを更新していく形で対応していく予定です。また、pybitflyerに更新があった場合にも追随していく予定です。(もし大幅な機能アップデートとなる場合、途中からNoteの値上げをする可能性もありますことをご了承ください)

もちろん、有料パートに関して無断で他への転載・転売等は固くお断りさせていただきます。ご購入いただいたご本人様のみでご利用いただきますよう、よろしくおねがいします。

ここから先は

31,142字 / 3画像

¥ 3,000

期間限定!PayPayで支払うと抽選でお得

この記事が気に入ったらチップで応援してみませんか?