# 2020年〜 中央競馬 確定単勝・確定馬連オッズ — 手順まとめ

作成: 2026-06-12

## 欲しいデータ

| 項目 | JV レコード | 内容 |
|------|------------|------|
| 確定単勝オッズ | **O1** | 馬番ごとの単勝（TanOdds） |
| 確定馬連オッズ | **O2** | 組番ごとの馬連（Kumi + Odds） |

どちらも **`--spec RACE`** に含まれる（`--spec O1` / `O2` 単体は -111）。

---

## 切り分けの順番（必ずこの順）

```
① JV 生データにオッズ値があるか
② 生データをパースできるか（JV/fetch 不要のオフライン）
③ keiba.db / MySQL に正しく入るか
```

2026年で確定済み:

| 段階 | 単勝 O1 | 馬連 O2 |
|------|---------|---------|
| ① JV 生 | OK（1512/1536 レース） | **要確認**（下記 STEP A） |
| ② オフラインパース | OK（1506 races, 21362 rows） | **要確認**（下記 STEP B） |
| ③ keiba.db | NG（491 レースのみ） | **要確認**（下記 STEP C） |
| ③ MySQL import | `import_jrvltsql_db.py` は **単勝のみ** | **未実装** |

**結論（現時点）:** 単勝は ②まで成立。馬連は ①②の確認が先。本番取込は両方とも **jrvltsql NL_O* を信用しない** 経路が安全。

---

## 環境（固定）

| 項目 | 値 |
|------|-----|
| Windows 作業Dir | `C:\Users\oshim\jrvltsql` |
| JV-Link | `JVDTLab.JVLink`（32bit venv32） |
| コード置き場 | `root@133.130.90.66` … `ai-horse-race.maspis.com` |
| 新本番 | `root@163.44.117.9` … `tools.kachiumaai.com` |

**やらないこと:** `pip install git+https://github.com/miyamamoto/jrvltsql.git`（jltsql が壊れる）

**jltsql 壊れたときの復旧:**

```bat
cd /d C:\Users\oshim\jrvltsql
venv32\Scripts\pip.exe uninstall jltsql -y
venv32\Scripts\pip.exe install -e .
```

---

## 毎回最初にやること（ファイル同期）

**どの STEP でも、実行前に必ずこれを1回貼る。**

```bat
cd /d C:\Users\oshim\jrvltsql
scp root@133.130.90.66:/var/www/html/ai-horse-race.maspis.com/scripts/windows/sync_from_git.bat .
sync_from_git.bat
```

`sync_from_git.bat` は GitHub から `git pull` して `scripts\windows\*.py` / `*.bat` を `jrvltsql` にコピーする。

GitHub にまだ無い場合の代替（scp 直取り）:

```bat
cd /d C:\Users\oshim\jrvltsql
scp root@133.130.90.66:/var/www/html/ai-horse-race.maspis.com/scripts/windows/check_keiba_odds_local.py .
scp root@133.130.90.66:/var/www/html/ai-horse-race.maspis.com/scripts/windows/check_keiba_odds_local.bat .
```

**やらないこと:** `python -c "..."` で SQL に `||` を含む1行コマンド（cmd がパイプと誤認して壊れる）。

---

## STEP 0 — 現状確認

```bat
cd /d C:\Users\oshim\jrvltsql
check_keiba_odds_local.bat
```

| 見る数字 | 目安（2020〜全体） |
|---------|-------------------|
| NL_RA 2020 | ~3,400（年あたり） |
| NL_O1 tanodds races | **18,000+** が目標（今は ~6,700 程度で不足） |
| NL_O2 umaren races | O1 と同程度が目標（**未確認**） |

---

## STEP A — ① JV 生データ確認（単勝・馬連）

### A-1 単勝（2026 済み）

`o1_raw_all.txt` あり。再取得不要。

### A-2 馬連（2020〜 要実行）

```bat
cd /d C:\Users\oshim\jrvltsql
scp root@133.130.90.66:/var/www/html/ai-horse-race.maspis.com/scripts/windows/dump_o2_raw_all.py .
venv32\Scripts\python.exe dump_o2_raw_all.py
```

成功: `Wrote N O2 records -> o2_raw_all.txt` と **length distribution** が表示される。

`jltsql fetch` は **使わない**（stall する）。JVRead 直叩きのみ。

### A-3 整合性サマリ（任意）

```bat
cd /d C:\Users\oshim\jrvltsql
scp root@133.130.90.66:/var/www/html/ai-horse-race.maspis.com/scripts/windows/diag_jvlink_integrity.py .
```

`diag_jvlink_integrity.py` の `FROM_TO` を `20200101000000-20261231000000` に編集してから:

```bat
venv32\Scripts\python.exe diag_jvlink_integrity.py
type diag_result.txt
```

| 行 | 意味 |
|----|------|
| O1+odds | 単勝値ありレース数 |
| O2 行 | 馬連レコードありレース数（要 O2 中身確認） |

---

## STEP B — ② オフラインパース（fetch 不要）

### B-1 単勝（済み）

```bat
cd /d C:\Users\oshim\jrvltsql
copy /Y C:\Users\oshim\Downloads\o1_to_sqlite.py .
python o1_to_sqlite.py o1_raw_all.txt odds_o1_2026.db
python -c "import sqlite3;c=sqlite3.connect('odds_o1_2026.db');print('races_with_tansho:',c.execute('SELECT COUNT(DISTINCT race_key) FROM odds_tansho').fetchone()[0])"
```

**実績:** records=1536, races_with_tansho=**1506**

### B-2 馬連

```bat
cd /d C:\Users\oshim\jrvltsql
scp root@133.130.90.66:/var/www/html/ai-horse-race.maspis.com/scripts/windows/o2_to_sqlite.py .
python o2_to_sqlite.py o2_raw_all.txt odds_o2.db
```

成功の目安:

- `records` ≈ O2 生レコード数（2020〜なら **数万** 想定）
- `races_with_umaren` ≈ 成績確定レース数の **80%以上**

### B-3 2020年〜全体の単勝ダンプ（未実施なら）

`dump_o1_raw_all.py` の `FROM_TO` を `20200101000000-20261231000000` に変更:

```bat
cd /d C:\Users\oshim\jrvltsql
scp root@133.130.90.66:/var/www/html/ai-horse-race.maspis.com/scripts/windows/dump_o1_raw_all.py .
venv32\Scripts\python.exe dump_o1_raw_all.py
python o1_to_sqlite.py o1_raw_all.txt odds_o1_2020_2026.db
```

---

## STEP C — ③ 本番取込

### 現状のギャップ

| 経路 | 単勝 | 馬連 |
|------|------|------|
| `keiba.db` NL_O* → import | 壊れてる（491/1506） | 要 STEP 0 確認、おそらく同様 |
| `odds_o1_2026.db` | パース OK | — |
| `odds_o2.db` | — | STEP B-2 後 |
| `import_jrvltsql_db.py --odds-only` | NL_O1 のみ | **馬連未対応** |

### C-1 レース・着順・払戻（既存）

`keiba.db` の NL_RA / NL_SE / NL_HR はレース本体として使える（オッズ以外）。

```bash
# 新本番 163.44.117.9
cd /var/www/html/tools.kachiumaai.com
./scripts/import_keiba_db.sh /root/keiba.db 2020 2026
./scripts/import_keiba_payouts.sh /root/keiba.db 2020 2026
```

### C-2 単勝オッズ取込（現行）

```bash
./scripts/import_keiba_odds.sh /root/keiba.db 2020 2026
```

**問題:** keiba.db NL_O1 が欠けてる → **odds_o1_*.db からの取込スクリプトが必要**（未実装・次タスク）。

### C-3 馬連オッズ取込

`odds_lines.odds_type='umaren'` への投入は **未実装**。STEP B-2 成功後に `import_odds_o2_sqlite.py` を追加する。

### C-4 Windows → サーバー転送

```bat
scp C:\Users\oshim\jrvltsql\odds_o1_2020_2026.db root@163.44.117.9:/root/
scp C:\Users\oshim\jrvltsql\odds_o2.db root@163.44.117.9:/root/
scp C:\Users\oshim\jrvltsql\data\keiba.db root@163.44.117.9:/root/keiba.db
```

---

## 取れるか？ — 調査結果（2026-06-12）

| データ | 2020〜取得可能？ | 根拠 |
|--------|-----------------|------|
| **確定単勝** | **YES** | JV RACE に O1。2026 で 1506 レースパース実証。2020〜は `dump_o1` の FROM_TO を広げれば同じ手順 |
| **確定馬連** | **YES（高確率）** | jrvltsql 公式: RACE に O2 → NL_O2。パーサー・スキーマあり。**ただし 2026 でのオフライン実証は未完了**（STEP A-2 / B-2 要実行） |
| **jrvltsql fetch 経由** | **非推奨** | Download stall、NL_O1 書き込み欠陥（491 vs 1506） |
| **推奨経路** | **JVRead ダンプ → o1/o2_to_sqlite → 専用 import** | keiba.db NL_O* を使わない |

### 2020〜の件数目標

| 年 | 中央レース数（目安） |
|----|---------------------|
| 1年 | ~3,200〜3,500 |
| 2020〜2026 | **~22,000〜24,000** レース |
| 単勝・馬連オッズ | 成績確定レースの **80%+**（削除・中止除く） |

---

## 最短チェックリスト（今日やる順）

1. [ ] STEP 0 — keiba.db の NL_O1 / NL_O2 件数
2. [ ] STEP A-2 — `dump_o2_raw_all.py` → `o2_raw_all.txt`
3. [ ] STEP B-2 — `o2_to_sqlite.py` → `races_with_umaren` 確認
4. [ ] `dump_o1` FROM_TO を 2020〜 に広げて単勝全期間 DB 作成
5. [ ] サーバー側 import 拡張（odds_o1 / odds_o2 → MySQL）

---

## 関連ファイル

| ファイル | 用途 |
|----------|------|
| `scripts/windows/dump_o1_raw_all.py` | O1 生ダンプ |
| `scripts/windows/dump_o2_raw_all.py` | O2 生ダンプ |
| `o1_to_sqlite.py`（Downloads） | 単勝パース → SQLite |
| `scripts/windows/o2_to_sqlite.py` | 馬連パース → SQLite |
| `scripts/windows/parse_o1_raw_file.py` | 単勝パース診断 |
| `collectors/import_jrvltsql_db.py` | keiba.db → MySQL（単勝のみ） |
| `docs/ops_jv_o1_handoff.md` | O1 障害の詳細 |
