クリプトHFTとか競プロとか

競技プログラミングや仮想通貨に関することを中心にブログを書いていきます.

BTCMEXが公式に用意しているPython用WebSocketコネクタがなんかおかしい?話

仮想通貨取引所であるBTCMEX*1用のbotを開発している際に使おうとしていた WebSocketコネクタが,なにかおかしい様なので記事にしてみました.

github.com

目次:

f:id:KabukiMining:20201220151939j:plain
困った顔をしている男性

おかしい?こと

無限にwaiting

そのままコピペして公式コネクタを使おうとすると,182行目の __wait_for_symbol関数で待ったまま一生を過ごしてしまいます.

というのも, __wait_for_symbol関数は"instrument" , "trade", "quote"トピックのデータが来るまで待ち続けますが,そもそも"quote"トピックはサブスクライブされていないためデータが送られてくることはありません.

f:id:KabukiMining:20201220143030p:plain
wait_for_symbol関数

実際にトピックをサブスクライブする部分の処理を見ると, サブスクライブしているトピックは"instrument", "order", "ordeBookL2", "trade", "liquidation"のみで "quote"トピックはサブスクライブされてないことがわかります.

f:id:KabukiMining:20201220143340p:plain
__get_url

172行目を変更して"quote"を追加することで無限ループから開放されます.

f:id:KabukiMining:20201220143741p:plain
変更後のget_url

KeyError: "instrument"

ときには KeyError: "quote" として現れることもあります.

標準出力に出てくるのが鬱陶しいですが,出るのは最初の数回のみなので今回は無視することにします.

Partialが来る前にUpdateなどが来ることによって発生します.

open_orders関数が機能しない

そのままです. 機能してくれません.

新規orderに関するデータがupdateトピックを通して送られてきますが,当然同じorderIDを持つ注文に関するデータはないため,updateするものが見つからずバグってしまいます.

(245行目でreturn してしまう)

f:id:KabukiMining:20201220145417p:plain
elif action == "update"

そこで,updateでデータが送られてきた場合にも,トピックが"order"の場合いい感じにデータを挿入するようにしてみます.

242行目から249行目を以下のように変更します

for updateData in message['data']:
                            item = findItemByKeys(self.keys[table], self.data[table], updateData)
                            if not item:
                                if table == "order":
                                    self.data[table] += message["data"] # insert order data
                                    self.keys[table] = ["orderID"] # self.keys["order"] should be ["orderID"]
                                return  # No item found to update. Could happen before push
                            item.update(updateData)

f:id:KabukiMining:20201220145831p:plain
変更後のelif action == "update"

これによって,正しくorderの情報を更新/保持 するようになりました!

キャンセルされたOrderのデータも持っているのが気に食わない

これは宗教かもしれないですが,open_orders("null")を呼んでいるのにopenでないorderのデータが来るのはおかしい気がします.

254行目のremoveする条件が甘いです. サイズが0になる以外にも orderがRejectされたりCancelされる場合があるはずです.

f:id:KabukiMining:20201220150609p:plain
変更前のremove条件

254行目を

if table == 'order' and (not order_leaves_quantity(item) or not item["ordStatus"] in ("New", "PartiallyFilled")):

とすると,本当にOpenでないデータが帰ってくることはなくなります.

これで大部分の人の希望が叶ったのではないでしょうか?

おわりに

あとは各自自由に煮るなり焼くなり好きにしてください.

私の場合はopen_ordersのprefixがNoneの場合はopen_orderを全て返すように変更してみました

f:id:KabukiMining:20201220150740p:plain
変更してみたopen_order

これで僕にとっての”いいかんじ”なwebsocketコネクタを作ることができました!

*1:巷ではパチMEXとも呼ばれている