# MLB Home Run Radar — daily refresh

**What it is:** Top 10 hitters most likely to homer each day, ranked by Statcast power (barrel%, hard-hit%), HR/PA, **season-long consistency**, park factor, opposing SP HR/9, platoon, lineup slot, and recent form. Includes **HR prop EV** vs sportsbooks and an **evening report** after games.

**Where it lives:**

| Surface | URL |
|---------|-----|
| Dedicated page | https://courtedge.net/mlb-hr |
| Members desk tab | https://courtedge.net/picks → **HR Radar** tab |
| MLB DK lab panel | https://courtedge.net/mlb-dk-lineup-lab.html#hr-radar-panel |
| API | `GET /api/mlb/hr-picks` (optional `?date=YYYY-MM-DD`) |

**Model:** `mlb-hr-composite-v2` — see weights in `scripts/lib/mlb-hr-scoring.mjs`. Adds `season_consistency` (10%) so year-long sluggers (e.g. Schwarber +350) aren’t buried by a cold L14.

---

## Daily refresh (morning workflow)

Run from repo root **after** FTN slate + lineups are current:

```bash
cd ~/courtedge-deploy

# 0) Optional — paste HR prop lines (FanDuel, DK, BetMGM, Caesars, Novig, …)
cp data/mlb-hr-prop-lines-manual.example.json data/mlb-hr-prop-lines-2026-05-31.json
# edit player_name + books[].price (American odds, over 0.5 HR)

# 1) Refresh MLB slates (FTN CSV → slate JSON)
SLATE_DATE=2026-05-31 bash scripts/refresh-ftn-mlb-slates.sh

# 2) Build HR radar (Savant + slate + schedule + prop EV)
SLATE_DATE=2026-05-31 TOP_N=10 node scripts/build-mlb-hr-picks-today.mjs

# 3) Deploy production
bash scripts/quick-deploy-mlb.sh
# or: bash scripts/deploy-production.sh
```

**Outputs:**

| File | Purpose |
|------|---------|
| `data/mlb-hr-picks-{date}.json` | Today's ranked picks + embedded `prop_ev` |
| `data/mlb-hr-prop-ev-{date}.json` | Full prop EV table (all books per player) |
| `data/mlb-hr-track-record.json` | Rolling + lifetime graded accuracy |
| `data/mlb-hr-evening-report-{date}.json` | Post-game hits/misses + lines (after grade) |

**One command** (slate + HR + deploy):

```bash
SLATE_DATE=2026-05-31 bash scripts/quick-deploy-mlb.sh
```

Set `HR_TOP_N=10` (default) or `TOP_N=10` on the build script.

---

## Evening workflow (after games)

Grades box scores **and** writes the evening report (HR calls + best line at pick time):

```bash
./scripts/grade-mlb-hr-tonight.sh
# or: npm run mlb:hr-evening

bash scripts/quick-deploy-mlb.sh   # publish evening report to /mlb-hr
```

Each hit in the evening report shows:
- **at_pick** — best book/odds from morning prop lines (or `live_edges`)
- **closing** — if you paste `data/mlb-hr-prop-lines-closing-{date}.json`
- **hit_line_summary** — human-readable line the HR would have cashed at

---

## HR prop lines — manual paste (no paid odds feed required)

Without a live Odds API pull in the build script, paste lines into JSON:

**Path:** `data/mlb-hr-prop-lines-{YYYY-MM-DD}.json`

```json
{
  "date": "2026-05-31",
  "source": "manual",
  "lines": [
    {
      "player_name": "Kyle Schwarber",
      "books": [
        { "book": "FanDuel", "price": 350, "line": 0.5, "side": "over" },
        { "book": "DraftKings", "price": 340, "line": 0.5, "side": "over" },
        { "book": "BetMGM", "price": 325, "line": 0.5, "side": "over" },
        { "book": "Novig", "price": 360, "line": 0.5, "side": "over" }
      ]
    }
  ]
}
```

- **price** = American odds (`+350`, `+280`, etc.)
- **line** = always `0.5` for “to hit a HR” (over 0.5)
- Book aliases: `FD`, `DK`, `MGM`, `Caesars`, `Novig` all normalize

See `data/mlb-hr-prop-lines-manual.example.json`.

**Closing lines (optional, for evening report):**

`data/mlb-hr-prop-lines-closing-{date}.json` — same format, filled after lock.

---

## Prop sourcing from pipeline (when available)

If Supabase `live_edges` has MLB `batter_home_runs` rows (from Odds API ingest via `edges.js` / MCP sync):

```bash
SUPABASE_URL=... SUPABASE_SERVICE_ROLE_KEY=... node scripts/build-mlb-hr-picks-today.mjs
```

The build merges **manual JSON + live_edges** and picks best EV per player across books.

Browse live HR edges on the main board: `/picks` or `GET /api/edges?league=mlb` (filter client-side for `batter_home_runs`).

**Honest limits:**
- The HR radar build does **not** call Odds API directly (saves quota).
- No automatic closing-line capture without ingest or manual paste.
- Prop EV uses the **radar model probability** (`hr_prob`), not the full quantile MC from the prop board.
- Novig/`live_edges` coverage depends on your ingest schedule — often sparse for HR markets.

---

## After games — grade results

```bash
SLATE_DATE=2026-05-31 node scripts/grade-mlb-hr-picks.mjs
bash scripts/deploy-production.sh
```

Updates `result: hit|miss`, rolling track record, and evening report.

---

## Optional: push to Supabase

```bash
SLATE_DATE=2026-05-31 node scripts/build-mlb-hr-picks-today.mjs --push
```

Requires `SUPABASE_URL` + `SUPABASE_SERVICE_ROLE_KEY`. Table: `mlb_hr_picks` (migration `20260530120000_mlb_hr_picks.sql`).

---

## Verify

```bash
node scripts/build-mlb-hr-picks-today.mjs
python3 -m json.tool data/mlb-hr-picks-$(date +%Y-%m-%d).json | head -40
python3 -m json.tool data/mlb-hr-prop-ev-$(date +%Y-%m-%d).json | head -30
curl -sS https://courtedge.net/api/mlb/hr-picks | python3 -m json.tool | head -30
./scripts/grade-mlb-hr-tonight.sh
```

---

## Inputs

| Source | Path | Required |
|--------|------|----------|
| Games index | `data/mlb-games-{date}.json` | Yes |
| Slate JSON | `data/mlb-dk-slate-main.json` | Yes |
| MLB schedule | `data/mlb-schedule-{date}.json` or Stats API | Yes (lineups) |
| Savant CSV | Fetched live by build script | Optional (falls back to slate proxies) |
| HR prop lines | `data/mlb-hr-prop-lines-{date}.json` | Optional (EV table empty without) |
| live_edges | Supabase `batter_home_runs` | Optional |

---

## Troubleshooting

| Symptom | Fix |
|---------|-----|
| Empty HR tab / panel | Run `build-mlb-hr-picks-today.mjs`; deploy `data/mlb-hr-picks-{date}.json` and `data/mlb-hr-picks-latest.json` |
| API 404 for today | Missing dated file — run build + deploy, or rely on API fallback to `mlb-hr-picks-latest.json` (stale banner) |
| Empty prop EV table | Paste `data/mlb-hr-prop-lines-{date}.json` or sync `live_edges` |
| No evening report | Run `./scripts/grade-mlb-hr-tonight.sh` after finals |
| Savant fetch failed | Script continues with FTN/slate proxies — check network |
| Stale after deploy | Hard refresh (Cmd+Shift+R); `_headers` no-cache on `/data/mlb-hr-*.json` |
| Wrong date | Set `SLATE_DATE=YYYY-MM-DD` explicitly |

---

## FTN-only fallback

If Savant/schedule are unavailable, `scripts/build-mlb-hr-predictor.py` produces a quick FTN heuristic list to `data/mlb-hr-predictions-latest.json`. **Prefer the Node pipeline above** for production picks.

```bash
python3 scripts/build-mlb-hr-predictor.py --date today --top 10
```
