Architecture Guide
System Overview
┌─────────────────────────────────────────────────────────────┐
│ Frontend (Next.js 16) │
│ Dashboard | Real-time ticker | Edge leaderboard | Position │
│ | Backtest runner | Research reports │
└──────────────────────────┬──────────────────────────────────┘
│ WebSocket + REST
┌──────────────────────────▼──────────────────────────────────┐
│ FastAPI Backend │
│ ├─ Market Data Service │
│ │ └─ Gamma API polling (1s), order book, OHLCV │
│ ├─ Edge Detection Service │
│ │ └─ Fair probability vs market price │
│ ├─ Inference Engine │
│ │ └─ Bayesian probability + ensemble models │
│ ├─ Portfolio Management │
│ │ └─ Position tracking, correlation, risk │
│ ├─ Order Management │
│ │ └─ Entry, laddering, execution simulation │
│ └─ Research Service │
│ └─ Semantic search, embeddings, reports │
└──────────────────────────┬──────────────────────────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Gamma │ │ NewsAPI│ │ Twitter│
│ API │ │ │ │ API │
└────────┘ └────────┘ └────────┘
▲
│
├─────────────────────────────────────────┐
│ │
┌───▼────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│Postgres│ │TimescaleDB │ Chroma │ │ Redis │
│Positions │OHLCV, order │Embeddings │Cache, │
│Orders │ │book snapshots │Vector DB │ │Alerts │
│Trades │ └──────────────┘└──────────┘ └──────────┘
└────────┘
Core Services
1. Market Data Service
File: src/polysuggest/market_data.py
Async polling of Gamma API for real-time market data.
class MarketDataPoller:
async def fetch_all() -> List[Market]
# Returns: {id, bid, ask, yes_price, no_price, volume, spread_pct, timestamp}
async def subscribe(market_id: str, callback: Callable)
# Stream updates to callback (WebSocket handler)
Storage: TimescaleDB
- Table:
market_prices(timestamp, market_id, bid, ask, yes_price, volume, spread_pct) - Index:
(market_id, timestamp DESC)for fast lookups
2. Edge Detection Service
File: src/polysuggest/edge_detector.py
Continuously compares fair probability (model estimate) vs market probability.
class EdgeDetector:
async def detect_edges() -> List[Edge]
# For each market:
# fair_prob = inference_engine.estimate(market)
# market_prob = market.yes_price
# edge_pct = (fair_prob / market_prob) - 1
# if |edge_pct| > threshold: emit alert
def _decay_score(last_update: datetime) -> float
# Older edges decay; fresh edges score 1.0
Output: Edges ranked by EV × Liquidity × Confidence
3. Inference Engine (Bayesian)
File: src/polysuggest/inference_engine.py
Produces calibrated probability estimates using Bayes theorem.
class BayesianInferenceEngine:
def estimate_fair_probability(market) -> Tuple[float, Tuple[float, float]]
# Inputs:
# - market.category (prior from base_rates)
# - market.trend_sentiment (likelihood)
# - market.order_flow_5m (likelihood)
#
# Outputs:
# - fair_probability (0.55)
# - credible_interval ((0.47, 0.63))
Dependencies:
PyMC3orPyrofor MCMC samplingbase_rates.pyfor historical priors by market type- Training data: 12 months of historical Polymarket resolutions
4. Portfolio Tracker
File: src/polysuggest/portfolio_tracker.py
Real-time tracking of user positions and P&L.
class PortfolioTracker:
def add_position(user_id, market_id, outcome, quantity, entry_price)
def close_position(position_id, exit_price)
def get_pnl(user_id) -> Dict
# Returns: realized_pnl, unrealized_pnl, total, win_rate
def get_portfolio_heat() -> float
# Max loss as % of bankroll (all correlated scenarios)
Storage: PostgreSQL
- Table:
positions(user_id, market_id, outcome, quantity, entry_price, exit_price, pnl) - Table:
orders(user_id, market_id, outcome, size, limit_price, status, fill_price)
5. Risk Manager
File: src/polysuggest/risk_manager.py
Correlation analysis, VaR calculation, liquidation risk.
class PortfolioRiskManager:
def compute_portfolio_heat() -> Dict
# max_loss, total_exposure, liquidation_risk, correlation_matrix
def hedge_suggestion(new_position) -> Optional[str]
# If new position is correlated to existing, suggest a short hedge
6. Order Manager
File: src/polysuggest/order_manager.py
Order lifecycle: entry, execution simulation, fill tracking.
class OrderManager:
def place_order(market_id, outcome, size, limit_price, user_id) -> Order
def ladder_order(order_id, num_tranches: int, time_window: timedelta)
# Splits order across time for better execution
def estimate_slippage(size, liquidity, spread) -> float
# What will this order actually fill at?
7. Backtester
File: src/polysuggest/backtester.py
Historical simulation of edge detection and execution.
class Backtester:
def backtest(start_date, end_date, strategy) -> BacktestResult
# Replay historical market data
# Generate edges as of each timestamp
# Simulate executions at historical prices
# Compute realized P&L, Sharpe, max drawdown
Data Models
Market
@dataclass
class Market:
id: str
title: str
category: str # "crypto", "sports", "geopolitical", "economics"
yes_price: float
no_price: float
bid: float
ask: float
volume: float
spread_pct: float
liquidity: float
trend_sentiment: float # -1.0 to +1.0 from trend scanner
last_update: datetime
Edge
@dataclass
class Edge:
market_id: str
fair_prob: float # Model estimate
market_prob: float # Current YES price
edge_pct: float # (fair_prob / market_prob) - 1
liquidity: float
trend_sentiment: float
confidence: float # 0-1, based on freshness + liquidity
decay_score: float # 1.0 → 0.0 as it ages
detected_at: datetime
Position
@dataclass
class Position:
id: str
user_id: str
market_id: str
outcome: str # "YES" or "NO"
quantity: int
entry_price: float
entry_date: datetime
exit_price: Optional[float]
closed_at: Optional[datetime]
pnl: Optional[float]
Suggestion
@dataclass
class Suggestion:
id: str
trend: str
suggested_outcome: str # "YES" or "NO"
confidence: float # 0-1
reasoning: str
created_at: datetime
markets: List[str] # market IDs it applies to
resolved: bool
actual_outcome: Optional[str]
calibration_error: Optional[float]
Database Schema
PostgreSQL
-- Positions
CREATE TABLE positions (
id BIGINT PRIMARY KEY,
user_id TEXT NOT NULL,
market_id TEXT NOT NULL,
outcome TEXT NOT NULL, -- 'YES' or 'NO'
quantity INT NOT NULL,
entry_price FLOAT NOT NULL,
entry_date TIMESTAMP NOT NULL,
closed_at TIMESTAMP,
exit_price FLOAT,
pnl FLOAT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Orders
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id TEXT NOT NULL,
market_id TEXT NOT NULL,
outcome TEXT NOT NULL,
size INT NOT NULL,
limit_price FLOAT NOT NULL,
created_at TIMESTAMP NOT NULL,
filled_at TIMESTAMP,
fill_price FLOAT,
status TEXT, -- 'pending', 'filled', 'cancelled'
slippage FLOAT
);
-- Suggestions + Calibration
CREATE TABLE suggestions (
id BIGINT PRIMARY KEY,
trend TEXT NOT NULL,
suggested_outcome TEXT NOT NULL,
confidence FLOAT NOT NULL,
reasoning TEXT,
created_at TIMESTAMP NOT NULL,
resolved_at TIMESTAMP,
actual_outcome TEXT,
calibration_error FLOAT
);
-- Edges (detected mismatches)
CREATE TABLE edges (
id BIGINT PRIMARY KEY,
market_id TEXT NOT NULL,
detected_at TIMESTAMP NOT NULL,
fair_probability FLOAT NOT NULL,
market_probability FLOAT NOT NULL,
edge_pct FLOAT NOT NULL,
liquidity_available FLOAT NOT NULL,
trend_sentiment FLOAT NOT NULL,
decay_score FLOAT NOT NULL,
resolved_at TIMESTAMP,
actual_outcome TEXT,
pnl FLOAT
);
CREATE INDEX idx_positions_user_market ON positions(user_id, market_id);
CREATE INDEX idx_edges_market_detected ON edges(market_id, detected_at DESC);
CREATE INDEX idx_suggestions_created ON suggestions(created_at DESC);
TimescaleDB (Hypertable)
CREATE TABLE market_prices (
time TIMESTAMP NOT NULL,
market_id TEXT NOT NULL,
bid FLOAT,
ask FLOAT,
yes_price FLOAT,
no_price FLOAT,
volume FLOAT,
spread_pct FLOAT
);
SELECT create_hypertable('market_prices', 'time', if_not_exists => TRUE);
CREATE INDEX idx_market_prices ON market_prices (market_id, time DESC);
API Endpoints (FastAPI)
Markets
GET /api/markets– List all markets with current pricesGET /api/markets/{id}– Get market details + recent pricesGET /api/markets/{id}/history– OHLCV data (1m, 5m, 1h)
Edges
GET /api/edges– All detected edgesGET /api/edges?top=10– Top 10 by EVWS /api/edges/stream– WebSocket for real-time edge alerts
Portfolio
GET /api/portfolio/positions– User's open positionsGET /api/portfolio/pnl– P&L summaryGET /api/portfolio/risk– Portfolio heat, correlation, VaRPOST /api/portfolio/hedge-suggestion– Get hedge recommendations
Orders
POST /api/orders/place– Place a new orderPOST /api/orders/{id}/ladder– Ladder an orderGET /api/orders/{id}– Get order status + fills
Backtester
POST /api/backtest– Run a backtestGET /api/backtest/{id}– Get backtest results
Deployment
Local Development
# Start databases
docker-compose up postgres timescaledb chroma redis
# Run FastAPI server
uvicorn src.polysuggest.api.main:app --reload
# Run Celery worker
celery -A src.polysuggest.tasks worker --loglevel=info
# Run frontend
cd polysuggest && npm run dev
Production
- API: Cloud Run / Heroku / EC2
- Databases: AWS RDS (PostgreSQL), AWS Timestream or managed TimescaleDB
- Frontend: Vercel / Netlify
- Task Queue: AWS SQS / ECS / Celery on EC2
- Cache: ElastiCache (Redis)
Monitoring & Observability
- Logging: Loguru (Python), Pino (Node.js)
- Metrics: Prometheus + Grafana
- Tracing: OpenTelemetry (to DataDog / Jaeger)
- Alerts: PagerDuty (API errors, data staleness)