こんにちは、ぼっちbotterよだかです。
今回は、multi_market_probe で進めているリードラグ研究について、ようやく「実行候補っぽい形」が事実ベースで見え始めたので、その時点での進捗を整理しておきます。具体的には、4市場を継続観測しつつ、現時点で優位候補として見えている binance_perp に絞って SIGNAL から ORDER_INTENT までを接続し、Grafana 上でもその挙動を追える状態まで持っていきました。もっとも、これはまだ「勝ち筋が確定した」という話ではありません。6時間ほど回した観測でも形が崩れていないことは確認できた一方で、執行ベースで本当に安定して取れるかどうかは、まだ切り分けが必要です。今回は、その「見えてきたこと」と「まだ言い切れないこと」を分けながら、現時点の到達点をまとめます。

-
-
🛠️開発記録#495(2026/3/27)multi_market_probe開発ログ ― リードラグの先行市場候補を、fact ベースで並べて見始めた話
続きを見る
1. 今日の進捗:SIGNAL から ORDER_INTENT まで繋いだ状態を継続観測した
今日は、リードラグ研究を「観測して終わり」にせず、実際に SIGNAL から ORDER_INTENT までを繋いだうえで、その状態をしばらく回し続けて観測するところまで進めました。
ここで意識していたのは、単にコードを動かすことではありません。見たかったのは、これまで別々に確認してきたもの――たとえば「どの市場をリード候補として残すか」「どの方向だけを使うか」「Grafana 上で何を見ればよいか」といった判断が、runtime 上でもちゃんと一つの系として成立するかどうかでした。研究段階ではそれっぽく見える構造でも、実際にシグナル化して流してみると、母数が消えたり、想定外の方向で発火したり、執行候補の段で詰まったりすることは珍しくありません。なので今日は、「見えたものを雑に前進させる」のではなく、「見えてきたものが本当にシステムとして繋がるか」を確かめる日として進めました。
今回の構成では、leadlag の DIAG は複数市場で継続観測しつつ、実際に SIGNAL を出す対象は binance_perp に限定しました。さらに side も short 系だけに絞り、現時点で事実ベースで優位候補として残っている条件だけを runtime に翻訳しています。言い換えると、「まだ白黒がついていない部分は観測に残し、いま深掘りする価値がある部分だけを実行候補として前に出す」という構成です。ここを曖昧にしたまま進めると、あとから「何を見ていたのか」が分からなくなるので、まず最初にこの責務分離をはっきりさせました。
そのうえで、システムを短時間で切り上げず、数十分ではなく数時間単位で回し続けました。結果として、少なくとも現時点では、絞り込みを入れたあとでも SIGNAL は死んでおらず、ORDER_INTENT まで継続的に流れる状態を確認できています。ここは今回の進捗としてかなり大きいところです。これまでは「構造としてあるかもしれない」という観測寄りの話が中心でしたが、今日はそこから一歩進んで、「実行候補としての形が runtime 上でも残るか」を見にいける段階まで来ました。
もちろん、これで勝ち筋が確定したわけではありません。まだ ACCEPTED と REJECTED の差が何で生まれているのかは十分に切り分けられていませんし、Grafana 上で見えている expected_edge も研究で見てきた EV そのものではありません。ただ、それでも今日の時点で言えるのは、リードラグ研究が単なる観測テーマではなく、少なくとも一度「実行候補」として組んで動かしてみる価値のあるところまで来た、ということです。今回はその出発点を、感覚ではなく、実際に動かした系の観測結果として持てたことに意味がありました。
2. 現時点で固定した条件:4市場DIAG、binance_perp short 限定
今日の実装でまず固定したのは、「何を広く観測し、何を狭く使うか」です。今回ここを曖昧にしなかったのは、リードラグ研究がようやく「観測テーマ」ではなく「実行候補」を意識してよい段階に入り始めたからです。だからこそ、探索対象と実運用候補を同列に扱わず、事実ベースで濃淡をつける必要がありました。
観測対象として残したのは、binance_perp、bybit_perp、binance_spot、coinbase_spot の4市場です。一方で、実際に SIGNAL を出す対象は binance_perp のみに限定し、さらに side も SELL_BASE_BUY_REF、つまり short 系だけに絞りました。設定上も、leadlag の DIAG は4市場で継続観測しつつ、実運用向け SIGNAL は signal_markets=[binance_perp]、signal_allowed_sides=[SELL_BASE_BUY_REF] に固定しています。つまり今回は、「構造観測は広く残し、シグナル化は現時点で最も筋の良い条件にだけ絞る」という構成にしました。
なぜ binance_perp に絞ったのかというと、ここはもう感覚ではなく、直近のデータ検証でかなりはっきりしていたからです。まず24時間窓の比較では、執行コスト 7.6bps を控除した short@30s の net が、binance_perp だけ +0.345bps とプラスで、bybit_perp は -2.778bps、binance_spot は -0.769bps、coinbase_spot は -3.196bps、bf_spot は -6.391bps でした。しかも自作スクリプトの判定でも deep_dive_markets=binance_perp、それ以外は minimal という整理になっていました。少なくともこの時点で、「4市場を同格の lead 候補として扱う」理由は薄くなっていました。
さらに binance_perp について48時間窓で深掘りしたところ、short 側は h1 +1.839bps、h3 +2.107bps、h5 +2.278bps、h10 +2.425bps、h30 +2.993bps と、執行コスト控除後でも一貫してプラスでした。quality=1 かつ signal_pass=1 を掛けても h30 は +1.824bps で正を維持しており、少なくとも「runtime へ一段落としてみる価値がある候補」として扱うには十分な材料がありました。一方で他市場は、同じ short・h30 の条件でも bybit_perp -1.247bps、coinbase_spot -1.787bps、bf_spot -6.278bps とマイナスで、binance_spot だけは mean で +1.437bps でしたが median は -0.262bps で、歪みが強く安定性不足という判断でした。ここまでくると、現時点で深掘り対象を binance_perp に寄せるのはかなり自然です。
方向を short 側のみにしたのも同じ理由です。48時間窓の確認では、binance_perp は short 側で優位性あり、long 側は明確に劣後 という結論でした。だから今回は long / short を両方残して様子を見るのではなく、現時点で優位候補として残っている short 側だけを runtime に翻訳しました。ここで両方向を残してしまうと、「まだ白黒がついていない条件」と「すでに候補として残った条件」が同じパイプラインに流れ込み、後から解釈しづらくなります。今回はそこを避けて、あくまで確定事実に沿った最小構成に寄せました。
もちろん、これは他市場を不要と決めたという意味ではありません。bybit_perp、binance_spot、coinbase_spot についても leadlag の DIAG 自体は継続観測していますし、「今は未成立だが、将来の変化検知のために観測対象としては残す」という整理です。実際、24時間窓の判断でも「他3市場は lead 候補としては未成立だが、観測対象としては残す価値がある」という形になっていました。つまり今回は、探索を止めたのではなく、探索と実行候補を同じレイヤーで扱うのをやめたということです。この切り分けによって、観測の幅を残しながら、runtime の解釈コストだけを下げることができました。
3. runtime に翻訳したこと:研究結果をそのまま設定へ落とした
今回やったことを一言で言うと、研究で見えていた事実を、そのまま runtime の条件へ落とし直したことでした。ここで意識したのは、新しいロジックを足して賢く見せることではありません。むしろ逆で、すでに比較検証の中で残った条件だけを、余計な解釈を挟まずに最小構成で実装へ写すことを優先しました。
まず一つ目は、SIGNAL 対象の絞り込みです。ここまでの比較で、現時点の実行候補として扱うのは binance_perp が本線であり、方向も short 側だけを残すのが妥当だと整理できていました。そこで overlay 側では、leadlag の DIAG は4市場で継続観測しつつ、実際に SIGNAL を出す対象だけを signal_markets=[binance_perp] に固定し、さらに signal_allowed_sides=[SELL_BASE_BUY_REF] を追加しました。これにより、「複数市場で構造判定は回すが、runtime で前に出すのは binance_perp short だけ」という研究上の結論が、そのまま設定として表現されるようになりました。ここで long 側や他市場も残してしまうと、runtime 上ではまだ白黒のついていない条件まで同じパイプラインに流れてしまいます。今回はそれを避けて、あくまで現時点で残った条件だけを前に出しています。
二つ目は、研究で見てきた EV と runtime 側の expected edge を混同しないようにしたことです。これは今回かなり大事な修正でした。これまで研究側では、roundtrip_cost_bps=7.6 を前提にした執行コスト控除後EVを見ていました。一方、runtime の ORDER_INTENT.expected_edge_bps は、即時の signal strength から expected slip と expected fee を引いた推定値であって、研究で比較していた尺度そのものではありません。このズレを曖昧にしたまま運用候補を眺めると、「Grafana で positive に見えるから研究でも優位」といった誤読が起きやすくなります。そこで service 側で j_leadlag_eval.execution_eval.roundtrip_cost_bps を order_intent.research_roundtrip_cost_bps へ自動注入し、engine 側でも expected_edge_basis="runtime_slip_fee_estimate" を必ず付与するようにしました。さらに research_ev_equivalent_bps も追加し、runtime 推定値と研究基準値を少なくともイベント上では並べて見られるようにしています。要するに、今回は「定義を統一した」のではなく、「別物であることを明示した」という修正です。
この修正は、設計思想としてもかなり重要でした。自分が今やりたいのは、研究で見えたことをそのまま実行判断へ繋げることであって、研究と runtime の間に新しいブラックボックスを置くことではありません。だからこそ、両者の尺度が一致していないなら、一致していないこと自体を見えるようにしておく必要があります。今回の expected_edge_basis や research_roundtrip_cost_bps は、そういう意味での防波堤です。これによって、「runtime で ACCEPTED が出ている」という事実と、「研究で EV>0 が出ていた」という事実を、同じものとして雑に扱わずに済むようになりました。
三つ目は、あとから再点検できるように signal 系イベントの保存を戻したことです。今回の leadlag 研究では、Prometheus と Grafana 上で時系列を見るだけでなく、必要になれば SIGNAL や ORDER_INTENT のイベントを掘り返して、「どの条件で通ったのか」「何が理由で落ちたのか」を見返せる状態が欲しかった。そこで signal stream の保存対象に SIGNAL と ORDER_INTENT を追加しました。これで可視化の上では動いていても、後から event ベースで検証できない、という片手落ちは避けられます。今はまだ runtime の採否条件を細かく詰め切っている段階ではないので、こういう再検証導線を残しておくこと自体に価値があります。
結果として今回の修正は、何か新しいアルゴリズムを発明したという話ではありません。むしろ、「研究で残った条件だけを runtime に写し、そこで生じる解釈のズレを減らした」という話です。4市場DIAG継続、binance_perp short 限定、研究EVと runtime edge の区別、signal イベント保存の復活。どれも派手ではありませんが、実行候補としての形を崩さずに一段前へ進めるには必要な修正でした。今回の実装を通して、ようやくリードラグ研究が「面白そうな観測テーマ」から「条件付きで実行候補として扱えるかを見にいく段階」へ入ってきたと感じています。
4. 6時間回して見えてきたこと:シグナルは死んでいない


今回、個人的にいちばん大きかったのはここでした。設定を絞って runtime に落としたあと、数分だけ動かして「一応出ていますね」で終わらせず、6時間ほど回した状態でも形が崩れていなかったことです。ここが崩れるようなら、研究で見えていたものはあくまで一時的な見え方でしかなかった、という可能性も十分ありました。逆に言えば、ここを通ったことで、少なくとも「実行候補っぽい形」が短時間の偶然ではないところまでは進めたと思います。
まず確認できたのは、binance_perp short 限定にしても SIGNAL が死んでいないことです。今回の runtime では、leadlag の DIAG 自体は4市場で継続観測しつつ、実際に SIGNAL を出すのは signal_markets=[binance_perp]、かつ signal_allowed_sides=[SELL_BASE_BUY_REF] に固定しています。かなり絞った条件なので、ここでシグナルが痩せすぎるなら「構造は見えても、実運用候補としては母数が足りない」という話になりかねませんでした。しかし実際には、数時間スパンでも [SIGNAL] leadlag SIGNAL PASS/BLOCKED rate に PASS が継続して出ており、完全に細ってしまう状態にはなっていませんでした。少なくとも現時点では、「条件をきちんと絞ったら何も残らなかった」という結論ではありません。
次に見えたのは、ORDER_INTENT も継続して ACCEPTED が出ていることです。これは短時間のスクショだけでは判断しにくい部分でしたが、6時間ほど動かした状態でも、ACCEPTED が断続的ではなく継続的に流れていました。acceptance ratio も、母数が薄いタイミングの針のような動きはあるものの、全体としては極端に崩れている印象はありませんでした。ここはかなり重要です。SIGNAL が出ているだけなら、まだ「構造候補がある」程度の話ですが、ORDER_INTENT の段まで通っているということは、少なくとも runtime の採否条件を通過する群が一定割合で存在しているということです。もちろん、それがそのまま「執行ベースで取れる」に直結するわけではありませんが、「実行候補として前に出す意味があるか」という問いに対しては、かなり前向きな材料になりました。
さらに、4市場DIAG継続と1市場SIGNAL化の責務分離が、実際に機能していることも確認できました。DIAG パネルでは複数市場の PASS/BLOCKED が動いている一方、SIGNAL パネルや ORDER_INTENT パネルはかなり細く限定されています。これは単に見た目の問題ではなく、「観測対象を広く残しつつ、現時点で有望な条件だけを実行候補として絞る」という今回の設計が、Grafana 上でもちゃんと表現されているということです。もしここが崩れていたら、観測と実行候補がまた混線してしまいます。今回そこが保たれていたことで、少なくとも runtime の振る舞いと自分の意図が大きくズレていないことは確認できました。
一方で、だからといって「もう勝ち筋が見えた」と書くつもりはありません。実際、Latest expected_edge_bps by ORDER_INTENT status を見ると、ACCEPTED と REJECTED の値はかなり重なって見えます。つまり現時点では、ORDER_INTENT の採否が expected edge の大小だけで綺麗に分かれているわけではなさそうです。これは runtime 上の採否条件が edge 以外のガードにもかなり依存していることを示唆していますし、何が主因で通って何が主因で落ちているのかは、まだもう少しイベントを掘って確認する必要があります。しかもここで使っている expected edge は、研究で見てきた EV そのものではなく、runtime 側の推定値です。この違いを意識しないまま「positive が出ているからいける」と読むのは危険です。ダッシュボード側でも、この点は research EV とは別尺度だと分かるようにしてあります。
ただ、それでも今回の観測に意味はありました。いま言えるのは、「取れる構造かどうかはまだ未確定だが、少なくとも“通る構造”としては維持されている」ということです。これは地味に見えるかもしれませんが、実際にはかなり大きい前進です。研究で見えていた候補を runtime に落としてみたら、シグナルが消える、採否が極端に偏る、ログ導線が詰まる、といった形で崩れることは珍しくありません。今回そうならず、6時間回しても「実行候補っぽい形」が残っていたこと自体が、今日の成果だったと思っています。
5. ACCEPTED も継続して出ているが、まだ勝ち筋確定ではない
ここまで書くと、かなり前向きな話に見えると思います。実際、自分でも今回は少し嬉しかったです。4市場比較を経て binance_perp に絞り、さらに short 側だけに限定したうえで runtime に落としてみても、SIGNAL は死なず、ORDER_INTENT まで継続して流れている。ここまでは、少なくとも「研究で見えていたものが runtime 上でも完全には崩れなかった」と言ってよいと思います。
ただ、そのことと「もう勝ち筋が見えた」は同じではありません。ここは今回かなり意識して分けておきたいところでした。
まず、ORDER_INTENT の ACCEPTED が継続して出ていること自体は良い事実です。実際、6時間ほど回した状態でも ACCEPTED はゼロ張り付きではなく、一定割合で出続けていました。これは、「binance_perp short に絞ったら、採否条件を満たす候補がほとんど消える」という状態ではなかった、という意味です。SIGNAL から ORDER_INTENT までの導線が機能し、そのうえで採択される候補も残っている。これは実行候補として前に進めるかどうかを見るうえで、かなり重要な確認でした。
ただし、現時点で見えている ACCEPTED は、「研究で検証した EV の高い群がそのまま綺麗に通っている」とまではまだ言えません。実際に Grafana を見ていると、Latest expected_edge_bps by ORDER_INTENT status において、ACCEPTED と REJECTED の値はかなり重なって見えます。もし採否が expected edge の大小で素直に決まっているなら、ACCEPTED だけが明確に上に寄り、REJECTED はその下に綺麗に分かれていてほしいところです。しかし現状はそうなっておらず、両者はかなり近い帯域を動いています。これは、runtime の採否が expected edge 単独ではなく、他のガード条件や瞬間的な状態にも依存している可能性が高いことを示しています。
しかも、ここで見ている expected_edge_bps は、研究で比較してきた EV そのものではありません。研究側では、たとえば roundtrip_cost_bps=7.6 を前提にした執行コスト控除後の future return を見ていました。一方、runtime の ORDER_INTENT.expected_edge_bps は、signal strength から expected slip と expected fee を引いた推定値です。つまり、同じ “edge” という言葉を使っていても、実際には見ている尺度が違います。今回この点が混ざらないように、イベント上で expected_edge_basis="runtime_slip_fee_estimate" を明示し、research_roundtrip_cost_bps や research_ev_equivalent_bps も併記するようにしたのですが、それでもなお、「ACCEPTED が出ているから研究でも優位が確認された」と読み替えてしまうのは危険です。今ここで言えるのは、runtime 推定値の世界で採択される候補が一定割合で存在している、というところまでです。
要するに、現時点で確認できたのは「取れる構造」ではなく、まずは「通る構造」が存在することです。これは軽く見えるかもしれませんが、個人的にはかなり大事だと思っています。研究で見えていた候補を runtime に落としてみると、思ったより SIGNAL が細る、意図しない方向の side でばかり出る、採否段で全滅する、といったことは普通に起こり得ます。今回はそこが崩れなかった。だからこそ、「実行候補として前に出す意味はある」と言えるところまで来ました。ただし、その先にある「安定して取れる勝ち筋かどうか」は、まだ別の問いです。
この違いを自分の中で保っておかないと、少し形が見えてきた段階で解釈を先走らせてしまいます。今日は確かに嬉しい日でした。でも今の段階で自分が言うべきなのは、「binance_perp short 限定のリードラグが、事実ベースで実行候補として残った」であって、「これで勝てる」ではありません。この距離感を守ること自体が、今回の進捗を無駄にしないために必要なことだと思っています。
6. 現時点の結論:実行候補としては一段前進した
ここまでの内容をまとめると、今回の進捗はかなりはっきりしています。リードラグ研究はまだ「勝ち筋確定」の段階ではないけれど、少なくとも “実行候補として扱ってよいかを観測する段階” には入った と言ってよいと思います。個人的には、ここが今回いちばん大きな到達点でした。
まず、研究段階で比較してきた事実に基づいて、lead 市場を binance_perp に絞り、さらに short 側だけを runtime に落としました。この時点で、単に「それっぽいものが見えたから前に進めた」のではなく、24時間窓・48時間窓の比較で他市場が弱く、binance_perp short だけが相対的に残った、という事実を踏まえて条件を固定できています。ここは、ただ気分で一つに決めたのとはかなり違います。少なくとも「現時点で何を前に出すべきか」は、かなり筋よく整理できていたと思います。
そのうえで、実際に SIGNAL から ORDER_INTENT まで繋ぎ、さらに短時間ではなく6時間ほど回した観測でも、シグナルは死なず、採否も完全には崩れませんでした。ここが大きいです。研究で見えていた候補を runtime に落とすと、条件を絞った瞬間に母数が消えたり、想定外の方向でしか出なくなったり、執行候補としては成立しないことが普通にあります。今回は少なくともそうならなかった。つまり、「リードラグが構造としてありそう」から、「リードラグが実行候補として残るかもしれない」へ、一段階前に進めたわけです。
ただし、ここで浮かれて終わるのは違うとも思っています。実際、Grafana 上で見えている expected_edge_bps と研究で比較してきた EV は同じ尺度ではありませんし、ACCEPTED と REJECTED の差もまだ綺麗には分かれていません。runtime 側の採否条件が何で効いているのか、採択される群が研究側の優位候補とどれだけ重なっているのかは、まだもう少し掘る必要があります。だから今回の結論は、「勝ち筋が見えた」ではなく、「勝ち筋候補として観測する価値のある形が残った」です。この言い方が、現時点ではいちばん正確だと思います。
それでも、個人的にはかなり嬉しい日でした。ずっと「観測としては面白いけれど、実行候補として扱えるかは別」という感覚があった中で、今回はその境界線を少し越えられた気がしています。もちろん、ここから先はさらに厳しく見る必要があります。ですが少なくとも今日は、リードラグ研究が単なる観測テーマではなく、実装して回し、採否を観測し、次の白黒判定へ進めるだけの形になり始めた――そう整理してよい一日だったと思っています。
7. 次に詰める論点:ACCEPTED / REJECTED の差分要因
今回、リードラグ研究はかなり前に進みました。ですが、ここから先は「シグナルが残っている」「採択もされている」という事実だけでは足りません。次にやるべきなのは、その採択が何に支えられていて、逆に何が理由で落ちているのかを、もう一段細かく切り分けることです。要するに、次のテーマは ACCEPTED / REJECTED の差分要因の観測 です。
なぜここが重要かというと、現時点の Grafana では expected_edge_bps が ACCEPTED と REJECTED でかなり重なって見えるからです。もし runtime の採否が expected edge の大小だけで綺麗に決まっているなら、採択群と棄却群はもっと素直に分かれていてほしい。しかし実際にはそうなっていません。これは、runtime の ORDER_INTENT 採否が単なる edge 推定値だけでなく、他のガード条件や瞬間的な状態にも強く依存している可能性を示しています。ここを曖昧にしたままだと、「ACCEPTED が出ているから良い」「REJECTED が多いから悪い」といった雑な解釈に引っ張られてしまいます。次はそこを避けたい。
そのために、まず見たいのは event ベースの差分です。今回、signal stream に SIGNAL と ORDER_INTENT を保存するように戻したので、あとから採択群と棄却群を掘り返せる状態にはなっています。ここで確認したいのは、ACCEPTED と REJECTED で何が違っていたのかです。たとえば expected edge の差なのか、expected slip の差なのか、データ品質や hedge 可否のようなガードが効いていたのか。あるいは、そもそも採否に効いている主因が自分の想定と違っているのか。次はそこをログから具体的に見る必要があります。今回の6時間観測で「実行候補として残る」ことまでは見えたので、次は「その実行候補の中で、どの条件が本当に採否を分けているか」を見にいく段階です。
もう一つ重要なのは、研究EVと runtime edge の関係を雑に混ぜないことです。今回の修正で、ORDER_INTENT.expected_edge_bps は runtime 側の推定値であり、研究側の EV とは別尺度だと分かるようにしてあります。これはかなり前進でしたが、では両者がどれくらい整合しているのか、どれくらいズレるのかは、まだ観測していません。たとえば runtime で ACCEPTED された群が、研究側の基準でも相対的に良い群として見えているのか。あるいは逆に、runtime では弾かれたものの中に研究EV的には惜しい群が混ざっていないか。ここを見ていくことで、runtime の採否条件が今のままで良いのか、それとも研究結果に寄せてもう少し設計を調整するべきかが見えてくるはずです。
さらに、時間帯依存の確認も今後の論点になると思っています。今回は6時間回して形が崩れていないことを確認できましたが、それでも観測した時間帯は市場の一部にすぎません。acceptance ratio や SIGNAL の出方が時間帯によって大きく変わるなら、「形がある」と言っても使える時間帯は限定されるかもしれない。逆に、ある特定の時間帯でだけ極端に強いなら、それはそれで構造として価値があります。今の段階ではまだ日内構造まで白黒をつける必要はありませんが、次の観測では少なくとも「どの時間帯でも同じように出るのか、それとも偏りがあるのか」は意識して見ていきたいところです。
現時点での自分の感覚としては、次に必要なのは大きな設計変更ではありません。むしろ、今は動いているものをしばらく回し、そのうえで採否差分を事実ベースで見ることの方が重要です。ここで焦ってロジックをいじると、まだ観測しきれていない差分要因まで消してしまう可能性があります。今の構成は、少なくとも「観測して切り分ける」だけの形にはなりました。だから次回は、その形を壊さずに、ACCEPTED / REJECTED の差を丁寧に読むこと。それが、今回見え始めた“実行候補っぽさ”を、次の白黒判定へ進めるための論点になると思っています。