A modern +EV prop betting automation engine from scratch
Build instructions for an LLM creating a system that pulls lines from 7 DFS platforms, compares against 5 sharp odds sources, identifies +EV edges across NBA, NFL, MLB, NHL, Golf, Tennis, Soccer, CFB, CBB, and UFC, generates optimal slips, and submits automatically.
What you are building
A complete +EV prop betting system that pulls player prop lines from 7 DFS platforms, compares them against 5 sharp odds sources, identifies +EV edges across NBA, NFL, MLB, NHL, Golf, Tennis, Soccer, CFB, CBB, and UFC using sport-specific probability models, generates optimal slip combinations, and submits them via headless browser automation and REST APIs.
Pull and compare lines
Pull player prop lines from PrizePicks, Underdog Fantasy, Betr Picks, Sleeper, DraftKings Pick 6, ParlayPlay, and Fliff. Compare against sharp odds from ETR, DataGolf, The Odds API, manual books, and Betano.
Probability models and scoring
Normal CDF and Poisson distribution for golf strokes-gained. Monte Carlo simulation with historical NBA stats. Multi-factor scoring with stochastic rolls, under-direction penalty, contention penalty, and 60+ prop types across 10 sports.
Submit and track
Headless browser submission via Puppeteer/Steel.dev with anti-detection. REST API submission for supported platforms. NFL QB+Receiver combo workflows. Supabase persistence for backtesting and P&L.
These instructions cover the complete +EV prop betting system — all platforms, all sports, all odds sources.
Tech stack
A modern Node.js CLI tool with TypeScript strict mode, no web framework.
Runtime: Node.js 22 LTS (ES modules)
Language: TypeScript 5.x (strict mode)
Browser: Playwright + Steel.dev cloud sessions
HTTP Client: undici (Node built-in)
Database: Supabase (PostgreSQL)
Cache: Redis 7+ with ioredis
Odds Sources: ETR, DataGolf API, The Odds API, OddsPapi, Manual JSON
DFS Platforms: PrizePicks, Underdog, Betr Picks, Sleeper, DK Pick 6, ParlayPlay, Fliff
Stats Data: nba_api (Python), DataGolf API, ESPN API
Sports: NBA, NFL, MLB, NHL, WNBA, Golf (PGA/LPGA), Tennis,
Soccer, CFB, CBB, UFC/MMA, Esports (CS2/LoL/Valorant),
KBO, Lacrosse, NASCAR — and any sport with props
Math: @stdlib/stats (Normal CDF, Poisson), simple-statistics (Monte Carlo)
Formatting: Biome (replaces Prettier + ESLint)
Testing: Vitest
CI: GitHub Actions
Package Manager: pnpm
Project structure
Create this exact directory structure. Every platform normalizer produces Line objects. Every engine function operates on Line[] and Slip[].
better/
├── src/
│ ├── index.ts # CLI entry point (commander)
│ ├── config.ts # Env validation with zod
│ ├── constants.ts # Sport enums, prop types, thresholds
│ │
│ ├── platforms/ # Platform adapters
│ │ ├── adapter.ts # Abstract PlatformAdapter interface
│ │ ├── prizepicks/ # PrizePicks (DFS props)
│ │ ├── underdog/ # Underdog Fantasy (DFS props + rival lines)
│ │ ├── betr/ # Betr Picks (GraphQL, multi-sport props)
│ │ ├── sleeper/ # Sleeper (Over/Under pick'em)
│ │ ├── dk-pick6/ # DraftKings Pick 6 (pick'em contests)
│ │ ├── parlayplay/ # ParlayPlay (NFL QB+WR combos)
│ │ ├── fliff/ # Fliff (odds aggregator via The Odds API)
│ │ └── registry.ts # Platform registry for CLI dispatch
│ │
│ ├── odds/ # Sharp odds aggregation
│ │ ├── the-odds-api.ts # The Odds API client
│ │ ├── oddspapi.ts # OddsPapi (Pinnacle, sharp books)
│ │ ├── etr.ts # Establish The Run projections scraper
│ │ ├── datagolf.ts # DataGolf API (golf projections)
│ │ ├── manual.ts # Manual JSON odds loader
│ │ └── consensus.ts # Multi-source implied probability
│ │
│ ├── sports/ # Sport-specific models
│ │ ├── models.ts # Line, Slip, PropType interfaces
│ │ ├── basketball.ts # NBA: 15+ prop types, fantasy calc
│ │ ├── football.ts # NFL: yards, completions, combos
│ │ ├── golf.ts # Golf: strokes-gained, birdies, bogeys
│ │ └── tennis.ts # Tennis: aces, double faults
│ │
│ ├── engine/ # Core analysis engine
│ │ ├── probability.ts # Normal CDF, Poisson, Monte Carlo
│ │ ├── combinations.ts # C(n,k) generator with validation
│ │ ├── scoring.ts # Multi-factor slip scoring
│ │ ├── picker.ts # Slip selection with player/stat caps
│ │ └── ev.ts # +EV calculation
│ │
│ ├── browser/ # Browser automation
│ │ ├── session.ts # Steel.dev / Playwright session
│ │ ├── stealth.ts # Ghost cursor, typing simulation
│ │ └── captcha.ts # CAPTCHA solving
│ │
│ ├── storage/ # Persistence
│ │ ├── supabase.ts # Database client
│ │ ├── redis.ts # Cache-through utility
│ │ └── schemas.sql # Database schema
│ │
│ └── utils/
│ ├── logger.ts # Pino structured logger
│ ├── csv.ts # CSV read/write
│ └── retry.ts # Exponential backoff
│
├── tests/
├── scripts/
├── .env.example
├── package.json
├── tsconfig.json
├── biome.json
├── vitest.config.ts
├── Dockerfile
└── docker-compose.yml
Why prop markets are exploitable
Player prop markets are the softest lines in sports betting. Sportsbooks focus resources on sides and totals. Props get less scrutiny, lower limits, and are priced off public perception rather than true probability.
$250–$500 caps
Sportsbooks cap prop bets at $250–$500 because they know these markets are exploitable. Low limits mean less sharp action correcting the lines.
Too many lines to price well
A single NBA slate produces hundreds of player props. Oddsmakers cannot hand-price each one. Automated pricing creates systematic mispricings.
Overs are overbet
Casual bettors love overs. This inflates over lines and creates value on unders — which is why the scoring engine applies an under-direction penalty to avoid overcorrelation.
Most exploitable markets (ranked by line softness)
WNBA
The single softest prop market in US sports. Fewer bettors, minimal media coverage, books devote far less resources to pricing. DraftKings WNBA props are flagged as "exploitable due to weak pricing." Rebounds and assists lines are especially imprecise.
College Basketball
March Madness props are among the most exploitable on the board. Rotation changes, matchup edges, and public overreactions create constant value. Regular season CBB is even softer — books barely price mid-major games.
Esports
CS2, League of Legends, Valorant, Dota 2. Sportsbooks are still learning how to price these. Regional leagues (LCK, LEC) are especially soft. Available on PrizePicks and growing fast.
KBO & International Baseball
Korean Baseball Organization lines are significantly softer than MLB. Less coverage, fewer data sources for books. PrizePicks offers KBO props.
LPGA & Niche Golf
LPGA receives a fraction of PGA betting volume. First-round leader markets are one of the most inefficient in all of golf betting. European Tour and LIV events are also soft.
Lacrosse, NASCAR, UFC
Any niche sport with props on PrizePicks or Underdog. Lower volume means less price discovery. MMA fight props are notoriously soft — the information gap between insiders and books is massive.
In WNBA, esports, and niche sports, injury news and lineup changes are not aggregated by major media. Following team beat reporters and insiders gives you information before sportsbooks adjust their lines. The system exploits this lag by comparing platform lines against sharp projections that incorporate this information faster.
The same player prop can differ by a full point across platforms. PrizePicks might set Caitlin Clark assists at 6.5 while Underdog has 7.5. Shopping across all 7 platforms turns marginal +EV into significant +EV. This system automates that comparison.
The three parts
Foundation and Platform Clients
Project initialization, core types with 60+ prop types across 10 sports, adapter interface, and all 7 platform clients: PrizePicks, Underdog, Betr Picks, Sleeper, DK Pick 6, ParlayPlay, and Fliff.
Core Engine and Odds Sources
ETR projections, DataGolf strokes-gained model, The Odds API integration, probability models, combination generation, and multi-factor scoring.
Infrastructure and Reference
Redis cache, browser automation, database schema, CLI, Docker, testing, and reference materials.