🚀 New Features
✨ 取引所 OKX をサポートしました
海外主要取引所の OKX をサポートしました。
Private API 認証及び WebSocket API による DataStore クラスを利用できます 🎉
OKX API ドキュメント:
https://www.okx.com/docs-v5/en/
API 認証
pybotters に渡す API 辞書に `okx` のキーで API 情報をリストで格納してください。
OKX は他の取引所と異なり API のパスフレーズが存在します。
リストの3要素目にパスフレーズを記載してください。
json
{
"...": ["...", "..."],
"okx": ["OKX_API_KEY", "OKX_API_SECRET", "YOUR_PASSPHRASE"]
}
Demo Trading
pybotters は OKX の Demo Trading に対応しています。
デモ版はリアルマーケットとは別の API キーの作成が必要です。
デモ版 API は `okx_demo` のキーで API 辞書に格納してください。
デモ版 API を選択してリクエストを行うには、ヘッダーに `{"x-simulated-trading": "1"}` を指定してください。
py
async def main():
apis = {"okx_demo": ["OKX_API_KEY", "OKX_API_SECRET", "YOUR_PASSPHRASE"]}
headers = {"x-simulated-trading": "1"}
async with pybotters.Client(apis=apis, headers=headers) as client:
...
DataStore のプロパティ
OKX の DataStore は WebSocket のチャンネルごとに紐づいています。
Public
(https://www.okx.com/docs-v5/en/#websocket-api-public-channel)
- instruments
- tickers
- openinterest
- candle
- trades
- estimatedprice
- markprice
- markpricecandle
- pricelimit
- books
- optsummary
- fundingrate
- indexcandle
- indextickers
Private
(https://www.okx.com/docs-v5/en/#websocket-api-private-channel)
- account
- positions
- balance_and_position (※親クラス)
- balance
- position
- orders
- ordersalgo
- algoadvance
- liquidationwarning
- accountgreeks
(※) balance_and_position WebSocket から取得するデータ構造が階層構造になっています。
そのため `store.balance_and_position.balance` `store.balance_and_position.position` といったように子クラスを定義しています。
親クラスには差分処理していないイベントがメッセージが格納されています。
DataStore の initialize
OKX の DataStore は以下のエンドポイントの initialize に対応しています。
- GET /api/v5/trade/orders-pending (DataStore: orders)
- GET /api/v5/trade/orders-algo-pending (DataStore: ordersalgo, algoadvance)
サンプルコード
initialize と ws_connect で全チャンネルを接続するサンプルです。
while True のループでは試しに ticker 情報を表示しています。
コメントアウトの部分はデモ版 API です。
py
import asyncio
import pybotters
async def main():
headers = {"x-simulated-trading": "1"}
async with pybotters.Client(base_url="https://www.okx.com") as client:
store = pybotters.OKXDataStore()
initialize
await store.initialize(
client.get("/api/v5/trade/orders-pending"),
client.get("/api/v5/trade/orders-algo-pending?ordType=conditional"),
)
ws_connect
ws_public, ws_private = await asyncio.gather(
client.ws_connect(
"wss://ws.okx.com:8443/ws/v5/public",
"wss://wspap.okx.com:8443/ws/v5/public?brokerId=9999",
send_json={
"op": "subscribe",
"args": [
{"channel": "instruments", "instType": "SWAP"},
{"channel": "tickers", "instId": "BTC-USD-SWAP"},
{"channel": "open-interest", "instId": "BTC-USD-SWAP"},
{"channel": "candle1m", "instId": "BTC-USD-SWAP"},
{"channel": "trades", "instId": "BTC-USD-SWAP"},
{"channel": "estimated-price", "instType": "SWAP", "uly": "BTC-USD"},
{"channel": "mark-price", "instId": "BTC-USD-SWAP"},
{"channel": "mark-price-candle1m", "instId": "BTC-USD-SWAP"},
{"channel": "price-limit", "instId": "BTC-USD-SWAP"},
{"channel": "books", "instId": "BTC-USD-SWAP"},
{"channel": "opt-summary", "uly": "BTC-USD"},
{"channel": "funding-rate", "instId": "BTC-USD-SWAP"},
{"channel": "index-candle1m", "instId": "BTC-USD"},
{"channel": "status"},
],
},
hdlr_json=store.onmessage,
),
client.ws_connect(
"wss://ws.okx.com:8443/ws/v5/private",
"wss://wspap.okx.com:8443/ws/v5/private?brokerId=9999",
send_json={
"op": "subscribe",
"args": [
{"channel": "account"},
{"channel": "positions", "instType": "ANY"},
{"channel": "balance_and_position"},
{"channel": "orders", "instType": "ANY"},
{"channel": "orders-algo", "instType": "ANY"},
{"channel": "algo-advance", "instType": "ANY"},
{"channel": "liquidation-warning", "instType": "ANY"},
{"channel": "account-greeks", "instType": "ANY"},
],
},
hdlr_json=store.onmessage,
),
)
loop
while True:
print(store.tickers.find())
await store.tickers.wait()
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
✨ 取引所 Bitget をサポートしました (Contributed by kunmosky1 💖)
コピートレードが可能な海外取引所の Bitget をサポートしました。
Private API 認証及び WebSocket API による DataStore クラスを利用できます 🎉
Bitget API ドキュメント:
https://bitgetlimited.github.io/apidoc/en/spot/
https://bitgetlimited.github.io/apidoc/en/mix/
API 認証
pybotters に渡す API 辞書に `bitget` のキーで API 情報をリストで格納してください。
Bitget も上記 OKX と同様に API のパスフレーズが存在します。
リストの3要素目にパスフレーズを記載してください。
json
{
"...": ["...", "..."],
"bitget": ["BITGET_API_KEY", "BITGET_API_SECRET", "YOUR_PASSPHRASE"]
}
DataStore のプロパティ
Bitget の DataStore は WebSocket のチャンネルごとに紐づいています。
Public
(https://bitgetlimited.github.io/apidoc/en/mix/#public-channels)
- trade
- orderbook
- ticker
- candlesticks
Private
(https://bitgetlimited.github.io/apidoc/en/mix/#private-channels)
- account
- orders
- positions
DataStore の initialize
Bitget の DataStore は以下のエンドポイントの initialize に対応しています。
- GET /api/mix/v1/order/current (DataStore: orders)
サンプルコード
initialize と ws_connect で全チャンネルを接続するサンプルです。
while True のループでは試しに ticker 情報を表示しています。
py
import asyncio
import pybotters
async with pybotters.Client(base_url="https://api.bitget.com") as client:
store = pybotters.BitgetDataStore()
initialize
await store.initialize(
client.get("/api/mix/v1/order/current", params={"symbol": "BTCUSDT_UMCBL"}), リニア契約
client.get("/api/mix/v1/order/current", params={"symbol": "BTCUSD_DMCBL"}) インバース契約
)
ws_connect
ws = await client.ws_connect(
"wss://ws.bitget.com/mix/v1/stream",
send_json={
"op": "subscribe",
"args": [
インバース契約
{"instType":"DMCBL", "channel":"account", "instId":"default"},
{"instType":"DMCBL", "channel":"positions", "instId":"default"},
{"instType":"DMCBL", "channel":"orders", "instId":"default"},
{"instType":"mc", "channel":"trade", "instId":"BTCUSD"},
{"instType":"mc", "channel":"ticker", "instId":"BTCUSD"},
{"instType":"mc", "channel":"candle1m", "instId":"BTCUSD"},
{"instType":"mc", "channel":"books", "instId":"BTCUSD"},
リニア契約
{"instType":"UMCBL", "channel":"account", "instId":"default"},
{"instType":"UMCBL", "channel":"positions", "instId":"default"},
{"instType":"UMCBL", "channel":"orders", "instId":"default"},
{"instType":"mc", "channel":"trade", "instId":"BTCUSDT"},
{"instType":"mc", "channel":"ticker", "instId":"BTCUSDT"},
{"instType":"mc", "channel":"candle1m", "instId":"BTCUSDT"},
{"instType":"mc", "channel":"books", "instId":"BTCUSDT"},
],
},
hdlr_json=store.onmessage,
)
loop
while True:
print(store.ticker.find())
await store.ticker.wait()
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
✨ WebSocket の接続状況が確認できるようになりました
wc_connect の返り値から WebSocket の接続状況が確認できるようになりました。
DataStore で発注管理している bot などの場合は、格納されているデータが信頼できる状態か確認を行うことで誤発注などを避ける手段となります。
以下のように `connected` で処理を分岐することが可能です。
py
async def main():
async with pybotters.Client() as client:
ws = await client.ws_connect("...")
while True:
if ws.conneted: ws.conneted: bool
print("ws is connected")
else:
print("ws is disconnected")
await asyncio.sleep(5.0)
Ctrl+C to break
※ 従来の機能として ws_connect で接続したコネクションは常に自動で再接続されます。 再接続の隙間や、取引所のメンテナンス中などのタイミングで connected が False になります。
また `wait` で `connected` が True になるまで待機することができます。
接続されている場合は await は即時終了します。
py
async def main():
async with pybotters.Client() as client:
ws = await client.ws_connect("...")
while True:
await ws.wait()
print("ws is connected. continue logic...")
...
Ctrl+C to break
_返り値の変更:_
ws_connect の返り値は `asyncio.Task` から独自の `WebSocketRunner` クラスに変更されます。
⏫ Improvements
- ✨ bitbankDataStore の Depth に timestamp を追加しました (Contributed by yota-p 💖)
階層構造ではないので DataStore に格納していなかった timestamp をクラスプロパティとして格納するようになりました。
py
store = pybotters.bitbankDataStore()
store.depth.timestamp
- ✨ WebSocket でのエラーメッセージの logging を向上しました
殆どの取引所において認証エラーや、DataStoreを利用した場合に subscribe エラー等を logging するようになりました。
- ✨ いくつかの取引所の API 認証タイムスタンプを弾かれないようにしました
pybotters が裏で利用している認証タイムスタンプは 秒 で使っていましたが、ccxt などから ミリ秒 で API を一度でも利用すると弾かれる事象がありました(Coincheck など)。
取引所が 秒 で指定していない限りは ミリ秒 を利用するようになりました。
🐛 Bugfix
- CoincheckDataStore の orderbok.sorded の型アノテーションを修正しました
- BybitUSDTDataStore で kline が initialize できない問題を修正しました
Issues
✅WebSocketの接続状況を確認できるようにする 100
✅OKXのAPI認証をサポートする 129
✅OKXのDataStoreをサポートする 130
✅CoincheckDataStoreの型アノテーションが正しくない 131
✅BybitUSDTDataStoreのinitializeにklineがない 134
✅認証Nonce(Timestamp)を13桁に見直す 135
✅README.mdにDiscordのリンクを追加する 136
✅WebSocketのエラーメッセージをloggingする 138
Pull requests
✅bitbankDataStoreのDepthにtimestampを追加 137
✅Bitgetの認証とDataStoreをサポートした 139