Bot 開発ログ

🛠️開発記録#283(2025/8/18)本日の開発ログ

本日は、止める→見える→触れるまで一気に進めた日でした。しかし、「止めの基盤」と「EV検証」の部分がまだ数字と噛み合ってない部分もあるので、明日はこの点を潰していくのがメインタスクになりそうです。

以下の4つに加えてガンマスキャルピングbotの雛形も作成しましたが、実装レベルに満たないため本日の掲載は省略します。

MMbot作業ログ

0) ゴール

  • 自動停止メカニズム(Alert → /am-webhookdisable_live)の完成
  • p99/RPS の安定観測KPIメトリクス基盤の常時可視化

1) タイムライン(重要イベント)

  • [構成修正] Exporter と Runner の単一プロセス統合(/metrics & /emit & /control & /am-webhook を同一REGで提供)
  • [配線修正] /control 実装(POST, X-Auth-Token)→ Runner の new_orders_enabled=False に連動
  • [REG問題解決] REG ID不一致(別プロセス)の解消。ホットパッチ/app/mm_bot に直接差し替え
  • [重複メトリクス] Duplicated timeseries の排除(宣言の重複を整理:Runner側に一意、Monitor側と二重にしない)
  • [録画式反映] p99/RPS 録画ルールを *_seconds_bucket 前提の式に統一(低トラフィック耐性つき)
  • [ウォームアップ] /emit 経由で観測データ注入(WARM)→ Prom 側で p99/RPS を非NaN
  • [KPI基盤] mm_ev_order_total を /metrics に掲載(発注時インクリメントの足がかり)

2) 実測・検証結果

  • /control:HTTP 200(手動停止OK)
  • p99 / RPS
    • mm_total_p99_ms:5m = 832.16 ms
    • mm_total_obs_rps:5m = 0.3221
  • ヒストグラムmm_lat_total_seconds_bucket の行数 = 60
  • KPI掲載mm_ev_order_total 0.0(メトリクスは可視、配線は最小)
  • (一時未達) disable_live reason=...理由ログが未表示(/control は効いているがログが拾えない場面あり)

3) 主要な問題と対処

3-1) 古いコードが走っていた

  • 兆候:HAS_control_counter=False など
  • 原因:ビルド反映漏れ//app/src ではなく /app/mm_bot 配置だった
  • 対処:ホットパッチ/app/mm_bot/... に直接 runner.py/http_exporter_std.pydocker cp → 再起動

3-2) Duplicated timeseries

  • 兆候:起動時に Duplicated timeseries in CollectorRegistry
  • 原因:同名メトリクスの二重宣言(Runner と Monitor)
  • 対処:宣言を一意の場所に集約、他は参照のみに変更

3-3) p99 が NaN / RPS = 0

  • 原因:観測不足 or 録画式が _agg_ 参照
  • 対処:*_seconds_bucket を参照する式に統一+WARM注入 → 解消

3-4) disable_live の理由ログが出ない

  • 可能性:logger設定/ハンドラ登録のタイミング、stdout不達
  • 対処案(実装方針):_disable_live()logger+stdout の二重出力に修正(パッチ準備済み)

4) 現在地(達成度)

  • 制御フロー基盤:100%(/control 200、停止フラグ、Webhook口あり)
  • メトリクス収集:100%(p99/RPS 非NaN、bucket 60)
  • KPI基盤70%(order は見える/fill・reject・P/L分解は配線中)
  • ログ出力(停止理由)90%想定(二重出力パッチ適用で確実化)

総合進捗:~80–85%


5) 直近の改善パッチ(最小差分・要点のみ)

5-1) _disable_live() の確実ログ化

# src/mm_bot/core/runner.py
import logging, sys
...
def _disable_live(self, reason: str = "no_reason"):
    self.new_orders_enabled = False
    mm_control_actions_total.labels(action="disable_live").inc()
    msg = f"disable_live reason={reason}"
    logging.getLogger("mm_bot.control").error(msg)  # logger経由
    print(msg, flush=True)                           # stdout保険

5-2) Exporterでの受信ログ(任意)

# src/mm_bot/services/http_exporter_std.py (/control 分岐)
logging.getLogger("mm_bot.control").info(f"control executed: disable_live reason={reason}")

5-3) KPIの“配線”を最低1行ずつ

  • 発注成功:mm_ev_order_total.inc()
  • 約定:mm_ev_fill_total.inc() + mm_pnl_components_total.labels(kind="spread").inc(spread_jpy)
  • 拒否:mm_ev_reject_total.inc()

6) 即時チェック(3本)

# A) /control → 200 → カウンタ増分&理由ログ1行
curl -s -X POST http://localhost:8080/control \
  -H "X-Auth-Token: mm-bot-control-2024" -H 'Content-Type: application/json' \
  -d '{"action":"disable_live","reason":"manual_test"}' -w "\nHTTP:%{http_code}\n"
curl -s http://localhost:8080/metrics | grep -m1 '^mm_control_actions_total{action="disable_live"}'
docker logs mm-bot-mainnet --tail 200 | grep -i "disable_live reason=" | tail -1

# B) p99 / RPS(非NaN/非0の継続確認)
curl -s 'http://localhost:9090/api/v1/query' --data-urlencode 'query=mm_total_p99_ms:5m'
curl -s 'http://localhost:9090/api/v1/query' --data-urlencode 'query=mm_total_obs_rps:5m'

# C) KPI 1本(order)
curl -s http://localhost:8080/metrics | grep -m1 '^mm_ev_order_total'

7) 次フェーズ(完了後 30〜60分)

  • Alertmanager E2E/am-webhook で Critical firing → disable_live 1行ログ
  • Grafana 4パネル(プリセット):
    • Fill/Reject 率(5m)
    • SpreadPnL(日次合算)
    • Cancel p95(ms)
    • 実行RPS
  • Paper EV/bp ミニ集計(CSV→日次EV、分解4要素)

MMbot達成度(「稼ぐ」をゴールにすると)

約 50%(±7%)

土台はかなり前進しましたが、“お金を生む証明”=EV>0 の実証が未了です。いまは「止められる・見える・流れる」段まで整い、**“勝てるかを示す”**の最終区間が残っています。


内訳(重みづけ評価)

項目重み現状達成加点
アルファ/EV検証(Backtest→Paper→最小Live)40%20%8
実行/レイテンシ(p99/RPS、配線)25%70%17.5
リスク/自動停止(Alert→disable_live)15%70%10.5
可観測性(/metrics, Prom, 録画式)10%90%9
運用/オペ(手順化・スケール準備)10%50%5
合計100%≈50

いま効いている:/control 200、p99/RPS 非NaN、同一REG、KPI基盤(order)
まだ:disable_live 理由ログの確実化(微修正)、fill/reject/PnL のKPI配線Paper→最小LiveのEV実証


ここから 70% に跳ねさせる“3本”

  1. Paper 24–48h(現実寄り Fill 模型)
    • 受け入れ:EV>0 / Fill≥35% / Reject≤3%
  2. KPIの配線を3行だけ追加(各イベントで1行)
    • 発注成功:mm_ev_order_total.inc()
    • 約定:mm_ev_fill_total.inc()mm_pnl_components_total{kind="spread|fees|…"}
    • 拒否:mm_ev_reject_total.inc()
  3. 停止E2Eの確証
    • /am-webhookdisable_live reason=…ログ+カウンタで残ることを確認

“Go/No-Go”の受け入れ基準(最小Liveへ)

  • Prom:mm_total_p99_ms:5m 非NaN、mm_total_obs_rps:5m > 0(継続)
  • Paper 24–48hEV>0 / Fill≥35% / Reject≤3%
  • /am-webhook停止ログ1行mm_control_actions_total{action="disable_live"} 増分
  • 最小Live(1×, 1日):ネットPnL ≥ 0

MMbot開発:今日の“筋の悪い”ところ(短評)

  1. インフラの最終1%に時間を使いすぎ
     /metrics・/control・REG統一は既に“勝つための必要条件”は満たしていました。そこからログ体裁やプロセス競合の詰めに長く滞留し、EV証明の着手が遅れたのが痛い。
  2. KPI配線が“基盤止まり”
     mm_ev_order_total は出せたのに、fill / reject / PnL分解の1行配線を後回しに。
     → P/Lの内訳が見えない = 明日の意思決定ができない(最短経路を外す典型)。
  3. 反映戦術がブレた(ビルド vs ホットパッチ)
     build中断→ホットパッチ→再起動…の流れで、/app/src と /app/mm_bot の差に振り回されました。
     → 「今日はホットパッチだけ」など手段を固定し、確認コマンドをテンプレ化すべき。
  4. “止めた”事実の監査が弱い
     発注スキップは効いているのに、disable_live reason=... の監査ログが未出力のまま先へ進んだ。
     → “止まる”は利益を守る最後の柵。ログ+カウンタの二重で即可視化が最短。
  5. 実験の受入基準/終了条件の宣言が薄い
     「いつをもってOKで次へ進むか」が曖昧で、作業の終点が伸びる
     → “p99/RPSが数値→KPI3行→Paper 60分”の順番ロックを掛けるべきでした。

明日の改善プラン(3時間で70%ラインへ)

ブロックA(45分)— 停止の監査を確実化

  • Runner _disable_live()logger+stdout 二重出力に(今日のパッチ案でOK)。
  • 受入:
    • /control 200 → disable_live reason=manual_test がログ1行
    • mm_control_actions_total{action="disable_live"}+1

ブロックB(60分)— KPI配線を“3行だけ”

  • 置く場所は最低3箇所:
    1. 発注成功直後 → mm_ev_order_total.inc()
    2. 約定ハンドラ → mm_ev_fill_total.inc()mm_pnl_components_total{kind="spread|fees|slippage|adverse"}
    3. 拒否ハンドラ → mm_ev_reject_total.inc()
  • 受入:/metrics で各メトリクスが見えWARM/ドライランで非0になる。

ブロックC(45分)— Paper 60分スモーク→EV/bp

  • 先頭距離×確率+部分約定の“簡易モデル”でOK(既に実装済みベース)。
  • 受入:EV/bp(spread/adverse/fees/slippageの分解付き)1枚出力

ブロックD(30分)— Alertmanager E2E

  • /api/v2/alerts に firing POST → disable_live ログ+カウンタで確認。
  • 受入:MMBotLatencyCritical firing→ 停止の事実がログに残る

明日のガードレール(迷いを潰すルール)

  • Exporter/REGには触れない(凍結):/app/mm_bot のホットパッチのみ。
  • “ビルド or ホットパッチ”を開始時に固定(明日はホットパッチのみ推奨)。
  • 各ブロックに明確な受入条件(上記の「受入」を満たしたら即次へ)。
  • 作業前にこの2行だけ実行:
    赤が出たら基盤数値が出たらKPI/EVへ。迷わない。
docker exec mm-bot-mainnet python -c "import mm_bot.core.runner as r; import inspect; print('HAS_disable_live=', 'disable_live reason=' in inspect.getsource(r.Runner))"
curl -s 'http://localhost:9090/api/v1/query' --data-urlencode 'query=mm_total_p99_ms:5m'

一言まとめ

  • 今日の躓きは 「基盤の1%詰め」>「EVの可視化」 に偏ったこと。
  • 明日は “停止ログ1行+KPI3行+EV1枚” を時間箱でやり切るのが最短ルート。

CEX/DEX arbbot開発ログ

1. 立て直し・計測開始

  • status_now.pyで健全性確認:watcher=UP/killswitch=UP、429カウンタ=0
  • 時間帯制御ON:time_slot_control.sh(USオープン±30分のみ自動GO)
  • 近接アラート再起動(単発化のため flock):
    • near_go_alert.sh SOL 0.05AUTO_TH採用時のみ自動GO)
    • near_go_alert.sh RAY 0.03

2. Jupiter応答の堅牢化(KeyError/data対策)

  • fetch_now.py:汎用パーサ _parse_jup_out_usdc 追加
    • data[0].outAmount / トップレベル outAmount / routes[0].outAmount / otherAmountThreshold に対応
  • 直ルート+最良ルートの二段取得安い方を採用
  • amount=0.8 SOL、slippageBps=20 に最適化

3. “叩かない”設計(429抑止)

  • rate_guard.sh適応式に:GUARD_SEC 基本+429回数で自動延長
  • fetch_now.pyget()429検知→カウント/成功→0リセット

4. 刺す直前の制御(AUTO→GO 0%対策:ミニパッチA/B/C)

  • A: 1stヒット後クールダウン解除 → 2ndヒットを1–2sで確実評価
  • B: last-look の計算式を preok と統一(同MID)→ 境界誤キャンセル抑制
  • C: WHYログ分解 を導入(stage=gross0/gross10/depth/dry8/preok_false/last_look)

5. depthでの空振り抑止(当たり寄せ)

  • ladder_try_now.shVWAP-BIDの採用($10を呑める平均価格)
  • (拡張)depth_ok_any.py 作成:OKX/Binance/BybitのVWAPを比較し最良VWAPを採用

6. 観測ログ(第1→第2回)

  • 第1回:NEAR=1 / AUTO=69 / GO=0、skip={'pre-net':53, 'gross<0':84, 'gross<10':2}
  • 第2回:NEAR=1 / AUTO=85 / GO=0、why={'depth':6}(WHY生成開始)
    AUTO↑(+16)depthで落ちていることが可視化

7. 運用・調整ノブ(If/Then)

  • gross<0 多い → CEX優先/VWAPを維持(OKX→Binance→Bybit)
  • pre-net 多い → 0.8SOL/20bpsfx_bp自動反映を維持
  • AUTO→GO<30% が継続 → TTLを 2.5s→3.0sへ +0.5s 、429平均>1なら GUARD_SEC=2

8. 今日のDone基準(据え置き)

  1. 二重ゲートで新規5本(NO-GOは不足数値ログ)
  2. 5本サマリ:win_rate>0.60 & avg_pnl>0(未達→実行ライン±1bps)
  3. exec_log.jsonl{ts,tap,pre_net,fx_bp,ladder,dq,df,cb,cf}(+need_delta_px/tap_age_secがあれば尚良)

CEX/DEX arbbot:総合評価(いまの立ち位置)

  • 総合達成度:40% ±5%(目安) 収益化の“土台”はほぼ整備済みだが、**実行フェーズ(AUTO→GO→約定)**でまだ刺さっていない状況。

軸別スコア(根拠つき)

達成度根拠(直近ログから)
インフラ/監視90%watcher/killswitch=UP、429適応ガード=0、flock導入済み、時間帯制御ON
価格取得/レート制御85%fetch_now堅牢化(Jupiter汎用パーサ、直/最良ルート、0.8SOL/20bps、キャッシュ+バックオフ)
実行パイプライン(NEAR→AUTO→GO)55%NEAR→AUTOは十分(直近200行でAUTO=69→85へ改善)だがGO=0。2ヒット/last-look/深さで止まる
フィルタ・安全性(ムダ打ち抑止)80%gross<0/gross<+10/dry pre-net<+8/depth/VWAP/last-look の多層フィルタ完備
アルファ/シグナル品質25%gross<0が最多(84件)、pre-net不足(53件)。TRADES=11・win_rate=0
データ量/再同定可能性30%実弾N=11は統計が薄い。near-goスナップショットは蓄積中(p50 needΔ≈0.0112 USDTと“近い”が未到達)

目下の主要ブロッカー(AUTO→GO=0の原因)

  1. 板厚不足(WHY: depth):$10を一撃で呑めるBIDが不足(stage=depth 記録あり)
  2. 境界判定の取りこぼし:2ヒットのTTL/COOLDOWN/last-lookの直前ロジックでキャンセル
  3. CEX_BID ≤ DEX_Qの場面が多い(gross<0=84) → そもそも到達しにくい時間帯/銘柄が多い

今週の“進捗が見える”目標(Done定義の落とし込み)

  • :二重ゲートで 新規5本(NO-GOは不足数値ログ)
  • :5本サマリ win_rate > 0.60 & avg_pnl > 0
  • ログexec_log.jsonl{ts,tap,pre_net,fx_bp,ladder,dq,df,cb,cf}(+必要なら need_delta_px/tap_age_sec

ここから“稼ぎへ”最短の3手(設計据え置き・即実行)

  1. 深さで落ちない最良VWAP×複数CEX を last-look まで貫通
    • 既に導入済:depth_ok_any.pyOKX/BNB/BYBIT で $10 VWAP 最良を採用
    • 効果指標:WHY: depth 比率が下がること、AUTO→GO比が上がること
  2. 2ヒットの取りこぼしをさらに減らす
    • 1stヒット後COOLDOWN解除は実装済 → **TTLを+0.5s(2.5→3.0s)**に小緩和(429はrate_guardで吸収)
    • 効果指標:AUTO→GO ≥ 30% 到達
  3. 当たり時間帯に集中(USオープン±30のみ自動GO)
    • すでにスロット制御ON。**AUTO_TH(SOL 0.015/RAY 0.025)**は据え置き(NEAR→AUTOは十分)
    • 429が増えたら一時的に GUARD_SEC=2(0.5 req/s)→落ち着いたら戻す

期待値の見立て(短評)

  • 土台の完成度は高い(≈85–90%)。
  • 勝ちに直結する差分は“刺す直前の数秒”:深さ/VWAP/TTLを詰めればAUTO→GOが立ち上がる見込み。
  • 近接度のp50≈0.0112 USDTは“届く距離”。CEX側VWAPが乗った瞬間に、2ヒット+last-lookを通過できるはず。

結論

  • いまの達成度:40%前後
  • 短期の勝ち筋最良VWAP×複数CEX2ヒットTTLの小緩和時間帯集中で、AUTO→GOを“0→30%”へ引き上げ、最初の5本で**+PnL**を取りに行く。
  • 60–90分計測後の数字(サマリ・ファネル・WHY内訳)を頂ければ、実行ライン(±1bps)/AUTO_TH/GUARD_SECその場で微調整します。

CEX/DEX arbbot:今日の筋悪ポイント(原因 → 影響)

  1. AUTOは増えたのに GO=0 を“その場”で潰し切れていない
  • 原因:2ヒットTTL/COOLDOWN/last-lookの最終段で落下。変更は入れたが効果確認ループが当日中に回り切ってない
  • 影響:NEAR→AUTOの増加(69→85)に対して、当日の実GOが0のまま。
  1. stage=depth の未解決を後回し(WHY: depth が早期に可視化された)
  • 原因:$10を呑めるVWAP(しかも複数CEXでの最良)を最終段まで一貫適用する処置が遅れた/確認不足。
  • 影響板薄い見かけBidでpreokまで進んで落ちる → AUTO→GOが立ち上がらない。
  1. ログの“一致”を崩したまま計測を進めた(NEAR=1に対してAUTO=69/85)
  • 原因:near_go の多重起動・ログ源の非対称(SOL/RAY混在/旧プロセス生存)を潰す前にファネルを読んだ。
  • 影響NEAR→AUTO の比率評価が歪む→しきい値の調整判断が遅れる/誤る。
  1. NET_EDGE_MIN_BPS が unset の時間帯があった
  • 原因:環境変数の輸出忘れ/表示上の食い違い。
  • 影響:Watcherの表示・挙動の不一致リスク(実行ラインの誤認)。
  1. “時間帯と負荷”より“設定の微修正”を優先
  • 原因:429/awkなどのインフラ改善に時間が割かれ、USオープン±30の当たり時間帯での刺し込みが薄くなった。
  • 影響当たり母集団を取りに行く機会損失。ログは増えたが、稼ぐための打席が増えていない。

明日の改善アクション(90分プラン)— “刺さる”に一点集中

A. 最終段を一気に通す(AUTO→GO ≥30% にする)

  1. TTL 小緩和を当日中に検証(+0.5s)
    • いま 2.5s3.0s へ。
    • 成功条件:AUTO→GO ≥30%(直近200行で GO≧60×0.3)
  2. VWAP×複数CEX を last-look まで一貫適用(落ち所=depth潰し)
    • depth_ok_any.py最良VWAPpreok直前→last-look直前の両方で採用(CBの上書き一貫)。
    • 成功条件why_breakdowndepth 比率↓、GO増加。
  3. 単価サニティ(unit mismatch)で“異常値”は即キャンセル
    • abs(cb−dq)/mid < 0.10 を満たさなければ [WHY] unit_mismatch で落とす。
    • 成功条件:誤発射ゼロ(NO-GO理由に unit_mismatch が出たら観測)

B. 観測→判断→即ノブ(10分×2回)

  1. ログの一致を先に担保
    • pkill -f near_go_alert.shsource time_slot_control.sh単発起動(flock済みでも古い個体は止める)。
    • 成功条件NEAR の増加に対して AUTO が過大にならない(NEAR≲AUTO)
  2. ファネル+WHYで即判断
    • summary_5_trades.py(skip + WHY 内訳)/NEAR・AUTO・GO の3値。
    • If/Then
      • AUTO→GO <30% かつ WHY=depth 多い → GUARD_SEC=2(429抑止&連打抑制)
      • WHY=last_look 多い → TTLを +0.5s(最大3.0sまで/戻しは数字で)
      • NEAR→AUTO <10% → AUTO_THSOL 0.015→0.02RAY 0.025→0.03 に +0.005 のみ
  3. 当たり時間帯に集中
    • 迷わず USオープン±30分だけ自動GO、他時間は通知のみ。
    • 成功条件:その時間帯に GO が立つ(ladder_watch.log に “GO (ladder …)” が出る)

C. ガード(落ちない工夫)

  • export NET_EDGE_MIN_BPS=38 を明示輸出 → check_main_watcher.sh 再起動
  • 429 が 10分平均で >1 → 一時的に export GUARD_SEC=2(戻すときは unset GUARD_SEC

“やらないこと”(明日は削る)

  • しきい値の大幅いじり(±1bps以上の変更)
  • BTC再挑戦(Jupiter mint/ルートが健全化するまでOFF)
  • 新しい監視や可視化の追加(WHY内訳・ファネルが揃っている)

できていた良い点(このまま維持)

  • Jupiter堅牢化(汎用パーサ、直/最良ルート、0.8SOL/20bps)
  • 適応レートガード(429=0)
  • 多層フィルタ(gross/乾式pre-net/depth/VWAP/last-look/2ヒット)
  • 時間帯制御(USオープン±30の集中)

一言でまとめると

  • 筋の悪さは、「最終段の数秒」を今日中に詰め切れず、当たり時間帯の打席を増やし切れなかった点。
  • 明日は最良VWAP×複数CEX一貫適用TTL+0.5s時間帯集中で、AUTO→GOを 0%→30% まで引き上げ、最初の5本に到達する。

オンチェーン精算スナイプbot:作業ログ

概要

  • 目的:REPLAY基準で KEEP≥60% / p95≤350ms を達成し、その後 drop≤10% を“測れる状態”へ。
  • 現在地:p95=300ms 達成KEEP=48%(16%→48%へ大幅改善)。ltK(insufficient_kinds)支配が残課題。

1. 基盤・計測の是正(統一・可視化)

  • 設定一元化:runtime.RALIGN_MS / KEEP_CONFIRM_MS / JOIN_WINDOW_MS / TTL_MS / KEEP_CONFIRM_STEPS_MS=[KEEP, KEEP*2] を集約。
  • 時刻正規化(sec/µs/ns→ms)& ALIGN依存へ統一。align_ms_current/metrics で公開。
  • REPLAYの flush を十分未来へ変更:future = last_ts + KEEP×2 + ALIGN + 200ms
  • Registry統一:すべて get_registry()/self.m 経由に修正し、default混入を排除。

効果

  • p95 が 1000ms固着→300ms へ正常化(ALIGN=300ms)。

2. KEEP確認回路の可視化・安定化

  • 確認ジョブ系メトリクス追加:confirm_(scheduled|processed|kept|faded)_total / heap_depth / next_at_ms
  • exactly-one 設計:JOIN未成立/KEEP失敗の各出口で miss 理由を必ず1つ inc()
  • keep_wait_ms(JOIN→KEEP遅延)/ fade_alive_kinds(最終確認での生存種)を追加。

実測

  • confirm_scheduled=confirm_processedkept+faded ≈ processed を確認(正常動作)。

3. 片翼死の直叩き(fade対策)

  • 弱条件 refresh 実装(毎tick/最小間隔80–100ms):FIREは据置、REFRだけ1クリック緩和。
  • 心拍パルス 実装:JOIN→KEEPの間、80–100msごとに missing側だけ refresh(JOIN水増しなし)。

実測

  • confirm_pulse_total 大量、confirm_faded_total → 0fade_alive_kinds 偏重解消。
  • KEEP 16% → 48% に改善。

4. ltK(K=2未達)への対処(K到達率↑)

  • FIREしきい 1クリック緩和(段階的):
    • 例)OI_Z: 1.5→1.4 / BBO_COLLAPSE: 3.5→3.0 / L2_THIN: 0.72(据置)/ BURST_BP: 7(据置)
  • 以後の攻め案(必要時):L2_THIN: 0.72→0.75 / BURST_BP: 7→6

実測

  • JOIN増・ltK比率の低下を確認(KEEP=48%まで上昇)。
  • ただし insufficient_kinds≈886 がなお支配的 → さらなる1クリックが必要。

5. 窓/TTL(現行セット)

ALIGN_MS=300
KEEP_CONFIRM_MS=450
JOIN_WINDOW_MS=700
TTL_MS=3000
REQUIRE_PAIR=0
REPLAY_MODE=0
  • ルール:TTL ≥ KEEP_CONFIRM×2 + 100ms を厳守。
  • keep_wait_ms ピーク(400–600ms/900–1200ms帯)と矛盾なし → 現状据置で良好。

KPIスナップショット(最新)

  • p95:300ms(ヒスト算出/ALIGN=300)✅
  • KEEP48.0%(16%→48%)↗️
  • fade0件confirm_faded_total=0)✅
  • ltKinsufficient_kinds≈886 ❗(残課題)

次の一手(1クリック)

  • 目標:KEEP 48% → 60%+(p95は維持)。
  • 実施:FIREを1クリック(K到達率↑、質は維持)
    • OI_Z: 1.4→1.3 / BBO_COLLAPSE: 3.0→2.8〜3.0
    • (必要なら)L2_THIN: 0.72→0.75 / BURST_BP: 7→6
  • 観測:2行ヘルス+insufficient_kinds / keep_wait_ms / fade_alive_kinds / confirm_* を5分ループで確認。
  • ガードレール:p95>350ms or keep%<50% になったら直近変更をロールバック。

その次:drop計測ON(影/実 4カウンタ)

  • shadow/live_exec_attempt_totalshadow/live_fill_success_total を配線 →
    fill_rate_shadow/livedrop = 1 - (live/shadow)(目標 ≤ 10%)を常時計測。

オンチェーン精算スナイプ:達成度

ざっくり結論:達成度は ~56%(私の目安) です。
「動く・測れる」は整い、p95=300msもクリア。一方でKEEP=48%(目標≥60%)と、drop≤10%の計測/EVゲートが未達。


いまの達成度(重み付きざっくり採点)

  • 検知/シグナル実装(20)… 14/20(主要シグナル+整流OK)
  • 合議品質(20)… 11/20(KEEP 16%→48%へ大幅改善、目標60–90%まで一歩)
  • レイテンシ(15)… 12/15(p95=300ms:ALIGN依存で安定)
  • 執行品質/ドロップ(15)… 2/15shadow/live dropの4カウンタ未配線
  • 会計/EVゲート(10)… 3/10(日次EV→昇格ラインは未運用)
  • 監視/可視化(10)… 8/10(confirm系・keep_wait・fade分布まで可視化)
  • 安全/運用(10)… 6/10(冪等化・ガード類OK、ゲート最終確定はこれから)

合計:56/100


できていること ✅

  • p95=300ms 達成(ALIGN=300ms依存で正常)
  • KEEP=16%→48% まで改善(fade=0に収束)
  • 確認ジョブ(予約→処理→保持/失敗)メトリクスで動作が数で証明
  • 設定・時刻正規化・Registry統一、測定の基盤は安定

まだのこと ❌

  • KEEP ≥ 60%(ltK=886が支配 → K=2到達率の底上げが必要)
  • drop ≤ 10% の“計測”そのもの(shadow/live 4カウンタ)
  • 手数料込みEV>0の運用ゲート(5営業日連続、MaxDD制御)

すぐ上げるための“次の1クリック”

  1. FIRE だけを段階的に緩めて ltK削減(p95はALIGNで維持)
    • 例:A:OI_Z 1.4→1.3, BBO 3.5→3.0(L2/BURST据置)
    • 効果が小さければ B:L2 0.72→0.75, BURST 7→6
  2. drop 計測 ON(影/実 4カウンタ)
    • shadow/live_exec_attempt_total, shadow/live_fill_success_totaldrop = 1 - live/shadow を常時計測

KPI判定(REPLAY基準):KEEP≥60% / p95≤350ms / insufficient_kinds↓ を満たせば、低ノッチCanaryで drop≤10% を見に行けます。


Go/No-Go の“稼ぐ”基準(再掲)

  • KEEP ≥ 70–90%
  • p95 ≤ 350–400ms
  • drop ≤ 10%(shadow vs live)
  • 手数料込みEV>05営業日連続(MaxDDは許容内)

清算スナイプbot:今日の“筋が悪かった”ポイント(なぜ悪い→どう直す)

  1. 複数ノブを同時に動かした
     なぜ悪い:因果がぼけて、効果検証が遅れる(KEEP%が上がった/下がった理由が不明)。
     どう直す:1クリック=1ノブ。A/B(前後)で join/keep/keep%/p95/insufficient_kinds を必ず比較。
  2. パルス/refreshの“対象”が広すぎた(当初)
     なぜ悪い:missingでない側も延命→JOIN質が落ちやすい・CPU浪費。
     どう直す:missing側限定(JOIN時 alive ∪ 現在 alive ∪ near)− 今alive だけに refresh。
  3. 窓/TTLをいじり続けた(既に fade はゼロ)
     なぜ悪い:ボトルネックは ltK(K未到達)。窓/TTLはもう効かない。
     どう直す:窓/TTLは ALIGN=300 / KEEP=450 / JOIN=700 / TTL=3000固定。以後は FIRE/REFR/pulse だけ。
  4. 再生プロセスの不安定運用(ポート衝突・旧メトリクス参照)
     なぜ悪い:古い結果を見て判断誤り。
     どう直す:1プロセス運用+ 起動順の固定start_http_server(..., get_registry())ScoringEngine())+ 強制 flush
  5. KPIの“反応速度指標”を見ていなかった
     なぜ悪い:パルスやREPRの効き所が分からない。
     どう直す:keep_wait_msfade_alive_kinds を必ず見る(ピーク帯&最頻値)。今後の窓合わせの根拠に。
  6. ltKをFIREで削る判断が遅れた
     なぜ悪い:fadeが消えた時点で、次のボトルネックは明確に ltK。
     どう直す:FIREだけ段階的に緩める(REFR/窓は据置、p95はALIGNで固定)。
  7. “稼ぐ”直結の drop 計測が後ろ倒し
     なぜ悪い:KEEPが上がった瞬間に drop を見始めるべき。
     どう直す:keep≥60% 到達直後に影/実の4カウンタ配線(attempt/fill_success)。

明日の“最短”プラン(午前で勝ち筋確認)

0. ルール(固定)

  • 窓/TTL:ALIGN=300 / KEEP_CONFIRM=450 / JOIN_WINDOW=700 / TTL=3000 固定
  • パルス:80ms、missing側限定 refresh(実装済)
  • REFR:毎tick、最小間隔 80ms、近い閾値(実装済)

1. 検証ループ(1クリックずつ)

段階A(保守的) — まずこれ

  • FIREOI_Z 1.4→1.3BBO 3.5→3.0L2/BURST据置
  • 再生 → 2行ヘルス+内訳
    • 合格keep≥60% / p95≤350ms / insufficient_kinds↓drop配線ONへ
    • 未達:段階Bへ

段階B(攻め) — Aで伸びが小さければ

  • FIREL2_THIN 0.72→0.75 または BURST 7→6一度に片方だけ
  • 再生 → 同じKPI判定
    • p95>350ms or keep<50% に落ちたら直前をロールバック

いずれも 1クリック=1ノブ を厳守。A/B前後をCSV出力すると迷いません。

2. 合格したらすぐ drop 計測ON(影/実4カウンタ)

  • shadow/live_exec_attempt_totalshadow/live_fill_success_total
  • レポート:
    • fill_rate_shadow/livedrop = 1 - (live/shadow)(目標 ≤10%)
    • 2行KPIに drop を追記(明日中に“測れる状態”へ)

明日の作業チェックリスト

  • 起動順:http_server→ScoringEngine(Registry統一)
  • セット固定:ALIGN=300/KEEP=450/JOIN=700/TTL=3000
  • 段階A FIRE 1クリック → 再計測
  • 合格 or 段階B FIRE 1クリック → 再計測
  • すぐ drop 4カウンタ配線
  • 2行ログ+insufficient_kindskeep_wait_msピーク+fade_alive_kinds最頻値を保存

成果目標(明日中)

  • KEEP ≥ 60%(p95は維持)
  • drop 計測ON(影/実)
  • 以降:EVゲートへ

短く言えば、**“FIREだけ一段ずつ”**が明日のコア作業です。

ショート系bot:作業ログ

0) サマリー

  • ゴール:24h Testnet Canary → α判断
  • 進捗:/metrics 集約完全復旧、CB表示の二重化(真実値agg)、数量ゼロ丸め根絶、Canary Smokeのtaker ping実装、発注系4カウンタ導入。
  • 残タスク:実 fill の安定発生(EVメトリクス通電)※IOC待機/価格/size or Market pingで即解決可

1) 計測・集約まわり(復旧〜強化)

実装

  • metrics-servesymlink /tmp/bsb_mp/current 集約に変更(env→import順序を厳守、WSGIで registry= 明示)。
  • epoch切替:起動時に run-<ts> を生成 → current に相対symlinkを張替え。
  • ジャニター:stale PID を mark_process_dead で定期掃除(手動 metrics-janitor --ttl-sec も可)。
  • metrics-sanity で aggregated registry の中身を直検査できるように。
  • CB真実値:JSON直読の short_circuit_state_agg{category} を serve 側 Collector で追加(mp残骸に非依存)。

検証・結果

  • mini_counter_total が /metrics に出現 → 集約復旧 OK
  • short_req_ack_ms_* / short_cancel_ms_*bucket/sum/count 出現を確認(dryrun 10本)。
  • CBドリル:error-sim → health-sim-recover2→1→0/metrics と JSON の両方で整合。
    • ダッシュは short_circuit_state_agg を既定に。

2) 収益メトリクスと可観測性(増強)

実装

  • 収益メトリクス(EVの分解と集計)を配線:
    • short_ev_bps_total|_count, short_trades_total, short_win_trades_total,
    • スリッページ分離:short_slip_cost_bps_total(max(slip,0)), short_price_improve_bps_total(max(-slip,0))
  • 発注系4カウンタ(ゼロ詰まりの切り分け用):
    • short_orders_sent_total, short_cancels_total, short_reject_total, short_fills_total
  • 数量ゼロ丸め対策qty_from_notional(price, min_notional, min_qty, step) を新設(ceil系+min強制)。
  • Canary Smoke拡張
    • --interval-sec, --duration, --taker-every N, --min-notional-usdt
    • taker ping(IOC or Market)で確実に fill を狙える経路を追加

検証・結果

  • 4カウンタの テスト記録orders_sent_total/cancels_total/fills_total が /metrics に出現(動作OK)。
  • 数量min_notional=50 指定で BTCUSDT qty≈0.001 に量子化、0丸めなしを確認。
  • EVメトリクス:fill 未発生時は ev_bps_count=0(想定どおり)。

3) Canary / Gate / ENV

実装

  • load_settings() 経由で ENV オーバーライドを適用(CANARY_ENABLED=true, CANARY_RATIO, MAX_NOTIONAL など)。
  • Canary gate の“サンプリング5%”に詰まるケースに備え、デバッグ時は CANARY_RATIO=1.0 で通す手順を整理。

検証・結果

  • preflightOK、canary-smoke 実行・ループ稼働(post_only→即cancel と taker ping が選択可)。

4) いまの指標スナップ(代表的なものだけ)

  • 発注系orders_sent_total↑, cancels_total↑, reject_total=0, fills_total=0(=まだ実 fill 未発生)
  • レイテンシshort_req_ack_ms_* / short_cancel_ms_* が蓄積(dryrun/Smokeで確認済)
  • CBshort_circuit_state_agg == 0(平常時)

5) いま残っている詰まり(1点)

  • 実 fill が未発生 → EV系が動かない
    • 有力因:IOCの置き方/待ち方/サイズ あるいは 約定レポート待機(WS/REST)未配線
    • 切り分けに short_ioc_timeout_total{mode,symbol}(未実装なら追加)を推奨
      • 発注は通るのに fill/done が返らない場合に増える

6) 次の一手(10〜20分でEVを動かす)

python -m src.cli canary-smoke --symbol BTCUSDT \
  --duration 120 --interval-sec 10 \
  --taker-every 1 --min-notional-usdt 50 --force-market
  1. 上記ワンライナーででMarket ping で先に1件 fill を作る
    /metrics: short_fills_total>0, short_ev_bps_count>0 を先に確認
  2. IOC に戻して継続
    • 価格:SELLは best_bid - 1tickfloor_to_tick
    • キャンセル/置換禁止(IOCは1発完結)
    • 2.0s待機await_fill_or_done()(WS or 200ms×10 REST)
  3. 10分Smoke(コスト最適化)
    • --taker-every 6(1分に1回 taker)へ戻す
    • Go判定:EV_bps_avg > +3 & win% > 55% & reject < 1% & CB==0

以降、比率は 0.02 に戻して 24h Testnet Canary へ。


7) 追加で入れておくと楽な計測

  • short_ioc_timeout_total{mode,symbol}(Counter):IOC待機のタイムアウト可視化
  • 発注ログ(taker経路のみ):price / qty / orderId / tif / elapsed_ms を1行

8) DoD(このフェーズ)

  • /metrics 非空(bucket/sum/count 蓄積)
  • short_fills_total>0short_ev_bps_count>0(EVが動き出す)
  • 10分スモークで Go判定クリア
  • 24h Testnet Canary へ移行

ショート系bot:達成度

約 50%(±10%)

内訳(目安)

  • 計測・信頼性基盤90%
    multiprocess集約の復旧、CB永続化+_agg、ジャニター、収益メトリクス配線、4カウンタ追加、数量ゼロ丸め根絶まで完了。
  • 執行性能(短時間)65%
    req→ack/cancel のヒストグラム取得は安定。24h連続SLOは未評価。
  • 実約定&EV計測20%
    送信/取消/拒否は記録OKだが、実fillが未発生=EV_bps系が未通電
  • 24h Testnet Canary10%
    直前まで準備完了。スモークでEV>0確認→24hが未実施。
  • 収益実績0%
    実PnL/EVの連続実績はまだ無し。

いま足りないもの(上げ止まり要因)

  1. 実fillの安定発生(IOCの価格・待機・サイズ or Market ping)
  2. EVページの通電ev_bps_total/count が実トレードで伸び始めること)
  3. 24h連続SLOの実測req→ack p99<250ms / cancel p99<300ms / reject<1% / CB=0

60%へ上げる最短手順(今日〜明日)

  • Market ping(確実に1件fill)short_fills_total>0 & ev_bps_count>0 をまず作る
  • IOC経路で継続:SELLは best_bid-1tickキャンセル/置換禁止2.0s待機
  • 10分スモーク(taker-every=1→6)
    Go: EV_bps_avg>+3 & win%>55 & reject<1% & CB=0
  • 24h Testnet Canary:比率0.02で連続SLOとEVを検証

ここまで通せば 達成度は60〜65%、EV>0の連続実績が乗り始めた段階で70%台に入ります。

ショート系bot:本日の筋悪ポイント

きょうの動きを“稼ぐ最短経路”基準で振り返ると、筋が悪かった(回り道になった)点は主に5つです。明日の改善アクションもペアで置きます。


1) 「fillが出るか」を最初に確定しなかった

  • 筋が悪い理由: EV系は約定が起きない限り永遠に0。にもかかわらず、IOCの置き方/待機/サイズの検証より前に周辺を整え続けた。
  • 明日の改善: 最初の1件をMarketで必ず約定させてEV配線を確定→その後にIOCへ戻す。
    • 実行例:
python -m src.cli canary-smoke --symbol BTCUSDT \
  --duration 120 --interval-sec 10 --taker-every 1 \
  --min-notional-usdt 50 --force-market
  • DoD: /metricsshort_fills_total>0short_ev_bps_count>0 が増える。

2) IOCで“置く/待つ/サイズ”の3点セットが未完了

  • 筋が悪い理由: SELL IOC は best_bid−1tick で置く・置換/キャンセル禁止2.0s待機 が三種の神器。どれか欠けると fill しない/検知できない。
  • 明日の改善: 下3点を一気に固定
    1. 価格: ioc_price = floor_to_tick(best_bid - tick, tick)
    2. 置換/キャンセル: IOC経路では一切呼ばない
    3. 待機: await_fill_or_done(timeout=2.0s)(WSなければREST 200ms×10)
    • DoD: Marketを外しても short_fills_total が増える/ioc_timeout_total==0 付近に収束。

3) サイズ検証を早めに固定しなかった

  • 筋が悪い理由: min_notional/step/min_qty を満たさず qty=0 へ丸め→「送ってるのに刺さらない」と誤解。
  • 明日の改善: qty_from_notional() を IOC/Market 両方で使用し、最初は --min-notional-usdt 50 に固定(BTCUSDT, step=0.001想定で qty≒0.001)。
    • DoD: ログに spec: tick, step, min_qtyCalculated qty: ... を1行出し、qtyが0/未満にならない。

4) “返事が来ていない”を測る指標がなかった

  • 筋が悪い理由: orders_sent↑ & fills==0 でも、rejectなのか、report未到達なのかが判別不能で時間が溶ける。
  • 明日の改善: short_ioc_timeout_total{mode,symbol}(Counter)を追加し、待機満了時に必ずinc。
    • DoD:
      • rejectなら short_reject_total
      • 未到達なら short_ioc_timeout_total
        → 根因が1分で判別できる。

5) 安全運用の切り替えを明示せずに回した

  • 筋が悪い理由: デバッグで CANARY_RATIO=1.0 を使ったまま遷移しがち。事故時に露出が大きい。
  • 明日の改善: デバッグ→運用を明示切替。
    1. デバッグ(最初のfill確認): CANARY_RATIO=1.0, --force-market
    2. 検証(IOCチューニング): CANARY_RATIO=1.0, --taker-every 1
    3. 運用開始(コスト最適): CANARY_RATIO=0.02, --taker-every 6
    • DoD: 切り替え直後の /metrics 4行(orders/fills/reject/EV)を残す。

明日の実行チェックリスト(30–60分でOK)

  1. Market ping(fill発生の確定)
    • 期待: short_fills_total>0, short_ev_bps_count>0
  2. IOC固定(best_bid−1tick/置換キャンセル無し/2.0s待機)
    • 期待: Market外しても fills_total が増え続ける
  3. サイズ--min-notional-usdt 50qty_from_notional()
    • 期待: qtyログが常に >= min_qty
  4. 時系列4行を保存
curl -s :9523/metrics | grep -E 'short_(orders_sent|fills|reject|cancels|ioc_timeout)_total'
curl -s :9523/metrics | grep -E 'short_(req_ack|cancel)_ms_(bucket|sum|count)' | head
curl -s :9523/metrics | grep -E 'short_(ev_bps_total|ev_bps_count|trades_total|win_trades_total)'
curl -s :9523/metrics | grep -E 'short_circuit_state_agg{category="network"}'

“やめること”メモ(最短経路を守るために)

  • REPLAY/インフラの磨き直し先行(fill未確定のまま)
  • IOCでキャンセル/置換を混ぜる(fill直前キャンセルの温床)
  • 小さすぎる notion(qtyが0に丸められる)
  • 板staleness無視(1s超は再取得)

この4点(Marketで1件→IOCで継続→サイズ固定→タイムアウト可視化)を先に通せば、EVメトリクスが動き始め、明日中に「+3bp超/10分スモーク」まで持っていけます

-Bot, 開発ログ