Releases: pybotters/pybotters
BETA v0.4.1 リリース
✅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 リリース
✅ 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 リリース
✅ 試験的にBinanceのDataStoreを実装する(各取引所のDataStoreを実装する) #20
✅ BybitのInstrumentが重複する #45
🌈 Experimental
✨ 試験的にBinanceのDataStoreを実装しました #20
一部のマーケットストリームとユーザーデータストリームのDataStoreを実装しました。
** 重要 **
基本的にはFutures(USDⓈ-M、COIN-M)でテストをしており、Spotは対応できてない可能性があります。
板情報は未実装です。ベスト値のみ取れる板ティッカー(bookticker
)のみ使えます。
また、initialize
のようなメソッドも実装していないのでポジションやオーダーの初期値は取得できません。
完全なDataStoreは今後実装予定です。
実装済みストリーム
trade
(Market Streamstrade
,aggTrade
)bookticker
(Market StreamsbookTicker
)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 リリース
🚀 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のリリースノートを参照してください。
BETA v0.2.1 リリース
🐛 Bugfix
(hot-fix)FTXのサブアカウントのWebSocket認証に対応した #37
BETA v0.2.0 リリース
🚀 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 リリース
BETA v0.1.1 リリース
🚀 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 リリース
✨ Features
- API認証
- Bybit, Binance, FTX, BTCMEX, BitMEX, bitFlyer, GMO Coin, Liquid, bitbankに対応
- DataStore
- Bybit, BTCMEXに対応
- パッケージング
- PyPIに登録済み
🧪 Tests
- API認証ロジックは単体テスト、本番環境でテスト済み