見出し画像

FTXで最後までML botを動かした結果1500万溶けた話

(この記事は2023仮想通貨アドベントカレンダーのために書いた記事です)


自己紹介

こんにちは。
機械学習使って株とか仮想通貨で遊んでる者です。
いわゆる、ML botterと呼ばれる部類だと思います。
https://twitter.com/ky12345012
そろそろ傷も癒えてきたので、今更ながら去年FTXでやらかした話を書いてみようと思いました。

私が当時運用していたbotは、ML使って良い感じに指値を出したりするものでした。内部で方向予測とかリスク予測っぽいことをMLでゴチャゴチャやる感じです。主にBTCやETHなどメジャー通貨のPERPをトレードしていて、特にマイナス手数料の取引所が得意で、volumeがあるとき調子が良い傾向にありました。

これをメインに用いて、一時期はFTXのMM3というfee tierまで行ったりしてました。これは、"Maker volume 0.25% of exchange volume"でもらえるtierだったらしいです。ほんまにそんな取引したんか?
(昔のtier tableのアーカイブ: 
https://web.archive.org/web/20221129233719/https://help.ftx.com/hc/en-us/articles/360044358751-2020-06-05-VIP-Program-and-Market-Maker-Policy)

マイナス手数料がおいしかった

当時の話

さて、話は2022年11月上旬、私が呑気に北海道を旅行している時期であり、またFTX崩壊に繋がるニュースがどんどん出て来て大騒ぎだったころのことです。
普通は「なんか危ないから出金しておこう」とか、「出金が止まった?仕方ないから、少なくともbotは止めておとなしくしておこう」とか考えると思います。

しかし当時の私は、あろうことかそのままbotを動かし続けていました。
なぜかは分かりませんが、だいたい以下のようなことを考えていた気がします。

  • 雑な成行が増えるだろうから、指値出してる自分のbotはいつもより有利なんじゃね^^

  • すでに出金が止まってるし、FTX JPから金戻ってくるのに賭けて、せっかくだから(?)bot動かしとくか^^

  • botterとして、恣意的な判断でbot止めるのはよくない

  • 海鮮美味しいから後でいいや^^

結果
1日で10万ドル以上溶けました。

https://twitter.com/ky12345012/status/1591125023921930240
真っ赤や^^

損益データの振り返り

1年経って痛みも収まったので、残っているデータをちょっとだけ振り返ってみます。
まずは約定履歴を適当にPLにしてグラフに。

取引所別のPL推移。FTXだけ損が大きい。

複数の取引所でbotを並行に動かしています。青がFTX、赤がBybit、緑がBinanceです。
この3つのbotは設計や特徴量がほぼ一緒なので、だいたいPLも似るはずという前提があります。
実際BybitとBinanceのbotは同じようなPLの推移でなんとか耐えてますが、なぜFTXだけ大きく損を出しているんでしょうか?特に、ちょうど10日の00:00あたりからすごい勢いで損を出しています。普通にキレそうです。
longとshortに分けた場合の損益や、ポジション方向も確認してみます。

ポジション方向別のPL推移と、ポジション方向

botが途中で止まったとか片方のポジションを取り続けて損したとかではなく、ふつうにがちゃがちゃトレードした結果負けているように見えます。

マーケットデータの振り返り

FTXだけで大きく損失を被ったので、(仮想通貨全体の相場環境によって損したわけではなく)どうやらFTXでのトレードに特有の問題がありそうです。何が原因なんでしょうか?
当時のBTC-PERPのohlcvを他の取引所と比較してみます。

取引所別、BTCの価格。FTXだけおかしい。

・・・大きな価格の乖離が発生している時期と、私のbotが負け始めた時期がだいたい一致しているような気がします。
FTXの価格の乖離率をグラフにしてみると、こんな感じです。

Binanceに対するFTXの価格乖離。でかすぎ。

大きな乖離が常に発生してますね。この時点でもう答えが出ているようなものですが、volumeはどうでしょうか。
大騒ぎが起こる前である11月1日~11月5日の各取引所volumeの平均を基準にして、volumeの変化を比較してみます。

取引所別のvolume変化率。FTXだけ萎んでいる。

9日の12:00ごろから急激に減ってますね。これも結構影響ありそうな感じです。
乖離率もvolumeの変化も「損失の原因がこれである」と証明するのには分析が足りてないかもしれませんが、そもそもここまで異常な状況で普段と変わらずbotを動かすのは明らかに良くなさそうな状況だった、ぐらいは分かりました。
当然ボラティリティや価格のrange、funding rateなども変な値になっていたに違いありません。
この状況で何も考えずbot動かし続けたってまじ???

ML的にどうなのか?

そういえば私のモデルは、他取引所との価格の乖離率も、volumeも、ボラティリティも、funding rateも、ごちゃごちゃと適当に特徴量として使っているのでした。
中でも代表して、他取引所との価格の乖離率はかなり大きな問題だったように思います。
学習データの中にはこんなに大きな乖離が発生したときのデータがなく、つまり完全に外れ値での外挿をしてたことになります。
使っているモデルが線形モデルやNNだったらそのまま予測値がぶっとんでもおかしくないですし、仮に特徴量を何かしらnormalizeしたりclipしたりツリー系のモデルを使ったとしても、多くの特徴量が学習データのmaxかminに数時間張り付くのはモデルにとって想定外です。

どうすれば防げたのか?

できるだけ人間の判断を入れたくないというスタンスなので、botを止める判断も任せたいです。
なので、失敗の原因は「botを止める判断をしなかったから」ではなく、「実運用時の特徴量が学習データの範囲から大きく離れてしまったことを検知して、自動で止める仕組みを作ってなかったから」だと思いました。
つまり、異常検知的なことをしておいて閾値にひっかかったらbotを止めたりアラートを出す、これでよかったのです。

実際、やってたら防げたんでしょうか?sklearnのLocalOutlierFactorを用いて、雑にやってみました。
疑似コードはだいたい以下のような感じです。


# === 学習時 ===
train_df: pd.DataFrame
train_df = normalize(train_df)
model.fit(train_df[features], train_df[label]) # トレードのためのモデル学習

# ここから異常検知の学習
outlier_model = LocalOutlierFactor(novelty=True) # 他のパラメータは適当に
pca_model = PCA(n_components=pca_components)
train_df[features] = pca.fit_transform(train_df[features]) # 必要なら
train_df = train_df.sample(10000, random_state=seed) # 必要なら
outlier_model.fit(train_df[features]) # outlier_modelを学習


# === 推論時 ===
test_df: pd.DataFrame
test_df = normalize(test_df)
preds = model.predict(test_df[features]) # これはトレードに使う

# ここから異常検知の推論
test_df[features] = pca_model.transform(test_df[features]) # 必要なら
outlier_score = outlier_model.score_samples(test_df[features]) * -1 # これを外れ値検知に使う
if outlier_score > threshold:
    stop_bot('外れ値に引っかかった')

outlier_scoreの結果は以下のようになりました。

取引所別の外れ値スコア。FTXだけoutlier_scoreが高い。

FTXだけ継続的にoutlier_scoreの値が大きくなってくれています。
他の取引所のデータでも相場が動く時に多少反応しちゃってますが、この程度なら、閾値の設定も難しくなさそうです。
高い勉強代ですね。

感想

こういう、特殊な状況下での防御力を高める実装ってなかなか後回しになりがちだなあと思いました。

残っているお金はFTX JPから無事出金されました。ありがとうございます。


いつかもらったswag。プレミア付きますか?


この記事が気に入ったらサポートをしてみませんか?