
マーケット・メイクにおける在庫管理と実運用上の懸念点
今回のnoteでは、bitFlyerでHFTボットを稼働する際の注意点の一つとして、ポジション取得APIの遅延や誤差による損失可能性についてまとめます。
今回の記事の主な対象は、HFTの中でもAsk、Bidの両側に指値を出す「マーケット・メイカー型」のボットです。
マーケット・メイカー型ボットのあらまし
一言でHFTと言っても、様々な戦略が存在します。その中でも「マーケット・メイキング戦略」により取引を行うボットは、現在のBotter界隈では最も主流となっている、という印象を受けます。
マーケット・メイキング戦略とは、板に売りと買いの両方の指値注文を供給し、その両方を約定させることで、その価格差分を収益源とする戦略です。
ワンペアの約定ごとの価格差は小さいため、高頻度化することで収益を積み重ねます。
指値注文の出し方は何通りかあり、売りと買いを同時に発注するものもあれば、片側の約定を待ってからもう片側の注文を発注する「Wait for the other side」という手法もあります。
共通して言えることは、この戦略の収益減は価格の変動によるポジション損益では「ない」ということです。この戦略では、あくまで両側の注文の価格差を収益源とします。
つまり、長期的な視点でみたときの保有ポジションはなるべくゼロであることが望ましく、このため、他のHFT戦略よりも在庫管理の重要性が大きくなります。
在庫を管理して、在庫リスクを抑制する
以前のUKIの記事をご覧ください。
この中で、Avellaneda, Stoikov [2008]の論文が紹介されていますが、この論文では、自身の保有在庫量(Inventory)を基に上下の指値幅を動的に調整することにより、在庫リスクを抑制しようとしています。
モデルの数式は少し複雑なのですが、これは単純に
①プラスの在庫(買いポジション)を持っている場合、
新たな買い指値は少し遠くに置く(約定しにくくする)
新たな売り指値は少し近くに置く(約定しやすくする)
②マイナスの在庫(売りポジション)を持っている場合、その逆
ということです。
より発展したアイデアとして、在庫量に応じて発注量も変化させる、約定のしやすさを判断するために板の厚みも考慮に入れる、などが考えられます。
この在庫管理の仕組みにより、値動きが一方に偏ったとき(例えば連続的な価格上昇が起こった場合)、片側の注文だけ約定して反対在庫を抱えてしまうリスクを、ある程度低減することができます。
「持っている在庫に応じて注文の出し方を変える」というのは、在庫リスクを抑制してリターンを安定させるための、直観的かつ現実的な解決手法なのです。
在庫を加味した発注ロジック
上記を踏まえてマーケット・メイクのロジックを設計すると、ざっくりと以下のような流れになります(ざっくりです)。
①現在のポジションを取得
②そのポジションに応じて、買い指値と売り指値の価格を設定
③発注
④約定またはキャンセル そして①へ戻る
このロジックは、現在ポジションに応じて発注のされ方がまるで変わりますので、ロジック内において「現在ポジションが決定的な役割を担っている」と言ってしまってよいでしょう。
そしてこのような場合、「正確に現在ポジションを取得できない」ということが、致命的な問題となります。
ポジション情報の遅延や誤差の実情
以上が長い前置きとなったわけですが、
bitFlyerを始め、暗号通貨の各取引所では、この「正確に現在ポジションを取得できない」という事態が往々にして発生します。
なんか、bFのポジション遅延が散見するな。約定履歴みたら明らかにポジションできてるのに、APIでポジション取得しても反映されてない。
— Hoheto (@i_love_profit) January 17, 2019
「情報自体は正確だがタイムリーに送られてこない」場合と、「そもそも情報自体が正しくない(=約定情報が反映されていない)」場合があります。
原因は、例えば以下のようなことにあるでしょう。
・ポジション取得用のAPIのネットワーク遅延、およびサーバ側の処理遅延
・自身の注文やキャンセルのネットワーク遅延、およびサーバ側の処理遅延
・ポジション取得と約定のタイミングの誤差
・約定情報が取引所サーバのポジションデータに反映されるまでのラグ
・その他リクエストエラー
この中には、ロジックによって多少回避できるものもあります。
乱暴に言ってしまうと、例えばキャンセル注文を5秒置きに3回発注してからポジション取得を3回繰り返し、全て合致していたら正しいとみなす、などですが、追求するごとにロジックの戦略性が毀損されますし、どのみち100%正しいことを保証するものにはなりません。
実際に、APIによるポジション取得にどの程度遅延が生じているかを、例示します。
こちらは2月某日における某時刻に、テスト運用中のボットが構築したポジションについて、二種類のポジション推移を時系列に示したものです。
青線:実際のポジション(約定履歴を正としたときのポジション)
後日、REST APIから取得できる約定履歴を用いて
ポジション推移を再現したもの。
時刻は約定情報に記載されているexec_date。
赤線:APIによるポジション
実運用の際に、REST APIから取得したポジション。
時刻はリクエスト時刻とレスポンス時刻を足して2で割ったもの。
グラフの横軸の単位は秒です。APIで取得するポジション(赤線)は、約定履歴から再現した実際のポジション(青線)よりも大幅に遅れている様子が分かります。
また、青線は約定後に遅延なくポジションに反映されています(当然)が、赤線は遅延しながらじわじわとポジションに反映されていく様子が見て取れます。これはおそらく、bitFlyer側の約定~ポジション反映の処理遅延のためだと考えられます。
このような状況では、「現在ポジションが決定的な役割を担っている」ロジックは破綻してしまいます。グラフで実際に起こっていますが、「実際はプラスのポジションなのにAPIはマイナスのポジションを返す(またはその逆)」こともあります。この場合、本来は積極的に売り約定をさせないといけない場面で、積極的に買い約定をさせてしまうことになります。
この遅延や誤差は、価格変動時により顕著に現れます。当然価格変動時ですので、間違った方向に在庫を抱えてしまうとあっという間に損失が広がってしまいます。
消極的な対策方法としては、遅延監視を行い、閾値以上になったタイミングでそもそも発注事態を止めてしまうことですが、いまとなっては貴重な収益機会をみすみす見逃してしまうことになります。
対策と現状
WSで送られてくる約定履歴を一定時間分プールしておいて、前ループと現ループのポジション差分と約定情報の矛盾を見つける、くらいでなんとかしようかな。 https://t.co/766nXvhAvE
— Hoheto (@i_love_profit) January 19, 2019
HFT系のボットは在庫管理がやはり肝になる。在庫管理のためには当然自分のポジションを確認する必要があるのだが、そこで以前ツイートしたポジション遅延がやはり損益にインパクトを与えているので、面倒くさがらずにその対策を行うことにする。
— Hoheto (@i_love_profit) January 21, 2019
先に結果から書きますが、いまのところよい解決策は見つかっていません。
REST APIに限界を感じた僕は、Websocketから配信されてくる約定履歴と自らが発注した注文履歴を突き合わせ、リアルタイムで自分のポジションを把握しようとしたのですが、
遅延時には結局Websocketからの配信も遅れており、どちらかというと素直にREST APIを利用したほうがまだマシという結果になっています。
これらを踏まえて、
①現在ポジションを、タイムリーに、完全に正確に把握するのは非現実的
②なので、現在ポジションを肝とするロジックはなるべく作らない
③とはいえ、どうしても現在ポジションを利用しないといけない場合、
その回数を最小限にする
という結論に達しています。
現状のbitFlyerで、厳密な在庫管理が必要なロジックや、現在ポジションがロジック内の決定的な役割を担っているロジックは、安定した利益を出すことができない(もしくは著しく難しくなる)と考えたほうが良いと思います。
これは自分も試行錯誤しましたが、うまくいきませんでした…
— Hoheto (@i_love_profit) February 11, 2019
なので、ポジションに応じてどうこうするようなロジックは入れない方がベター、という結論になっています。 https://t.co/hcrISoSIix
総括
今回のnoteでは、bitFlyerでボットを運用する際に実際にポジション遅延が発生すること、そして、発注ロジック内にこの現在ポジションをパラメータとして組み込むことについての懸念事項をまとめました。
理論値を用いてモデル化され、シミュレーション上ではきれいな損益曲線を描くロジックであったとしても、実際の運用環境ではうまくいかないというのはよくあることです。
ロジックに応じて、実環境下での変化に強いか弱いか(ロバストであるか)が変わってきます。そして、この「変化に強く劣化しにくい」という特性はロジックの強力な長所になります。
残念ながらこのロジックは、実際の運用においては安定せず、シミュレーション結果は絵に描いた餅となってしまった。。
— Hoheto (@i_love_profit) February 7, 2019
おそらく、使っている指標が繊細で遅延その他の要因に左右されやすい(=ロバストでない)ため。 https://t.co/yXK7KLdio3
能力が高いけど怪我しやすくコンディションに左右されやすいスポーツ選手と、能力はまずまずだが怪我しにくく安定している選手では、長い目で見たとき後者のほうが結果を出せる、みたいなもの。
— Hoheto (@i_love_profit) February 7, 2019
「ストラテジーの性能とは、バックテストの損益曲線のことでは『ない』。」てことですね。 https://t.co/pvQtBUhg12
逆に言うと、いくらバックテストの資産曲線がきれいでも、環境変化に弱いロジックは実運用では大成しないということです。
シミュレーション上でロジックを洗練させて資産曲線の傾きを大きくしようとする前に、粗削りでもよいので実環境下で動かしてみて、劣化するようであればまずはその原因を分析し、取り除きができる性質のものなのか、そうでないのかを判断しましょう。
もしも取り除きができないタイプの原因であれば、そのロジックは引き出しの中にしまい、他のロジックの検討を進めたほうが成功に近づけるかもしれません。
今回のnoteは以上です。
最後に、
シミュレーション上の資産曲線を大々的に掲げて人集めをしているようなWebサイトや広告には、注意しましょう笑
おしまい。