# LottoSight — Project Documentation ## App Overview **Name:** LottoSight **Type:** Desktop Application **Framework:** Python + Tkinter **Database:** SQLite (local, zero-config) **Purpose:** Analyze historical lottery drawing data and predict next winning numbers using multiple statistical strategies. --- ## Tech Stack | Component | Technology | |---------------|-----------------------------------| | UI | Tkinter + ttk | | Charts | Matplotlib (embedded in Tkinter) | | Database | SQLite via sqlite3 | | Data Fetch | requests + BeautifulSoup | | Analysis | collections, statistics, numpy | | Scheduler | APScheduler | | Export | openpyxl | | Packaging | PyInstaller | --- ## Supported Games | Game | Main Balls | Pool | Bonus Ball | Pool | |---------------|------------|-------|------------|-------| | Powerball | 5 | 1–69 | 1 | 1–26 | | Mega Millions | 5 | 1–70 | 1 | 1–25 | | Custom | config | config| optional | config| --- ## Data Sources | Source | Game | Coverage | Method | |-------------------------|---------------|------------------|--------------| | NY Open Data API | Powerball | 2010–present | REST API | | NY Open Data API | Mega Millions | 2002–present | REST API | | Texas Lottery CSV | Mega Millions | 2003–present | CSV download | ### API Endpoints - **Powerball (NY):** `https://data.ny.gov/resource/d6yy-54nr.json` - **Mega Millions (NY):** `https://data.ny.gov/resource/5xaw-6ayf.json` - **Mega Millions (TX):** `https://www.texaslottery.com/export/sites/lottery/Games/Mega_Millions/Winning_Numbers/download.html` --- ## File Structure ``` lottosight/ ├── main.py # Entry point, app window, toolbar ├── db/ │ ├── database.py # SQLite setup, schema, migrations │ └── models.py # CRUD operations, duplicate check ├── core/ │ ├── analyzer.py # All analysis logic │ ├── predictor.py # Prediction strategies (5 total) │ └── fetcher.py # Fetch logic — auto + manual, all 3 sources ├── ui/ │ ├── dashboard.py # Home/summary screen │ ├── history.py # Draw history browser │ ├── analysis.py # Charts and stats screen │ ├── predictor_ui.py # Prediction generator screen │ ├── settings.py # Settings screen + manual fetch button │ └── statusbar.py # Bottom status bar component ├── assets/ │ └── icon.png ├── exports/ # Excel/CSV exports output folder ├── requirements.txt └── CLAUDE.md # This file ``` --- ## Database Schema ### Table: `games` | Column | Type | Description | |--------------|---------|------------------------------------| | id | INTEGER | Primary key | | name | TEXT | Game name (e.g. Powerball) | | main_count | INTEGER | Number of main balls | | main_max | INTEGER | Max value for main balls | | bonus_count | INTEGER | Number of bonus balls (0 if none) | | bonus_max | INTEGER | Max value for bonus ball | | active | INTEGER | 1 = active, 0 = disabled | ### Table: `draws` | Column | Type | Description | |--------------|---------|------------------------------------| | id | INTEGER | Primary key | | game_id | INTEGER | Foreign key → games.id | | draw_date | TEXT | ISO date string (YYYY-MM-DD) | | numbers | TEXT | Comma-separated main numbers | | bonus | TEXT | Bonus ball number(s) | | multiplier | TEXT | Power Play / Megaplier (nullable) | | source | TEXT | Data source identifier | | created_at | TEXT | Record insert timestamp | ### Table: `predictions` | Column | Type | Description | |--------------|---------|------------------------------------| | id | INTEGER | Primary key | | game_id | INTEGER | Foreign key → games.id | | strategy | TEXT | Strategy name used | | numbers | TEXT | Predicted main numbers | | bonus | TEXT | Predicted bonus number | | created_at | TEXT | Prediction timestamp | ### Table: `fetch_log` | Column | Type | Description | |--------------|---------|------------------------------------| | id | INTEGER | Primary key | | source | TEXT | Source name | | fetched_at | TEXT | Timestamp of fetch | | added | INTEGER | New records inserted | | skipped | INTEGER | Duplicate records skipped | | status | TEXT | success / error | | message | TEXT | Error message or notes | --- ## Fetch System ### Auto-Fetch - Triggers on **app launch** (background thread) - Repeats every **24 hours** via APScheduler - Runs in background — does not block UI ### Manual Fetch - Button in **Toolbar** (always visible, all screens) - Button in **Settings screen** - Shows "Fetching…" state while running ### Duplicate Handling - Compare incoming records by `draw_date` + `game_id` - Skip if already exists in DB - Report result in **status bar**: `X added, Y skipped` ### Status Bar Format ``` Last fetch: Powerball — 3 added, 2 skipped | Mega Millions — 5 added, 0 skipped | 2026-05-23 08:42 AM ``` --- ## Analysis Features | Feature | Description | |-----------------------|------------------------------------------------------| | Frequency analysis | Hot/cold numbers by total draw count | | Gap/skip analysis | How many draws since each number last appeared | | Positional frequency | Which numbers appear most in each draw position | | Pair/triplet patterns | Number combinations that appear together often | | Odd/even ratio | Ratio of odd vs even numbers per draw | | Sum range analysis | Distribution of total sums across all draws | | Delta patterns | Differences between consecutive numbers in a draw | --- ## Prediction Strategies | # | Strategy | Description | |---|--------------------|-----------------------------------------------------------| | 1 | Hot Numbers | Top N most frequent numbers in last X draws | | 2 | Due Numbers | Numbers overdue based on expected frequency gap | | 3 | Weighted Random | numpy random choice weighted by historical frequency | | 4 | Monte Carlo | 10,000 simulations, pick most common result | | 5 | Positional | Most frequent number per draw position | --- ## UI Screens | Screen | Description | |--------------|----------------------------------------------------------| | Dashboard | Summary stats, last draw result, quick actions | | History | Searchable/sortable draw history table | | Analysis | Charts — frequency bar, heatmap, gap chart | | Predictor | Pick strategy → generate ticket numbers | | Settings | Game config, data sources, fetch interval, manual fetch | --- ## Logging All actions are logged to console and optionally to a log file: - `[FETCH]` — auto/manual fetch events - `[DB]` — insert, skip, error events - `[PREDICT]` — prediction generated - `[EXPORT]` — export actions - `[ERROR]` — any exception with traceback --- ## Build Phases & To-Do ### ✅ Phase 0 — Planning - [x] Define app scope and features - [x] Choose tech stack - [x] Design database schema - [x] Design fetch system - [x] Define data sources and API endpoints - [x] Create CLAUDE.md --- ### ✅ Phase 1 — Database Setup - [x] Create `lottosight/` project folder structure - [x] Write `db/database.py` — SQLite init, create all tables - [x] Write `db/models.py` — CRUD: insert draw, get draws, check duplicate, insert prediction, insert fetch log - [x] Seed default game configs (Powerball, Mega Millions) - [x] Write `requirements.txt` - [x] Test DB creation and seed on fresh run - [x] Write `tests/conftest.py` — shared tmp_db fixture - [x] Write `tests/test_database.py` — 8 tests for database.py (47/47 pass) - [x] Write `tests/test_models.py` — 39 tests for models.py (47/47 pass) - [x] Write `.gitea/workflows/ci.yml` — CI on every push (syntax check + pytest) --- ### ✅ Phase 2 — Fetch System - [x] Write `core/fetcher.py` - [x] `fetch_powerball_ny()` — NY Open Data API - [x] `fetch_megamillions_ny()` — NY Open Data API - [x] `fetch_megamillions_tx()` — Texas Lottery CSV - [x] `fetch_all()` — calls all 3, aggregates results - [x] Duplicate detection logic - [x] Return added/skipped counts per source - [x] Write `ui/statusbar.py` — bottom status bar widget - [x] Wire auto-fetch on app launch (background thread) - [x] Wire 24hr scheduled fetch (APScheduler) - [x] Write `main.py` — app window, toolbar with manual fetch button - [x] Wire manual fetch button → `fetch_all()` → update status bar - [x] Test: fresh DB → fetch → verify records inserted (67/67 pass) - [x] Test: second fetch → verify duplicates skipped, counts correct - [x] Test: cross-source dedup (same date, different source → skipped) --- ### ✅ Phase 3 — History Browser - [x] Write `ui/history.py` - [x] Treeview table with columns: Game, Date, Numbers, Bonus, Mult., Source - [x] Filter by game (dropdown) - [x] Search by date range (From / To entries) - [x] Sort by column headers (▲/▼ indicators, numeric sort for bonus/multiplier) - [x] Row count display - [x] Connect history screen to DB reads via `get_draws_with_game()` - [x] Auto-refresh after fetch completes - [x] 13 tests (80/80 total passing) --- ### ✅ Phase 4 — Analysis Engine + Charts - [x] Write `core/analyzer.py` - [x] `frequency_analysis(game_id, last_n)` - [x] `gap_analysis(game_id)` - [x] `positional_frequency(game_id)` - [x] `pair_analysis(game_id)` - [x] `odd_even_ratio(game_id)` - [x] `sum_range_analysis(game_id)` - [x] `delta_analysis(game_id)` - [x] Write `ui/analysis.py` - [x] Frequency bar chart (Matplotlib + FigureCanvasTkAgg) - [x] Positional frequency heatmap (imshow, YlOrRd colormap) - [x] Gap chart (color-coded: blue=recent, red=due) - [x] Game dropdown + frequency window selector - [x] NavigationToolbar on each tab for zoom/pan - [x] 26 tests for all 7 analysis functions (106/106 total passing) --- ### ✅ Phase 5 — Prediction Engine - [x] Write `core/predictor.py` - [x] `hot_numbers(game_id, last_n=100)` — top-frequency + most-frequent bonus - [x] `due_numbers(game_id)` — highest gap numbers from pool - [x] `weighted_random(game_id)` — numpy weighted choice (min weight 1 for unseen) - [x] `monte_carlo(game_id, simulations=10000)` — tally-based selection - [x] `positional_pick(game_id)` — per-position best with dedup - [x] All strategies: random fallback on empty DB - [x] Write `ui/predictor_ui.py` - [x] Game + strategy + ticket count dropdowns - [x] Generate button (disables during generation) - [x] Treeview results: #, zero-padded numbers, bonus - [x] Save to DB (insert_prediction per ticket) + Clear - [x] Strategy description label - [x] 18 tests — all 5 strategies × validity + empty DB + edge cases (124/124 total) --- ### 🔲 Phase 6 — Settings Screen - [ ] Write `ui/settings.py` - [ ] Game enable/disable toggles - [ ] Fetch interval display (24hrs, read-only for now) - [ ] Manual fetch button (same as toolbar) - [ ] Last fetch timestamp per source - [ ] DB stats (total records per game) - [ ] Wire settings to DB config reads/writes --- ### 🔲 Phase 7 — Export + Polish - [ ] Add export to Excel (`openpyxl`) for: - [ ] Draw history - [ ] Predictions - [ ] Frequency analysis - [ ] Add export to CSV - [ ] Add `assets/icon.png` - [ ] App title bar + icon - [ ] Window min-size + resizable layout - [ ] Error handling — network down, API timeout, bad CSV --- ### 🔲 Phase 8 — Packaging - [ ] Write PyInstaller `.spec` file - [ ] Test build on target OS (Windows / Mac / Linux) - [ ] Bundle SQLite DB, assets, exports folder - [ ] Test packaged app fresh install (no Python required) --- ## Notes - SQLite DB file stored at: `lottosight/data/lottosight.db` - Exports land in: `lottosight/exports/` - All fetch operations run in **background threads** to keep UI responsive - NY Open Data API supports `$limit` and `$offset` params for pagination - Texas Lottery CSV requires parsing — columns vary, needs header detection - Powerball matrix changed Oct 7, 2015 (5/69+1/26) — pre-2015 data has different pool sizes, flag in DB or filter