v1.2 preview — EdgeTerminal × TruthLayer. Aggregating Polymarket, Kalshi, Metaculus, PredictIt, and Manifold into a single canonical probability per event with confidence, trend, and cross-venue disagreement scoring. This is the unified signal view shipping in v1.2 (in progress). The live demo currently runs v1.1 — Polymarket × Kalshi arb feed with historical P&L proof — documented below.
EdgeTerminal continuously ingests prediction markets from Polymarket and Kalshi (with Metaculus, PredictIt, and Manifold arriving in v1.2), matches equivalent contracts across venues using a multi-tier pipeline (keyword similarity → FAISS embeddings → Claude LLM verification → entity extraction), and surfaces fee-adjusted arbitrage opportunities in a live streaming dashboard — with historical P&L proof that every detected opportunity was real.
Core value: When two prediction markets disagree on the same event, show the trader exactly where, by how much, and with what confidence — in real time, with a historical record that detected opportunities were real.
EdgeTerminal is a research and analysis tool, not financial advice. It surfaces price discrepancies and does not execute trades automatically. See the Disclaimer below.
Prediction market arbitrage is operationally fragile. Retail traders manually refresh Polymarket and Kalshi tabs and still miss the best windows.
- Contract wording varies — "Will Trump win?" vs "Trump to win 2024 presidential election" reference the same event with potentially different resolution criteria.
- Settlement sources differ — Two venues may resolve the same contract against different data sources or at different times.
- Liquidity is thin — Apparent arbs can vanish the moment you try to fill both sides.
- Pricing models differ — Polymarket uses AMM + CLOB hybrid; Kalshi is pure CLOB with different tick sizes and fee structures.
- False positives destroy trust — Showing a "10% arb" that isn't real is worse than missing a real one.
- Continuous 30-second polling of both venues with circuit breakers, retry, and freshness tracking.
- Precision-first matching — keyword similarity → FAISS candidate discovery → Claude LLM verification → entity extraction → framing-pattern taxonomy (17 patterns). False positives are treated as worse than misses.
- Fee-adjusted spreads with lifecycle tracking:
DETECTED → CONFIRMED → STALE → EXPIRED. - Historical P&L proof — every detected arb is tracked through settlement so the scoreboard is verifiable, not theoretical.
- Multi-tier matcher — keyword similarity, FAISS candidate discovery, Claude LLM verification, entity extraction.
- Framing pattern taxonomy — 17 patterns for complementary contracts and false-match rejection.
- Seed-list bootstrap for high-traffic recurring events (sports, elections, macro).
- Multi-leg decomposition for composite contracts.
- Fee-adjusted spreads across every venue pair carrying the same canonical event.
- Lifecycle tracking —
DETECTED → CONFIRMED → STALE → EXPIRED. - Confidence scoring with venue-pair trust multipliers.
- Settlement-risk indicator (green / yellow / red) based on resolution-criteria comparison.
- SSE streaming arb feed — sub-second updates, no polling on the client.
- Sortable & filterable cards with venue deep links.
- Side-by-side pair comparison with historical spread charts (
lightweight-charts). - OHLC candlestick price charts per market.
- Category + full-text search across every matched event.
- Mobile-responsive terminal layout.
- Market regime bar — live VIX, BTC, S&P 500, and DXY as macro context.
- Correlated-asset ticker mapping — prediction market events auto-tagged with underlying tickers (e.g.,
BTC > $120K→BTCUSDT). - Arb enrichment panel — TA summary (
tradingview-ta), Reddit sentiment, and Google News headlines for the correlated underlying. - News catalyst badges (Google News RSS) with click-through to the source.
- Volume breakout warnings — Binance + Yahoo Finance scans flag unusual underlying activity.
- GDELT news-heat signal — live article volume + top headline (GDELT 2.0 DOC API) over a 24h window, scored 0–100 per matched event; surfaces whether an arb is news-driven or stale.
- One-click crowd-reaction simulation — trigger a MiroShark multi-agent simulation directly from any arb in the feed. The arb's event title, both venues' descriptions, prices, and active news catalyst are packaged as a document bundle and handed off via MiroShark's
graph-build → simulation-create → startAPI chain. - Live SSE progress stepper — 7-stage stepper (preparing, fetching catalyst, ontology, graph, sim, personas, start) streams updates from the backend; the final
doneevent auto-opens the simulation in a new tab on MiroShark's own results UI. - Idempotent —
miroshark_sim_idis stored on the arb row, so repeat clicks deep-link to the existing simulation instead of wasting LLM work.
Local-dev only. The button is hidden in production unless MIROSHARK_URL (backend) and NEXT_PUBLIC_MIROSHARK_URL (frontend) are set, since MiroShark runs locally against its own LLM credits.
- Configurable alerts — in-app toasts + webhook delivery (Discord, Slack, generic JSON), 30-minute cooldown dedupe.
- Personal watchlist — anonymous session identity (no login), JSON export / import.
- Performance analytics — confidence calibration curves, venue-pair P&L breakdowns, category stats over configurable time ranges.
- Backtest conviction scoring — data-backed TA → prediction-market correlation per arb.
- Per-event P&L tracking through settlement.
- Immutable price-snapshot history (PostgreSQL, append-only, indexed).
- OHLC candle rollups and top-of-book depth capture (top 5 levels).
Polymarket and Kalshi are polled asynchronously, normalized into a common schema, matched into canonical events, and streamed to the dashboard over SSE. Enrichment sources attach to each arb as a side branch.
graph LR
subgraph Ingest["🛰️ Ingest (async httpx)"]
P[Polymarket CLOB]
K[Kalshi API<br/>RSA-signed]
end
subgraph Scheduler["⏱️ APScheduler"]
PL[pricing_loop<br/>30s]
ML[matching_loop<br/>15m]
end
subgraph Data["🗄️ PostgreSQL 16"]
RM[raw_markets]
CE[canonical_events]
PS[price_snapshots]
AO[arb_opportunities]
end
subgraph Matching["🧩 Matching Pipeline"]
KW[keyword similarity]
FA[FAISS embeddings<br/>all-MiniLM-L6-v2]
LLM[Claude LLM<br/>verification]
EE[entity extraction]
end
subgraph Enrich["🧠 Enrichment"]
TV[TradingView TA]
RD[Reddit sentiment]
GN[Google News RSS]
BY[Binance + Yahoo volume]
end
subgraph Frontend["💻 Next.js 16 Dashboard"]
UI[Arb feed · Watchlist · Analytics]
end
subgraph Miro["🦈 MiroShark (local-only, optional)"]
MS[Multi-agent simulation]
end
P --> RM
K --> RM
PL --> RM
ML --> KW
KW --> FA --> LLM --> EE --> CE
RM --> PS
CE --> AO
PS --> AO
TV -.-> UI
RD -.-> UI
GN -.-> UI
BY -.-> UI
AO -->|/api/arbs/stream SSE| UI
CE -->|/api/events| UI
UI -.->|POST + SSE<br/>optional| MS
- Docker & Docker Compose — for the one-command stack
- Python 3.12 — for backend-only development
- Node.js 20 — for frontend-only development
git clone <repo-url> edgeterminal
cd edgeterminal
cp .env.example .env # fill in KALSHI_KEY_ID, ANTHROPIC_API_KEY, etc.
docker compose upThen open:
- Frontend → http://localhost:3000
- Backend → http://localhost:8000
- API docs → http://localhost:8000/docs
| Variable | Purpose |
|---|---|
DATABASE_URL |
PostgreSQL async connection string (asyncpg) |
KALSHI_KEY_ID |
Kalshi API key identifier |
KALSHI_PRIVATE_KEY_PATH |
Path to RSA private key used for Kalshi request signing |
ANTHROPIC_API_KEY |
Claude API key for LLM match verification |
POLLING_INTERVAL_SECONDS |
Pricing-loop cadence (default: 30) |
MATCHING_INTERVAL_MINUTES |
Matching-loop cadence (default: 15) |
NEXT_PUBLIC_API_URL |
Backend URL consumed by the Next.js frontend |
MIROSHARK_URL |
Optional; enables MiroShark button in ArbDetail (local dev). Backend reads this to reach a self-hosted MiroShark instance. |
NEXT_PUBLIC_MIROSHARK_URL |
Optional; enables MiroShark button in ArbDetail (local dev). Frontend reads this to construct deep-links to simulation results. |
See CLAUDE.md for the complete list including logging and Supabase pooler settings.
| Service | URL |
|---|---|
| Frontend (Vercel) | https://frontend-indol-five-84.vercel.app |
| Backend (Railway) | https://backend-production-228e.up.railway.app |
| Database (Supabase) | Capstone project, us-west-2, session pooler at aws-1-us-west-2.pooler.supabase.com:5432 |
Railway auto-deploys from main. Vercel auto-deploys the frontend/ directory from main.
The backend exposes a small, documented REST + SSE surface. Production base URL: https://backend-production-228e.up.railway.app.
| Endpoint | Purpose |
|---|---|
GET /api/health |
Liveness + matched-event count |
GET /api/health/scheduler |
Pricing-loop status + last error |
GET /api/status |
Per-venue freshness and staleness |
GET /api/debug/raw |
Unfiltered pipeline state (canonical events, raw markets, snapshots, arbs) |
GET /api/events |
Matched cross-venue events with latest prices |
GET /api/arbs |
Active arb opportunities |
GET /api/arbs/stream |
SSE stream of active arbs (used by the dashboard) |
POST /api/debug/trigger-matching |
Manually kick the matching loop |
POST /api/debug/trigger-pricing |
Manually kick the pricing loop |
POST /api/miroshark/simulate/arb/{arb_id} |
Trigger a MiroShark simulation for an arb (returns cached sim_id on repeat; 409 if MIROSHARK_URL not configured) |
GET /api/miroshark/simulate/stream/{job_id} |
SSE progress stream for a running MiroShark simulation (events: progress, done, error) |
Interactive schema browser (Swagger / OpenAPI) is available at /docs on any running backend.
- Python 3.12 · FastAPI 0.115 · Uvicorn 0.32
- SQLAlchemy 2.0 (async) · asyncpg 0.30 · Alembic 1.14
- APScheduler 3.11 — background pricing (30s) + matching (15m) loops
- httpx 0.28 — async clients for Polymarket + Kalshi (Kalshi uses RSA request signing via
cryptography) - pytest — unit and integration tests
- Next.js 16 (App Router, SSR) · React 19 · TypeScript 5 (strict)
- SWR 2.4 — stale-while-revalidate data fetching with 30s refresh
- TailwindCSS 4 ·
tailwind-merge·tw-animate-css - lightweight-charts 5 — TradingView-style historical spread and OHLC charts
- Claude via
anthropic0.43 — LLM verification of candidate matches - sentence-transformers 5.3 (
all-MiniLM-L6-v2, ~90 MB) — semantic embeddings - FAISS — approximate nearest-neighbor candidate discovery
- PyTorch 2.11 — transformer runtime
- Docker Compose — local dev (Postgres + backend + frontend)
- Railway — backend hosting, auto-deploy from
main - Vercel — frontend hosting, auto-deploy from
frontend/ - Supabase — managed PostgreSQL 16 (session pooler)
- ✅ v1.0 MVP — shipped 2026-04-13 (Phases 1-10: data ingestion → matching → arb detection → live dashboard → historical P&L)
- 🚧 v1.1 Market Intelligence & Multi-Venue Expansion — in progress (Phases 11-22: foundation hardening, multi-venue via PMXT, market regime, enrichment panel, news & volume signals, alerts, watchlist, performance analytics, cloud deploy, synthetic-ID fix)
- 🔭 v1.2 TruthLayer Merger — planned (Phases 23-27: porting the strongest primitives from the sister TruthLayer project — diff-prefilter matching quick wins, 5-level equivalence grading + hedgeability, resolution-validation backtesting harness, cross-venue signal computation, and a Fact → Interpretation → VenueMarket graph schema enabling 5-platform aggregation pictured above)
Detailed phase breakdown, success criteria, and plan-level status live in .planning/ROADMAP.md.
EdgeTerminal is a capstone project being built in the open. Issues and pull requests are welcome — especially around matching precision, new venue adapters, and enrichment sources.
Before contributing:
- Read
CLAUDE.mdfor conventions, naming patterns, and error-handling style. - Browse
.planning/— the project uses the GSD (Get Shit Done) workflow; planning artifacts, phase breakdowns, and decision logs live there. - Keep changes scoped and atomic; run tests locally before opening a PR.
EdgeTerminal is a research and analysis tool. It surfaces price discrepancies across prediction markets but does not provide financial advice, does not execute trades automatically, and makes no guarantees about the validity, fillability, or profitability of any detected arbitrage opportunity. Prediction market trading carries risk including total loss of capital; users are solely responsible for verifying opportunities and managing their own execution. Past performance of detected arbs is not indicative of future results.
No LICENSE file is currently included in this repository. Until one is added, all rights are reserved by the author under default U.S. copyright law. If you would like to use this code, please open an issue to discuss licensing.
