Skip to content

Repository files navigation

SideLine — Real-Time NBA Analytics

A full-stack NBA analytics platform with a live/replay game dashboard, historical prop-line movement charts, and a machine-learning prop-bet screener.

Stack: React · Node.js · WebSockets · Python · PostgreSQL


Architecture

┌─────────────┐      REST/WebSocket      ┌───────────────┐
│  React      │ ◄──────────────────────► │  Node.js      │
│  Dashboard  │                          │  API + WS     │
└─────────────┘                          └──────┬────────┘
                                                │ internal
                                                │ HTTP push
                                         ┌──────▼────────┐
                                         │  Python        │
                                         │  Pipeline      │
                                         │  - Backfill    │
                                         │  - Live poller │
                                         │  - Replay eng  │
                                         │  - ML screener │
                                         └──────┬────────┘
                                                │
                                         ┌──────▼────────┐
                                         │  PostgreSQL    │
                                         └───────────────┘

Live and replay events flow through the same pathway (Python → internal Node endpoint → WebSocket broadcast), so the frontend never branches on whether data is real or replayed.


External APIs

API Purpose Env var Notes
stats.nba.com (via nba_api) Season backfill, schedule sync, nightly boxscores Free, no key
The Odds API v4 Live player-prop lines from real sportsbooks THE_ODDS_API Free tier: 500 credits/month
ESPN injury endpoint Injury status feature for ML model Free, no key

Without API keys the system uses a deterministic synthetic season (1,230 games) so it runs fully offline.


Quickstart (local)

Prerequisites

  • Node.js 20+
  • Python 3.10+
  • PostgreSQL 14+ (Homebrew or Docker)

1. Database

# Homebrew
brew services start postgresql@18
psql postgres -c "CREATE USER sideline WITH PASSWORD 'sideline'"
psql postgres -c "CREATE DATABASE sideline OWNER sideline"

# Or Docker
docker compose up -d

2. Python pipeline

cd pipeline
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env          # add API keys if available

python -m sideline_pipeline.migrate                            # apply schema
python -m sideline_pipeline.backfill --seasons=2020,2021,2022,2023,2024,2025   # 6 seasons of real NBA data
python -m sideline_pipeline.augment --events-games 40           # build synthetic odds + events
python -m sideline_pipeline.screener train                      # train XGBoost + score screener

3. Node server

cd server
npm install
cp .env.example .env
npm run dev                    # starts on :4000

4. React frontend

cd frontend
npm install
cp .env.example .env
npm run dev                    # starts on :5173

5. Replay engine (streams live events to the dashboard)

cd pipeline
python -m sideline_pipeline.replay --loop   # cycles through historical games

Open http://localhost:5173 — the ticker should start scrolling player stats within seconds.


Pages

Page Path Description
Dashboard / Live/replayed game scores, WebSocket-driven updates
Line Movement /lines Search any player → step chart of prop line history across DraftKings & FanDuel
Screener /screener ML-ranked prop edges, filterable by stat/side/min edge
Game Picks /picks Top ML plays for any selected game with probability bars
Parlay Builder /parlay Auto-build or hand-pick optimal multi-leg parlays across games
Game Detail /game/:id Full box score + ML picks for a single game (from Dashboard cards)
Player Profile /player/:id Rolling averages, recent games, favored picks, most likely hits
About /about Project overview, features, model metrics, tech stack

Tests

# Python (10 unit tests)
DATABASE_URL=postgresql://sideline:sideline@localhost:5433/sideline \
  python -m pytest pipeline/tests/ -v

# Node (2 integration tests — WebSocket push pipeline)
cd server && node --test src/ws.test.js

# Playwright e2e (4 tests — UI smoke tests)
cd frontend && npx playwright test

ML Screener

XGBoost classifiers with isotonic calibration (CalibratedClassifierCV), one per prop category, trained on 6 real NBA seasons (2020-2025) — 127K+ player-game rows across 6,000+ games. Time-ordered train/test split (not random) for honest generalization numbers.

Category AUC Brier Simulated ROI
Points 0.784 0.189 +38.6%
Rebounds 0.742 0.203 +31.7%
Assists 0.727 0.207 +28.7%
3-Pointers 0.760 0.186 +26.3%

Test set: 28,823 games. Blended ROI across categories: +31.3%.

Features: L5/L10/season rolling averages (season-aware groupby), cross-season career average, minutes, home/away, rest days, back-to-back flag, opponent defensive rating, injury severity (out=1.0, doubtful=0.75, questionable=0.5, probable=0.25).

Parlay math: joint probability assumes leg independence — P(parlay) = ∏ P(leg). Auto-Build ranks candidates by quality = model_prob × (1 + edge × 2)^1.2 and greedily picks the top N unique players.


Continuous ingestion (in-season automation)

Three modules make the system self-updating once the NBA season is live:

Module Cost What it does
schedule_sync Free Pulls the next N days of scheduled games from stats.nba.com; auto-detects season rollover (Oct 1)
nightly_retrain Free Ingests yesterday's completed boxscores, upserts players/games/stats, retrains XGBoost on all seasons
odds_poll Uses Odds API credits Fetches live player-prop odds from featured games, re-scores the screener

Cost model for odds_poll (Odds API v4):

  • /events enumeration → FREE
  • /event/{id}/odds for 4 markets × 1 region (us) → 4 credits/game
  • Default ODDS_POLL_FEATURED_GAMES=28 credits per poll
  • Free tier = 500 credits/month → ~62 game days of coverage

Safety layers (all must pass):

  1. ODDS_POLL_ENABLED=true in .env (default: false — no credits burn until you flip it)
  2. THE_ODDS_API key present
  3. Current month's usage under ODDS_MONTHLY_CREDIT_CAP (default 450, tracked in odds_api_usage table)
  4. ODDS_POLL_FEATURED_GAMES caps games polled per run

Enabling for the 2026-27 season:

# 1. Add to pipeline/.env
THE_ODDS_API=your_key_here
ODDS_POLL_ENABLED=true

# 2. Install cron jobs (macOS launchd or crontab). Example crontab:
#    crontab -e
crontab -l | cat << 'EOF' | crontab -
0 5 * * *  /path/to/SideLine/pipeline/scripts/run_pipeline_job.sh schedule_sync --days 7
0 3 * * *  /path/to/SideLine/pipeline/scripts/run_pipeline_job.sh nightly_retrain --days 1
0 17 * * * /path/to/SideLine/pipeline/scripts/run_pipeline_job.sh odds_poll
EOF

# 3. Verify without burning credits
./pipeline/scripts/run_pipeline_job.sh odds_poll --dry-run

Logs land in pipeline/logs/{module}_YYYYMMDD.log. Credit burn rate is queryable:

SELECT date_trunc('day', called_at) AS day, SUM(credits_used) AS credits
FROM odds_api_usage
GROUP BY 1 ORDER BY 1 DESC;

Deployment

Component Recommended host
React frontend Vercel / Netlify
Node API + WebSocket Render / Railway / Fly.io
Python pipeline (worker) Same host as Node, or separate cron worker
PostgreSQL Neon / Supabase (free tier)

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages