Skip to content

Releases: pybotters/pybotters

BETA v0.4.1 リリース

21 Jun 16:16
6244c5f
Compare
Choose a tag to compare
Pre-release

✅Binanceのイベント仕様に従ってDataStoreを更新する #58
✅Bybit DataStoreのKline(ローソク足)のキーが足りていない #62
✅DataStoreにおいてWebSocketエラーメッセージのWarningを表示する #63

✅Python 3.7以外のテストが通っていない #51
✅Linter, Formatter を導入したい #59

🎉 New Features

✨ BinanceのDataStoreでREST API経由の板情報の更新に対応しました

BinanceのAPIドキュメント(How to manage a local order book correctly)のロジックに準拠して板情報を更新できるようになりました。
これによりBinanceの板情報のDataStoreのREST API経由の初期化が可能になり、より正確かつ1000行以上のなデータが補完できるようになります。

🎈 板情報をREST APIで初期化し、WebSocketのイベントごとに最良気配値5行を表示するサンプル
※REST APIでの初期化(initialize)はAPIドキュメント通り、WebSocket接続後に行います

async def main():
    async with pybotters.Client(base_url='https://fapi.binance.com') as client:
        store = pybotters.BinanceDataStore()

        streams = '/'.join([
            'btcusdt@depth@100ms',
        ])
        wstask = await client.ws_connect(
            f'wss://fstream.binance.com/stream?streams={streams}',
            hdlr_json=store.onmessage,
        )
        await store.initialize(
            client.get('/fapi/v1/depth?symbol=BTCUSDT&limit=1000'),
        )

        while not store.orderbook.initialized:
            await store.wait()

        while True:
            book = store.orderbook.sorted()
            pybotters.print({'a': book['a'][:5], 'b': book['b'][:5]})
            await store.orderbook.wait()

✔ Improvements

✨ WebSocketのsubscribeのメッセージを間違えた場合にもDataStoreがWarnningを表示するようになりました

🐛 Bugfix

BybitのDataStoreでKlineにおいて複数時間足が正しく反映されないバグを修正しました。

♻ CI/CD

テストコードの改善や、Linter・Formatterを導入しました。

BETA v0.4.0 リリース

13 Jun 19:15
dba3ef4
Compare
Choose a tag to compare
Pre-release

✅ GMOコインのWebSocket API制限により複数購読ができない #50
✅ BybitのDataStoreクラスにタイムスタンプを追加する #47
✅ ws_connectのハンドラ未指定の場合はprintハンドラを選択する #46
✅ Binanceで認証を利用するとPublic APIがパラメーターエラーとなる #44
✅ HTTPリクエストのparams/data引数の指定間違いに警告を表示する #43
✅ Binance Futures USDⓈ-MのDataStoreを実装する #20

✅ DataStore サブクラスインスタンス取得時の型エラーを解決 #55
✅ GitHub Actions の matrix 実行で fail-fast を無効化 #54
✅ GitHub Actions による自動テスト実行 #49

🚀 New Experience

✨ Binance Futures USDⓈ-MのDataStoreを正式に実装しました

BinanceのWebSocketをハンドリングする pybotters.BinanceDataStore の実装が完了しました。
リアルタイムで板情報・ティッカー・アカウントのオーダーやポジションなどがDataStoreにキャッシュされ高速に参照することが可能です!
今回はBinance Futures USDⓈ-Mのみ対応しており、Binance Futures COIN-M、Spotは未対応です。
「listenKey」の自動延長はDataStoreのinitializeメソッドの機能で組み込んであるのでこれを利用することで持続的にユーザーストリームを購読できます。

全てのマーケットストリーム・ユーザーストリームを購読しREST APIで初期化する全部入りサンプル🔥

async def main():
    async with pybotters.Client(apis=apis, base_url='https://fapi.binance.com') as client:
        store = pybotters.BinanceDataStore()
        await store.initialize(
            client.get('/fapi/v2/balance'),
            client.get('/fapi/v2/positionRisk?symbol=BTCUSDT'),
            client.get('/fapi/v1/openOrders?symbol=BTCUSDT'),
            client.post('/fapi/v1/listenKey'),
        )

        streams = '/'.join([
            'btcusdt@aggTrade',
            'btcusdt@markPrice',
            'btcusdt@kline_1m',
            'btcusdt_perpetual@continuousKline_1m',
            'btcusdt@ticker', # or btcusdt@miniTicker
            'btcusdt@bookTicker',
            'btcusdt@forceOrder',
            'btcusdt@depth20@500ms',
            'btcusdt@depth',
            store.listenkey,
        ])
        wstask = await client.ws_connect(
            f'wss://fstream.binance.com/stream?streams={streams}',
            hdlr_json=store.onmessage,
        )

        while not all([
            len(store.markprice),
            len(store.kline),
            len(store.continuouskline),
            len(store.ticker),
            len(store.bookticker),
            len(store.orderbook) >= 40,
        ]):
            await store.wait()

        # サンプル: オーダーブックを監視
        while True:
            pybotters.print(store.orderbook.sorted())
            await store.orderbook.wait()

✨ BybitのDataStoreにタイムスタンプ機能を追加しました

BybitのWebSocketで配信される一部データにあるタイムスタンプ(timestamp_e6)を pybotters.BybitDataStoreに整数型で記録します。
疑似的にBybitのサーバータイムスタンプとして遅延を計ることなとが可能です。
この機能はorderBookL2_25, orderBook_200, instrument_info, klineV2を購読することで利用が可能です。

async def main():
    async with pybotters.Client() as client:
        store = pybotters.BybitDataStore()
        wstasks = await asyncio.gather(
            client.ws_connect(
                'wss://stream.bybit.com/realtime',
                send_json={'op': 'subscribe', 'args': [
                    'orderBookL2_25.BTCUSD|BTCUSDM21', # or orderBook_200.100ms.BTCUSD|BTCUSDM21
                    'instrument_info.100ms.BTCUSD|BTCUSDM21',
                    'klineV2.1.BTCUSD|BTCUSDM21',
                ]},
                hdlr_json=store.onmessage,
            ),
            client.ws_connect(
                'wss://stream.bybit.com/realtime_public',
                send_json={'op': 'subscribe', 'args': [
                    'orderBookL2_25.BTCUSDT', # or orderBook_200.100ms.BTCUSDT
                    'instrument_info.100ms.BTCUSDT',
                    'candle.1.BTCUSDT',
                ]},
                hdlr_json=store.onmessage,
            ),
        )

        while True:
            print(store.timestamp_e6)
            # 1623609894038501
            await store.wait()

✨ API自動認証をオフにする引数を追加しました

pybottersはREST/WebSocket APIを自動認証していますが、全て自動的に認証を行っていたので一部の取引所のPublic APIは認証により逆にエラーとなっていました。
リクエストメソッドの auth 引数を None にすることで手動で認証をオフに出来ます。

async def main():
    async with pybotters.Client(apis=apis) as client:
        # ERROR
        r = await client.get('https://api.binance.com/api/v3/depth', params={'symbol': 'BTCUSDT', 'limit': '10'})
        print(await r.json())
        # {'code': -1101, 'msg': "Too many parameters; expected '2' and received '4'."}

        # OK
        r = await client.get('https://api.binance.com/api/v3/depth', params={'symbol': 'BTCUSDT', 'limit': '10'}, auth=None)
        print(await r.json())

細かい新機能

GMOコインのWebSocketにおいて複数チャンネルを購読できない問題を解消しました。
その他は各Issueをご覧ください。

♻ CI/CD

✨ GitHub Actions による自動テスト実行などを追加しました

自動テスト実行などによってpybottersの開発品質が向上します!
こちらは @supermomonga 氏にコントリビュートして頂きました💖

BETA v0.3.0 リリース

06 Jun 15:06
8b67598
Compare
Choose a tag to compare
Pre-release

✅ 試験的にBinanceのDataStoreを実装する(各取引所のDataStoreを実装する) #20
✅ BybitのInstrumentが重複する #45

🌈 Experimental

✨ 試験的にBinanceのDataStoreを実装しました #20

一部のマーケットストリームとユーザーデータストリームのDataStoreを実装しました。
** 重要 **
基本的にはFutures(USDⓈ-M、COIN-M)でテストをしており、Spotは対応できてない可能性があります。
板情報は未実装です。ベスト値のみ取れる板ティッカー(bookticker)のみ使えます。
また、initializeのようなメソッドも実装していないのでポジションやオーダーの初期値は取得できません。
完全なDataStoreは今後実装予定です。

実装済みストリーム

  • trade (Market Streams trade, aggTrade)
  • bookticker (Market Streams bookTicker)
  • balance (User Data Streams)
  • position (User Data Streams)
  • order (User Data Streams)

ユーザーデータストリーム(USDⓈ-M)の例

WebSocket受信ごとにオーダー・残高・ポジションを表示する。
listenKeyの自動keepaliveは現状pybotters側で実装していないので手動でタスク化する必要があります。

async def main():
    async with pybotters.Client(base_url='https://fapi.binance.com') as client:
        store = pybotters.BinanceDataStore()
        r = await client.post('/fapi/v1/listenKey')
        data = await r.json()
        listenKey = data['listenKey']
        pybotters.print(data)
        wstask = await client.ws_connect(
            f'wss://fstream.binance.com/ws/{listenKey}',
            hdlr_json=store.onmessage,
        )
        listentask = asyncio.create_task(keepalive(client))
        while True:
            pybotters.print(store.order.find())
            pybotters.print(store.balance.find())
            pybotters.print(store.position.find())
            print('-' * 80)
            await store.wait()


async def keepalive(client: pybotters.Client):
    while not client._session.closed:
        await client.put('/fapi/v1/listenKey')
        await asyncio.sleep(1800.0) # 30 minutes

🐛 Bugfix

🐛 BybitのDataStoreのレコードが重複するバグを修正しました #45

再接続時にレコード重複するバグを修正しました。(Issues参照)

BETA v0.2.2 リリース

23 May 12:27
d399787
Compare
Choose a tag to compare
Pre-release

🚀 New Experience

データストアでソート済みの板情報の取得可能にする #40

✨ ソート済みの板情報が取得できるようになりました

FTXの例

async def main():
    store = pybotters.FTXDataStore()
    ws = await client.ws_connect(
        'wss://ftx.com/ws',
        send_json={'op': 'subscribe', 'channel': 'orderbook', 'market': 'BTC-PERP'},
        hdlr_json=store.onmessage,
    )
    pybotters.print(store.orderbook.sorted())
# {
#     'asks': [
#         [35389.0, 0.38],
#         [35392.0, 0.05],
#         [35393.0, 0.39],
#         ...
#     ],
#     'bids': [
#         [35388.0, 0.6244],
#         [35386.0, 0.1177],
#         [35382.0, 0.2],
#         ...
#     ]
# }

Bybitの例

async def main():
    store = pybotters.BybitDataStore()
    ws = await client.ws_connect(
        'wss://stream.bybit.com/realtime',
        send_json={'op': 'subscribe', 'args': ['orderBookL2_25.BTCUSD']},
        hdlr_json=store.onmessage,
    )
    pybotters.print(store.orderbook.sorted())
# {
#     'Sell': [
#         {'price': '35508.50', 'symbol': 'BTCUSD', 'id': 355085000, 'side': 'Sell', 'size': 432225},
#         {'price': '35509.00', 'symbol': 'BTCUSD', 'id': 355090000, 'side': 'Sell', 'size': 1},
#         {'price': '35514.50', 'symbol': 'BTCUSD', 'id': 355145000, 'side': 'Sell', 'size': 213690},
#         ...
#     ],
#     'Buy': [
#         {'price': '35508.00', 'symbol': 'BTCUSD', 'id': 355080000, 'side': 'Buy', 'size': 1004576},
#         {'price': '35507.50', 'symbol': 'BTCUSD', 'id': 355075000, 'side': 'Buy', 'size': 88192},
#         {'price': '35507.00', 'symbol': 'BTCUSD', 'id': 355070000, 'side': 'Buy', 'size': 86766},
#         ...
#     ]
# }

🐛 Bugfix

Bybitデータストアのinitializeメソッド引数仕様の変更漏れ #41

🐛 Bybitデータストアのinitializeメソッド引数仕様

v0.2.0リリースの実装が変更漏れとなっていました。
変更点はv0.2.0のリリースノートを参照してください。

https://github.com/MtkN1/pybotters/releases/tag/v0.2.0

BETA v0.2.1 リリース

02 May 12:34
289b382
Compare
Choose a tag to compare
Pre-release

🐛 Bugfix

(hot-fix)FTXのサブアカウントのWebSocket認証に対応した #37

BETA v0.2.0 リリース

30 Apr 15:25
aa57c85
Compare
Choose a tag to compare
Pre-release

🚀 New Experience

FTXのデータストアを実装した #20
同期リクエストをサポートした #27
apisの暗黙的な読み込みに対応した #36
FTXのサブアカウントのWebSocket認証に対応した #37

✨ FTXのデータストアを実装しました、サブアカウントのWebSocket認証に対応しました

FTXのWebSocketのデータを簡単に扱えるようになりました!

Reference、およびExchangesをご覧ください。

✨ 同期リクエストをサポートしました

requestsライブラリのように、asyncioを表面的に使用せずいとも簡単にリクエストが可能になりました!

import pybotters

r = pybotters.request('GET', 'https://...', apis=apis)
r = pybotters.get('https://...', params={'foo': 'bar'}, apis=apis)
r = pybotters.post('https://...', data={'foo': 'bar'}, apis=apis)
r = pybotters.put('https://...', data={'foo': 'bar'}, apis=apis)
r = pybotters.delete('https://...', data={'foo': 'bar'}, apis=apis)

print(r.text())
print(r.json())

NOTE:
この呼び出し方は自動的にセッションを開き必ず閉じるのでkeep-alive接続はありません。
対話モードや検証に利用する際に便利ですが、botとして実装する場合は非同期のClientクラスの利用をおすすめします。

詳細はAdvanced Usageをご覧ください。

✨ apisの暗黙的な読み込みに対応しました

カレントディレクトリにJSONファイルを配置したり、環境変数を設定することでapisの設定を省力可能になりました!

詳細はAdvanced Usageをご覧ください。

🚧 Specification Change

♻️ BybitDataStore.initialize の引数仕様を変更しました

initializeメソッドはリストを受け入れていましたが、可変長引数に変更しました。

store = pybotters.BybitDataStore()
# before
await store.initialize([
    client.get('https://...'),
    client.get('https://...'),
])
# after
await store.initialize(
    client.get('https://...'),
    client.get('https://...'),
)

BETA v0.1.2 リリース

19 Apr 15:08
a09d24e
Compare
Choose a tag to compare
Pre-release

🔧 Bugfix

BybitデータストアのUSDTの契約ポジションが正常に反映されない #34

📖 Documentation

READMEとWikiに取引所APIドキュメントのリンクを追加する #33

BETA v0.1.1 リリース

18 Apr 18:03
24981d3
Compare
Choose a tag to compare
Pre-release

🚀 New Experience

#23 WebSocket接続時に複数回リクエストに対応した(bitFlyerなどで複数チャンネルが購読に対応した)
#28 BybitデータストアのREST API経由の初期化に対応した
#29 リクエストメソッドのkwargsに対応した
#30 apisをJSON形式のファイルオープンに対応した

✨ WebSocketの複数回リクエストに対応しました

bitFlyer等、WebSocketの購読に複数回リクエスト送信がいる取引所で、必要なトピックを購読できるようになりました。

send_json(またはsend_str)をリストで指定します。

async def main():
    async with pybotters.Client(apis=apis) as client:
        wstask = await client.ws_connect(
            'wss://ws.lightstream.bitflyer.com/json-rpc',
            send_json=[
                {
                    'method': 'subscribe',
                    'params': {'channel': 'child_order_events'},
                    'id': 'subscribe:child_order_events',
                },
                {
                    'method': 'subscribe',
                    'params': {'channel': 'parent_order_events'},
                    'id': 'subscribe:lightning_ticker_FX_BTC_JPY',
                },
            ],
            hdlr_json=lambda msg, ws: print(msg),
        )
        await wstask

✨ BybitデータストアのREST API経由の初期化に対応しました

BybitのWebSocketは初期データ(オーダー・ポジション・ウォレット等)が配信されませんでしたが、REST API経由のデータを取得できるようになりました。

async def main():
    async with pybotters.Client(apis=apis.getall(), base_url='https://api.bybit.com') as client:
        store = pybotters.BybitDataStore()
        await store.initialize([
            client.get('/v2/private/order', params={'symbol': 'BTCUSD'}),
            client.get('/v2/private/position/list', params={'symbol': 'BTCUSD'}),
            client.get('/v2/private/wallet/balance'),
        ])
        print(store.order.find())
        print(store.position.find())
        print(store.wallet.find())

✨ リクエストメソッドのkwargsに対応しました

主にFTXで、リクエスト毎にサブアカウントを指定できるようになります。

async def main():
    async with pybotters.Client(apis=apis, base_url='https://ftx.com/api', headers={'FTX-SUBACCOUNT': 'my_subaccount_nickname'}) as client:
        r = await client.get('...')
        r = await client.get('...', headers={'FTX-SUBACCOUNT': 'my_alt_subaccount_nickname'})

✨ apisをJSON形式のファイルオープンに対応しました

API情報をJSONで保存している場合、コード内に変数で書かなくても読み込みるようになりました。

(ファイル名:apis.json)

{
    "bybit": ["BYBIT_API_KEY", "BYBIT_API_SECRET"],
    "btcmex": ["BTCMEX_API_KEY", "BTCMEX_API_SECRET"],
    "binance": ["BINANCE_API_KEY", "BINANCE_API_SECRET"],
    "....": ["...", "..."]
}

文字列(ディレクトリパス)を指定して読み込む。

async def main():
    async with pybotters.Client(apis='apis.json') as client:
        ...

BETA v0.1.0 リリース

13 Apr 15:10
28776b7
Compare
Choose a tag to compare
Pre-release

✨ Features

  • API認証
    • Bybit, Binance, FTX, BTCMEX, BitMEX, bitFlyer, GMO Coin, Liquid, bitbankに対応
  • DataStore
    • Bybit, BTCMEXに対応
  • パッケージング
    • PyPIに登録済み

🧪 Tests

  • API認証ロジックは単体テスト、本番環境でテスト済み