「どちらに動くのか」を当てようとして、疲れていませんか。
秒足、分足、5分足。
インジケーターを重ね、ロジックを組み替え、検証を繰り返す。
それでも最終的に残るのは、思ったほど伸びない損益曲線と、
「もう少しで掴めそうだった」という感覚かもしれません。
私も同じところで何度も立ち止まりました。
バックテストでは優位に見える構造も、
実際に約定可能な価格(executable)を前提にすると、
スプレッドやスリッページに削られ、静かに消えていきます。
そこで、発想を転換しました。
問題は「読む力」が足りないことではなく、
そもそも 読むべき対象を間違えていた のではないか、と。
価格の方向を読むのではなく、
価格同士の「相対関係」を測る。
同一銘柄の市場間差。
現物とCFDの乖離。
更新タイミングのズレ。
もしそこに構造的な歪みがあるなら、それは偶然の方向性よりも、
はるかに検証可能で、再現可能な対象になります。
本記事では、方向当てをいったん脇に置き、
まず「歪みを正しく測る装置」を作るところから始めた記録をまとめます。
今回は戦略の話ではありません。
その前段階である「観測器」の話です。

1. なぜ方向当てをやめたのか
方向当てをやめた理由は、シンプルに言うと「当たる/外れる」の問題ではありません。
当たっているように見えても、取れないことが多すぎたからです。
短期足のロジックを作ると、最初はそれなりに“それっぽい形”になります。
OFIや出来高、レンジ、連続約定、板の偏り。材料はいくらでもあります。
しかし、検証を進めていくほど、同じ壁にぶつかりました。
- 価格は確かに動く
- シグナルも確かに反応する
- なのに、損益が積み上がらない
原因は、約定可能な価格を前提にした瞬間に露わになります。
たとえば「上がる」と当てても、実際に買えるのは ask です。
利確するときに売れるのは bid です。
この時点で、往復でスプレッド分が確定コストとして乗ります。
さらに短期ほどスリッページが効きますし、遅延や板の薄さも効きます。
結果として、方向が合っていても、利益が残りません。
残るのは「当たっていたのに負けた」という後味の悪さです。
もう一つ問題だったのは、方向当てが評価を濁らせることです。
方向当ての戦略は、検証が進むほど「例外」が増えます。
トレンドならOK、レンジならダメ。急変時は除外。時間帯でフィルタ。
気づくと、“当たる条件”を後付けで増やしていく方向に引っ張られます。
そしてそのプロセスは、ほぼ必ずこうなります。
- 「この時は仕方ない」
- 「たまたま負けただけ」
- 「条件を少し足せば改善するはず」
こうして、上流の観測や定義が曖昧なまま、戦略だけが複雑になります。
最終的に残るのは、再現性の判断ができないコードと、よく分からない損益です。
私はこれを避けたかった。
だから、方向当てそのものを「努力すれば改善できる課題」として扱うのをやめました。
代わりに、問いを変えました。
「どちらに動くか」ではなく、
**「取れる歪みが存在するか」**です。
価格が動くこと自体は、当たり前に起きます。
でも、動いたからといって利益が取れるとは限りません。
取れるかどうかは、約定可能な価格で見たときに、
コストを超える“構造”があるかで決まります。
そこで最初に着手したのは、戦略ではなく観測器でした。
- mid ではなく executable でスプレッドを定義する
- stale や更新遅延を除外し、幻の歪みを排除する
- 入力の異常(crossed book やジャンプ)を上流で捨てる
- 歪みの発生頻度と解消時間を分布で見る
こうして「読めた気がする」ではなく、
「取れる歪みがある/ない」を白黒で言える状態を先に作る。
方向当てをやめたのは、諦めではありません。
評価を澄ませるための決断でした。
次章では、その“澄んだ評価”を成立させるために、
どんな定義を固定し、どんなノイズを排除したのかを具体的に書いていきます。
2. 価格差戦略に舵を切った理由
方向当てをやめたあと、次に考えたのはこうでした。
それでも市場には、何らかの「構造」はあるはずだ。
ただし、それは“価格の方向”ではないのではないか。
そこで目を向けたのが、価格の相対関係です。
同じBTCでも、
- 取引所が違えば価格は微妙に違います
- 現物とCFD(あるいは先物)でも値は一致しません
- 更新タイミングや流動性の差によって、一瞬ズレることもあります
これらはランダムなノイズに見えることもありますが、
実際には参加者の構成、ヘッジ需要、在庫制約、流動性の厚みといった
構造的な要因が反映されています。
ここが、方向当てとの決定的な違いでした。
方向当ては、未来の価格変化を予測します。
しかし価格差戦略は、今すでに存在している“ズレ”を測ります。
未来を読むのではなく、
現在の歪みがコストを超えているかどうかを確認する。
この問いは、検証可能です。
たとえば、
- FX_BTC_JPY と BTC_JPY のスプレッドは、
executableベースで何bpsまで広がるのか - それはどのくらいの頻度で発生するのか
- 解消までにどれくらいの時間がかかるのか
- 手数料・スリッページを差し引いても余地が残るのか
これらは、すべて観測できる事実です。
もちろん、価格差戦略も万能ではありません。
見えている歪みの多くは、単なる更新遅延や板の薄さが生む“幻”です。
だからこそ、staleを除外し、crossed bookを捨て、
executableで定義し直す必要があります。
それでもなお、価格差戦略には一つの強みがあります。
評価がブレにくいことです。
方向当ては、条件を追加するほど「改善したように見える」余地があります。
一方で価格差は、
「コストを超える歪みがあるか、ないか」
という二択に収束します。
この単純さが、私にとっては大きな魅力でした。
さらにもう一つ重要だったのは、
価格差は「レジームに依存しにくい」可能性があることです。
トレンドでもレンジでも、
市場参加者の分断や更新の非同期は発生します。
つまり、方向そのものよりも安定した観測対象になり得ます。
だから私は、戦略を作る前にこう決めました。
まずは、
- 同一銘柄の市場間差を測る
- 現物とCFDの乖離を定義する
- 更新タイミングのズレを可視化する
そして、その分布を冷静に見る。
取れる歪みが存在するなら、次に進めばいい。
存在しないなら、迷わず捨てればいい。
価格差戦略に舵を切ったのは、
より賢い方法を見つけたからではありません。
より誤魔化しにくい問いに移っただけです。
次章では、その問いを支えるために実装した
Spread Observer V1 の設計について詳しく書きます。
3. 戦略より先に作ったもの:Spread Observer V1
価格差戦略に舵を切ると決めたとき、最初に作ったのはエントリー・ロジックではありませんでした。
観測器です。
取れる歪みが存在するかどうかを判断できない状態で戦略を書くのは、
方向当てと同じ轍を踏むことになるからです。
そこで実装したのが、Spread Observer V1 です。
観測対象
まずは最小構成に絞りました。
- base:FX_BTC_JPY(bitFlyer CFD)
- ref:BTC_JPY(bitFlyer 現物)
主戦場は FX。
ref は“方向予測の材料”ではなく、**アンカー(基準)**です。
この2系列を同時に購読し、同一プロセス内で観測します。
算出する指標
Spread Observer V1 で固定した指標は、次のとおりです。
- mid_bps
- executable_bps(AB / BA)
- exec_best_bps
- distortion_flag
- base_lead_ms(更新差)
- stale_flag
- resolve_duration
重要なのは、mid と executable を明確に分けたことです。
mid は参考値です。
判断はすべて executable ベースで行います。
executable 定義の固定
価格差戦略で最も濁りやすいのは、
「本当に取れる価格で定義しているか」という点です。
そこで executable を以下のように固定しました。
- AB = (A_bid - B_ask) / denom
- BA = (B_bid - A_ask) / denom
- signed = +AB if AB >= BA else -BA
つまり、
- A を売り、B を買う場合の実行可能差
- B を売り、A を買う場合の実行可能差
を両方計算し、良い方を採用します。
分母は設定化し、現状は ref_mid_adj を使用しています。
将来的な通貨換算やプロダクト差を見据えた設計です。
歪み(distortion)の定義
歪みは mid では定義しません。
exec_best >= fee + slip + safety (+ extra)
かつ stale_flag = 0
この条件を満たしたときのみ distortion_flag を立てます。
現状の trigger は 6bps(fee2 + slip2 + safety2)です。
「見えているズレ」ではなく、
コストを超えるズレだけを歪みと呼ぶ。
この定義を最初に固定しました。
ノイズの排除
価格差は簡単に“幻”が発生します。
そこで以下を上流で排除しました。
- non-finite / non-positive 値
- crossed book
- 異常ジャンプ
- stale quote
stale や resolve duration の計測は、
すべて monotonic 時刻基準で行っています。
時刻系が濁ると、評価が壊れるからです。
resolve duration の導入
歪みは発生頻度だけでなく、
どれくらいで解消するかが重要です。
そこで、
- distortion ON → OFF までの時間を計測
- histogram に蓄積
- p50 / p90 を可視化
という仕組みを入れました。
歪みが出ても、解消に数十秒かかるなら
短期で扱うのは難しい可能性があります。
逆に数秒で収束するなら、構造があるかもしれません。
可視化(Grafana)
Prometheus へメトリクスを出力し、
Grafana で以下を可視化しました。
- exec_best 分布(quantile)
- distortion 発生頻度
- resolve duration
- lead-lag
- stale / invalid イベント
これにより、
「歪みがあるかどうか」を主観ではなく分布で判断できます。
なぜここまでやるのか
戦略は、いくらでも複雑にできます。
しかし観測器が曖昧なままでは、
改善なのか偶然なのか判断できません。
Spread Observer V1 は、
勝つための装置ではありません。
“勝てる可能性があるか”を判定する装置です。
戦略は、その後です。
まずは、
- コストを超える歪みが存在するか
- それはどのくらいの頻度か
- どのくらいの時間で解消するか
この3点を、冷静に見る。
Spread Observer V1 は、そのために作りました。
4. executable定義を固定する
価格差戦略をやるなら、最初に固定すべきものがあります。
それはロジックでも閾値でもなく、
「executableとは何か」という定義です。
ここが曖昧なままでは、どれだけ精緻に分析しても、
最終的な評価は必ず濁ります。
midではなく、約定可能価格で考える
多くの検証は、mid価格を基準に行われます。
spread = (A_mid - B_mid) / B_mid
しかし実際の取引では、
- 買うときは ask
- 売るときは bid
で約定します。
この時点で、midベースのスプレッドと
実際に取れるスプレッドは一致しません。
特に短期戦略では、
この差がそのまま収益を削ります。
だからSpread Observerでは、
最初から executable(実行可能価格)で定義しました。
AB / BA の両方向を明示する
価格差には必ず“向き”があります。
- Aを売ってBを買う場合
- Bを売ってAを買う場合
この2通りを明確に計算します。
AB = (A_bid - B_ask) / denom
BA = (B_bid - A_ask) / denom
そして、
signed = +AB if AB >= BA
signed = -BA otherwise
と定義しました。
つまり、
- 正の値 → A売り/B買いが有利
- 負の値 → B売り/A買いが有利
と一意に解釈できるようにしています。
この「符号の意味」を固定することで、
後段の解析やログ解釈がブレなくなります。
分母(denominator)も固定する
意外と見落とされがちなのが分母です。
- B_askで割るのか
- A_askで割るのか
- midで割るのか
分母が揺れると、bpsの意味が変わります。
Spread Observer V1 では、
executable_denominator_basis = ref_mid_adj
を設定化しました。
現状は ref_mid_adj(参照側のmid)を基準にしていますが、
将来的な通貨換算やプロダクト差を考慮して
変更可能な形にしてあります。
重要なのは、「何で割っているか」を明文化し、
一貫して使い続けることです。
“良い方を取る”ロジックの落とし穴
「ABとBAの良い方を使う」という処理は単純に見えますが、
ここも曖昧だと後で混乱します。
よくある誤りは、
- midの符号に引っ張られる
- 両方の絶対値を比較して符号が逆転する
といった実装上のブレです。
そこで、
exec_best = max(AB, BA)
exec_signed = +AB if AB >= BA else -BA
と明示的に固定しました。
これで、
- 強さ(exec_best)
- 方向(exec_signed)
が明確に分離されます。
なぜここまで厳密にするのか
価格差戦略は、
「見えている歪み」と
「実際に取れる歪み」がズレやすい分野です。
executable定義が曖昧だと、
- 見かけ上は6bpsある
- でも実際は2bpsしか取れない
という状況が簡単に起こります。
その状態で戦略を作ると、
評価は必ず楽観的になります。
だから最初にやるべきことは、
executableの定義を固定し、
後から動かさないことです。
ここが固まっていれば、
- triggerの位置
- 分布の評価
- resolve時間の解釈
すべてが一貫します。
戦略を複雑にする前に、
価格の定義を単純にする。
これが、Spread Observer V1 で最初にやったことでした。
5. “濁り”を徹底的に排除する設計
価格差戦略で一番怖いのは、「エッジがないこと」ではありません。
**エッジがあるように“見えてしまうこと”**です。
その多くは、ロジックの高度さではなく、
観測の“濁り”から生まれます。
Spread Observer V1 では、
戦略を作る前に、この濁りを徹底的に排除することに集中しました。
1. staleを除外する ― 幻の歪みを消す
価格差は、更新の非同期で簡単に発生します。
- Aは更新された
- Bはまだ古い
この瞬間、見かけ上のスプレッドは広がります。
しかしそれは「市場の歪み」ではなく、
単なる更新タイミングのズレです。
そこで、
- base_stale_ms
- ref_stale_ms
- stale_flag
を導入し、
stale_flag = 1 の間は distortion を無効化
というルールを固定しました。
さらに stale 判定は wall-clock ではなく
monotonic時刻基準で計測しています。
NTP補正や時刻ずれで誤判定しないためです。
2. 入力ガード ― 異常値を上流で捨てる
観測器は、生データに近い位置にあります。
だからこそ、入力が壊れていると全体が壊れます。
Spread Observer V1 では、以下を即座に invalid として破棄します。
- non-finite(NaN / inf)
- non-positive 価格
- crossed book(bid > ask)
- 異常ジャンプ(閾値超過)
さらに invalid イベントは可視化しています。
「捨てたデータ」を見える化することで、
市場側の異常やデータ品質の問題も検知できます。
3. hysteresis ― ON/OFFのチャタリングを防ぐ
歪みは、閾値付近で揺れやすいものです。
もし
exec_best >= trigger
だけで ON/OFF を決めると、
わずかな上下でフラグが高速に反転します。
これでは resolve duration が濁ります。
そこで、
- trigger_on = 6bps
- trigger_off = 5bps(例)
のようにヒステリシスを入れました。
ON と OFF の条件をわずかにずらすことで、
イベントの境界を安定させます。
4. resolveの二重計測を防ぐ
歪みの「解消時間」は重要な指標です。
しかし状態遷移の設計が曖昧だと、
- 解消が二重に記録される
- 逆に一度も記録されない
という事故が起きます。
そこで、
- event_id を持つ
- ON→OFF の瞬間のみ histogram に observe
- 一度解消したイベントは再度記録しない
という明示的な制御を入れました。
分布が正しく出ているかどうかは、
戦略の前に確認すべきポイントです。
5. midとexecutableを混ぜない
midは参考値、
判断はexecutable。
この分離を徹底しました。
midベースで歪みを検出し、
executableで評価する、という混在は行いません。
定義が揺れると、評価も揺れます。
なぜここまでやるのか
価格差戦略は、
“それらしく見えるノイズ”が非常に多い領域です。
- 更新遅延
- 板の薄さ
- 一瞬のcross
- データ欠損
これらを放置したまま戦略を組むと、
後からいくら改善しても本質は濁ったままになります。
Spread Observer V1 で目指したのは、
「きれいなグラフ」ではありません。
誤魔化しにくい観測環境です。
濁りを排除すると、
ときに「何もない」という結果が出ます。
しかしそれは、
誤ったエッジに期待するより、はるかに価値があります。
戦略を作る前にやるべきことは、
エッジを信じることではなく、
エッジが存在しない可能性を受け入れられる設計にすることでした。
6. Prometheus / Grafana で可視化したもの

Spread Observer V1 を作っただけでは、まだ十分ではありません。
観測器は、見える化して初めて意味を持ちます。
そこで Prometheus でメトリクスを収集し、
Grafana 上で歪みの分布・頻度・寿命を可視化しました。
ここでは、実際に何を表示しているのかを整理します。
1. Spread(Mid / Executable, bps)
まず表示しているのは、最も基本となるスプレッドです。
- mid_bps
- executable_bps(signed)
mid は参考値です。
判断は executable ベースで行います。
この2本を並べることで、
- 見えているズレ(mid)
- 実際に取れるズレ(executable)
の差を常に確認できます。
「動いている」ことと「取れる」ことを、
同じグラフで切り分けるのが目的です。
2. Executable Inputs(A/B Bid-Ask)
a_bid / a_ask / b_bid / b_ask をそのまま表示しています。
これはデバッグ用ではありますが、非常に重要です。
- AB = (A_bid - B_ask)
- BA = (B_bid - A_ask)
を手計算で即座に検算できるようにしておくことで、
符号や分母の事故を防ぎます。
観測器は「合っているはず」ではなく、
常に検算可能であることが重要です。
3. exec_best 分布(Quantiles)
exec_best_bps のヒストグラムから、
- p50
- p90
を表示しています。
これが、価格差戦略の核心です。
- どの程度のズレが“通常値”なのか
- trigger(6bps)が分布のどこに位置しているのか
を客観的に判断できます。
もし p90 が 3bps 程度であれば、
6bps の歪みはほとんど発生しない可能性があります。
これは戦略の成否以前に、
土俵の存在有無を示す指標です。
4. Distortion Events(発生頻度)
5分間あたりの歪み立ち上がり回数を表示しています。
exec_best >= trigger かつ stale_flag = 0
で distortion と定義しています。
ここを見ることで、
- 歪みがほとんど発生していないのか
- 特定の時間帯で偏っているのか
が分かります。
5. Resolve Duration(解消時間)
歪みが ON になってから OFF になるまでの時間を、
- p50
- p90
で表示しています。
歪みが出ても、解消に長時間かかるなら
短期戦略として扱うのは難しいかもしれません。
逆に、数秒〜十数秒で収束するなら
構造がある可能性が出てきます。
発生頻度と寿命を同時に見ることが重要です。
6. Recv Lag / Lead-Lag
base と ref の更新到着差を表示しています。
これは、
- 片側更新による幻の歪み
- 更新非同期の構造
を切り分けるための指標です。
lead-lag を見ない価格差戦略は、
ノイズをエッジと誤認しやすくなります。
7. Stale / Invalid 指標
- stale_flag
- invalid_quote_flag
も可視化しています。
歪みが出ているときに stale が多発していれば、
それは構造ではなくデータ問題です。
上流の濁りを、常に目に見える形にしています。
なぜここまで可視化するのか
戦略は、主観でいくらでも正当化できます。
しかし分布は嘘をつきません。
- 6bpsの歪みは本当に出ているのか
- それはどのくらい持続するのか
- それはstaleを除外した後でも残るのか
これらをグラフで見ることで、
「いけそう」という感覚を排除できます。
Prometheus / Grafana の役割は、
見栄えの良いダッシュボードを作ることではありません。
誤魔化せない事実を突きつけることです。
Spread Observer V1 は戦略ではありません。
その前段階の、評価装置です。
そしてこの可視化こそが、
次に進むか、ここで止まるかを決める材料になります。
7. 現時点で見えていること
Spread Observer V1 を実装し、可視化まで終えた段階で、ようやく「感覚」ではなく「分布」で話ができるようになりました。
まだ観測期間は十分とは言えませんが、いくつかの事実はすでに見え始めています。
1. mid と executable の差は明確に存在する
まず確認できたのは、midベースのスプレッドと executableベースのスプレッドには、はっきりとした差があるということです。
midではそれなりに振れているように見えても、
executableに落とすと値幅は縮小します。
これは当たり前の話ですが、
実際に可視化すると、その影響の大きさがよく分かります。
「動いている」ことと「取れる」ことは違う。
この前提が、数値として確認できました。
2. 通常時の歪みは想像より小さい
exec_best_bps の分布を見ると、
- p50 は数bps未満
- p90 でも数bps台
に収まる時間帯が多いことが分かります。
現在の trigger は 6bps です。
この位置関係を見ると、
通常時には trigger に到達する歪みはほとんど発生していない可能性があります。
これは悲観的な結果ではありません。
むしろ、
「この条件では、ほぼ何も起きない」
という事実が分かったこと自体が重要です。
3. 歪みは“常に”発生しているわけではない
Distortion Events を見る限り、
歪みは連続的に発生しているわけではありません。
特定のタイミングでまとまって出る可能性があり、
時間帯や市場状況に依存していることが示唆されます。
つまり、
- 常時型のエッジではない
- レジーム依存の可能性が高い
という仮説が浮かびます。
4. stale や invalid の影響は抑えられている
stale_flag や invalid イベントを可視化したことで、
歪みが「データ上の幻」でないかどうかを確認できています。
歪みが出ている瞬間に stale が多発していれば、
それは構造ではなく更新遅延です。
現時点では、少なくとも観測上の明らかな誤検出は抑えられています。
これは観測器としての信頼性を担保する意味で大きな前進です。
5. resolve duration はまだ評価段階
一時的に trigger を下げたデバッグでは、
resolve が正しく計測されることを確認しました。
現在は trigger=6bps に戻しています。
この条件で、
- resolve がどの程度発生するのか
- 解消時間はどのくらいなのか
は、24時間程度の観測が必要です。
ここが最終的な白黒判定に直結します。
現時点の暫定結論
いま分かっているのは、
- 見かけの歪みはある
- しかし executableで見ると多くは小さい
- 6bpsを安定して超える歪みは少ない可能性がある
ということです。
これは「勝てない」という結論ではありません。
しかし、
通常状態で安定的に取れる構造があるとは、まだ言えない
というのが正直なところです。
だからこそ、次にやるべきことは戦略を組むことではありません。
- 観測期間を延ばす
- レジーム別に再集計する
- trigger位置を再評価する
です。
エッジがあると信じるのではなく、
エッジがあるかどうかを測る。
Spread Observer V1 は、そのための装置です。
現時点では、少なくとも「幻想を削った」という点で、
方向当て時代より一歩前に進めています。
8. 次の検証
Spread Observer V1 によって、「歪みを測る土台」は整いました。
ここから先は、戦略を作る前にやるべき“検証フェーズ”です。
重要なのは、焦ってエントリーロジックに進まないことです。
いまはまだ、「取れる歪みが存在するか」を白黒つける段階にいます。
次の検証は、大きく三つに分かれます。
1. 24時間観測による安定評価
まずは、十分な観測期間を確保します。
短時間のスナップショットでは、
- 偶然の歪み
- 一時的な流動性低下
- 特定時間帯の偏り
を見誤る可能性があります。
そこで、
- exec_best の分布(p50 / p90)
- distortion 発生頻度
- resolve duration
を、最低でも 24時間単位で評価します。
ここで見るのは「平均」ではなく、
- 通常時の位置
- 外れ値の頻度
- 時間帯ごとの偏り
です。
もし trigger=6bps が分布の遥か外側にあるなら、
この土俵では“常時型の価格差エッジは存在しない”可能性が高くなります。
2. レジーム分割による再集計
価格差は常に同じ振る舞いをするとは限りません。
次のような条件で再集計します。
- 時間帯(東京・欧州・米国)
- ボラティリティ急変時
- 出来高増加時
- stale頻発時
「通常時には無いが、急変時にだけ出る歪み」が存在するなら、
それは“常時戦略”ではなく“イベント戦略”になるかもしれません。
ここで重要なのは、
- レジームを後付けで作らないこと
- 分布を見てから仮説を立てること
です。
3. trigger位置の再評価
現在の trigger は 6bps です。
この値は、
- fee
- slip
- safety
を足し合わせた保守的な水準です。
しかし分布を見た結果、
- 6bpsはほとんど到達しない
- 4bps付近で集中している
という可能性もあります。
その場合、
- triggerを下げるのか
- それでも期待値が残るのか
- そもそもこの市場では難しいのか
を冷静に検討します。
重要なのは、triggerを下げることが“改善”なのか、
単なる妥協なのかを区別することです。
4. 白黒判定を出す
最終的にやることはシンプルです。
- コストを超える歪みが、安定して存在するか?
- その歪みは、解消までに扱える時間幅を持つか?
この2点がYESなら、戦略に進みます。
NOなら、別の土俵を探します。
ここで曖昧な判断をしないことが重要です。
方向当ての時代は、「もう少し改善すれば」という余地がありました。
価格差戦略では、そこを誤魔化さない設計にしています。
今回の姿勢
次の検証でやるのは、期待を膨らませることではありません。
むしろ、
この市場では取れない可能性を受け入れられるか
を試す工程です。
Spread Observer V1 は、
エッジを作るための装置ではありません。
エッジが存在するかどうかを、
事実ベースで判断するための装置です。
次章では、この検証結果をどう判断し、
どう次の一手を決めるかについて書いていきます。
9. 今回得た開発上の知見
Spread Observer V1 を実装して感じたのは、「価格差が取れるかどうか」以上に、開発プロセスそのものに対する学びでした。
今回のフェーズは、戦略を作る工程ではありませんでした。
むしろ、戦略を作らないための工程だったとも言えます。
その中で得られた開発上の知見を整理しておきます。
1. 戦略より先に、測定器を作る
これが一番大きな学びです。
これまでの方向当て戦略では、
- 仮説を立てる
- ロジックを書く
- バックテストする
- 改善する
という流れを繰り返していました。
しかし、測定器が曖昧なままでは、
改善なのか偶然なのかが判断できません。
今回やったことは逆です。
- まず観測器を作る
- 分布を可視化する
- 土俵が存在するか確認する
- それから戦略を考える
この順番に変えただけで、
議論が一段階クリアになりました。
2. executable を固定しない戦略は、必ず濁る
midベースの検証は、どこかで必ず楽観に傾きます。
実際に約定可能な価格で定義し直すと、
- 期待値は縮む
- 歪みは小さくなる
- 多くの仮説は消える
しかし、それが現実です。
executable定義を最初に固定し、
そこから一切ブレないようにしたことは、
今回の最重要ポイントでした。
3. ノイズは“削る”のではなく、“見える化する”
stale、invalid、crossed、ジャンプ。
これらは単に除外すれば良いわけではありません。
どれだけ発生しているかを可視化することが重要です。
ノイズを削るだけでは、
「都合の悪いデータを隠す」ことになりかねません。
観測器は、エッジだけでなく、
ノイズの量も示す必要があります。
4. 分布は感情を冷やす
「いけそう」「惜しい」という感覚は、
グラフを見ると消えます。
- p50はいくつか
- p90はいくつか
- triggerはどこにあるか
この三つを見るだけで、
幻想はほとんど消えます。
分布は、感情を冷やす装置でもあります。
5. “ない”という結論も成果
価格差が取れない可能性もあります。
しかし、
- 観測した
- 定義を固定した
- 分布で確認した
上での「ない」は、敗北ではありません。
むしろ、
次に何を試さないかが決まる
という意味で、大きな前進です。
6. 上流が濁ると、すべてが濁る
今回の実装で強く感じたのは、
観測層が曖昧なまま戦略層を積み上げることの危険性です。
- 時刻系が揺れる
- 定義が揺れる
- 分母が揺れる
- 符号が揺れる
この状態では、どれだけ改善しても評価は安定しません。
Spread Observer V1 は、
上流を固定するための装置でした。
まとめ
今回の開発で得た最大の知見は、
「戦略は、測定器の上にしか立てない」
という当たり前の事実でした。
方向当てをやめたことも、
価格差に舵を切ったことも、
本質ではありません。
本質は、
- 定義を固定し
- ノイズを排除し
- 分布で判断する
という姿勢を、実装レベルで徹底したことです。
勝てるかどうかは、まだ分かりません。
しかし少なくとも今は、
“何が起きているか分からない状態”ではありません。
それだけでも、前に進んでいます。