Skip to content
@_P_E_N_T_A edited this page Apr 18, 2020 · 23 revisions

インストール

方法1: パスの通った場所にシンボリックリンクを貼る(おすすめ)

少し行儀の悪い方法ですが、おそらく一番トラブルの少ない方法です。

  1. パスの通っている場所を調べる。
$ python3 -c 'import sys; print(sys.path)'
['', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload',
 '/home/sk/.local/lib/python3.8/site-packages', '/usr/lib/python3.8/site-packages']
  1. どこでも良いので(できれば管理者権限の必要ないディレクトリ)にbotfwのシンボリックリンクを作成。
$ cd /home/sk/.local/lib/python3.8/site-packages  # pip install --user で使われるディレクトリ
$ ln -s /path/to/btc_bot_framework/botfw botfw

方法2: PYTHONPATHにプロジェクトディレクトリを追加

使用しているシェルの設定ファイル(.bashrc, .zshrc等)にPYTHONPATHを追加します。
正しい作法ですが、IDEによってはlinterのエラーがでたり、自動補完が効かなかったりします

export PYTHONPATH="/path/to/btc_bot_framework:$PYTHONPATH"

方法3: インストールしない

プロジェクト内に直接コードを書いて、プロジェクトルートからモジュールとして実行する場合は
特にインストール作業は必要ありません。
例えば、samples/bitflyer/orderbook.pyなら以下のように実行できます。(__init__.pyが必要かも)

$ python3 -m samples.bitflyer.orderbook

マニュアル

概要

定数値(の内部値)はccxtとの一貫性や親和性のため取引所固有の値ではなく、ccxtに準拠しています。

  • 'FX_BTC_JPY'(bitflyer) -> 'FX_BTC_JPY'(ccxt)
  • 'BTC_JPY(bitflyer) -> 'BTC/JPY'(ccxt)
  • 'BUY'(bitflyer), 'Buy'(bitmex), 'BUY'(binance) -> 'buy'(ccxt)
  • 'LIMIT'(bitflyer), 'Limit'(bitmex), 'LIMIT'(binance) -> 'limit'(ccxt)

具体的な実装例はsamples内のファイルを参照してください。

  • samples/simple_bot.py 簡単なbot。あくまで使い方を確認する用。
  • samples/bitlyfer/trade.py 約定データを取得して表示します。
  • samples/bitflyer/orderbook.py 板情報を取得して表示します。

trade.pyとorderbook.pyで利用されているtest_trade()とtest_orderbook()は それぞれ'botfw/base/trade.py'と'botfw/base/orderbook.py'内にあります。

初期化

ログ情報はすべてlogging(標準ライブラリ)から出力されるので、 はじめにロガーの初期化を行ってください。
ログフォーマットに拘りがなければ、setup_logger()で必要最低限の設定を行えます。

import logging
import botfw

botfw.setup_logger(logging.INFO)
log = logging.getLogger('MyLogger')
log.info('Hello!')

約定情報

対象の取引所のクラスを生成して、create_trade()に取得したい通貨ペアのシンボルを渡すことでTradeクラスが生成されます。
Tradeは約定情報を受け取るとadd_callback()で設定されたコールバック関数を呼び出します。
引数は前から順にts(タイムスタンプ), price(価格), size(約定サイズ)です。

# Bitflyerの'FX_BTC_JPY'を取得する例
bitflyer = botfw.Bitflyer()
trade = bitflyer.create_trade('FX_BTC_JPY')
trade.add_callback(lambda ts, price, size: print(ts, price, size))
input() # 入力待機してプログラムが終了するのを防ぐ
  • 注意点1
    概要にもありますが、通貨ペアのシンボルはccxtに準拠します。例えば、Bitmexの'XBTUSD'は'BTC/USD'になります。
    ccxtが対応していない取引所、または通貨ぺアについては取引所の表記に従います。
  • 注意点2
    コールバック関数は別スレッド(受信用のスレッド)から呼び出されるため、関数内部で長時間ブロッキングするような処理は避けてください。
  • 注意点3
    約定サイズは取引所の仕様に関わらず、Base通貨のサイズになります。
    例えば、Bitmexの'BTC/USD'のサイズはQuote通貨(USD)で配信されていますが、Base通貨(BTC)に変換されます。

create_trade()はTradeクラスの無駄な複製を防ぐためのものです。
以下のように取引所クラスを生成せずに直接Tradeクラスを生成しても問題ありません。

trade = botfw.Bitflyer.Trade('FX_BTC_JPY')

コールバック関数は複数の追加・削除が可能です。参考

板情報

基本的には約定情報と同じですが、取得したデータを内部に保持するという点で異なります。
買い板、売り板の参照はそれぞれbids(), asks()で取得でき、現在価格に近い順に(best bid, best askが先頭)[price, size]のリスト(ビューオブジェクト)で保存されています。
コールバック関数は板情報が更新されたことを知らせるためのものであり、特に設定は必要ありません。
約定情報の注意点1,2,3が同様に当てはまるのでご注意ください。

# Bitflyerの'FX_BTC_JPY'を取得する例
bitflyer = botfw.Bitflyer()
orderbook = bitflyer.create_orderbook('FX_BTC_JPY')
# orderbook.add_callback(lambda: print('updated'))
while True:
    for price, size in orderbook.bids()[:5]:
        print('bid', price, size)
    for price, size in orderbook.asks()[:5]:
        print('ask', price, size)
    time.sleep(1)

注文管理

アカウントの初期化

取引所クラスを生成して、init_account()メソッドにccxt同様のフォーマットでapi_keyとapi_secretを渡します。 この関数は内部でccxtの初期化、注文イベント用のwebsocketの認証などを行い以下の4つの変数を生成します。

  • api
    ccxt apiにapiカウントの機能を付け加えたクラスです。
  • websocket
    認証済みのwebsocket。注文イベントの受信用。
  • order_manager
    注文イベントの処理を行うクラス。基本的に直接利用することはありません。
  • order_group_manager
    注文グループを生成・管理するためのクラス。

次に、order_group_manager.create_order_group()に通貨シンボルとグループ名(任意の名称)を渡してorder_groupを生成します。
order_groupは注文をグルーピングするためのクラスで同一のシンボルに対しても複数作成することができます。
これは日本の取引所のように複数アカウントを持つことが難しい取引所において複数のロジックを実行する際に有用です。
注文、キャンセル、ポジション・(未実現)損益の確認はorder_groupを通して行います。
また、注文オブジェクト・ポジション情報の更新は注文イベント受信用のスレッドから非同期に行われます。

bitflyer = botfw.Bitflyer()
bitflyer.init_account({
    'apiKey': 'YOUR_API_KEY',
    'secret': 'YOUR_API_SECRET',
})
api = bitflyer.api
ogm = bitflyer.order_group_manager
# trade = bitflyer.create_trade('FX_BTC_JPY')
# orderbook = bitflyer.create_orderbook('FX_BTC_JPY')

og = ogm.create_order_group('FX_BTC_JPY', 'group_name_1')
og.set_order_log(logging.getLogger('group_name_1'))  # 自動で注文・キャンセルのログを表示

注文

order_groupからcreate_orderを呼び出すことで注文を行います。
引数は前から順に以下の通りで、sync以外の引数はすべてそのままccxtのcreate_orderに渡されます。

  • type
    注文タイプ。 'limit'または'market'
  • side
    売買の向き。 'buy'または'sell'
  • size
    注文サイズ。
  • price
    注文価格。(type='limit'の場合のみ)
  • params
    追加オプション
  • sync
    注文を同期で行うかどうか。Trueにすると呼び出されたスレッドに同期して注文を行います。 デフォルトではFalseで非同期で注文が行われます。
order = og.create_order('limit', 'buy', 0.01, 700000)
print(order)

返り値は注文オブジェクト(Order)で、注文を管理する上で重要なのは以下の2つです。

  • state
    Order Stateのいずれかの値で、注文の状態を表します。
  • state_ts
    stateが最後に変更されたタイムスタンプ。

stateは発注直後はWAIT_OPENになりますが、受付が正常に完了した場合OPENとなり、約定後はCLOSEDになります。 注文受付に失敗した場合、または途中(部分約定を含む)でキャンセルされた場合は、CANCELEDとなります。

非同期注文(デフォルト)では注文エラーが発生した際に注文スレッドから例外を補足することはできません。
注文エラーが発生したか知りたい場合はstateがCANCELEDでidがNoneになっているかどうかを確認してください。
エラー内容自体はログに表示されるため、エラー原因を後から特定する上ではこれで十分です。
どうしてもエラーの内容(エラーコード)を注文スレッドから知りたい場合は、同期注文(sync=True)にした上で例外を補足してください。

try:
    order = og.create_order('limit', 'buy', 0.01, 700000, sync=True)
except Exception as e:
    print(e)

キャンセル

create_orderが返す注文オブジェクトをorder_group.cancel_order()に渡します。
注文と同様にデフォルトでは非同期でキャンセルを行います。
stateはキャンセルが完了するまでの間WAIT_CANCELになり、キャンセル完了後はCANCELEDになりますが、 「キャンセルに失敗して再度OPENになる場合」や「キャンセル完了前に全約定によりCLOSEDになる場合」があることに注意してください。

og.cancel_order(order)

ポジション・(未実現)損益

TODO

ポジションの不整合の自動修復

TODO

エラー処理

TODO

各取引所固有の仕様

bitbank

TODO

bitflyer

TODO

binance

TODO

bitmex

TODO

bybit

TODO

gmocoin

TODO

liquid

TODO

リファレンス

定数値一覧

Order Type

注文形式。create_order()のtypeに指定する値です。

  • LIMIT (='limit')
    指値注文。priceで価格を指定してください。
  • MARKET (='market')
    成行注文。priceは不要です。

Order Side

注文の売り又は買い。create_order()のsideに指定する値です。

  • BUY (='buy')
    買い注文。
  • SELL (='sell')
    売り注文。

Order State

注文クラスのstate変数にセットされる値。

  • OPEN (='open')
    注文が有効(部分約定含む)である状態。
  • CLOSED (='closed')
    注文が全て約定した状態。
  • CANCELED (='canceled')
    注文が失効もしくはキャンセル(部分約定含む)された状態。
  • WAIT_OPEN (='wait_open')
    注文が送信されて、受付待ちの状態。
  • WAIT_CANCEL (='wait_cancel')
    注文のキャンセルを送信して、キャンセル待ちの状態。

Order Event

注文に変化があった際に通知されるイベントです。

  • EVENT_EXECUTION (='execution')
    (部分)約定通知。
  • EVENT_OPEN (='open')
    注文の受付完了。
  • EVENT_CANCEL (='cancel')
    注文のキャンセル完了。
  • EVENT_OPEN_FAILED (='open_failed')
    注文の受付失敗。
  • EVENT_CANCEL_FAILED (='cancel_failed')
    注文のキャンセル失敗。
  • EVENT_CLOSE (='close')
    注文の全約定によるクローズ。取引所によっては通知されません。
  • EVENT_ERROR (='error')
    エラー通知。

取引所共通クラス一覧

各取引所のクラスは共通のベースクラスを継承して以下のように定義されています。
{Exchange}の部分はそれぞれの取引所の名称に置き換えて考えてください。

Order

TODO

  • symbol
  • type
  • side
  • amount
  • price
  • params

TODO

  • id
  • filled
  • state
  • state_ts
  • trade_ts
  • open_ts
  • close_ts
  • editing
  • external

TODO

  • group_name
  • event_cb

OrderEvent

TODO

  • id
  • ts
  • type
  • price
  • size
  • fee
  • message
  • info

{Exchange}

このクラスは取引所毎に異なるクラスの名称を共通の名前にエイリアスし、初期化処理を共通化するためのものです。
例えば、bitflyerの場合、以下のように定義されています。

class Bitflyer(ExchangeBase):
    Api = BitflyerApi
    Websocket = BitflyerWebsocket
    OrderManager = BitflyerOrderManager
    OrderGroupManager = BitflyerOrderGroupManager
    Trade = BitflyerTrade
    Orderbook = BitflyerOrderbook

{Exchange}Api

ccxtを継承したクラスで通常のccxtメソッドに加えて、追加のメソッドとAPIの呼び出し回数を勘定する機能を提供します。
このクラスは主に内部で使用されるものなので、apiの余力を確認する以外の目的で参照することは基本的にありません。

{Exchange}Websocket

websocketのコネクションを管理するクラスです。
内部で利用するクラスなので直接利用することはありません。

{Exchange}OrderManager

内部的に注文を管理するためのクラスです。

{Exchange}OrderGroupManager

OrderGroupの生成と管理を行うクラスです。

{Exchange}PositionGroup

ポジション管理・損益計算を行うクラスで、OrderGroupの内部で利用されます。

{Exchange}OrderGroup

OrderGroupManagerによって生成されるクラスで、このクラスから注文とキャンセルを行います。

{Exchange}Trade

約定情報を提供するクラスです。
受信したデータを予め設定したコールバック関数に約定毎に渡します。

  • add_callback(cb)
    約定データを受信した際に呼び出されるコールバック関数(引数: ts, price, size)を指定します。
    コールバック関数は複数追加した場合、登録した順に呼び出されます。
  • remove_callback(cb)
    add_callbackで追加したコールバック関数を削除します。
    メソッドはインスタンス経由で参照する度にidが変わるため、コールバック関数として追加したメソッドを後から削除する場合は、予めadd_callbackに渡す前に変数に控えておいてください。
cb = obj.method
trade.add_callback(cb)

# trade.remove_callback(obj.method) # エラー
trade.remove_callback(cb) # 正常にコールバック関数を削除できる

{Exchange}Orderbook

板情報を提供するクラスです。
受信したデータを買い板(bids)と売り板(asks)に適切にソートして保持します。

  • bids() ! 買い板のリスト(正確にはビューオブジェクト)を返します。 価格が高い順(best bidが先頭)に[price, size]の形式で格納されています。
  • asks()
    売り板のリスト(正確にはビューオブジェクト)を返します。 価格が低い順(best askが先頭)に[price, size]の形式で格納されています。
  • add_callback(cb)
    板が更新された際に呼び出されるコールバック関数(引数なし)を追加します。 コールバック関数は複数追加可能ですが、websocketのスレッドから登録した順に呼び出されるため、ブロッキングする処理は避けてください。
  • remove_callback(cb)
    add_callbackで追加したコールバック関数を削除します。 メソッド変数はインスタンス経由で参照する度にidが変わるため、コールバック関数として追加したメソッドを後から削除する場合は、予めadd_callbackする際に変数に控えておいてください。

その他クラス一覧

TODO

コーディングスタイル

  • 多少コードが冗長になる場合でも、基本的には設計上の正しさを優先します。

  • フレームワーク部分(botfw)については以下の規則を適用します。

    • pep8に準拠。ただし__init__.pyは例外
    • コメントを含めて英語(askiiコードのみ)で記述。それ以外のsampleやgitログ等は自由。
  • メソッド名や引数の変数名とその順序、また定数変数(全部大文字の変数)の内部値は可能な限りccxtと揃えます。

    • 'FX_BTC_JPY'(bitflyer) -> 'FX_BTC_JPY'(ccxt)
    • 'BTC_JPY(bitflyer) -> 'BTC/JPY'(ccxt)
    • 'BUY'(bitflyer), 'Buy'(bitmex), 'BUY'(binance) -> 'buy'(ccxt)
    • 'LIMIT'(bitflyer), 'Limit'(bitmex), 'LIMIT'(binance) -> 'limit'(ccxt)
  • メソッド名の英単語は省略しませんが、変数名、及び引数名は意味の分かる範囲内で自由に省略します。

  • 日本語部分(サンプルコード、README)を含め、全角スペース全面禁止

重要な変更点

commit 161 (9537ca0a8404e68d4021eac02c86d675492e0545) ----------

  • 注文・キャンセルを非同期(デフォルト)に変更。同期はsync=Trueを引数に渡す。
  • simulation mode 実装
  • liquid 追加
  • OrderGroupの注文一覧(orders)を削除。代わりにget_orders()を追加。
  • 変数名commissionをfeeに変更。手数料周りの実装を共通化。

commit 217 (6667332febf181d03ad7f77f15600de9f82a6bb8) ----------

  • bitflyer web注文API 削除

commit 251 (b453d933ee80907ff7bfec3b18894f63088d69ae) ----------

  • メソッド名変更: create_basics -> init_account

commit 262 (a875b395cedb4e52dec09446233cc68ad3c3e6eb) --------