Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pybotters v1.0 Roadmap #205

Closed
9 tasks done
MtkN1 opened this issue Dec 2, 2022 · 6 comments
Closed
9 tasks done

pybotters v1.0 Roadmap #205

MtkN1 opened this issue Dec 2, 2022 · 6 comments
Assignees
Labels
enhancement New feature or request

Comments

@MtkN1
Copy link
Member

MtkN1 commented Dec 2, 2022

💡 2024/1/8 Updated

Summary

この Issue では pybotters v1.0 リリースのロードマップを決めます。

Background info

メンテナ (@MtkN1) としては pybotters 設計を刷新する計画があり、計画としては全てのコードベースを書き直すつもりだったので、その刷新したバージョンを pybotters v1.0 としてリリースしたいと考えていました。

しかしライブラリとしての正しさを追求すると、その時点で考えていた仕様が間違えていることが分かる事があり、そしてそれが繰り返しありました。 experimental ブランチをリリースしたり、本 Issue 下部の「破棄された案」を検討したり色々な考えを尽くしましたが、結果的に 2 年間刷新の作業が完了することはありませんでした。

これではいつまで経っても v0.x が続いていくので、現状の設計のバージョンを v1.0 としてリリースする方針にします。 メンテナ的にはテストが難しい設計のままでバグが心配ですが、ユーザーには機能や使い方が充分に広まっているかと思われるのでよし 👉 とします。

設計の刷新は v2.0 で計画することにして、v1.0 は現設計のままでいくつかの課題を解決した時点でリリースする計画とします。

Roadmap

これらの課題が対応完了したら v1.0 をリリースする予定です。

破棄された案

詳細

📌 TL;DR

  • 設計の刷新
    • ライブラリ機能全体を aiohttp に依存しすぎない設計を刷新する。
      • pybotters.Client は引き続き aiohttp ラッパーとして提供する。
    • 認証機能を共通化して aiohttp 以外にも httpx, requests をサポートする。
      • HTTP クライアントを超えて利用できるようになる。
    • pybotters.Client の破壊的な変更。
      • WebSocket アプリの提供を Client.ws_connet から Client.ws に変更する。
      • Client.ws_connet はベーシックな aiohttp そのままの ws_connet 機能を提供する。
    • pybotters.Clientfetch ヘルパーを追加する。
      • 上記 ws と併せて、pybotters.Client は aiohttp のオリジナル機能 + 独自機能の役割を提供する。
      • ユーザーは pybotters が用意した fetch ws か aiohttp の get,post,... ws_connect どちらを利用するか選択できるようになる。
    • DataStoreManager から WebSocket メッセージパーサー機能を分離する。
      • イベント発火クラスとして別機能で提供することで、再利用性を高める。
    • WebSocket アプリにイベントリスナー機能を追加する。
      • 上記イベント発火クラスと組み合わせることで、bot 以外の独自のアプリケーションを簡単に作成できる。
  • その他

🤔 v0.x の現状と課題

現状実装されている機能

プレビュー版としている v0.x では以下のクラスをエンドユーザーに公開している。

  • pybotters.Client
    • aiohttp に各取引所の自動認証と WebSocket アプリの実装を加えてたクラス。
  • pybotters.XXXEchangeDataStore
    • 各取引所の高レベルな WebSocket データハンドラクラス。

これらは直接 HTTP や WebSocket レベルで取引所 API を操作できる機能である。
特に高度なトレード bot を作成したいユーザーや ccxt の不透明な実装を嫌うユーザーに人気を博している。

設計レベルの課題

pybotters の今後のリリースとしては、勿論新しい取引所 (認証と DataStore) を追加していくつもりではある。 しかし著者は基盤としての pybotters.Client は拡張性の限界があると感じている。
各取引所向けの高レベルな実装として pybotters-wrapper なども登場している。 pybotters としては直接的なエンドユーザー向けの機能よりも、基盤的な機能の強化を測りたいと考えている。 基盤強化の点についてユーザーからの要望は少ないが、著者としてはそれが「Crypto トレーダー向けの HTTP / WebSocket クライアントライブラリ」の正しい立ち振る舞いであると信じている。

v1.0 では以下の設計レベルの課題を解決したい。

  1. 認証機能が aiohttp に依存している。

HTTP クライアントだけがある状態からトレード bot を作成したいユーザーにとってまず必要となるのが「認証機能」である。 しかし現状の pybotters の認証は aiohttp に組み込まれている。 したがってユーザーは必然的に asyncio で非同期処理について学ばなければならない。 asyncio / aiohttp は素晴らしい非同期フレームワークではある。 しかし著者としては Crypto トレードライブラリの根幹である認証機能が aiohttp ユーザー限定されるのは果たして pybotters としあるべき姿なのかと考えている。 httpx は WebSocket の API は提供していないが素晴らしい HTTP クライアントである。

そうしたとき、認証機能を HTTP クライアントごとに実装するのは車輪の再発明である。

実際に ccxt でも署名が完全にライブラリに組み込まれてしまっていて再利用が不可能となっている。
多くの HTTP クライアントで利用できる認証機能を実装ができれば、より多くのユーザーに対応できる。 最も有名な requests に対応できるし、先ほど挙げた httpx は asyncio とは別非同期 I/O である trio に対応している。

著者は pybotters で多くの取引所の署名を実装してきたが、署名は HMAC-SHA256 などを利用して HTTP ヘッダーまたは URL クエリまたは Body を編集するだけものである。 その為 aiohttp に依存することはなく抽象化して共通化できるものと考えている。 v1.0 へのロードマップとしてまずはこの認証の共通化について取り組みたい。

  1. WebSocket メッセージパーサーが再利用できない。

DataStore をまとめる DataStoreManager は RDB で言うテーブルとデータベースのようの関係である。
しかし現状 DataStoreManager はその役割を超える機能が実装されている。 _onmessage にて「取引所の WebSocket メッセージを解釈して DataStore に渡す」という機能がある。
これの問題点としては、例えばユーザーが DataStore ではなく独自のアプリケーションで WebSocket データを利用したいときパーサー機能を再利用できない。 再利用性を高めることで、pybotters の利用幅が広がるのでパーサーを別の機能として分離するべきである。

その他の課題

なども設計上ではないが pybotters における実用上の大きな課題である。

🎨 v1.0 モジュール構成

以上の課題を踏まえ各モジュールの依存性を解消し再利用を高める為、モジュール構成を刷新する。

  • pybotters/
    • auth/
      • Auth (Top-level)
      • BaseAuth (Top-level)
      • XXXEchangeAuth
      • ...
    • client/
      • Client (Top-level)
    • handler/
      • TBD ...
    • store/
      • XXXEchangeDataStore (Top-level)
      • ...

⚙️ auth

認証機能を提供する。 公開するクラスは以下の通り。

  • pybotters.auth.Auth
    • ホスト名から自動判定して署名を提供する。
    • pybotters (aiohttp), httpx, requests に互換性を持たせる。
    • トップレベルから公開する。 pybotters.Auth
  • pybotters.auth.BaseAuth
    • ユーザー実装用の認証クラス。 このクラスを継承してユーザーは署名を独自実装できる。
    • トップレベルから公開する。 pybotters.BaseAuth
  • pybotters.auth.XXXEchangeAuth
    • 個別の取引所の認証クラス、ホスト名自動判定なしで個別に利用ができる。
    • auth モジュール内で各認証クラスを公開する。

認証の共通化について

v1.0で変更: 認証機能の内部の実装として、pybotters (aiohttp), httpx, requests のどのリクエストクラスが渡されても同様の署名が実施されるようにする。

Usage

auth = pybotters.Auth(apis={...: ...})

# httpx
httpx.get("https://...", auth=auth)
# requests
requests.get("https://...", auth=auth)

# 署名のみ、httpx, requests 以外のライブラリに渡すことができる。
url, body, headers = auth.sign("GET", "https://...", body=None, headers=None)
with urllib.request.urlopen(url, data=body, headers=headers) as response:
    ...

抽象化される署名メソッドとしては、 HTTP メソッド, URL, Body, ヘッダー の 4 つを受け取る。 そのメソッドでは受け取った URL クエリ, Body, ヘッダー の編集を抽象的に実装する。
つまり URL, Body, ヘッダー はインターフェースクラス化される。 インターフェースクラスはどの HTTP クライアントの型が渡されても指示された編集内容を実行するように実装する。

参考として各 HTTP クライアントのリクエスト型、プロパティ名、プロパティの型を記載する。

開く

リクエスト型

aiohttp httpx requests
aiohttp.ClientRequest httpx.Request requests.PreparedRequest

HTTP クライアントのリクエストに対する各要素のプロパティ名

aiohttp httpx requests
Method .method .method .method
URL .url .url .url
Body .body .stream .body
Headers .headers .headers .headers

※ httpx の Body (.stream) 以外共通。

HTTP クライアントのリクエストに対する各要素のプロパティ型

aiohttp httpx requests
Method str str str
URL yarl.URL httpx.URL str
(Query internal) multidict.MultiDict httpx.QueryParams -
Body
  • JSON: aiohttp.JsonPayload
  • Form: aiohttp.BytesPayload
  • Empty: Literal[b""]
httpx.ByteStream
  • JSON: bytes
  • Form: str
  • Empty: None
(Body internal) bytes bytes -
Headers multidict.CIMultiDict httpx.Headers requests.structures.CaseInsensitiveDict

HTTP クライアントの型以外にも、ユーザーが手入力で利用しそうな型も考慮する。

User input
Method str
URL str
Body
  • JSON: dict[str, str]
  • Form: list[tuple(str, str)]
  • Empty: None
Headers dict[str, str] | list[tuple(str, str)]

インターフェースクラス

上記の型の編集をサポートするインターフェースを実装する。

  • URLInterface
    • 以下プロパティで対応する値を提供する。
    • schema
    • host
    • port
    • path
    • path_qs
    • query
      • QueryInterface を返す。
    • query_string
  • QueryInterface
    • .setdefautl
      • クエリの編集 (元の値を尊重) を提供する。
    • __setitem__
      • クエリの上書きを提供する。
  • BodyInterface
    • .setdefautl
      • ボディの編集 (元の値を尊重) を提供する。
    • __setitem__
      • ボディの上書きを提供する。
  • HeadersInterface
    • .setdefautl
      • ヘッダーの編集 (元の値を尊重) を提供する。
    • __setitem__
      • ヘッダーの上書きを提供する。
    • update_from_body
      • ヘッダー (HeadersInterface) から Content-Lengh を編集する。

⚙️ client

aiohttp ベースのクライアントを提供する。 公開するクラスは以下の通り。

  • pybotters.client.Client
    • aiohttp.ClientSession を扱うクライアントクラス。
    • トップレベルから公開する。 pybotters.Client

pybotters.Client の役割

pybotters.Client は aiohttp.ClientSession を便利に利用する為のラッパークラスである。

auth モジュール編では pybotters の認証を他の HTTP クライアントもサポートすると提起した。 しかし高度なトレード bot を実装したい場合は aiohttp が優れた選択肢なのは確かである。 aiohttp であれば同一のインターフェースから HTTP と WebSocket を利用できる。 その為 pybotters は aiohttp のラッパーを引き続きサポートする。

pybotters.Client の役割としては以下の通り。

  1. aiohttp に提供されていないカスタム認証を追加する。

aiohttp.ClientSession の各リクエストメソッドは auth 引数があるが、aiohttp におけるベーシック認証しかサポートしていない。
pybotters で提供するカスタム認証を aiohttp 側に実施して貰う必要があるので、aiohttp のリクエストクラスをカスタマイズする。

v1.0 で変更: auth 引数で渡されたオブジェクトが callable であればリクエストクラス (self) を渡して独自の情報を付与できるようにする。 これによってユーザーは pybotters に標準実装されていないカスタム認証を独自に実装することが可能になる。

  1. WebSocket アプリケーション API を提供する。

aiohttp は ClientSession.ws_connect で WebSocket に接続する API を提供しているがベーシックな単一の接続の API となっている。 WebSocket は HTTP のような 1 つの接続においてリクエスト/レスポンスで対話するシンプルなプロトコルとは異なり持続的な接続をもつより複雑なプロトコルである。 トレード bot では再接続やイベントリスナーなどより多くの機能が必要であり、つまりより多くの実装が必要となる。 そこで pybotters では 1 つのリファレンス実装として実用的な aiohttp 用 WebSocket クライアントアプリケーションの API を提供する。

v1.0で変更: WebSocket 接続のインターフェースは v0.x では Client.ws_connect としていたが、Client.ws に変更する。 Client.ws_connect は pybotters の WebSocket アプリケーションを利用しない aiohttp 水準のベーシックな単一の接続を提供する。

WebSocket アプリケーションの機能

  • 自動再接続
  • v1.0で変更: イベントリスナー
    • v0.x では単一のハンドラ引数を提供していたが、より高度なイベント駆動をする機能を提供する。
  1. Fetch メソッドを提供する。

v1.0で追加: getpost メソッドは別に fetch メソッドを追加する。 現状 get リクエストを行うには以下の書き方をする。

async with pybotters.Client() as client:
    async with client.get("https://...") as resp:  # Receive headers
        data = await resp.json()  # Receive body
    print(data)

aiohttp においてレスポンスは Headers 受信 -> Body 受信と await を 2 回する冗長的な書き方となっている。 またコンテキストマネージャーを開くことも推奨されている。 pybotters においても HTTP リクエストメソッドは aiohttp を単純にラップしているだけなのでこのような書き方になる。

aiohttp はベーシックな非同期 HTTP クライアントであるのでこの様な API デザインは合理的である。 しかし REST API で JSON をやり取りする事が前提とされている pybotters ではよりシンプルな API を提供できる。 具体的には以下の書き方ができる API を提供する。

async with pybotters.Client() as client:
    r = await client.fetch("GET", "https://...")
    print(r.data)  # JSON data

⚙️ handler

v1.0で追加: WebSocket イベント発火用のクラス群。 各取引所の WebSocket メッセージをパースする。

TBD ... (未決定)

⚙️ store

WebSocket 向けの JSON オブジェクトを高速に CRUD 処理できる軽量データクラス。 公開するクラスは以下の通り。

  • pybotters.store.XXXExchangeDataStore
    • DataStore の各取引所の実装クラス。
    • トップレベルから公開する。 pybotters.XXXExchangeDataStore

v1.0で変更: DataStoreManager からパース機能を hander モジュールのクラス群に分離する。

@MtkN1 MtkN1 self-assigned this Dec 2, 2022
@MtkN1
Copy link
Member Author

MtkN1 commented Apr 13, 2023

pybottesr v1.0 仕様案を記載しました。

auth, client についてはだいぶ固まってきてますが、handler, store は未決定が多いです。

@MtkN1 MtkN1 added the enhancement New feature or request label Sep 15, 2023
@MtkN1
Copy link
Member Author

MtkN1 commented Sep 18, 2023

@MtkN1 MtkN1 changed the title pybotters v1.0 Specification pybotters v1.0 Roadmap Jan 2, 2024
@MtkN1
Copy link
Member Author

MtkN1 commented Jan 2, 2024

これ以前の仕様検討を破棄して、現状のコードベースから v1.0 をリリースする方針に変更する旨に概要を更新しました。

@MtkN1
Copy link
Member Author

MtkN1 commented Jan 2, 2024

@MtkN1 MtkN1 mentioned this issue Jan 9, 2024
@MtkN1
Copy link
Member Author

MtkN1 commented Jan 31, 2024

リリースノートの準備。


Generate release notes

What's Changed

Full Changelog: v0.17.0...v1.0.0

@MtkN1 MtkN1 closed this as completed Jan 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant