PQAP Architecture

Overview

PQAP (Polymarket Quant Automation Platform) is a trading system for prediction markets. It's designed around finding real edge - not just fitting historical noise, but discovering genuine market inefficiencies.

Core Philosophy

  1. Data First: Collect extensive historical data before betting
  2. Validate Everything: Use calibration analysis to verify predictions
  3. Paper Trade: Always paper trade before risking real capital
  4. Measure Edge: Track expected value, not just win rate

System Components

┌─────────────────────────────────────────────────────────────────┐
                         PQAP Main                               
                    (src/main.py - PQAP class)                   
├──────────────┬──────────────┬──────────────┬───────────────────┤
   Ingest       Strategies    Execution       Analytics      
                                                             
 - API Client  - Registry    - Paper       - Metrics         
 - Orderbooks  - Signals     - Live        - Calibration     
 - Markets     - Risk        - Tracking    - Backtesting     
└──────────────┴──────────────┴──────────────┴───────────────────┘
                                                  
                                                  
┌─────────────────────────────────────────────────────────────────┐
                        Data Layer                                
  - SQLite (market_history.db) - Historical snapshots             
  - SQLite (pqap_dev.db) - Trades, signals, strategy state        
└─────────────────────────────────────────────────────────────────┘

Directory Structure

polymarket/
├── src/
   ├── main.py              # Application entry point
   ├── core/                # Core infrastructure
      ├── config.py        # Configuration loading
      └── events.py        # Event bus for decoupled communication
   
   ├── ingest/              # Data ingestion
      ├── polymarket.py    # Polymarket API client
      └── orderbook.py     # Orderbook management
   
   ├── strategies/          # Trading strategies
      ├── base.py          # Base strategy class, Signal dataclass
      ├── registry.py      # Strategy discovery and management
      ├── arb_scanner.py   # Arbitrage opportunity scanner
      ├── dual_arb/        # Dual arbitrage strategy
      ├── momentum/        # Momentum strategy
      └── value_bet/       # Value betting strategy
   
   ├── execution/           # Order execution
      ├── engine.py        # Live execution engine
      └── paper_trading.py # Paper trading simulation
   
   ├── risk/                # Risk management
      └── engine.py        # Risk checks and kill switch
   
   ├── tracking/            # P&L and attribution
      ├── attribution.py   # Strategy attribution
      └── storage.py       # Database storage
   
   ├── analytics/           # Performance analytics
      ├── metrics.py       # Strategy metrics, Sharpe, Kelly, etc.
      └── resolution_tracker.py  # Outcome tracking
   
   ├── backtest/            # Backtesting framework
      ├── engine.py        # Backtest execution
      ├── simulator.py     # Market simulation
      └── cli.py           # Command-line interface
   
   ├── data/                # Data collection
      └── collector.py     # Historical data capture
   
   ├── admin/               # Web admin interface
      ├── api.py           # REST API and web UI
      └── controller.py    # Strategy control
   
   └── alerts/              # Alerting
       └── telegram.py      # Telegram notifications

├── configs/                 # Configuration files
   ├── dev.yaml             # Development config
   └── prod.yaml            # Production config

├── data/                    # Data storage
   ├── market_history.db    # Historical market snapshots
   └── pqap_dev.db          # Trading state

└── deploy/                  # Deployment
    ├── Dockerfile
    └── docker-compose.yaml

Data Flow

1. Market Data Ingestion

Polymarket API → PolymarketClient → Markets cache → Strategies
                      ↓
              DataCollector → market_history.db

2. Signal Generation

Market Update → Strategy.on_orderbook_update() → Signal
                                                    ↓
                                              Risk Check
                                                    ↓
                                    ┌───────────────┴───────────────┐
                                    ▼                               ▼
                              Paper Trade                      Live Trade
                                    ↓                               ↓
                              PaperTradingEngine              ExecutionEngine

3. Performance Tracking

Trades → AttributionTracker → MetricsStorage → PerformanceReport
                                    ↑
              ResolutionTracker ────┘
               (market outcomes)

Key Classes

Signal (src/strategies/base.py)

The core data structure for trading decisions:

@dataclass
class Signal:
    strategy_id: str
    market_id: str
    signal_type: SignalType  # BUY, SELL, HOLD
    confidence: float        # 0.0 to 1.0
    size_suggestion: Decimal # Fraction of capital
    # ... other fields

Strategy (src/strategies/base.py)

Abstract base for all strategies:

class Strategy(ABC):
    @abstractmethod
    def on_orderbook_update(self, market: Market) -> Signal | None:
        """Process market update, optionally return signal."""
        pass

    @abstractmethod
    def on_trade_executed(self, trade: dict) -> None:
        """Handle trade execution notification."""
        pass

BacktestEngine (src/backtest/engine.py)

Runs strategies against historical data:

engine = BacktestEngine("data/market_history.db")
result = engine.run(
    strategy=my_strategy_function,
    start_date=datetime(2024, 1, 1),
    end_date=datetime(2024, 6, 1)
)
print(result.summary())

Finding Real Edge

The key insight: most trading strategies fail because they fit noise, not signal.

The Edge Validation Process

  1. Collect Data
  2. Run the system to accumulate market snapshots
  3. More data = more reliable backtests

  4. Backtest Strategies bash python -m src.backtest.cli momentum --verbose

  5. Check Calibration

  6. Are 70% confidence predictions winning ~70% of the time?
  7. Use CalibrationAnalyzer to verify

  8. Measure Expected Value

  9. Positive EV = edge
  10. Negative EV = no edge, don't trade

  11. Paper Trade

  12. Validate in real-time without risking capital
  13. Watch for execution slippage

  14. Scale Carefully

  15. Use Kelly criterion for position sizing
  16. Start with Kelly/4 or Kelly/2

Key Metrics

Metric Good Value Meaning
Expected Value > $0 Average profit per trade
Win Rate > 50% Percentage of winning trades
Profit Factor > 1.5 Gross profit / gross loss
Sharpe Ratio > 1.0 Risk-adjusted returns
Kelly Fraction > 0 Optimal bet size (edge exists)
Brier Score < 0.20 Prediction accuracy
ECE < 0.10 Calibration error

Configuration

configs/dev.yaml

env: dev
initial_capital: 100  # Small for testing

enabled_strategies:
  - dual_arb_v1
  - momentum_v1
  - value_bet_v1

risk_limits:
  max_capital_per_market: 0.15
  daily_loss_limit: 0.15
  max_open_positions: 20

strategies:
  momentum_v1:
    parameters:
      lookback_periods: 6
      min_momentum: 0.02

Admin Interface

Access at http://localhost:8080

Page URL Purpose
Dashboard / Strategy overview and controls
Markets /markets Market prices and arb opportunities
Signals /signals Signal generation history
Paper Trading /paper Simulated positions and P&L
P&L Report /pnl Performance attribution
Backtest /backtest Historical data status

API Endpoints

Endpoint Method Purpose
/health GET Health check
/api/status GET System status
/api/strategies GET List all strategies
/api/strategies/{id}/enable POST Enable strategy
/api/strategies/{id}/disable POST Disable strategy
/api/signals GET Recent signals
/api/trades GET Recent trades
/api/pnl GET P&L data
/api/backtest/stats GET Historical data stats

Extending the System

Adding a New Strategy

  1. Create directory: src/strategies/my_strategy/
  2. Create __init__.py with strategy class
  3. Extend Strategy base class
  4. Implement on_orderbook_update() and on_trade_executed()
  5. Add to registry in src/strategies/registry.py
  6. Enable in config: enabled_strategies: [my_strategy_v1]

Adding New Data Sources

  1. Add collector method to src/data/collector.py
  2. Create corresponding table in database schema
  3. Call from data collection loop in src/main.py

Database Schema

market_history.db

  • market_snapshots - Point-in-time market prices
  • market_resolutions - Market outcome resolutions
  • orderbook_snapshots - Orderbook depth data
  • price_history - Price timeseries from API

pqap_dev.db

  • signals - Generated trading signals
  • trades - Executed trades
  • strategy_state - Strategy configuration
  • collection_stats - Data collection metadata

Known Limitations

  1. No True Arbitrage: YES + NO always = 1.00 on Polymarket (no simple arb)
  2. API Rate Limits: Live trading limited by Polymarket API
  3. Resolution Delay: Market outcomes take time to confirm
  4. Liquidity: Small markets may have high slippage

Future Directions

  1. More Data Sources: External news, sentiment, related markets
  2. ML Models: Trained on historical resolution data
  3. Multi-Market Correlations: Find cross-market inefficiencies
  4. Automated Rebalancing: Dynamic position management

System Overview

Polymarket API

Market data source

Data Collector

Every 5 minutes

SQLite Database

Price history + trades

Strategy Engine

Signal generation

ML Model

XGBoost (72% acc)

Execution Engine

Paper trading

Dashboard

You are here!

Telegram

Alerts & updates

Trading Strategies

Each strategy looks for different market inefficiencies:

Dual Arbitrage Active

Finds when YES + NO prices don't add to 100%. Risk-free profit.

Mean Reversion Active

Buys when price drops too far from average, sells when it recovers.

Market Maker Active

Places bid/ask orders to capture the spread.

Time Arbitrage Active

Exploits predictable price patterns at certain hours.

ML Prediction Active

Uses machine learning to predict 6-hour price direction.

Value Betting Disabled

Finds underpriced outcomes based on implied probability.

Data Storage (Single Source of Truth)

All data lives on EC2. Local machines are for development only. The EC2 instance is the authoritative source for all market data, trades, and positions.
Database Purpose Location
market_history.db Price snapshots every 5 minutes (8.2 MB) EC2 (primary)
pqap_prod.db Trades, positions, P&L history EC2 (primary)
paper_trading_state.json Current portfolio state EC2 (primary)

Environment Architecture

EC2 (Production)

  • Runs 24/7
  • All databases live here
  • Executes all trades
  • Single source of truth

Local (Development)

  • For code changes only
  • Syncs code to EC2
  • No production data
  • Can be turned off

Environment Details

Component Details
Dashboard URL https://pqap.tailwindtech.ai
Server AWS EC2 (us-east-1)
SSL Let's Encrypt via Traefik
Mode Paper Trading (simulated)

How It Works (Simple Version)

1. Data Collection: Every 5 minutes, we fetch prices from Polymarket for 50 markets and save them to our database.

2. Analysis: Our strategies analyze this data looking for patterns - like prices that moved too far from normal, or markets where the math doesn't add up.

3. Signals: When a strategy finds an opportunity, it generates a "signal" - a recommendation to buy or sell.

4. Execution: The execution engine takes these signals and simulates trades (paper trading). Eventually, this will place real orders.

5. Monitoring: This dashboard shows you what's happening. Telegram sends alerts for important events.