Florida Lottery Intelligence
Market Overview
Real-time analytics engine — updated daily at 6:00 AM ET
Best EV Game
—
calculating...
Best Score
—
weighted rank
Top Prizes Left
—
games w/ jackpot intact
Avg Portfolio ROI
—
across all scratch-offs
FL Jackpot Pool
—
scratch-offs only
Powerball
$325M
Wed & Sat draw
Expected Value Ranking (EV/$ticket)
Top Prize % Remaining by Game
Today's Best Plays
Draw Game Jackpots
Florida Scratch-Off Games
Scratch-Off Analyzer
📍 Retailer Location Intelligence
PRO
How This Works: The FL Lottery publishes where winning tickets are sold — retailer name, city, ZIP, game, and prize amount.
We track every claim and cross-reference it against your location.
Why It Matters: Each scratch-off game is printed as a finite run. When a top prize is claimed at a store near you, that specific game has fewer remaining winners in your area's ticket distribution chain. Other games at the same store are unaffected — a Publix that paid out 500X THE CASH is still clean for GOLD RUSH LEGACY.
What To Do: Enter your ZIP code below. The system calculates a Location-Adjusted Score per game (EdgeScore × Freshness × AreaPenalty × RiskMultiplier) so you know exactly which games to buy where — and when to drive to a different region for a specific game.
Why It Matters: Each scratch-off game is printed as a finite run. When a top prize is claimed at a store near you, that specific game has fewer remaining winners in your area's ticket distribution chain. Other games at the same store are unaffected — a Publix that paid out 500X THE CASH is still clean for GOLD RUSH LEGACY.
What To Do: Enter your ZIP code below. The system calculates a Location-Adjusted Score per game (EdgeScore × Freshness × AreaPenalty × RiskMultiplier) so you know exactly which games to buy where — and when to drive to a different region for a specific game.
▸ PLAY = no nearby wins for this game, fresh in your area
▸ MAYBE = mid-tier wins nearby, top prizes still available
▸ SKIP = top prizes already claimed in your area for this game
Draw Games Analysis
Draw Game Analysis
Loading draw history...
Statistical Deep Dive
Capital Asset Modeling
Correlation · Cointegration · Drawdown · Sharpe · Kelly · Bell Curves
Game ROI Correlation Matrix (top 8 games)
Measures EV return correlation between games by prize tier overlap. Higher = similar risk/reward profile. Use for portfolio diversification.
Price vs EV Scatter — All Games
Each dot = one game. Dots above the diagonal line = positive EV relative to price.
Cross-Game Frequency Correlation — Number Overlap Analysis
Measures how number frequency distributions correlate across games. High correlation = similar hot/cold patterns. Based on actual draw history.
Econometric Test Suite — All Draw Games
ADF = Augmented Dickey-Fuller (stationarity) ·
χ² = Chi-Squared (uniformity/randomness) ·
E-G = Engle-Granger (pairwise cointegration)
H₀ for ADF: series has unit root (non-stationary). H₀ for χ²: numbers are uniformly distributed.
H₀ for ADF: series has unit root (non-stationary). H₀ for χ²: numbers are uniformly distributed.
Loading data... Select Scratch-Offs or Draw Games above.
Engle-Granger Pairwise Cointegration Matrix
Two-step Engle-Granger: OLS regression → ADF on residuals. Green = evidence of cointegration (p < 0.05). Tests whether game frequency patterns share long-run equilibrium.
Number Frequency Cross-Correlation Heatmap
Pearson correlation of number frequency vectors between game pairs. High values indicate similar hot/cold number distributions across games.
Lottery Sharpe Ratio (Top 10 Games)
Sharpe = (EV − RiskFree) ÷ StdDev(prize distribution). Higher = better risk-adjusted return. Risk-free set to $0 (no-play baseline).
Maximum Drawdown Simulation (200 ticket sessions)
Simulated cumulative P&L over 200 ticket purchases. Drawdown = peak-to-trough decline. Helps model bankroll volatility risk.
Risk-Adjusted Metrics Table
Prize Distribution Bell Curve — Select Game
Expected Outcome Distribution — 50 Ticket Simulation
Kelly Criterion Bet Sizing
Kelly Formula: f* = (bp − q) / b
where b = net odds, p = win prob, q = 1−p
Note: Kelly fractions are typically very small in lottery — this tool uses fractional Kelly (0.1×) for realistic bankroll sizing.
where b = net odds, p = win prob, q = 1−p
Note: Kelly fractions are typically very small in lottery — this tool uses fractional Kelly (0.1×) for realistic bankroll sizing.
Kelly Bankroll Growth Simulation
EV vs ROI Bubble Chart
Bubble size = ticket price. X = expected value. Y = ROI%. Upper-right = best plays.
Prize Tier Breakdown — Donut Charts
EV CONTRIBUTION %
PRIZES REMAINING %
Unified Probability-Weighted Point System (0–100)
Every game, retailer, and strategy is ranked by a single composite score built from statistically-weighted sub-components. The score drives ALL recommendations across the platform — scratch-off rankings, draw game picks, budget allocations, retailer PLAY/SKIP signals, and strategy tier selections. Hover any score ring for the full breakdown.
Every game, retailer, and strategy is ranked by a single composite score built from statistically-weighted sub-components. The score drives ALL recommendations across the platform — scratch-off rankings, draw game picks, budget allocations, retailer PLAY/SKIP signals, and strategy tier selections. Hover any score ring for the full breakdown.
Score Distribution — All Games
Component Contribution Breakdown
Master Probability Rankings — Full Table
CAPM Adaptation for Lottery Analytics
In traditional finance: R = Rf + β(Rm − Rf) + α. Here we adapt CAPM to model each scratch-off game as an "asset" where β (Beta) = sensitivity of a game's EV to the overall FL lottery market EV, α (Alpha) = game-specific excess return above what market exposure predicts, and Systematic vs Idiosyncratic risk = how much variance is market-driven vs game-specific. Games with high α and low β are the true edge plays — high return, low correlation to market downturns.
In traditional finance: R = Rf + β(Rm − Rf) + α. Here we adapt CAPM to model each scratch-off game as an "asset" where β (Beta) = sensitivity of a game's EV to the overall FL lottery market EV, α (Alpha) = game-specific excess return above what market exposure predicts, and Systematic vs Idiosyncratic risk = how much variance is market-driven vs game-specific. Games with high α and low β are the true edge plays — high return, low correlation to market downturns.
CAPM α (Alpha) — Excess Return vs Market
α > 0 = game outperforms market-predicted EV. Sort by α to find best plays regardless of market conditions.
CAPM β (Beta) — Market Sensitivity
β < 1 = defensive (less volatile than market). β > 1 = aggressive. Jackpot games have higher β.
Security Market Line — α vs β Scatter (Efficient Frontier)
Points above the SML line = underpriced (buy signal). Below = overpriced relative to their risk.
X-axis = β (systematic risk). Y-axis = actual EV return. SML = predicted fair return for given β.
CAPM Risk Decomposition Table — Systematic vs Idiosyncratic
R² = systematic risk share. (1−R²) = idiosyncratic (game-specific) risk.
High R², low α = market-driven game. Low R², high α = independent edge play.
Multi-State Expansion Architecture — Florida is the template.
Each state is added as a new
STATE_CONFIG entry with its scraper URL pattern, game ID range, API type, and prize structure.
The same CAPM, backtester, hot/cold, and retailer intelligence engines run for every state automatically.
State Comparison — Best EV Game per State
Play Strategy Engine
Budget Optimizer
Kelly-weighted recommendations by budget allocation
Configure Session
QUICK SELECT
Budget Allocation Pie
Area Intelligence — Where to Play
Loading area recommendations...
Frequency Analysis Laboratory
Hot / Cold Number Engine
Full historical frequency analysis · Hot = above avg · Cold = below avg · Due = longest gap
Number Frequency Heatmap — Last 500 Draws
Frequency Bar Chart with Probability %
🔥 HOT NUMBERS
❄ COLD NUMBERS
⚡ DUE NUMBERS
Note: "Due" is a statistical observation, not a predictor. Each draw is independent.
Number Pair Co-occurrence Frequency
Rolling Window Analysis (last 20/50/100 draws)
AI Number Suggestion Engine
Moderate: balanced approach across all signal types. Conservative optimizes for 2-3 number matches (frequent small wins). Aggressive targets full-match jackpots.
Loading suggestions...
AI Backtester — Historical Performance
ELITE
Loading backtester...
Intelligent Play System
Strategy Center
AI-powered ticket stacking, combined scratch + draw plans, and advanced play strategies
Today's Optimal Ticket Stack
Based on current EV rankings, prize freshness, historical patterns, and Kelly-weighted sizing
Loading ticket stack...
Combined Scratch-Off + Draw Game Plan
60% Scratch / 40% Draw
Loading combined plan...
Timing & Freshness Signals
Loading timing signals...
Advanced Play Strategies
ELITE
Loading advanced strategies...
🎭 Contrarian Play Strategy — Collision Minimization Engine
QUANT
Mathematical premise: You cannot change the odds of winning, but you can avoid splitting the jackpot.
Humans cluster their picks around dates (1–31), multiples of 5/7, and visual patterns on playslips.
The Contrarian engine generates tickets that statistically minimize overlap with other players' selections,
maximizing your payout when you do win — the true mathematical edge available to lottery players.
Configure Contrarian Engine
Human Bias Traps — What We Filter
✗
Birthday Trap — Numbers 1-31 represent only 44% of the pool but appear in ~70% of human picks
✗
Multiples Trap — Multiples of 5 (5,10,15...) selected 2× more than random
✗
Decade Clump — Players visually cluster ≥3 numbers in same 10-range on slip
✗
Sequential Runs — Patterns like 7,8,9 or 10,20,30 are human favorites
✓
We target — High numbers (32+), non-multiples, spread distribution
Generated Contrarian Tickets
Click regenerate to generate tickets...
⚡ Dynamic EV Trigger — When to Play Engine
QUANT
The premise: Most lottery tickets have negative expected value (EV ~$0.40 on a $2 ticket).
But as jackpots roll over, the EV improves. The EV Trigger calculates the exact jackpot threshold where
cash value × (1 − 0.37 federal tax) ÷ ticket odds > ticket cost — the mathematical "BUY" signal.
FL advantage: No state income tax — your net payout is higher than most states.
FL advantage: No state income tax — your net payout is higher than most states.
Custom EV Calculator
🎯 Anti-Split Jackpot Strategy — Number Popularity Map
QUANT
The math: If you win a jackpot shared with 3 other players, you receive 25% of the pot.
Studies show jackpot splits are 40-60% more common when players use "popular" numbers (birthdays, lucky 7, etc.).
This tool maps number popularity so you can deliberately choose unpopular combinations —
same odds of winning, significantly higher expected payout when you do win.
Number Popularity Map — Powerball (1-69)
🔴 = overplayed (avoid) · 🟡 = neutral · 🟢 = underplayed (target)
Source: Survey data on human number selection bias + FL historical patterns
Anti-Split Portfolio
Target number range: 32+ (above birthday bias zone)
Avoid: 1-31, multiples of 5/7, sequential runs
Sweet spot: 38-51, 57-63, 67-69 for Powerball
Loading anti-split picks...
Jackpot Sharing Risk Calculator
Calculating...
Data Infrastructure
Scraper + API Integration
Production-ready scrapers for Florida Lottery data feeds
Node.js + Puppeteer / Cheerio
// LottoEdge FL — Node.js Scraper (Puppeteer + Cheerio) // Scrapes: floridalottery.com/games/scratch-offs + draw results // Run daily via cron: 0 6 * * * node scraper.js const puppeteer = require('puppeteer'); const cheerio = require('cheerio'); const axios = require('axios'); const fs = require('fs'); const path = require('path'); // ── CONFIG ────────────────────────────────────────────── const CONFIG = { baseUrl: 'https://floridalottery.com', scratchUrl: 'https://floridalottery.com/games/scratch-offs', drawUrl: 'https://floridalottery.com/games/draw-games', gameIds: [1555,1562,1590,1594,1597,1604,1606, 1608,1618,1619,1620,1621,1622,1623,1627], outputDir: './data', delay: 1500 // ms between requests (be respectful!) }; // ── SCRAPE SINGLE SCRATCH GAME ────────────────────────── async function scrapeScratchGame(gameId) { const url = `${CONFIG.baseUrl}/games/scratch-offs/view?id=${gameId}`; const res = await axios.get(url, { headers: { 'User-Agent': 'Mozilla/5.0 (compatible; LottoEdgeBot/1.0)' } }); const $ = cheerio.load(res.data); const prizes = []; // Parse prize table $('.odds-prizes-table tr, table tr').each((i, row) => { const cells = $(row).find('td'); if (cells.length >= 3) { const prizeText = $(cells[0]).text().replace(/[$,]/g,'').trim(); const oddsText = $(cells[1]).text().match(/[\d,]+$/)?.[0] || '0'; const remText = $(cells[2]).text().trim(); const [rem, total] = remText.split(' of ').map(x => parseInt(x.replace(/,/g,''))); if (isNaN(rem)) return; prizes.push({ prize: +prizeText, odds: +oddsText.replace(/,/g,''), rem, total }); } }); const topPrize = $('[data-top-prize], .top-prize').first().text().replace(/[$,]/g,'').trim(); const topRemaining = $('.top-prizes-remaining').first().text().trim(); const overallOdds = $('.overall-odds').first().text().replace('1:','').trim(); return { gameId, topPrize: +topPrize || 0, topRemaining, overallOdds, prizes, scrapedAt: new Date().toISOString() }; } // ── SCRAPE ALL GAMES ───────────────────────────────────── async function scrapeAll() { console.log('[LottoEdge] Starting scrape...', new Date().toISOString()); const results = {}; for (const id of CONFIG.gameIds) { try { results[id] = await scrapeScratchGame(id); console.log(` ✓ Game #${id} — ${results[id].prizes.length} prize tiers`); } catch (e) { console.error(` ✗ Game #${id}:`, e.message); } await new Promise(r => setTimeout(r, CONFIG.delay)); } const outPath = path.join(CONFIG.outputDir, `scratch_${Date.now()}.json`); fs.writeFileSync(outPath, JSON.stringify(results, null, 2)); console.log(`[LottoEdge] Saved to ${outPath}`); return results; } // ── SCRAPE DRAW RESULTS ────────────────────────────────── async function scrapeDrawResults() { const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); await page.goto('https://floridalottery.com/games/draw-games/winning-numbers'); await page.waitForSelector('.winning-numbers', { timeout: 10000 }); const drawData = await page.evaluate(() => { const results = []; document.querySelectorAll('.draw-result-row').forEach(row => { const game = row.querySelector('.game-name')?.textContent; const date = row.querySelector('.draw-date')?.textContent; const nums = [...row.querySelectorAll('.ball')].map(b => +b.textContent); results.push({ game, date, numbers: nums }); }); return results; }); await browser.close(); return drawData; } scrapeAll().then(data => console.log('Complete', Object.keys(data).length, 'games'));
Python + BeautifulSoup + Selenium
# LottoEdge FL — Python Scraper # pip install requests beautifulsoup4 selenium pandas schedule import requests, json, time, schedule, logging from datetime import datetime from bs4 import BeautifulSoup import pandas as pd logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s') BASE_URL = "https://floridalottery.com" GAME_IDS = [1555,1562,1590,1594,1597,1604,1606, 1608,1618,1619,1620,1621,1622,1623,1627] HEADERS = {"User-Agent": "LottoEdge/1.0 (educational research)"} def scrape_game(game_id: int) -> dict: url = f"{BASE_URL}/games/scratch-offs/view?id={game_id}" r = requests.get(url, headers=HEADERS, timeout=10) r.raise_for_status() soup = BeautifulSoup(r.text, "html.parser") prizes = [] for row in soup.select("table tr"): cells = row.find_all("td") if len(cells) < 3: continue prize_str = cells[0].get_text().replace("$","").replace(",","").strip() odds_str = cells[1].get_text().replace(",","").strip() rem_str = cells[2].get_text().strip() try: rem, total = [int(x.replace(",","")) for x in rem_str.split(" of ")] odds_val = int(odds_str.split("-in-")[-1]) prizes.append({"prize": int(prize_str), "odds": odds_val, "rem": rem, "total": total}) except: continue return {"game_id": game_id, "prizes": prizes, "scraped_at": datetime.utcnow().isoformat()} def calc_ev(game: dict) -> float: return sum(p["prize"] * (1/p["odds"]) * (p["rem"]/p["total"]) for p in game["prizes"]) def daily_scrape(): logging.info("Starting daily FL Lottery scrape...") results = {} for gid in GAME_IDS: try: results[gid] = scrape_game(gid) ev = calc_ev(results[gid]) logging.info(f" Game #{gid}: EV=${ev:.2f}, {len(results[gid]['prizes'])} tiers") time.sleep(1.5) except Exception as e: logging.error(f" Error game #{gid}: {e}") fname = f"data/scratch_{int(time.time())}.json" with open(fname, "w") as f: json.dump(results, f, indent=2) logging.info(f"Saved {len(results)} games to {fname}") # Schedule daily at 6 AM ET schedule.every().day.at("06:00").do(daily_scrape) if __name__ == "__main__": daily_scrape() # run once immediately while True: schedule.run_pending(); time.sleep(60)
REST API Specification
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/games | All active scratch games |
| GET | /api/games/:id | Game detail + prize structure |
| GET | /api/ev/:id | Expected value calculation |
| GET | /api/rankings | Ranked game list by score |
| GET | /api/draw/:game | Draw game history + hot/cold |
| GET | /api/budget/:amount | Optimized play plan |
| POST | /api/simulate | Monte Carlo simulation |
| POST | /api/alerts | Set prize-remaining alert |
// Express.js API server — app.js const express = require('express'); const { scrapeAll, calcEV } = require('./scraper'); const app = express(); app.use(express.json()); // Auth middleware const auth = (req, res, next) => { const key = req.headers['x-api-key']; if (!key || !validKeys.has(key)) return res.status(401).json({ error: 'Invalid API key' }); next(); }; app.get('/api/games', auth, async (req, res) => { const data = loadLatestData(); res.json(Object.values(data).map(g => ({ id: g.gameId, ev: calcEV(g).toFixed(2), ...g }))); }); app.get('/api/budget/:amount', auth, (req, res) => { const b = +req.params.amount; res.json(optimizeBudget(b, loadLatestData())); }); app.post('/api/simulate', auth, (req, res) => { const { gameId, tickets, sims } = req.body; res.json(monteCarlo(gameId, tickets, sims || 10000)); }); app.listen(3000, () => console.log('LottoEdge API running on :3000'));
Automated Daily Pipeline
# crontab -e — add this line for daily 6 AM ET scrape: # 0 11 * * * cd /app && node scraper.js >> logs/scrape.log 2>&1 # GitHub Actions workflow (.github/workflows/daily-scrape.yml): --- name: Daily FL Lottery Scrape on: schedule: - cron: '0 11 * * *' # 6 AM ET = 11 UTC workflow_dispatch: # allow manual trigger jobs: scrape: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20' } - run: npm ci - run: node scraper.js env: DB_URL: ${{ secrets.DATABASE_URL }} WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK }} - uses: actions/upload-artifact@v4 with: name: scrape-data path: data/*.json retention-days: 30 # Docker Compose for full stack: --- version: '3.8' services: api: build: . ports: ["3000:3000"] environment: - DB_URL=postgresql://postgres:pass@db:5432/lottoedge db: image: postgres:16 volumes: [pgdata:/var/lib/postgresql/data] scheduler: build: . command: node scheduler.js depends_on: [db] volumes: pgdata:
Webhooks & Alert System
// Alert system — sends Discord/Slack/Email when key events occur const alerts = { // Trigger: top prize count drops (someone won!) topPrizeClaimed: async (gameId, prizeTier, newCount) => { const msg = { embeds: [{ title: `🎰 TOP PRIZE CLAIMED — Game #${gameId}`, description: `$${prizeTier.toLocaleString()} prize won! **${newCount} remaining**`, color: 0xFF4D6D, timestamp: new Date() }] }; await axios.post(process.env.DISCORD_WEBHOOK, msg); }, // Trigger: EV crosses threshold (game becomes better value) evThreshold: async (gameId, ev, price) => { if (ev / price > 0.85) { // 85%+ return threshold await axios.post(process.env.SLACK_WEBHOOK, { text: `⚡ HIGH EV ALERT: Game #${gameId} at $${ev.toFixed(2)} EV on $${price} ticket` }); } }, // Daily digest email via SendGrid dailyDigest: async (topPlays) => { await sgMail.send({ to: process.env.ALERT_EMAIL, from: '[email protected]', subject: `LottoEdge Daily Brief — ${new Date().toDateString()}`, html: buildEmailHTML(topPlays) }); } }; // Check for changes after each scrape async function detectChanges(prev, curr) { for (const [id, game] of Object.entries(curr)) { const p = prev[id]; if (!p) continue; // Top prize claimed? if (p.topPrizeCount > game.topPrizeCount) await alerts.topPrizeClaimed(id, game.topPrize, game.topPrizeCount); // EV improvement? await alerts.evThreshold(id, calcEV(game), game.price); } }
Data Export & Reports
Export Center
Download all analytics data as CSV or Excel for offline analysis, Excel modeling, or Python/Pandas import
📊 Scratch-Off Full Analysis
Exports all 15 scratch-off games with: EV, ROI, Sharpe, Kelly fraction, Edge Score,
prize structure per tier, top-prize freshness, drawdown estimate, and composite rankings.
🎰 Draw Games Analytics
Exports all draw games with: jackpot amount, ticket cost, EV, expected ROI, hot/cold/due numbers,
draw history count, backtester summary (if run), and strategy recommendations.
🤖 Backtester Results
Exports the full backtester history table: draw dates, actual numbers, AI picks per strategy,
hit counts, prize amounts, and cumulative ROI. Requires backtest to be run first.
📦 Full Portfolio Report
Master export: scratch-offs + draw games + strategy recommendations + statistical tests + Kelly sizes in one file.
Best for Excel modeling or sending to analysts.
🎯 Strategy Recommendations
Exports today's optimal play plan, budget allocations, AI number picks, EV trigger signals,
contrarian picks, and anti-split recommendations.
🔥 Hot/Cold Number History
Exports number frequency data per draw game: frequency counts, probability %, chi² deviation,
hot/cold classification, gap analysis, and signal composite scores.
Export Preview — Scratch-Off Data
| Game ID | Name | Price | EV | ROI % | Edge Score | Sharpe | Kelly % | Top Prize | Top Rem | Top Tot | Top % | Odds | Launched | Rec |
|---|
Preview shows first 10 rows of scratch-off export. Actual exports include all rows and additional columns.
Export Notes: CSV files open in Excel, Google Sheets, or any data tool.
Excel (.xlsx) exports use multi-sheet format — one sheet per data category.
All monetary values are in USD. ROI and probability values are expressed as percentages (%).
Data reflects current static + live Supabase values. Re-export after 6 AM ET daily scrape for freshest data.
SaaS Subscription Tiers
Choose Your Edge
Professional-grade lottery intelligence for serious players
All subscriptions include 7-day free trial · Cancel anytime · 18+ only · Gambling involves risk · Play responsibly