最終更新: 2026-09-17 / 全て ¥100 ペーパー・実配当(パリミュチュエル)決済。 戦略の正典説明は Controller の「システム構成・戦略一覧」(SystemInfoWindow)。本書はそれ+バックテスト結果を1枚に残す記録。
数字の種別に注意 - フォワード = 実運用の日々の結果(スコアカード)。締切前オッズで実選択・実配当。最も正直。 - 紙backtest(締切前) =
backtest_paper_tan.py。締切前スナップで選択→確定配当で決済。フォワード相当の信頼度。 - 確定オッズbacktest =backtest_rules_tiers.py等。選択に最終オッズを使う=先読みで単勝ROIを約+35pt盛る。参考値。 - walk-forward(連系/複勝/単勝 段別) = leak無しだが連系ROIは配当分散で暴れる → 判定は低分散の複勝/単勝で。⚠ 2026-08-27以前の紙backtestは「まだ届いていないオッズ」を使っている(下記 0.3)。 オッズを使う戦略の数字は過大なので、そのつもりで読むこと。
スコアカードには性質の違う2種類の成績が入っている。同じ名前だったので分けた。
| 現在の表示名 | 中身 | 出所 |
|---|---|---|
AI単勝(全) |
発注された実績 | bets の AI_TAN_v2(20260704–20260712) |
AI単勝(全)(再構成) |
参考値 | 現在の predictions から組み直し(20260502–) |
AI複勝(旧) |
発注された実績 | bets の AI_FUKU_v1(20260704–20260712) |
AI複勝(旧)(再構成) |
参考値 | 同上 |
Chalk-単勝 / Chalk-馬連 / Chalk-3連複 |
発注された実績 | paper_bets(chalk_bets.py が書く。20260705–) |
Chalk-…(再構成) |
参考値 | 同上 |
AI単勝(1位軸)(再構成) ほか |
参考値 | 凍結側に対応が無い(再構成のみ) |
⚠ 2026-09-03以前の記録では接尾辞が付いていない。
過去のジャーナル・Discord投稿の Chalk-単勝 などが、どちらの集計を引用したものかは
投稿ごとに確認しないと決められない(チャート・月別は再構成、セグメント表は凍結を
出していたため)。自動的にどちらかへ読み替えないこと。確認できないものは
「旧表示・由来未確定」として扱う。
db.sp.netkeiba.com/race/{id}/(既存種別 running_data)の
タイム指数・タイム指数M・スタート指数・追走指数・上がり指数。
9/16の調査で「追加候補の上位」と書いていたもの。individual_lap から取得済みの4指数
(idx_total/idx_start/idx_chase/idx_last)と、4本が完全に同じ値だった。| db版 | 対応する既存 | 値の完全一致 | 全一致レース※ | ピアソン r |
|---|---|---|---|---|
| タイム指数M | idx_total | 14773/14773 = 100.0%(最大差0) | 1072/1072※ | 1.000 |
| スタート指数 | idx_start | 14856/14856 = 100.0%(最大差0) | 1072/1072 | 1.000 |
| 追走指数 | idx_chase | 14856/14856 = 100.0%(最大差0) | 1072/1072 | 1.000 |
| 上がり指数 | idx_last | 14830/14830 = 100.0%(最大差0) | 1072/1072 | 1.000 |
| タイム指数(通常) | idx_total | 11088/14773 = 75.1%(最大差19) | 251/1072 | 0.991 |
※「全一致レース」は欠損馬を除いた比較(タイム指数Mは14,961頭のうち14,773頭が比較対象)。
標本 32開催日 1,072レース 14,961頭(2025年 15日 485R / 2026年 17日 587R。月ごとに競馬場の種類が最も多い日を選んだ)。事前に宣言していた却下条件は
「どれか1組でも |r| ≥ 0.80 なら同系統と判断して却下」(docs/design_db_result_kind.md)。
- 充足率は 2025-2026では条件(90%以上)を満たした。ただし段1の条件は「2024年以降」で、
2024年は突合相手の行が無いため測っていない(Codex 2巡目の指摘で訂正)。相関で落ちたので打ち切った
(段3の月次walk-forwardも、段4の全量取得=約9,000ページ・約16時間も実行していない)。
- 9/16の記述を訂正した(docs/netkeiba_master_data_survey_20260916.md §2・§5)。
当時「別系統だろう」と推測したのは、旧HTTP期のキャッシュが未ログインで取られていて
指数欄が会員ゲートで空(タイム指数7.3%・他0%)だったため、値を突き合わせていなかったから。
- 残る未検証: 「タイム指数(通常)」だけは 24.9% で値が違う(最大差 19)。
r=0.991 で宣言どおり却下したが、差分に予測価値が無いことまでは示していない(Codex指摘)。
差分を試すには馬ごとの過去走が必要=全量取得が前提なので、やるなら先に判定条件を書き直す。
- モデル・戦略の変更はなし(成績の数字は 0.8 と同じ)。
dataset.csv の2025年 32.3%・2026年 15.8%)
+偏差3本の基準が「対象レースに出てくる馬だけの平均」になっていたbase vs base+LOSS4 も複勝回収1勝6敗【2026-09-18 撤回】この節の「複勝目的は採用水準(7/7)」と「複勝回収 59.6-60.2%」は 誤り。§0.10 を見ること。
PHASES_DONE rc=0 → 00:21 mop-up 完了で status<>'ok'=通信・描画の失敗が0件)。
「取得失敗0件」ではない: partial 3件(ポジション or 走行距離表が出ないレース)・
中止レース由来 41件・旧HTTP期の unverified 953件が台帳には残る(後2者は現在の取得対象外。
ジャーナル152に内訳)。
年別 ok は 2026=2,288 / 2025=3,334 / 2024=3,327 / 2023(重賞のみ)=129。
走行距離とハロンごとポジションは2025年以降、受入品質(ok)の行では全ページ充足
(例外は partial の3件: 20250202-08-11=ポジションなし/20260712-03-11・
20260808-01-11=走行距離表なし)。2024年以前は走行距離が原則未提供・
ポジションも大半が未提供だが、2024年は一部提供あり(472/3,327。設計 §3.5)。c50b97e):ok_lap_only: ポジション/走行距離だけ欠けるページも上限まで取り直したうえで保存(ラップ・4指数・AI短評を捨てない)failures と NON_OK 行(error_type/final_url/attempt。final_url は
netkeiba 配下のみ・query 除去でトークンを出さない)plan() が
3.72s→0.11s(約34倍)。本番は同期間の前後比較ができないため参考値として、
旧コードの2026年8か月ぶんは backfill完了→verify完了で7分55秒・新コードの2025年12か月ぶんは55秒design_netkeiba_master_chrome.md §11 に確定・Codex 13巡で指摘ゼロ)。
現状は前夜準備のマスター取得が Chrome 経路では毎回スキップされており、定常運用が無い。モデル・戦略の変更はなし(成績の数字は 0.5 以前と同じ)。本日は入力データの拡張だけを行った。
取れるようになったもの(netkeiba マスターコースの「個別ラップAI」ページ。1ページに3表が入っている)
| 項目 | 範囲(実測) | 使いどころ |
|---|---|---|
| 馬ごとのハロンごとラップ | 2024年以降の平地(平場含む)100% | 道中の緩急・区間脚力 |
| 指数4種(全体/スタート/追走/上がり)・AI短評 | 同上 | 既存指数の補強 |
| ハロンごとのポジション(内③・中⑤ 等) | 2025年以降の平地(平場含む)、受入品質 ok のページで100%(例外1レース: 0.7 参照) |
コース取り・距離ロスの実測 |
| 走行距離(例 1,203.3m)・距離補正走破タイム | 同上(例外2レース: 0.7 参照) | 「外を回らされた分」を補正した能力比較 |
| 走行解析(完歩ピッチ・ストライド長) | 重賞のみ(2024年以降) | 走法の把握 |
この日に直した「データの取り違え」2件(詳細は ジャーナル 2026-09-16)
race_id で入り、
netkeiba 側のURL=キャッシュ鍵が一致して2行が同じファイルを奪い合っていた(36件が取り直し無限ループ)。
→ URLの一意性を計画と保存の両方で確認し、未施行側を外した。
教訓: JV の race_id の日付は「元の開催日」で、実際に走った日とは違うことがある。日付で突き合わせる処理は要注意。8/30の終業点検で発覚。本番の締切前レーンが2開催日ぶん動いていない。
| 開催日 | 締切前レーンの計上レース数 |
|---|---|
| 2026-08-23 | 31R |
| 2026-08-29 | 0R |
| 2026-08-30 | 1R(中京9R・live_loop側の安全網がたまたま10秒窓に入っただけ) |
gate_daemon.try_ens_chain() の中で親の ensemble_bet.capture(mode="close") を呼ぶ設計。
8/28に子の凍結実験 ens_disagree を終了(fae602a)したため、_skip_if_terminated() が
ens_done = True を返し(gate_daemon.py:530)、try_ens_chain() 自体が呼ばれなくなった。
加えて _ens_terminated() が真だと warm_ok = False になるので二重に塞がっている。AI単勝/馬連/3連複 × アンサンブル/GBM単独 の(締切前)7戦略が実質欠測。
§0 で「連系は締切前が明確に優位」としていた結論の追試が取れていない。8/28に freeze_terminate で打ち切った6本を、スコアカード上で終了として明示するようにした。
| 戦略 | 到達 | 点数 | 投資 | 的中 |
|---|---|---|---|---|
| AI3連複_アンサンブル不一致 | 6R | 6点 | ¥600 | 0(的中率0% / 回収率0%) |
| 堅3連単2頭軸GV2 | 14R | 252点 | — | 2 |
| 堅3連単2頭軸DV2 | 6R | 108点 | — | 0 |
| 堅3連単2頭軸O15V2 | 4R | 72点 | — | 1 |
| 堅3連単2頭軸S45V2 | 8R | 144点 | — | 2 |
| 堅3連単2頭軸C75V2 | 6R | 108点 | — | 1 |
| V2合計 | 物理16R / 38 strategy×race | 684点 | ¥68,400 | — |
kind="off"(月別・通算・ROI推移・ヒートマップ・セグメント・健康診断から除外)。
ただし _paper_ok() からは外さないので過去成績は残る。表示だけ ended で「終了(判定なし)」に分けたtools/publish_scorecard.sh が生成に成功したときだけアップし、失敗時は Discord に通知する
(同じ失敗は日付+理由ハッシュで1通・送信成功時だけ抑止キーを記録)。詳細はジャーナル(95)JRAは M:00 と刻んだ値をその1分をかけて配っている。
「新しい発表時刻を初めて観測した秒」の分布は :00-:09 = 0%(134件中0件) /
:30-:34 = 74% / :55-:59 = 98%。つまり :00 に配信しているのではなく :00 と刻んでいるだけ。
source_timestamp だけで絞ると、判断時点にはまだDBに無い行を掴む。
実測で144レース中130R(90%)が該当し、到着は中央57秒後。
本番デーモンは判断時点にDBを読むので、その行を持っていない。
→ chalk_gate.available() で source_timestamp と captured_at の両方が
判断時点以前であることを要求するようにした(コミット fae602a)。
全期間922Rのうち 760R(82%)で断面が変わり、85R(9%)で上位3頭の並びが変わる。
| 戦略 | 修正前 的中率/回収率 | 修正後 的中率/回収率 | 差 |
|---|---|---|---|
| AI単勝(無/NOODDS) | 5.7% / 70% | 5.6% / 72% | +2 |
| AI複勝(無/NOODDS) | 14.3% / 55% | 14.3% / 55% | 0 |
| AI単勝(無)BLEND | 7.2% / 82% | 7.1% / 80% | −2 |
| AI単勝(有/WITHODDS) | 8.5% / 91% | 7.7% / 83% | −8 |
| AI単勝(有)BLEND | 10.7% / 112% | 9.2% / 95% | −17 |
オッズを使う戦略だけが大きく下がった。 AI単勝(有)BLEND の「112%」は幻で、
実際に発注できる情報だけなら95%。オッズを使わない戦略はほぼ不変(±2pt)で整合的。
inflow_bet / drop_signal … 最近傍探索が abs() で判断時点の後ろも選んでいた
(実測45%のレース・中央16秒の先読み)chalk_policy_sim / build_scorecard … 「全体最新フォールバック」が残っていたpredict_win5 … 締切を各レースの発走時刻にしていた(WIN5は第1レース発走前に買うので
最大2時間の先読み)→ 第1レース発走に統一immutable=1 の全廃本番と同じ 9p 上の実測で immutable=1 は書込中に31%が偽の malformed、
mode=ro は0失敗。さらに immutable=1 はWALを一切見ないので、
未checkpointの行を取りこぼす(書き手をSIGKILLした状態ではテーブルの存在すら見えない)。
54箇所を mode=ro に統一し、接続を tools/db_open.py に一本化した。
horses.scratched は返還の正本ではない。IJyoCD != 0 を一律 scratched=1 にしており
競走中止・失格(出走した馬)まで混ざるうえ、SE取込のUPSERTで上書きされて消える(実測7頭)。
正本はJRA公式の HenkanUma。ijou_cd 別の返還率は
取消64% / 発走除外100% / 競走中止0% で規則が完全に説明できた。
過去の未計上分は全体で +0.19pt(スコアカード母集団 71.022% → 71.216%)。
過去は据え置き、これから先だけ正本化する(設計 docs/design_refund_void_bets.md)。
新戦略18本(新馬4/急落中11/投票量3)が初稼働。朝はdataset再構築54分+P3初日の再学習が直列に並ぶ
設計欠陥で第1Rに間に合わず、WSLのDB読取も半日不安定だった(当時はopen_roにimmutable=1を追加して凌いだ。
2026-08-27にそのimmutable=1は撤去した — ロック枯渇は救えるが、書込中に31〜36%の確率で偽の
malformedを返し、WALも見ないため数分古い断面になる。現在はリトライで待つだけ
(バックオフ63秒+接続待ち。busy競合時の概算上限は約303秒。9pのI/O自体には上限が無い))。
収集とデータは無傷。初日成績はジャーナル(15)参照 — 新馬は予測どおり86%、急落中は初日9%と苦戦、
投票量は発火0。連系の的中率はレース分母に統一。今夜からdataset+学習を前日20時に移設。
7/14以降の変化が大きいため、ここに現在地を集約する。詳細は各日のジャーナル。
| 系 | 特徴数 | 中身 |
|---|---|---|
walk_forward(live_v1) |
60 | リーク10列除去後の土台(7/26-27) |
| NOODDS系 | 88 | FEATURES−オッズ3 |
| WITHODDS/ensemble/WIN5 | 90 | 84 + P3(血統3+調教3) 2026-07-30 |
| 新馬用(maiden_top3 ×2) | 66/63 | base+P3・3着内目標・オッズ有/無 |
P3 = ped_sire_surf/ped_sire_top3/ped_bms_top3(父・母父の産駒成績をas-of自前算出) +
v3_best1f_z/v3_margin/v3_hard(netkeiba調教)。選定4期間とホールドアウト3期間の両方で
連系が改善した唯一の組(AUC 7/7・馬連回収6/7 平均+4.27pt。単勝は2/7=2〜4番手の識別に効く)。
血統は dataspec DIFN で初取得(従来DIFFと誤り3年間空だった)。直近JRA充足95.9%。
immutable=1がWALを
見なかったための回避策で、mode=roではWALを直接読める(可視オッズ最大3分古も解消)。
なお捕捉中の断面固定(read_txn)は見送った — capture()がDiscord送信(同期・最大50秒)
を含むため、read transactionで包むとWALリーダーを長時間保持してしまう。既知の課題として持ち越し。--day モード(前日20時 preday_prep)。| 区分 | 本数 | 備考 |
|---|---|---|
| 実bet表(実弾なし・全ペーパー方針) | 8 | 従来どおり |
| 新馬未勝利3連複(8/1〜) | 4 | 主張1+対照3(人気/オッズ無/1勝以上)。回収100%は超えない見込みと明記の検証 |
| 急落・中帯 静音監視(8/1〜) | 11 | 6→7月両月100%超の帯(10-20倍)。帰無p≈0.052につき私は反対、ユーザ裁定で採用 |
| 投票量(8/1〜) | 3 | 流入中7単/15単(帯内P75)・急落大口単。閾値凍結57,967/158,347/98,587票 |
| 継続ペーパー | 29 | Chalk/混戦/base帯/頭数仮説/複勝確率順/急落旧/アンサンブル他 |
| 休止 | 11 | スコアカード「休止・不採用」欄に理由つき |
| モデル | 特徴 | 用途 |
|---|---|---|
live_model |
walk_forward 70特徴 | predictions表+bet-rules(AI単勝(全)/本命/特別・AI複勝(旧))の予想=live_v1 |
noodds_model |
能力のみ 94特徴(2026-07-14〜) | NOODDS系 |
withodds_model |
能力+オッズ 94特徴 | WITHODDS系 |
combo_live |
WIN5用 94特徴(毎朝自動再学習) | WIN5 |
ab88 / ab70 |
特徴A/B用(当日より前で学習=リーク防止) | 追い切り・タイム差の効果検証 |
特徴段(model_noodds系の世代): - 70 = 土台(walk_forward=live_v1と同一)。〜2026-06-28。 - 88 = +追い切り(14) +着差タイム差(4)。2026-06-29〜。 - 94 = +コーナー通過順(6)。2026-07-14〜(本番採用)。 - 99 = +上がり3F順位(5)。実験・非採用。
| # | 戦略 (code) | ロジック | 状態 |
|---|---|---|---|
| ① | AI単勝(全) AI_TAN_v2 |
live_model。全レース。pwin≥0.15 & EV≥1.05 のEV上位2頭 +『10倍超×pwin≥0.12』の穴1枠。人気無制限=だから「全」 | 🚫休止(7/13) |
| ② | AI単勝(本命) AI_TAN_SMART |
①と同ロジック、特別・重賞かつ9頭以上に絞る | 🚫休止(7/13) |
| ②' | AI単勝(特別) AI_TAN_SPECIAL |
①ロジックを『特別/L のみ』に絞る。大標本で rank1×特別=回収104%と最良 | ★稼働(後継) |
| ③ | AI単勝(新/オッズ無) AI_TAN_NOODDS |
noodds_model。pwin≥0.08 & EV≥1.05 のEV上位3頭。単勝上限25倍 | 稼働 |
| ④ | AI単勝(新/オッズ有) AI_TAN_WITHODDS |
withodds_model で③と同条件 | 稼働 |
| ⑤⑥ | 〃 _BLEND |
③④を市場確率と60%ブレンド(モデル6:市場4) | 稼働 |
| — | AI単勝(1位軸) | rank_win 1位に単勝(再構成/スコアカード用) | 再構成 |
| # | 戦略 (code) | ロジック | 状態 |
|---|---|---|---|
| ⑦ | AI複勝(旧) AI_FUKU_v1 |
bet-rules の recommended_place で複勝 | 🚫休止(7/13) |
| ⑧ | AI複勝(新/オッズ無) AI_FUKU_NOODDS |
ptop3≥0.40 & 複勝EV≥1.05 の上位3頭 | 🚫休止(7/13) |
| ⑨ | AI複勝(新/オッズ有) AI_FUKU_WITHODDS |
withodds_model で⑧と同条件 | 🚫休止(7/13) |
chalk_bets.py)。| 戦略 | 条件 | 券種/枠 |
|---|---|---|
| ① 急落(直前)T60 | 発走10分前→5分前 10%↓(絶対1.5)・10〜100倍・人気上昇は不問・R最大下落1頭(2026-07-26 設定変更) | 単勝[bets] |
| ② 急落7穴 | 7→5分前 15%↓・20〜100倍・R最大下落1頭 | 単勝[paper/穴] |
| ③ 急落7広 | 7→5分前 15%↓・10〜100倍・全馬 | 単勝[paper/穴] |
| ③b 急落7穴複 | ②と同条件の複勝版(的中22.5%/回収172%・除最大益134%・train173≒test170) | 複勝[paper/穴] |
| ③c 急落7広複 | ③と同条件の複勝版(的中25.5%/回収158%・除最大益130%) | 複勝[paper/穴] |
| ④ 急落本命 | 10→5分前 5%↓・5〜7倍・全馬 | 単勝[paper/本命] |
| ⑤ 急落人気↑単 | 7→5分前 3%↓・5〜15倍・人気上昇必須(頑健:的中25%/回収189%,train220/test162) | 単勝[paper] |
| ⑥ 急落人気↑複 | 7→5分前 3%↓・10〜20倍・人気上昇必須(安定:好走50%/回収158%,train168/test142) | 複勝[paper] |
2026-07-13: 旧急落30(過剰最適化)退役。train/test で生存した設定のみ採用。
2026-07-25: ②③の複勝版(③b③c)を追加。しきい値は15%が最良で緩めない(backtest_drop_ana.py 563R: 穴単勝 5%169%→10%177%→12%235%→15%359% と単調)。5〜12%の複勝は除最大益86〜95%で元返し割れ=不採用。
ab_features.py)。ensemble_bet.py)。過去走のコーナー通過順 jyuni_1c〜4c(DB保存済みだが未使用だった)を頭数正規化して集約(corner_features.py)。
Chalk方針 walk-forward 1701R: 回収 140%→144%(+5pt)、単勝/馬連/3連複 全券種で悪化ゼロ → 94を本番採用。
| 段 | 単勝 | 馬連 | 3連複 | 合計 |
|---|---|---|---|---|
| 70 | 109% | 155% | 162% | 156% |
| 88 | 112% | 136% | 144% | 140% |
| 94 | 114% | 143% | 148% | 144% |
| 99 | 110% | 134% | 181% | 161% |
| ↑注 | 的中率6.0〜6.1%で不変=高ROIは配当運 |
複勝(上位K頭に複勝、的中率=順位精度そのもの): | 段 | 上位1的中 | 上位1/2/3 ROI | |---|---|---| | 70 | 60.8% | 94/92/92% | | 88 | 59.9% | 91/92/95% | | 94 | 60.8% | 92/94/96% | | 99 | 61.0% | 94/95/94% |
単勝(全レース上位K頭): | 段 | 上位1的中 | 上位1/2/3 ROI | |---|---|---| | 70 | 31.1% | 96/90/89% | | 88 | 30.5% | 92/87/88% | | 94 | 30.2% | 93/90/90% | | 99 | 30.9% | 97/90/90% |
結論: 低分散指標では全段の差は1pt未満=ノイズ。70/99の連系高ROIは配当分散のアーティファクト。 → 94を本番採用・99(上がり順位)は非採用(実験棚上げ)。 フォワードは94。
| 戦略 | 94 | 99 |
|---|---|---|
| 単勝(全) EV | 106.3% | 106.6% |
| 単勝(本命) SMART | 108.9% | 93.2% |
| 単勝(特別) rank1×特別L | 48.0%⚠️ | 50.0%⚠️ |
| 複勝(EV) | 94.5% | 94.6% |
⚠️特別48%は再現の不備(小標本+定義ズレ)。既知の大標本104%と乖離。
| 戦略 | 94 | 99 | 確定オッズ比 |
|---|---|---|---|
| 単勝(全) | 71.3% | 71.6% | 106% → 盛りが約35pt |
| 単勝(本命) | 73.8% | 70.6% | 109% → 同上 |
| 単勝(特別) rank1×特別L | 76.3% | 100.3% | (115点小標本) |
結論: - 単勝(全)・(本命)は94でも復活しない(締切前で71〜74%=控除割れ)。休止継続で正当。フォワード「負け越し」と一致。 - 複勝(無/旧/有)も 94/99で<100%(94.5%)=控除超えられず。据え置き。 - 単勝(特別) はこの窓では76〜100%(小標本)。稼働継続は妥当だが黒字は断言できない。
再構成ライン(live_v1=70特徴)の月別回収率(抜粋): | 戦略 | 6月 | 7月 | |---|---|---| | AI単勝(全) | 63% | 92% | | AI複勝(旧) | 76% | 81% | | AI3連複(1-2-3位) | 103% | 90% | | AI馬連(1-2位) | 94% | 51% | | Chalk-3連複 | 92% | 122% |
連系は当たった日だけ跳ねるので月次でも振れる。単勝/複勝の方が安定指標。
backtest_paper_tan.py)が正。スナップは締切約2分前(near-post)で妥当。horses.tan_odds10=×10(÷10で実オッズ) / odds_snapshots.tan_odds=実オッズ(÷10不要)。本番は正しく守っている。bets/paper_bets の実払戻を使う検証を第一級とし(検証と実運用が同じ土俵で乖離が原理的に起きない)、
モデル再スコア型は参考値に格下げする。単独で実弾の設定を変える根拠にせず、必ずペーパー並走を挟む。(2026-07-26追加) 送信済みの買い目は必ず凍結する。 発走時刻はJRAの遅延で動き(476件中3件)、 判断窓(post-5分)がずれると別のオッズを掴んで送信済みシグナルと決済が食い違う。凍結条件は 「送信済み or 判断時点経過」の2本立て(締切が発走に連動して動くので時刻条件だけでは外れる)。
(2026-09-20追加) 賭ける母集団と、検証した母集団が違っていた。 障害戦(track_cd51以上 /
syubetu_cd 18・19)に 71戦略・1,029点・投¥120,600 が出ていた。的中率 5.73% で
平地 10.15% のほぼ半分。原因は maiden_sanpuku.py:61 が jyoken_cd の末尾3桁しか見ず、
障害の未勝利戦を拾っていたこと。ただし本質は「障害を除外する場所がどこにも無かった」
(主要5戦略に track_cd/syubetu_cd/「障害」の言及が0箇所)。
一方で判定の定義は3箇所に重複していた(build_scorecard.py:1090/:1238、analyze_waku.py:23)。
→ ジャンル判定の正本を tools/race_genre.py に一本化し、障害は買わず記録だけにする。
「成績が悪いから外す」ではなく「判断材料が無いから買わない」(21Rの小標本で優劣は言えない)。
(2026-09-20追加) 学習の母集団も宣言されていない。 dataset.csv(280,538行)の実測で
地方 37.28%(104,575行)・障害 1.77%(4,979行)。walk_forward.load() に絞りが無い。
course_code/track_cd は特徴に入っているので区別できるが、区別させてはいない。
さらに 較正が時系列を無視している(CalibratedClassifierCV(cv=5) はランダム層化分割で、
「過去で学習→未来を予測」の運用に対し未来を含む fold で較正する)。
充足率50%未満の特徴が6本(追い切り系5本が19.1%)あり、feature-fill-rate-rule に違反した
ままである。→ 一度に1つだけ変える実験を事前宣言つきで行う。
(2026-09-20追加) 同じ既定値が5箇所に重複していると、1箇所直しても効かない。
スコアカード生成の BUILD_TIMEOUT は publish_scorecard / publish_if_changed /
publish_loop / live_loop / settle_and_post の5箇所に 300 が書かれ、
呼び出し側が明示的に渡すので下流の修正が上書きされていた。実測で生成は 371秒必要で、
300では原理的に通らないのに終日 rc=124 を出し続けた(74回)。
(2026-09-20追加) 累積ログを日付で切らずに数えない。 live_loop.out は44万行の累積で、
全体を数えて「今日4,343行の失敗」と誤報告した。日付で切ると今日は Traceback 1件。
過去の disk I/O error 3,414件は 8/29〜9/13 に集中し、snapshot_conn 導入で既に解消していた。
合計を出すときは、表示の打ち切り(上位N件)とも分けて集計する
(設計v1で「上位12戦略の合計」を全体の合計として書いた。2026-09-18 にも同じ誤りをしている)。
(2026-09-20追加) 「rc=0 で返る空振り」は監視をすり抜ける。 終業ラッパーは
runtime_native.py day_review --date <日付> と呼ぶが、day_review.py:main は
sys.argv[1] を日付として読む位置引数。日付が文字列 "--date" になり
race_id LIKE '--date-%' で0件 → 「確定レースなし」を印字してrc=0 で正常終了する。
そのため [ "$DAY_REVIEW_RC" = 0 ] || exit の門番も通り、
9/19・9/20の2日ぶん安全網が最初から死んでいた。
→ フォールバック経路は「動いた」ではなく「何件処理したか」で検査する。
0件を正常終了にしてよいのは、0件が正常だと分かっているときだけ。
(2026-09-20追加) 警報自身が禁止された経路でDBを読むと、健全な日に誤警報を出す。
prep_alarm.sh:8-13 は WSL から本番DBを直接開く
(sqlite3.connect('file:oddsdrop.db?mode=ro'))。prod_read.py が
「WAL上の本番DBをWSL版SQLiteに開かせない」と明記した経路で、コレクタが書いている時刻には失敗する。
判定が [ "$N" != "ERR" ] && … なので、レース数が読めないだけで警報が出る。
9/20は 08:35 にスタンバイ完了・poll稼働中なのに 09:10 に「準備遅延警報」が出た。
→ 本物の停止警報と誤警報が同じ見た目になると、警報そのものが信用を失う。
(2026-09-20追加) 重複抑止キーに時計を混ぜない。 notify_scorecard_fail.py:42-45 は
抑止キーをビルド出力全文のSHA256から作る。出力には毎回の時刻が入るので
ハッシュが毎回変わり、同じ rc=124 が82通届いた(08:40〜17:14)。
docstringの「同じ日の同じ失敗理由は1通」が成立していない。
→ キーは不変部分(理由の分類・終了コード)だけから作る。
(2026-09-20追加) 「反映される」とコメントに書いてあることを、一度も測っていなかった。
autostart.sh:218 は「毎回YSCHを最新化して中止/順延の改定も反映」と書いていた。
実測すると成り立っていない。build_race_calendar_legacy.py:32-44 は YS を
INSERT OR REPLACE するだけで行の削除も場の除去もしないので、
「中止で場が消える」を原理的に表現できない。
実例: JRAは9/20付で 9/21の中山を中止・9/22に中山で代替開催としたが、
我々の暦は「9/21=中山 阪神 / 9/22=行なし」のままだった。
→ 開催日の正本を JRA公式カレンダー(jra.go.jp/keiba/common/calendar/json/{YYYYMM}.json)
に移し、tools/jra_calendar.py --apply で上書きする。
コメントが主張する不変条件には、それを壊す入力でのテストを1本付ける。
(2026-09-20追加) 「買う対象」を日付だけで選んでいた。 買い目スクリプトは全部
races を race_id LIKE 'DATE-%' で列挙しており、その日の開催場で絞るフィルタが
どこにも無かった(gate_common.JRA_SQL はJRA10場かどうかだけ)。
中止された場のレース行が races に残ると、存在しないレースに買い目が出る。
多くの戦略は「判断時点のオッズが全頭揃わない」(capture_input.complete_odds)で
結果的に止まるが、オッズを要求しない noodds_sanrenpuku.py は止まらない。
→ tools/held_today.py を唯一の物差しにして絞る。
「結果的に止まる」は設計ではない。止める条件を明示的に書く。
(2026-09-20追加) 存在しないものを分母に入れると、健全な工程が止まる。
9/21の前日準備は netkeiba 調教を 12/24 しか取れず rc=5 で
dataset再構築とモデル学習にまるごと進まなかった。
内訳は 阪神 12/12・中山(中止) 0/12 — 中止された場は netkeiba にページが無い。
同時に出ていた「Cookie失効の疑い」は誤検知だった(阪神は全部取れている)。
→ 充足率の分母も held_today で絞る。
分母を疑う前に分子を疑うと、原因を取り違える。
(2026-09-21追加) テストが本番の成果物を書き潰していた。
logs/official_tracks.json(買い目の開催場フィルタが読む添付)が
4日分に縮んでいた。中身は tests/test_jra_calendar.py の見本データと
完全一致。原因は apply_plan() が write_sidecar() を既定パス(本番)の
まま呼び、apply_plan(dry_run=False) を呼ぶテストがそれを実行していたこと。
しかも 20260921 は偶然 阪神/09 で一見正しく見えた。
→ 既定引数が本番を指す関数を、テストから既定のまま呼ばない。
呼べてしまう設計なら、呼べないようにするか、
「呼んでいないこと」を検査するテストを書く(test_テストは本番の添付を書かない)。
(2026-09-21追加) 一括置換は「近さ」で判断してはいけない。
races の日付列挙に開催場フィルタを入れる作業で、
「FROM races の近くの race_id LIKE ?」という近接一致を使ったところ、
gate_common.py:26 の日付変数を r と誤認した(正しくは date)。
適用していればデーモン4本が翌朝 NameError で死んでいた。
他にも tail.lstrip() で空白を削って LIKE ?AND ... を作り(直す前より
悪い)、関数内の sys.path.insert に import をぶら下げて
IndentationError を作った。
→ 構文木で意味を特定する(execute() の引数から日付式を取る)。
→ 本番ツリーではなくコピーに適用して差分を目で見る。
上の3つはすべてこの段階で捕まえた。
(2026-09-21追加) 「賭ける側」と「決済する側」で厳しさを変える。
開催場フィルタを fin/win(結果の集合)にも一律に入れかけたが、
それらの一部は決済の可否に使われている。絞ると、公式データが誤って
いた場合に買った買い目を決済できなくなる。
→ 賭ける側は厳しく(開催していない場には出さない)、
決済する側は緩く(買ったものは必ず決済する)。
絞ったのは「分母と直接比較される数え上げ」だけにした。
| スクリプト | 内容 |
|---|---|
tools/backtest_tiers.py [70 88 94 99] |
段別 連系ROI(Chalk方針) |
tools/backtest_fuku_tiers.py |
段別 複勝(上位1/2/3) |
tools/backtest_tan_tiers.py |
段別 単勝(上位1/2/3) |
tools/backtest_rules_tiers.py 94 99 |
休止戦略を確定オッズで(全/本命/特別/複勝) |
tools/backtest_paper_tan.py --tier 94 |
単勝 紙検証(締切前実オッズ) |
tools/backtest_corner_compare.py |
88 vs 94(コーナー単体効果) |
tools/backtest_l3rank_compare.py |
94 vs 99(上がり順位単体効果) |
tools/corner_features.py / l3rank_features.py |
特徴生成(leak無し・過去走集約) |
段は model_noodds.FEATURES から自動導出(手書き二重管理なし)。全て本番と同じ isotonic(CV5)・leak無し walk-forward。
起動は tools\controller_launch.cmd から行う。 src\...\bin\Release の exe を
直接叩くと、配備した版が使われず ODDSDROP_HOME も設定されない。
配備は collector とは別経路(release_publish.sh は collector 専用):
bash tools/controller_publish.sh --prepare # clean検査→test→publish→隔離smoke→manifest
bash tools/controller_publish.sh --activate <stage> # manifest再検証→backup→原子的切替→smoke
--activate は 閲覧アプリの起動で本番DBが変わったら配備を取り消す。
Controller は 2026-09-06 から読み取り専用(Mode=ReadOnly + query_only=ON)で開き、
EnsureSchema() を呼ばない。意図的に許すときだけ ALLOW_DB_TOUCH=1。