Skip to content

Releases: pybotters/pybotters

Preview v0.12.0 アップデート✨

31 Mar 17:30
ecb1ea6
Compare
Choose a tag to compare

🚀 New Features

✨ 取引所 MEXC の API 認証をサポートしました

新たに海外取引所の MEXC をサポートしました 🚀
MEXC は取り扱いが銘柄が豊富で、複数のチェーンの入出金に対応しているのが特徴の取引所です。

Private REST / WebSocket API による DataStore クラスを利用できます。
(DataStore は今後サポート予定です)

MEXC API ドキュメント:
https://mxcdevelop.github.io/APIDoc/ (v1, v2)
https://mxcdevelop.github.io/apidocs/spot_v3_en/ (v3)

このリリース現在 MEXCには v1, v2, v3 の3種類の API エンドポイントが存在しています。
v2 と v3 が Spot 取引用、v1 が Contract 取引専用となっている模様です。
WebSocket ついては Contract 用の v1 のみ存在しており、Spot 用の v2, v3 にはありません。
どれも API 仕様が若干異なっていたりするので、他の取引所より多少難しいかもしれません。

pybotters ではこれら v1 ~ v3 全ての API 認証に対応しています ✨
(ccxt は v3 には未対応です!)

サンプルコード

オープンオーダーの取得、オーダーの送信、WebSocket のサンプルコードです。

async def mexc_v3():
    async with pybotters.Client(base_url="https://api.mexc.com") as client:
        # Get open orders
        r = await client.get(
            "/api/v3/openOrders",
            params={"symbol": "BTCUSDT"}
        )
        data = await r.json()
        print(data)

        # Place order
        r = await client.post(
            "/api/v3/order",
            data={
                "symbol": "BTCUSDT",
                "side": "BUY",
                "type": "MARKET",
                "quoteOrderQty": "5",
        )
        data = await r.json()
        print(data)

async def mexc_v1():
    async with pybotters.Client(base_url="https://contract.mexc.com") as client:
        # Get open orders
        r = await client.get(
            "/api/v1/private/order/list/open_orders/BTC_USDT",
        )
        data = await r.json()
        print(data)

        # Place order
        r = await client.post(
            "/api/v1/private/order/submit",
            data={
                "symbol": "BTC_USDT",
                "price": "40000.0",
                "vol": "10", # contract vol
                "side": 1,
                "type": 1,
                "openType": 1,
            }
        )
        data = await r.json()
        print(data)

        # WebSocket login authentication
        ws = await client.ws_connect(
            "wss://contract.mexc.com/ws",
            send_json={"method": "push.personal.order", "param": {}},
        )
        await ws

⏫ Improvements & Bugfix

  • ✨ 1つの API 情報を複数の pybotters.Client に渡たせるようになりました

こうしたとき apis が参考渡しだったので、バイト化の関係上2回目でエラーになっていましたが値渡しをするように変更することで解消しました。

apis = {"mexc": ["API_KEY", "API_SECRET"]}

try:
    client1 = async with pybotters.Client(apis=apis)
    client2 = async with pybotters.Client(apis=apis) # before: error, after: ok
    ...
finally:
    await client1.close()
    await client2.close()
  • ✨ 空の API 情報を指定できるようになりました

apis に空辞書 {} を指定しても、環境変数などが設定されているとそちらの apis を優先されていましたが、 {} が優先されようになり明示的に認証なしで利用できるようになりました。

  • ✨ Phemex と Bitget の initialize でエラーが表示されるようになりました (Contributed by @kunmosky1 💖)

Phemex と Bitget の DataStore で REST API の initialize が失敗したとき、エラーが表示されるようになります。

Issues

✅MEXCのAPI認証に対応する #142
✅ソースコードの文字列クォーテーションを正規化する #145
⏩試験的に既存の機能を分離し抽象化を強化する #147
✅API情報が参照渡しなので元のAPI情報を書き換えてしまう #149
✅空の辞書をapisに渡すと意図しない暗黙的な読み込みをする #151

Pull requests

✅initializeの際のエラー時(主に認証エラー)にエラーメッセージを表示するように #144

Full Changelog: v0.11.1...v0.12.0

Preview v0.11.1 リリース[Hotfix]

19 Mar 13:05
571fa20
Compare
Choose a tag to compare

👾 Hotfix

  • OKX Demo trading で WebSocket 認証ができない問題を修正しました
  • Bitget の API 認証ができない問題を修正しました

Preview v0.11.0 リリース

19 Mar 12:45
48377c3
Compare
Choose a tag to compare

🚀 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要素目にパスフレーズを記載してください。

{
    "...": ["...", "..."],
    "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"} を指定してください。

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 です。

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要素目にパスフレーズを記載してください。

{
    "...": ["...", "..."],
    "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 情報を表示しています。

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 で処理を分岐することが可能です。

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 になります。

また waitconnected が True になるまで待機することができます。
接続されている場合は await は即時終了します。

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 をクラスプロパティとして格納するようになりました。

store = pybotters.bitbankDataStore()
store.depth.timestamp
  • ✨ WebSocket でのエラーメッセージの logging を向上しました

殆どの取引所において認証エラーや、DataStoreを利用した場合に subscribe エラー等を logging するようになりました。

  • ✨ いくつかの取引所の API 認証タイムスタンプを弾かれないようにしました

pybotters が裏で利用している認証タイムスタンプは 秒 で使っていましたが、ccxt などから ミリ秒 で API を一度でも利用すると弾かれる事象がありました(Coincheck など)。
取引所が 秒 で指定していない限りは ミリ秒 を利用するようになりました。

#...

Read more

Preview v0.10.0 リリース

04 Feb 13:44
4174779
Compare
Choose a tag to compare
Pre-release

🎉 New Features

✨ Coincheck の DataStore をサポートしました

国内現物取引所の Coincheck の DataStore をサポートしました。 Coincheck の WebSocket API によるリアルタイムデータを活用できます 🚀

DataStore のプロパティ

  • trades: 取引履歴
  • orderbook: 板情報

※ Coincheck の WebSocket API はパブリックデータのみ提供しています。プライベートデータはありません。

以下、接続のサンプルコードです。

import asyncio
import pybotters

async def main():
    async with pybotters.Client(base_url="https://coincheck.com") as client:
        store = pybotters.CoincheckDataStore()
        wstask = await client.ws_connect(
            "wss://ws-api.coincheck.com/",
            send_json=[
                {"type": "subscribe", "channel": "btc_jpy-trades"},
                {"type": "subscribe", "channel": "btc_jpy-orderbook"},
            ],
            hdlr_json=store.onmessage,
        )
        await store.initialize(client.get("/api/order_books"))
        while True:
            pybotters.print("Trades")
            pybotters.print(store.trades.find()[-1:])
            pybotters.print("Orderbook")
            pybotters.print({k: v[:5] for k, v in store.orderbook.sorted().items()})
            await store.wait()

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass

詳しくは Coincheck のドキュメントもご覧ください。
https://coincheck.com/ja/documents/exchange/api#websocket

✨ DataStore のリバースイテレーションに対応しました

DataStore を reversed 関数でリバースイテレーションできるようになりました。
時系列データなどを逆順(時間の新しい順)で効率的に取得できます。

以下は、Bybit のトレードを WebSocket で10件取得するまで待機し逆順で表示するサンプルコードです。

※ この機能は辞書の reversed を行っている為、 Python 3.8 以降で利用できます

async def main():
    async with pybotters.Client() as client:
        store = pybotters.BybitUSDTDataStore()
        wstask = await client.ws_connect(
            "wss://stream.bybit.com/realtime_public",
            send_json=[
                {"op": "subscribe", "args": ["trade.BTCUSDT"]},
            ],
            hdlr_json=store.onmessage,
        )
        print("wait for trades")
        while len(store.trade) < 10:
            await store.wait()
        print("printing trades in reverse order")
        for item in reversed(store.trade):
            print(item)

✨ GMOコインのアクセストークンが自動延長されるようになりました

GMOCoinDataStore の initialize メソッドに「アクセストークンを取得」のリクエストを渡すと DataStore にトークンが保持され、アクセストークンが30分ごとに自動延長されます。
プログラムの起動中にアクセストークンが切れることがないので安全にプライベート WebSocket の再接続時されます。

サンプルコード

async def gmocoin():
    async with pybotters.Client(base_url="https://api.coin.z.com") as client:
        store = pybotters.GMOCoinDataStore()
        await store.initialize(
            client.post("/private/v1/ws-auth"),
        )
        wstask = await client.ws_connect(
            f"wss://api.coin.z.com/ws/private/v1/{store.token}",
            send_json=[
                {"command": "subscribe", "channel": "executionEvents"},
                {"command": "subscribe", "channel": "orderEvents"},
                {"command": "subscribe", "channel": "positionEvents"},
                {"command": "subscribe", "channel": "positionSummaryEvents", "option": "PERIODIC"},
            ],
            hdlr_json=store.onmessage,
        )
        while True:
            ...
            # something code

🎈 Improves

  • ✨ BybitInverseDataStore に wallet を追加しました

Bybit の更新に伴い BybitInverseDataStorewallet を追加しました。
ストアからインバースの残高情報を参照できます。
また initialize も残高エンドポイントの初期化に対応しました。

※ Bybit インバースの残高については、従来の position にもデータが存在しています。

  • ✨ PhemexDataStore で認証エラーの Warning が表示されるようになりました

🐛 Bugfix

✨ いくつかのバグを修正しました

  • GMOCoinDataStore の ticker が上書きされない問題を修正しました
  • Python 3.8 以下の場合 GMOCoinDataStore が TypeError で落ちる問題を修正しました
  • bitbankDataStore の depth.sorted() の型アノテーションの間違いを修正しました

Issues

✅ 各取引所のDataStoreを実装する #20
✅ DataStoreのリバースイテレーション可能にする #113
✅ PhemexDataStoreで認証エラーのWarningを表示する #114
✅ BybitInverseDataStoreにwalletを追加する #118
✅ GMOCoinDataStoreのtickerが上書きされない #120
✅ GMOCoinDataStoreがTypeErrorで落ちる。 #122
✅ GMOコインのPrivate WebSocketアクセストークンを自動延長する #124
✅ bitbankのDatastoreのDepthで、sorted()の返り値の型の定義が正しくない #126

Preview v0.9.0 リリース

03 Jan 07:54
5f3558a
Compare
Choose a tag to compare
Pre-release

🎉 New Features

✨ PhemexのDataStoreをサポートしました (Contributed by @kunmosky1 💖)

PhemexのDataStoreをサポートしました。PhemexのWebSocketによるリアルタイムデータを活用できます!

DataStoreのプロパティ

  • trade: トレード
  • orderbook: 板情報
  • ticker: ティッカー
  • market24h: マーケット
  • kline: ローソク足
  • accounts: アカウントデータ
  • positions: ポジション

以下接続のサンプルコードです。接続後はローソク足の更新を表示しています。

import asyncio
import pybotters
import time

apis = {'phemex': ['API_KEY','API_SECRET'],}

async def main():
    async with pybotters.Client(apis=apis, base_url='https://api.phemex.com') as client:
        store = pybotters.PhemexDataStore()
        endtime = int(time.time()) - 60 * 999 #ws接続時に1000本送られてくるので、それより前の2000本を取得(合計で起動時に2999本)
        await store.initialize(
            client.get('/exchange/public/md/kline', params={'symbol': 'BTCUSD', 'resolution': 60, 'from': endtime - 60 * 2000, 'to': endtime}),
        )
        wstask = await client.ws_connect(
            'wss://phemex.com/ws',
            send_json=[
                {'id': 100, 'method': 'trade.subscribe', 'params': ['BTCUSD']},
                {'id': 101, 'method': 'tick.subscribe', 'params': ['.BTC']},
                {'id': 103, 'method': 'orderbook.subscribe', 'params': ['BTCUSD']},
                {'id': 104, 'method': 'kline.subscribe', 'params': ['BTCUSD',60]},
                {'id': 105, 'method': 'market24h.subscribe', 'params': []},
                {'id': 200, 'method': 'aop.subscribe', 'params': []},
            ],
            hdlr_json=store.onmessage,
        )
        # Ctrl+C to break
        while True:
            await store.kline.wait()
            data = store.kline.find()
            print(data)

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass

✨ Bybit USDT契約のポジション ワンウェイモードに対応しました

Bybitのアップデートに伴い、pybotters.BybitUSDTDataStore もワンウェイモードに対応しました!

store = pybotters.BybitUSDTDataStore()
await client.ws_connect(...)
...
position = store.position.one("BTCUSDT") # one-way mode
position = store.position.both("BTCUSDT") # hedge mode

✨ Bybitのタイムスタンプ認証が通りやすくなりました

BybitはクライアントPCの時刻同期が少しでもズレいると、REST APIでは invalid request, please check your timestamp and recv_window param といったエラーが派生したり、WebSocketでは WSServerHandshakeError が発生することがありました。
今回のアップデートでは内部的にタイムスタンプのズレの許容幅を広げ、おおよそ5秒のズレまでは上記エラーを発生しづらくなります。

🐛 Bugfix

✨ 多数のバグを修正しました

コミュニティの方々のバグ報告により、7つのバグを修正しました。
いつもバグ報告ありがとうございます!

  • Bybit Spotで注文削除(DELETEリクエスト)などができない問題が修正しました
  • Binance Spot WebScoketの1秒につき5リクエスト制限に対応しました
  • bitFlyerの親注文(入れ子のリクエスト)などができない問題を修正しました
  • BybitUSDTDataStoreのinitializeにウォレットを再実装しました
  • PhemexやBybitのDELETEリクエストに params を指定しても警告を表示しないようにしました
  • GMOCoinDataStoreでタイムスタンプの例外が発生する問題を修正しました
  • bitbankの認証タイムスタンプをUNIXタイムスタンプ(13桁)に修正しました
  • bitbankDataStoreの板情報のsortedメソッドを数値でソートするように修正しました

Issues

✅ Bybit SpotのDELETE認証方式を修正する #95
✅ BinanceのWebSocket制限に対応する #96
✅ bitFlyerの親注文APIがエラーになる #98
✅ BybitUSDTDataStoreのウォレット実装が漏れている #99
✅ HTTPリクエストのメソッドにおけるパラメーター指定時の警告を削除する #101
✅ Bybitの認証タイムスタンプについて変更を検討する #102
✅ Bybit USDT無期限のワンウェイモードに対応する #105
✅ GMOコインのタイムスタンプにミリ秒がないレコードがパースできない #106
✅ Binance USDⓈ-M Futuresの新しいWebSocketエンドポイントに対応する #108
✅ bitbankの認証タイムスタンプを修正する #109
✅ 旧BybitDataStoreクラスがauto_castを受け付けない #111
✅ bitbankDataStoreの板情報のソートが間違っている #110

Pull requests

✅ Phemexのデータストアをサポートする #97
✅ GMOコインのタイムスタンプのミリ秒をパースする #107

Preview v0.8.0 リリース

11 Nov 13:27
Compare
Choose a tag to compare
Pre-release

🎉 New Features

✨ bitFlyerのDataStoreをサポートしました

DataStoreのプロパティ

  • board: 板情報
  • ticker: Ticker
  • executions: 約定
  • childorderevents: 注文イベント
  • childorders: アクティブな注文
  • parentorderevents: 親注文(特殊注文)イベント
  • parentorders: アクティブな親注文(特殊注文)
  • positions: 建玉の一覧

REST APIのinitializeとWebSocket購読のサンプルコード

import asyncio
import pybotters

async def main():
    async with pybotters.Client(apis=apis, base_url="https://api.bitflyer.com") as client:
        store = pybotters.bitFlyerDataStore()
        await store.initialize(
            client.get("/v1/me/getchildorders?product_code=FX_BTC_JPY"),
            client.get("/v1/me/getparentorders?product_code=FX_BTC_JPY"),
            client.get("/v1/me/getpositions?product_code=FX_BTC_JPY"),
        )
        wstask = await client.ws_connect(
            "wss://ws.lightstream.bitflyer.com/json-rpc",
            send_json=[
                {"method": "subscribe", "params": {"channel": "lightning_board_snapshot_FX_BTC_JPY"}, "id": 1},
                {"method": "subscribe", "params": {"channel": "lightning_board_FX_BTC_JPY"}, "id": 2},
                {"method": "subscribe", "params": {"channel": "lightning_ticker_FX_BTC_JPY"}, "id": 3},
                {"method": "subscribe", "params": {"channel": "lightning_executions_FX_BTC_JPY"}, "id": 4},
                {"method": "subscribe", "params": {"channel": "child_order_events"}, "id": 5},
                {"method": "subscribe", "params": {"channel": "parent_order_events"}, "id": 6},
            ],
            hdlr_json=store.onmessage,
        )
        while True:
            await store.wait()
            for name, ds in store._stores.items():
                print(f"{name}: {len(ds)=}")
            print()

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass

✨ [重要] BybitのDataStoreを Inverse/USDT 取引用にクラス分けしました

BybitのDataStoreは以下の2クラスに変更されました。それぞれの取引に最適化されます。

pybotters.BybitInverseDataStore, pybotters.BybitUSDTDataStore

既存のpybotters.BybitDataStore は引き続き利用できますが、非推奨になります。(今後廃止されます)

✨ DataStoreのstr型数値フィールド自動キャスト機能を追加しました

auto_cast=Trueにすることにより、「str型の数字」のデータを自動的にint/floatに変換します。

store = pybotters.BybitInverseDataStore(auto_cast=True)

この機能を有効にすることで演算が便利になりますが、WebScoketイベントごとのstr型フィールドを判定するので処理負荷が増加します。

✨ WebSocketにおけるバイナリ型データのリクエスト/ハンドリングをサポートしました

Client.ws_connectメソッドに、send_bytes, hdlr_bytesを追加しました。
Huobi Global(非対応非期初)などのデータハンドリングも可能になります。

Huobiのサンプル

import asyncio
import aiohttp
import gzip
import json
import pybotters

async def huobi_handler(msg_bytes: bytes, ws: aiohttp.ClientWebSocketResponse):
    msg_json = json.loads(gzip.decompress(msg_bytes).decode())
    if "ping" in msg_json:
        ping = msg_json["ping"]
        await ws.send_str(f'{{"pong":{ping}}}')
    else:
        print(msg_json)

async def main():
    async with pybotters.Client() as client:
        ws = await client.ws_connect(
            "wss://api.huobi.pro/ws",
            send_str='{"sub": "market.btcusdt.ticker"}',
            hdlr_bytes=huobi_handler,
        )
        await ws

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass

✨ GMOCoinDataStoreの板情報にタイムスタンプを追加しました

pybotters.GMOCoinDataStore.orderbooks.timestamp からタイムスタンプを取得できます

Issues

✅ Bybitの型問題の抜本的な解決方法について #82
✅ バイナリのWebSocketデータのハンドリングに対応する #87
✅ GMOコインのデータストアにタイムスタンプを追加する #88

Pull requests

✅ Remove default empty list #92
✅ add API Reference #93

Preview v0.7.1 リリース

28 Sep 12:04
f90a05b
Compare
Choose a tag to compare
Pre-release

🐛 Bugfix

✅ 一部ストアにおいてデータが更新されない不具合を修正しました

DataStoreの内部メソッド _clear が正しく動作しない不具合を修正しました。
これを使用している以下のストアが v0.6.0 リリース 以降、動作に問題がありましたがこの修正により改善されます。

  • pybotters.BinanceDataStore
    • Orderストア
  • pybotters.FTXDataStore
    • Marketsストア
  • pybotters.experimental.BybitUSDTDataStore
    • Walletストア

Preview v0.7.0 リリース

24 Sep 16:39
88a7405
Compare
Choose a tag to compare
Pre-release

🎉 New Features

✨ BybitのWebSocketのLiquidation(清算)をサポートしました

2021-9-14にサポートされた WebSocketのLiquidationトピックをDataStoreに追加しました!
なお、REST APIの /v2/public/liq-records2021-9-24に廃止される ので注意してください。

WebSocketの清算イベントを表示するサンプルです。
清算は直ぐには発生しないので気長に待ちましょう🛀

import asyncio
import pybotters

async def main():
    async with pybotters.Client() as client:
        store = pybotters.BybitDataStore()
        await client.ws_connect(
            "wss://stream.bybit.com/realtime",
            send_json={"op": "subscribe", "args": ["liquidation.BTCUSD"]},
            hdlr_json=store.onmessage,
        )
        while True:
            print(await store.liquidation.wait())

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass

🌈 試験的にBybitの型変換済みDataStoreを実装しました

Experimentalな機能ですが、 文字列になってる数値をfloatやintに変換 して保管する新設計のDataStoreを実装しました!
このように価格や数量などのフィールドはfloatやintに変換を掛けて保管するようになります。

#before
[
    {"symbol": "BTCUSD", "price": "1234.50", "id": 1234500, "side": "Sell", size: "100"}
]
#after
[
    {"symbol": "BTCUSD", "price": 1234.5, "id": 1234500, "side": "Sell", size: 100}
]

また、従来の pybotters.BybitDataStore はInverse契約とUSDT(Linear)契約の共通DataStoreでしたが、新しいDataStoreでは双方の契約の細かな仕様や型の違いに対応するために、クラスを2つに分割しました。
pybotters.experimental.BybitInverseDataStorepybotters.experimental.BybitUSDTDataStore から利用できます。

最も大きな違いとしては、クラスが共通でなくなった為にポジションストアのメンバ名が変更されています。

# before
store = pybotters.BybitDataStore()
store.position_inverse.getone("BTCUSD")
store.position_inverse.getboth("BTCUSDM21")
store.position_usdt.getboth("BTCUSDT")
# after
store = pybotters.experimental.BybitInverseDataStore()
store.position.one("BTCUSD")
store.position.both("BTCUSDM21")
store = pybotters.experimental.BybitUSDTDataStore()
store.position.both("BTCUSDT")

その他の細かい違いとしては、walletストアはUSDTのみ、insuranceストアはインバースのみ、USDTのstoporderストアはキー名を変換せずstop_order_idのまま利用するようにした、などです。

Bybitは 文字列の数値 のおかげで演算がやっかいなので、この試験的な機能は役に立つかもしれません。
型変換済みのDataStoreで板情報を表示するコードです!

import asyncio
import pybotters

async def main():
    async with pybotters.Client() as client:
        store = pybotters.experimental.BybitInverseDataStore()
        await client.ws_connect(
            "wss://stream.bybit.com/realtime",
            send_json={"op": "subscribe", "args": ["orderBookL2_25.BTCUSD"]},
            hdlr_json=store.onmessage,
        )
        while not len(store.orderbook):
            await store.wait()
        pybotters.print(store.orderbook.sorted())

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass

⚠ これは暫定的・試験的な実装なので、将来的に大きく変更が入るかもしれません

✨ BybitのKlineの初期化をサポートしました (Contributed by @LopeRope 💖)

initializeメソッドでKlineのデータを格納できる機能を追加しました!

使い方はこちらです。

import asyncio
import time
import pybotters

async def main():
    async with pybotters.Client(base_url="https://api.bybit.com") as client:
        store = pybotters.BybitDataStore()
        ts = int(time.time()) - 300
        await store.initialize(
            client.get(f"/v2/public/kline/list?symbol=BTCUSD&interval=1&from={ts}")
        )
        pybotters.print(store.kline.find())
        await client.ws_connect(
            "wss://stream.bybit.com/realtime",
            send_json={"op": "subscribe", "args": ["klineV2.1.BTCUSD"]},
            hdlr_json=store.onmessage,
        )
        while True:
            pybotters.print(store.kline.find())
            await store.kline.wait()

try:
    asyncio.run(main())
except KeyboardInterrupt:
    pass

Issues

✅ Bybitの型問題の抜本的な解決方法について #82
✅ BybitのLiquidationトピックを追加する #83

Pull requests

✅ BybitのKlineのinitializeを追加する #81

Preview v0.6.0 リリース

15 Aug 18:35
d69b54d
Compare
Choose a tag to compare
Pre-release

🎉 New Features

✨ GMOコインのDataStoreをサポートしました (Contributed by @supermomonga 💖)

pybottersでは初の国内取引所DataStoreをサポートしました!
pybotters.GMOCoinDataStore から、GMOコインのWebSokcetによるリアルタイムデータを利用することができます。
さらに本DataStoreは初の試みとして データの型付け をサポートしています。
symbolはstr型、priceなどはDecimal型、timestampはdatetime型など、データの意味通りの型でDataStoreに保管されます。
従来のDataStoreは数値や時刻データが文字列型でもそのまま(元の型のまま)保管していましたが、これにより演算やさらなる処理が容易になります。
GMOCoinDataStoreのインターフェースはリファレンスをご覧ください。

✨ CoincheckのAPI認証をサポートしました

国内取引所 Coincheck のAPI認証をサポートしました!
オーダー発注や残高の取得などのプライベートAPIが利用できます。 ※DataStoreは未対応です

✨ waitメソッドから受信データを取得できるようになりました (Contributed by @kaznak 💖)

DataStore.wait メソッドの返り値は従来はNoneでしたが、** 待機した結果取得したデータ ** を返すようになりました。
これにより ** PostOnlyオプションにより即時キャンセルされてしまったオーダー ** などのDataStoreに残らないオーダー(※)を取得できます。 ※各種DataStoreのオーダーはアクティブオーダーのみ管理する仕様なので約定orキャンセル済みは削除される
注意: 親クラスの DataStoreManager.wait メソッドの方にはこの機能はありません。

async def main():
    async with pybotters.Client(base_url='https://ftx.com/api, apis=apis) as client:
        store = pybotters.FTXDataStore()
        ws = await client.ws_connect(
            'wss://ftx.com/ws',
            send_json={'op': 'subscribe', 'channel': 'orders'},
            hdlr_json=store.onmessage,
        )

        asyncio.create_task(client.post('/orders', data=...)) # Send an order that will be canceled immediately
        result = await store.orders.wait()
        print(result)
        # {'id': ..., 'status': 'closed', ...: ...}
        print(store.orders.find())
        # []

📖 Documentation

✨ Sphinxによるドキュメント自動生成を導入しました (Contributed by @drillan 💖)

Read The Docsにドキュメントを生成できるSphinxを導入しました!
GitHub WikiからRead The Docsにドキュメントを移行する予定です。
https://pybotters.readthedocs.io/ja/latest/

Other

  • pybottersのリリース状況についての表記をBETAから Preview の名称に変更しました
  • DataStoreを管理する抽象クラスの名称をDataStoreInterfaceからDataStoreManagerに変更しました
  • DataStoreに隠しメソッド _pop, _find_and_delete を追加しました

詳細については以下をご覧ください。

Issues

✅ 対応取引所の追加(Phemex、Coincheck) #52
✅ GMO コインの DataStore を実装する #60
✅ リリース表記をPreview版にする #73
✅ FTXDataStore の orders チャネルにおける close されたオーダーの取り扱いについて #75
✅ DataStoreInterfaceのクラス名を変更する #79

Pull requests

✅ GMO コイン用の DataStore を一部実装する #74
✅ DataStore のレコード削除メソッドのサンプル実装 #76
✅ DataStore の wait メソッドが変更されたデータを返す実装 #77
✅ Sphinxのドキュメントを追加 #78

BETA v0.5.0 リリース

11 Jul 16:56
2f8504f
Compare
Choose a tag to compare
Pre-release

#20 bitbankのDataStoreをサポート (contributed by @Osaifu-Crypto )
#52 PhemexのAPI認証をサポート
#67 GMO コインの認証処理を修正 (contributed by @supermomonga)
#70 WebSocketのClientOSErrorをキャッチする
#71 BTCMEXのサポートを廃止する(BitMEXをサポートする)

🎉 New Features

✨ bitbankのDataStoreをサポートしました

bitbankのWebSocketデータをハンドリングするDataStoreを実装しました!
pybotters.bitbankDataStore から利用できます。
bitbankはSockei.io形式なので接続方法については従来とは少し異なります。下記サンプルコードを参照してください。
本機能はおさいふ君さん(@Osaifu_Crypto)にコードを提供して頂きました💖

各チャンネルのデータを監視するサンプルコードです。(コメントアウト/解除して利用してください)

async def main():
    async with pybotters.Client() as client:
        store = pybotters.bitbankDataStore()
        wstask = await client.ws_connect(
            'wss://stream.bitbank.cc/socket.io/?EIO=3&transport=websocket',
            send_str=[
                '42["join-room","ticker_xrp_jpy"]',
                '42["join-room","transactions_xrp_jpy"]',
                '42["join-room","depth_whole_xrp_jpy"]',
            ],
            hdlr_str=store.onmessage,
        )
        while True:
            # Transactions
            # await store.transactions.wait()
            # pybotters.print(store.transactions.find()[-1])

            # Depth
            await store.depth.wait()
            pybotters.print({k:v[:6] for k, v in store.depth.sorted().items()})

            # Ticker
            # await store.ticker.wait()
            # pybotters.print(store.ticker.find())

✨ PhemexのAPI認証をサポートしました

シンガポールを拠点とする新興取引所 Phemex のAPI認証をサポートしました。
REST/WebSocketのプライベートAPIを利用できます。(※WebSocketデータを保管するDataStore機能は未実装です)

新規オーダーを送信、プライベートWebsocketに接続するサンプルコード

async def main():
    async with pybotters.Client(apis=apis, base_url='https://api.phemex.com') as client:
        data = {
            'symbol': 'BTCUSD',
            'side': 'Buy',
            'priceEp': 334100000,
            'orderQty': 1,
            'ordType': 'Limit',
            'timeInForce': 'PostOnly',
        }
        r = await client.post('/orders', data=data)
        data = await r.json()
        pybotters.print(data)

        wstask = await client.ws_connect(
            'wss://phemex.com/ws',
            send_str='{"method":"aop.subscribe","params":[],"id":123}',
            hdlr_json=pybotters.print_hander
        )
        await wstask # Ctrl+C to break

✨ BTCMEXのサポートを廃止、BitMEXのDataStoreをサポートしました

BTCMEXが営業終了しましたのでコードやWikiの記述を削除しました。
代わりにBTCMEXはBitMEXのほぼ互換APIだったので、やっつけながらDataStoreを逆輸入しBitMEXのDataStoreをサポートしました。
pybotters.BitMEXDataStore から利用できます。

🐛 Bugfix

  • GMOコインのWebSocket認証トーンが正常にリクエストできるよう不具合を修正しました (本修正はめちゃコミッタさん(@supermomonga)に提供して頂きました💖)
  • WebSocketの接続がClientOSErrorといったエラーで落ちないように処理を修正しました