FIREして市場に落ちている金を拾うブログ

30代でFIREし、プログラムを勉強して米国株式と仮想通貨で落ちている金をせっせと拾う記録。

Websocket実装に向けて非同期処理を勉強する(WebSocket)その3

前回に引き続き、まちゅけんさん記事を見ながら勉強。

RESTベースで作っていたロジックを移植

どうやらBalanceについては実装されてないらしい。
また、Positionについても、Store.Positionは自炊よりも遅れる模様(RESTで取得しているため?)。
よって、Balance, Positionいずれも自炊することにした。Storeで使うのはOrderbook、Fills、Ordersのみ。

そういうわけなので、RESTベースで過去に作っていたBotからロジックを移植。
過去ロジックでは、Balance, PositionについてループのはじめにRESTで取得していたが、
Bot起動時に初期値を取得したあと、Store.Fillsのデータを使って自炊するように変更した。

なんとか動く感じになった。

Place Orderの待機ロジックを変更

公式サンプルでは、高頻度botにおいてはRESTよりWebSocketが早い可能性があるので、
下記コードでイベント待機することになっている。

            # オーダー執行
            if cond:
                # 高頻度では重複オーダーしないようにオーダー後WebSocketでデータ受信するまで待機させる
                # RESTの応答よりWebSocketのイベントの方が速い可能性があるので先にイベント待機タスクをスケジュールする
                event = asyncio.create_task(store.order.wait())
                await client.post('/v2/private/order/create', data={
                    'symbol': 'BTCUSD',
                    'side': side,
                    'order_type': 'Limit',
                    'qty': qty,
                    'price': price,
                    'time_in_force': 'GoodTillCancel',
                })
                await event

やってみたんだが、うまく動作しないようであった。

今回は両建てbotを移植したので、出しておいたMaker注文が約定したら、反対側のTaker注文を発するロジックになってるが、
上記コードでは

1. Maker注文約定認識(store.fills.findで把握)
2. Balance/ Position自炊(未ヘッジ分を把握)
3. 未ヘッジ分のTaker注文発注
4. Taker発注認識(store.order.waitイベント発生)
5. Taker注文約定認識(store.fills.findで把握)
6. Balance/ Position自炊(全量ヘッジを確認)

となるはずが、

1. Maker注文約定認識(store.fills.findで把握)
2. Balance/ Position自炊(未ヘッジ分を把握)
3. 未ヘッジ分の①Taker注文発注
4. ①Taker発注認識(store.order.waitイベント発生)
5. Balance/ Position自炊(3のTaker注文約定未認識のため、一部未ヘッジのままと認識)
6. 誤認識の未ヘッジ分②Taker注文発注

7. ①Taker注文約定認識(store.order.waitイベント発生)
8. ②Taker注文約定認識(時間経過)
9. Balance/ Position自炊(二回ヘッジオーダーをしたため、反対側へのヘッジが必要と認識)
10. 3~9をエンドレスループ

となり、ひたすら往復ビンタでOIを積み上げることになってしまった。
ロットを絞ってなかったらえらい目に合うとこだった。

対応策としては、シンプルだが

                event = asyncio.create_task(store.fills.wait())

として、ヘッジオーダーの約定まで待機することで解決。