競輪予想に必要なのは、選手の実力・ライン構成・競輪場の特性・直近の調子・
プロ解説者の知見を同時に考慮することです。
しかし人間が毎日数十レースぶんをすべて整合的に見続けるのは不可能に近い。
keirin.life TERMINAL は、この「見るべきものを見続ける」作業を
完全自動化された予想パイプラインに落とし込むプロジェクトです。
スクレイピング・正規化・パターン検出・AI予想・統括判定・結果追跡までを
一気通貫で動かし、どのパターンで何点・何円投じれば長期で回収率100%を超えるのかを、
実データで検証したうえで配信します。
ARCHITECTURE · 全体アーキテクチャ
本システムは大きく 4層 で構成されます。データ取得層、分析・特徴量層、予想ロジック層、そして配信層です。
各層は独立したプロセスで動作し、リモートサーバー上のバッチ群と Docker コンテナ化された Web アプリが疎結合に連携します。
flowchart TB
subgraph L1["① DATA LAYER 取得"]
S1["K-dreams
スケジュール/出走表"]
S2["WINTICKET
レース結果/払戻"]
S3["KEIRIN.JP
選手マスタ"]
end
subgraph L2["② FEATURE LAYER 分析"]
F1["analysis_features
ライン/脚質/得点差"]
F2["rider_recent_stats
直近10走ごと"]
F3["velodrome_chars
43場特性"]
F4["race_comments
前検・レース後"]
end
subgraph L3["③ PREDICTION LAYER 予想"]
P1["パターン検出
13種ルールベース"]
P2["知識カード
プロ解説由来"]
P3["マルチエージェント
予想シミュレーション"]
P4["統括判定官
最終意思決定"]
end
subgraph L4["④ DELIVERY LAYER 配信"]
D1["keirin.life
Webダッシュボード"]
D2["ChatWork
リアルタイム通知"]
D3["成績追跡
週次/月次ROI"]
end
L1 --> L2 --> L3 --> L4
PHASE 1 · DATA ACQUISITION 取得層
3つの独立ソースを毎日クロール
競輪のデータは1ヶ所には存在しません。スケジュール・出走表は K-dreams、
レース結果と配当は WINTICKET、選手マスタは KEIRIN.JP と、
それぞれ別サイトが持つデータを照合する必要があります。
さらに各サイトはレイアウトも ID 体系も別物のため、サイト間で選手・レース・競輪場コードを
突合するための正規化レイヤをすべて内製しています。
負荷配慮: すべてのスクレイピングには time.sleep(1) 以上を挟み、
先方サーバーへ迷惑をかけない運用を徹底。失敗時は即エラーにせず
「結果未公開の可能性」を考慮した 段階的リトライステータス (18/19/28/29/37/38/39) を持ちます。
process_status で進捗を厳密管理
レースごとに race_url.process_status を持ち、
0 → 1 → 2 → 3 → 4 の段階で「どこまで処理が済んでいるか」を
DB側でもつのが核です。これによりどのレースで失敗したか・どこから再開すべきかが
毎日の運用で即座に分かり、二重取得や取りこぼしが起きません。
flowchart LR
U["get_url
(status=0)"] --> R["races_racebase
(→1)"]
R --> D["get_race_desc
(→2)"]
D --> G["get_race_results
(→3)"]
G --> B["bunseki
(→4)"]
U -. "失敗" .-> E1["status=18/19
スキップ/再試行"]
D -. "失敗" .-> E2["status=28/29"]
G -. "失敗" .-> E3["status=37/38/39
結果未公開含む"]
B --> OK["分析特徴量完成"]
PHASE 2 · FEATURE ENGINEERING 特徴量層
選手の「直近10走」を毎日追跡
競輪は選手のコンディションが毎週変わる競技です。先週まで調子が悪かった選手が
今週から連対を続ける、ということが普通に起こります。通算成績だけを見ては負けます。
そのため rider_recent_stats テーブルで選手×日付ごとに直近10走の勝率・連対率・脚質発生回数・
平均着順を継続的に計算。予想時点の「その日時点の直近10走」を常にJOINできる設計です。
43競輪場すべての特性をDB化
バンク長 (333m / 400m / 500m)、カント角、ホーム直線長、決まり手の傾向…
競輪場ごとに勝ちパターンが変わります。例えば小倉や宇都宮のように「3番手突き抜け」が効く場と、
そうでない場を分けて評価する必要があります。
全43場について特性を個別に採取・DB化し、パターン判定に反映しています。
前検・レース後コメントの意味解釈
選手コメントは予想の重要なヒントですが、時期によって意味が変わります。
- 前検コメントは初日のみ「ライン・番手」の情報として有効
- レース後コメントは同開催の前日コメントが最も有効 (調子の推移)
- 古すぎるコメントは逆にノイズになる
ここは素直に実装するとバグの温床で、選手名の表記ゆれ (空白有無、旧字体) を正規化する
REPLACE(name, ' ', '') レベルの細工までコード化しています。
PHASE 3 · PREDICTION 予想層
予想は単一のモデルで行いません。性質の異なる4つのレイヤを直列に走らせ、
それぞれの出力を次レイヤの入力にします。
flowchart TB
I["RACE INPUT
出走表 + 特徴量"]
I --> A1["① パターン検出
ルールベース13種"]
I --> A2["② 知識カード照合
プロ解説命題"]
I --> A3["③ マルチエージェント
複数の視点で予想"]
A1 --> J["④ 統括判定官
全入力を俯瞰して最終判断"]
A2 --> J
A3 --> J
J --> O["OUTPUT
買い目 / 信頼度 / 根拠"]
① パターン検出エンジン
競輪評論家・元選手が口にする「勝ちパターン」を、プログラムとして記述可能な条件式に
落とし込んだのがパターン検出です。
ガールズ除外・逃げ人数・ライン構成・得点差・脚質比率・本命フラグ・競輪場・
選手の通算自力回数といった多次元の条件を AND/OR で組み立て、
さらに S / A / B / C のランクで強度を分類します。
同じ「逃げ一車」でもグレードや本命度によって期待値が大きく異なるため、この階層化は必須です。
パターンは実装するだけでなく、毎日結果が出るたびに ROI を再計算し、
期待値が劣化したパターンは設計から見直す運用です。
② 知識カードシステム
競輪解説者の動画 (YouTube) から、命題単位の知識を抽出してカード化しています。
「2分線は1番人気1点で固い」「逃げ1車で周りがマーク型のときは圧倒的有利」…
こうした暗黙知を構造化するのが狙いです。
flowchart LR
V["YouTube
競輪解説動画"] --> C["字幕取得
yt-dlp / VTT→SRT"]
C --> K["chunk分割
時刻レンジ単位"]
K --> L["LLM抽出
命題→bet_spec化"]
L --> S["スコアリング
信頼度/quote/SQL検証"]
S --> G["採用ゲート
ROI実測・lint・時系列分割"]
G --> R["統括判定官へ注入"]
採用ゲートは極めて厳格です: ROI 全期間115%以上、訓練期115%、検証期110%、
ホールドアウト期100%、ブートストラップ95%CI下限、ラント検証… これら全てを通過したもののみを
「採用」とします。実際、カード候補 50枚中でゲート完全通過は 0枚という水準で
選別しており、安易な「当たった・負けた」論ではない統計的妥当性を要求しています。
③ マルチエージェント予想
競輪予想は「得点派」「ライン派」「直近調子派」「コース適性派」など、
視点によって読みが変わります。1モデルで決めるのではなく、異なる予想者の視点を並行して走らせ、
その食い違い自体を情報として次段に渡します。
各エージェントは過去の自分の予想ログを参照し、以下の反省点が強制的にガードされます。
- 1着実績ゼロの選手を軸にしない
- 先頭3着粘り率の低い選手を単騎抜擢しない
- 単騎選手は原則2着までで買う
- 人気が揺れる局面では BOX 買いを検討する
④ 統括判定官
全エージェント出力・全パターン・適用カードを1人の判定官が俯瞰し、
最終の買い目を組み立てます。ここだけはレスポンス重視で Claude CLI モードと
API モードを切替可能にしており、用途に応じて品質とコストのバランスを取ります。
PHASE 4 · DELIVERY & FEEDBACK 配信と自己改善
日次デーモン常駐
result_daemon.py が24時間常駐し、新しいレース結果が公開されるたびに
取得→正規化→分析→パターン再検出→通知を自動実行します。
人の手を介さず、毎日同じ品質でパイプラインが回ります。
sequenceDiagram
participant D as result_daemon
participant K as 外部サイト
participant DB as MySQL
participant W as Webダッシュボード
participant N as ChatWork
loop 毎日 / 毎レース
D->>K: 新規URL取得 (status=0)
K-->>D: 出走表
D->>DB: analysis_features 更新
D->>D: パターン/カード照合
D->>N: 予想通知 (エージェント予想)
K-->>D: 結果公開
D->>DB: 払戻記録
D->>W: ダッシュボード反映
D->>N: 結果サマリ通知
end
成績追跡と自己改善ループ
予想を出すだけでは意味がありません。毎レース・毎パターン・毎カードごとに
ROI を追跡し、週次/月次集計で期待値劣化を検出。
- パターン別の回収率 → PATTERNS ページ
- 週次成績 → WEEKLY ページ
- 月次成績 → MONTHLY ページ
- 料金設計も回収率実績ベースで決定 → PRICING ページ
つまり「過去の自分の予想」を毎日 1 人の冷徹な評価者として監査し続けるループが
システムに組み込まれています。
ENGINEERING NOTES · 裏側の地道な作業
サイト上には見えませんが、このパイプラインを維持するために日々行っている作業の一部を列挙します:
- 3サイトのレイアウト変更に追従するパーサ継続メンテ
- IPバンされた際の WSL 経由 yt-dlp 字幕取得フローの整備
- 選手名の表記ゆれ (全半角・旧字体) 正規化辞書
- 券種コード (
st_2=2連単, sf_2=2連複 …) の混同バグ対策と回帰テスト
- 月単位の過去データ取得バッチと日付型のハンドリング
- 結果取得失敗を即エラーにしないステータス設計 (結果未公開を待つ)
- 競りレースの自動フィルタ (A1勝率が激減する特殊ケース)
- ミッドナイト開催のライン情報が空になる問題の再取得機能
- 43場ごとの特性 (勝ち脚質傾向) をひとつずつ収集
- ChatWork ルーム分離 (システム通知 と エージェント予想 で投稿先を分ける)
- 採用ゲート不通過カードを「実用採用」閾値で救う二段構え設計
どれも一晩で書けるコードではありますが、実運用で連続発見・修正してきた結果の積み重ねです。
「競輪予想を当てる」ではなく「予想パイプラインを壊さない」ことにこそ、もっとも時間がかかります。
THE STACK · 使用技術
BATCH Python 3.12 / MySQL (mysql-connector-python) / BeautifulSoup4 / requests
WEB FastAPI / Jinja2 / Docker / Chart.js
AI Anthropic Claude (API + CLI マルチモード)
INFRA AWS EC2 (Ubuntu) / AWS Lightsail / WSL2 (ローカル開発)
NOTIFY ChatWork API
CLOSING · 終わりに
競輪は情報量の多いギャンブルです。しかし情報は集めただけでは意味がなく、
そこから検証可能で再現可能な判断ロジックへ昇華させる工程が本質だと考えています。
本サイトは、その工程を誰でも検証できる形で公開することを目指して運営しています。
パターンも、カードも、ROI も、全て裏で走っているコードの出力結果です。
当たり外れに一喜一憂するためではなく、長期で回る設計を持っているかを
ダッシュボードから読み取っていただければ幸いです。