Bot

仮想通貨botの開発を本格的に始めてみる#38(2023/12/19)「MMBotの開発③MMbot解析-pybottersのサンプル」

2023年12月19日

前回の記事に引き続き、今回も仮想通貨botの開発状況をまとめていきます。

参考にしたソースコードはこちら

また、今回の記事からasyncとpybottersというライブラリを使うため、そのための基礎学習も並行して行なっていきます。

この点に関しては、非同期処理の知識があることが前提です。

概要

ひとまず、ChatGPTにざっくりコードの解説をさせてみます。

Yodaka

このコードが何をしているのか説明して。
(以下、ソースコードの貼り付け)

このコードは、Pythonの非同期プログラミングを使用してビットコインFXのマーケットメイキング(Market Making)ロボットを実装しています。

以下に、コードの主な機能と動作を説明します。

  1. Status クラス: マーケットの状態を管理するクラスです。板情報の自動更新、指値の計算、保有ポジションの管理などが含まれています。
  2. EventWatcher クラス: データストアの変更を監視するための抽象クラスです。具体的なイベントに対する監視クラスはこのクラスを継承して作成されます。
  3. ChildOrderEventWatcher、ExecutionWatcher、CancelWatcher クラス: イベント監視クラスの具体的な実装で、それぞれ子注文のイベント、約定のイベント、キャンセルのイベントを監視します。
  4. limit_order、cancel_order 関数: 注文を出すための非同期関数です。指定された条件で注文を出し、キャンセルを行います。
  5. market_making 関数: メインのマーケットメイキングロジックが実装されています。指定された条件でスプレッドが開いた時に、両サイドに対して注文を出すロジックが記述されています。
  6. main 関数: メインのエントリーポイントで、引数を受け取り、非同期でマーケットメイキングを実行します。WebSocketを使用してリアルタイムなデータの更新を監視し、指定された条件でメイキングを行います。
  7. parser: コマンドライン引数を処理するための argparse パーサーが定義されています。このスクリプトはコマンドラインから実行されることを想定しています。
  8. try-except ブロック: キーボード割り込み(Ctrl+C)を受け取ることでプログラムを停止できるようにしています。

これらの要素が組み合わさり、指定された条件が満たされた際にマーケットメイキングを実施するロボットが構築されています。


これだけでは、いまいち理解できないのでもっと絞り込んで質問してみます。

Yodaka

このコードは何をしているの

from __future__ import annotations
from typing import TYPE_CHECKING, Callable

このコードの最初の行は __future__ モジュールを使用して、新しいバージョンのPythonで導入された新機能や言語仕様を、現在のバージョンで使用できるようにするためのものです。具体的には、annotations オプションを有効にしています。annotations オプションは、関数やメソッドの引数や返り値に型アノテーションを使うためのものです。

2行目からは、typing モジュールから TYPE_CHECKINGCallable をインポートしています。

  • TYPE_CHECKING は通常の実行時ではなく、型ヒントの検証などのために型チェッカーが実行されているときにのみ特定のコードを実行するためのものです。通常、TYPE_CHECKING ブロック内のコードは型チェッカーが実行されている場合にだけ実行され、ランタイムでは無視されます。
  • Callable は、関数の型アノテーションに使用されるジェネリック型です。Callable[[Arg1Type, Arg2Type], ReturnType] のように使用され、引数の型と戻り値の型を指定します。

このような型の宣言や型ヒントは、コードの可読性を向上させ、静的解析ツールによるコードの品質向上をサポートします。Python 3.7以降では、型ヒントが言語仕様に正式に組み込まれているため、__future__ モジュールを使わなくても型ヒントを使用できますが、このコードでは互換性のために __future__ を使用している可能性があります。


Yodaka

各項目ごとに解説させると、少し分かりやすくなりましたね。

各項目ごとの解説

Yodaka

最初の質問で提示したコードの説明を各項目ごとにもっと詳しく解説して

提供されたコードを以下の項目ごとに詳しく解説します。

1. インポートと future モジュール

from __future__ import annotations
from typing import TYPE_CHECKING, Callable
  • __future__ モジュールのインポートを行っています。annotations オプションを有効にしています。これは、Python 3.7以降で導入された型アノテーションの新しい構文を使用するために必要です。これにより、型アノテーションを使った型ヒントがより効果的に利用できます。
  • TYPE_CHECKING および Callabletyping モジュールからインポートしています。TYPE_CHECKING は通常の実行時ではなく、型チェッカーが実行されているときにのみ特定のコードを実行するためのフラグです。Callable は、関数の型アノテーションに使用されるジェネリック型です。

2. Status クラス

class Status:
    # ... (クラスの中身は省略)

Status クラスは、マーケットの状態を管理するためのクラスです。主な機能は次の通りです。

  • 初期化メソッドでデータストアや最大ポジション数などの情報を受け取ります。
  • auto_update_board メソッドは非同期で板情報を自動更新するタスクを開始します。
  • get_limit_price メソッドは指定したサイド(askまたはbid)に対する指値を計算します。
  • 他にもポジションの取得や残りサイズの取得、板情報のプロパティなどがあります。

3. EventWatcher クラスおよびそのサブクラス

class EventWatcher:
    # ... (クラスの中身は省略)

class ChildOrderEventWatcher(EventWatcher):
    # ... (クラスの中身は省略)

class ExecutionWatcher(ChildOrderEventWatcher):
    # ... (クラスの中身は省略)

class CancelWatcher(ChildOrderEventWatcher):
    # ... (クラスの中身は省略)
  • EventWatcher はデータストアの変更を監視するための抽象クラスで、_watch メソッドでデータストアを監視しています。継承先のクラスで _is_trigger メソッドをオーバーライドして特定のイベントが発生したかどうかを判定します。
  • ChildOrderEventWatcher は特定の子注文イベントを監視するクラスで、_is_trigger メソッドで特定の注文IDと条件に一致するかどうかを判定します。ExecutionWatcherCancelWatcher はそれぞれ約定とキャンセルのイベントを監視します。

4. limit_order および cancel_order 関数

async def limit_order(client, symbol, side, size, price, time_in_force="GTC"):
    # ... (関数の中身は省略)

async def cancel_order(client, symbol, order_id):
    # ... (関数の中身は省略)
  • limit_order 関数は指定した条件で注文を出す非同期関数で、注文が成功した場合には注文IDを返します。
  • cancel_order 関数は指定した注文IDに対してキャンセルを行う非同期関数で、キャンセルが成功したかどうかをブール値で返します。

5. market_making 関数

async def market_making(
    client, store: pybotters.bitFlyerDataStore, status: Status, symbol: str,
    t: float, d: int, s_entry: float, s_update: float, size: float, logger: loguru.Logger
):
    # ... (関数の中身は省略)

market_making 関数はメインのマーケットメイキングロジックを実装しています。指定された条件でスプレッドが開いた場合に、両サイドに対して注文を出すロジックが記述されています。

6. main 関数

async def main(args):
    # ... (関数の中身は省略)

main 関数はプログラムのメインのエントリーポイントで、コマンドライン引数を受け取り、非同期でマーケットメイキングを実行します。WebSocketを使用してリアルタイムなデータの更新を監視し、指定された条件でメイキングを行います。

7. parser

if __name__ == "__main__":
    # ... (parser の定義および引数の解析)

__name__"__main__" の場合に、コマンドライン引数を解析して main 関数を非同期で実行するための部分です。この部分が実行されると、プログラムが起動します。

まとめ

main関数を見てから、それにまつわる関数を一つずつ読み込んでいくことで、コードの概要を掴みやすくなります。

次回以降の記事では、各項目ごとに必要な知識を学びながら、コードの解析を進めていきます。

#39(2023/12/20)「MMBotの開発④MMBotとは?/マーケットメイキング(MM)戦略のコスト分析」に続く...

-Bot