Skip to content

About

NCAA scouting apps and models, dbt/DuckDB warehouse, transfer-portal pipeline, plus MLB pitch models and game forecasting.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

baseball-analytics

By Trevor White (@tdub29 on GitHub).

Baseball scouting, player evaluation, and MLB game modeling. The NCAA platform combines transfer-portal scouting, pitch-level models, hitter and pitcher Streamlit apps, and play-by-play reports used by the University of San Diego coaching staff. The MLB work covers Statcast pitch and contact models, run expectancy, recency-weighted forecasting, batter-pitcher matchups, bullpen usage, and plate-appearance Monte Carlo game simulation.

MLB-trained xSLG and swing-decision models feed the NCAA hitter app; NCAA TrackMan trains the Stuff+, whiff, and pitch-location models. The model index connects trained artifacts to their source notebooks. Game-level MLB research has its own methods, experiments, and evaluation reports below.

Highlights

  • Coaches use these tools every week. USD's staff uses the hitter and pitcher apps, the transfer-portal board and the per-game PDF reports (samples).
  • One method at two levels. Stuff+ and whiff models are trained on NCAA TrackMan. The xSLG and swing-decision models are trained on MLB Statcast and applied to NCAA pitches in the hitter app (model index).
  • A dbt/DuckDB warehouse runs from committed fixtures with no credentials. It rebuilds the transform layer as staged, tested models. The SQLite pipeline still runs the operational workflow (try it).
  • Designed around a 2FA wall. The NCAA portal login needs a coach's 2FA code every time, so about 90 percent of the portal workflow runs from public sources with no login at all (design).

Hitter and pitcher dashboards

The hitter app moves from strike-zone heatmaps to spray charts and hitter metrics. The pitcher app compares pitch metrics, location and movement profiles. These paced screenshot sequences show three states from each running app, using the apps and data already in this public repository.

Hitter app: heatmaps, spray chart and hitter metrics

Pitcher app: pitch metrics, locations and movement profile

Scouting and pitch models

Work What it provides Start here
Hitter app xSLG, swing/take decision value, heatmaps, spray charts, and rolling trends Hitter app
Pitcher app Stuff+, whiff probability, movement, command and release plots, ideal locations, and reports Pitcher app
Transfer portal Multi-source ingestion, identity resolution, enrichment, fit scoring, alerts, and the coach board Portal pipeline
Play-by-play reporting Situational battle scoring and individual-game and season PDF reports Pipeline and sample reports
Pitch-level research Arm angle, shoulder coordinates, 3D wOBA, effective velocity, pitch mix, bunts, umpire analysis, and scouting notebooks Research notebooks

Pitch-location run-value analysis for right- and left-handed hitters

Pitch-location analysis from the scouting tools built for USD coaches.

Pitch movement colored by Stuff+, with pitcher and date filters

Pitch movement colored by Stuff+, with pitcher and date filters.

sources ──▶ ingest/dedupe/resolve ──▶ SQLite + dbt warehouse ──▶ models ──▶ apps + board
D1Baseball                            staging / intermediate      Stuff+     hitter app
VerbalCommits                         / marts, contracts          xWhiff     pitcher app
X/Twitter                             + source freshness          xSLG       Netlify board
CSV paste                                                         run value  (Supabase RLS)
PerfectGame bio
Sidearm bio
TrackMan

MLB forecasting and game simulation

The MLB pipelines build player and team estimates from public play-by-play and game logs, combine them into game forecasts, and evaluate them across seasons. The simulator also models how a game unfolds, including the starter's exit and which reliever is likely to enter.

Can a public-data model beat Vegas? No, and the test says how close it came. A model built only from Retrosheet and MLB StatsAPI was frozen, then scored once on 6,451 games from 2023 to 2025. Its log loss trails the no-vig closing line by 0.0036 per game (0.0018, borderline, once 12 dates with late-scraped "closing" lines are dropped). Its bets at the opening line moved toward the close by about 2 probability points, but the return cannot be told apart from zero. The rules for every verdict were written down before the test data was scored. Read the report.

Work What it provides Methods and results
Run expectancy and recency Rolling hitter, starter, bullpen, and team estimates; decay windows, offseason carry, shrinkage, and recent-form experiments Recency study and R pipeline
Batter-pitcher matchup models Handedness-specific outcome rates combined through log5, park adjustments, times through the order, bullpen availability, and walk-forward win forecasts Model card and matchup experiments
Monte Carlo game simulator Plate appearances, batting order, base-out transitions, starter hook, reliever selection, workload, win/run distributions, and hitter-pitcher exposure Simulator design and implementation
Evaluation and market comparisons Calibration, moneyline and totals benchmarks, closing-line value, conventional sabermetric baselines, and forward-season testing Research report and evaluation figures
Reliability and model development Sample-size stabilization, shrinkage tuning, context ablations, and comparisons of model variants Research report and experiment log
flowchart LR
    A["Retrosheet and MLB StatsAPI"] --> B["Player and team history available before each game"]
    B --> C["Decay and shrinkage estimates"]
    C --> D["Recency-based forecasts"]
    C --> E["Handedness and park-adjusted matchups"]
    E --> F["Walk-forward win model"]
    E --> G["Plate-appearance game simulator"]
    D --> H["Season-based evaluation and research reports"]
    F --> H
    G --> H
Loading

Related projects: original R pipeline and WanBattedBall, a CatBoost entry in Nick Wan’s NWDS competition.

Try the sample dbt warehouse

Build and test the staged DuckDB transform layer with the committed fixtures in warehouse/sample_data/. Python 3.10+; no credentials required. The SQLite pipeline still runs the operational workflow.

pip install -e ".[warehouse]"
cd warehouse
cp profiles.example.yml profiles.yml
dbt deps
dbt build --profiles-dir .

See the warehouse guide for the model layout and migration plan.

What is in here

Area Size Notes
src/ncaa/portal/ 28 files, 5,296 lines Portal ingest, dedupe, entity resolution, enrichment, geo, program tier, rollup, fit scoring, alerts
src/ncaa/pbp/ 26 code files, 6,550 lines NCAA play-by-play acquisition (Playwright plus ncaa-api.henrygd.me), situational "battle" scoring, season PDF reports
src/ncaa/cli.py 336 lines init, import-excel, ingest, enrich-643, evaluate, board, run-all
warehouse/ 18 SQL files, 925 lines dbt-duckdb rebuild of the transform layer: 3 staging, 1 intermediate and 7 mart models (dims, fct_pitch, season marts), 3 singular tests, a pitch-type seed, model contracts, source freshness and sample fixtures
apps/hitter/, apps/pitcher/ 5,275 lines The two Streamlit apps coaches open, with their 10 model artifacts
scripts/ 22 files NCAA bio fetchers (D1/D2/D3/portal), school geocoding, Excel import and export, board HTML build, Netlify publish, Supabase RLS verify
tests/ plus the pbp tests 16 pytest files, 103 test functions bio, board, d1baseball, dedupe, geo, overlay, paths, RLS schema, pipeline, program tier, resolve, rollup, speed, status, battle calc, and a guard that the battle converter stays linear in input size
research/notebooks/ 20 notebooks 8 MLB, 12 NCAA, outputs stripped (verified 2026-09-16: none carry embedded outputs). Every shipped model was trained in one of these
research/r/ MLB pipelines, studies, simulator, and testthat suite Run expectancy, recency and matchup models, bullpen usage, Monte Carlo game simulation, market comparisons, and forward-season evaluation. The original pipeline is preserved in research/r/legacy/.
docs/ 10 design docs Pipeline design, 2026 sourcing, capabilities and blockers, Netlify and Supabase recipes, the consolidation plan

Model provenance, which notebook trained which artifact: models/README.md.

Production versus research, stated plainly

The two Streamlit apps and the coach board are in active use. The dbt warehouse is a staged rebuild of the transform layer and has not cut over; the SQLite pipeline is still what runs. CI (.github/workflows/ci.yml) runs ruff, pytest, dbt build on the fixtures and the testthat suite. Everything under research/ is exactly that, and several notebooks depend on a TruMedia or 6-4-3 export this repo does not carry.

Quickstart

The pipeline runs from a fresh clone without credentials, but it needs portal entries to rank. Those come from the coaching staff's transfer-portal workbook (sheets Names + Notes, All Divisions Pitcher Data, Hitter Hot Board Data, RosterInfo), which is not committed, or from the live sources. Without either, evaluate and board run and produce an empty board. 6-4-3 Charts stat exports are licensed and are not committed either; data/643_exports/README.md gives the format to drop your own into.

pip install -e ".[scoring,ncaa-stats]"
python -m ncaa.cli init --force                     # create db/baseball.db from db/schema.sql
python -m ncaa.cli import-excel path/to/workbook.xlsx   # seed portal entries
python -m ncaa.cli enrich-643 --dir data/643_exports    # load your own 6-4-3 exports, if licensed
python -m ncaa.cli evaluate                         # compute fit scores
python -m ncaa.cli board --limit 150                # write data/hot_board.csv

Live sources need a config.yaml (copy config.example.yaml). The D1Baseball adapter needs a session cookie, and the Supabase overlay needs project keys; both degrade to no-op without them, so the rest of the pipeline still runs.

The apps pin numpy against each other, so install one per environment:

pip install -e ".[hitter]"  && streamlit run apps/hitter/streamlit_app.py
pip install -e ".[pitcher]" && streamlit run apps/pitcher/streamlit_app.py

For the credential-free warehouse build, use the sample dbt quickstart above. profiles.yml is gitignored; the example holds two local DuckDB paths.

The MLB R pipeline runs on its own, and its tests need no network:

Rscript research/r/tests/testthat.R
Rscript research/r/mlb/run_season.R 2019   # one season end to end

Sample output

docs/samples/ holds real per-game battle reports the pbp pipeline generated for the 2026 season. The coach board itself (scripts/build_html.py) is generated locally and not committed, because it names athletes and carries fit scores.

What this repo replaced

A manual Excel hot board plus a call-assignment spreadsheet. The interesting constraint was that USD's sso.ncaa.org login needs a 2FA code from a coach on every use, so roughly 90 percent of the workflow is built to need no login at all: entries are detected from public sources, stats come from collegebaseball against stats.ncaa.org, and the login is spent only on contact fields for the top call targets. docs/transfer-portal-pipeline.md has the full design.

Data and attribution

USD's own TrackMan data is committed on purpose, because an app nobody can start is a screenshot; USD branding, names and data are used with permission. Data licensed or scraped from third parties (6-4-3 Charts exports, PerfectGame, Sidearm and D1Baseball bios) and the generated recruiting boards are kept local and gitignored. The NCAA play-by-play under data/pbp/ comes from public box scores.

Secrets are a separate matter and are not committed: config.yaml, secrets/, .env, keys and service-account JSON are all ignored, and git ls-files is checked against that list before any push.

More projects

More of my work and contact details are at twhite.dev.

About

NCAA scouting apps and models, dbt/DuckDB warehouse, transfer-portal pipeline, plus MLB pitch models and game forecasting.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages