Real-time prediction market inefficiency dashboard & signal engine.
EdgeMap continuously ingests market data from Kalshi and Polymarket, joins it with external signals (sports stats from ESPN, polling aggregates, economic data), runs probabilistic models to estimate "true" probabilities, and surfaces detected pricing inefficiencies in a real-time dashboard.
This repo currently contains Phases 1 + 2 + 3: pipeline, models, dashboard.
- Phase 1 (done): Async pollers for Kalshi + Polymarket, ESPN ETL, SQLite storage, FastAPI service, scheduler.
- Phase 2 (done): Resolution backfill, feature engineering, calibrated logistic
regression + XGBoost + market-implied baseline, Brier / log-loss / reliability plots,
/predict/{market_id}API endpoint. - Phase 3 (done): React + TypeScript + Tailwind + Recharts dashboard with 4 views
(Markets, Market detail with price chart, Edges leaderboard, Calibration). Backend
serves
/edges,/metrics, and reliability plots via/static/plots/. - Phase 4: More signal sources (ESPN joins, FRED, polling aggregates), richer features (multi-snapshot per market, momentum, volatility), model refinement, accumulating track record, P&L simulator.
Requires Python 3.11+ and uv.
# 1. Install deps into a project-local venv
uv sync --extra dev
# 2. Copy env template and edit if needed (defaults work for public endpoints)
cp .env.example .env
# 3. Initialize the database
uv run edgemap db init
# 4. Run a one-off poll to verify connectivity
uv run edgemap poll kalshi --limit 50
uv run edgemap poll polymarket --limit 50
# 5. Start the API + scheduler
uv run edgemap serve
# -> API at http://127.0.0.1:8000 (try /markets, /healthz, /docs)# 1. Pull historical resolved markets so there's something to train on
uv run edgemap backfill kalshi --limit 1000
uv run edgemap backfill polymarket --limit 1000
# 2. Fit logreg + xgboost + market-implied baseline; writes joblib + PNGs
uv run edgemap train
# -> models/{logreg,xgboost,market_implied}.joblib
# -> models/plots/reliability_*.png
# -> models/metrics.csv
# 3. Predict for a single market
uv run edgemap predict 42 --model xgboost
# 4. Or hit the API: GET /predict/{market_id}?model=xgboost# Terminal 1 — keep the FastAPI running
uv run edgemap serve
# Terminal 2 — first time only
cd frontend
npm install
# Run the React dev server (Vite). Hot reload, proxies /markets etc. to :8000.
npm run dev
# -> http://127.0.0.1:5173Four views, all wired to the live backend:
- Markets — sortable, filterable table of every market the pipeline has seen
- Market detail — price-history chart (Recharts) with the model's prediction overlaid; switch between logreg / xgboost / market_implied
- Edges — leaderboard of open markets ranked by
|model_prob − market_implied| - Calibration — metrics table + reliability curves loaded from
models/plots/
Production build: npm run build (writes frontend/dist/).
src/edgemap/
config.py # Settings (pydantic-settings, .env-driven)
logging.py # structlog setup
cli.py # `edgemap` CLI entrypoint
db/
models.py # SQLAlchemy ORM models
session.py # Async engine + session factory
init.py # Schema bootstrap
sources/
base.py # Shared HTTP client + poller protocol
kalshi.py # Kalshi API client + normalizer
polymarket.py # Polymarket Gamma API client + normalizer
espn.py # ESPN signals ETL
pipeline/
scheduler.py # APScheduler wiring
ingest.py # Orchestrates a single poll -> upsert cycle
api/
app.py # FastAPI app
routes.py # /markets, /prices, /signals, /healthz
tests/
test_normalizers.py
test_db.py
See .env.example. The public Kalshi and Polymarket market data endpoints don't
require auth -- you can run the pipeline without any keys. Auth is only needed for
account-level Kalshi calls (placing orders, etc.) which Phase 1 doesn't need.
code /Users/eugenemokri/EdgeMapThe .vscode/settings.json is preconfigured for ruff, the project venv, and pytest.