Skip to content

Ito-Markets/basket-trader

Repository files navigation

Itô Markets - Prediction Market Trading Platform

Trade custom prediction market baskets across Polymarket and Kalshi with a single click. Built with Flask, deployed on Railway, featuring a complete REST API, API key management, and real-time price tracking.

Itô Markets

Features

Core Trading

  • Custom Baskets: Define multi-leg trades spanning both platforms
  • One-Click Execution: Bid YES or NO on entire baskets
  • Dual Platform Support: Polymarket (crypto) + Kalshi (regulated)
  • Weighted Allocation: Automatically split capital across legs
  • Real-time Price Tracking: Automatic price snapshots and history

Basket Creation V2 (NEW)

  • 18 System Baskets: Pre-built risk factor baskets (Energy, Politics, Commodities, etc.)
  • Automated Categorization: 10-stage ML pipeline for market classification
  • 70+ Risk Factors: Comprehensive risk factor taxonomy
  • Market Builder UI: 2-column interface for admins and users

Basket Suggestions System (NEW)

  • User Suggestions: Regular users can suggest new baskets or modifications
  • Admin Review: Administrators review and approve/reject suggestions
  • Role-Based UI: Different interfaces for admins vs regular users

API & Developer Tools

  • REST API v1: Complete API with authentication
  • API Key Management: Secure API key generation and management
  • User Authentication: Flask-Login with persistent sessions
  • Responsive Design: Mobile-optimized interface

Architecture Overview

Itô Markets is a Flask-based web application with a modular architecture designed for scalability and maintainability. The application is deployed on Railway and uses PostgreSQL (via Neon) for production or SQLite for local development.

High-Level Architecture Diagram

graph TB
    subgraph "Client Layer"
        Browser[Web Browser]
        API_Client[API Clients<br/>Python/JavaScript]
    end

    subgraph "Vercel Serverless"
        subgraph "Flask Application (app.py)"
            Router[Flask Router]
            
            subgraph "Web Routes"
                Landing[Landing Page]
                Dashboard[Dashboard]
                MarketBuilder[Market Builder<br/>Role-Based UI]
                Baskets[Baskets Page]
                Profile[User Profile]
                Login[Auth Routes]
            end
            
            subgraph "API Routes (Blueprints)"
                CronBP[Cron Jobs<br/>/api/cron]
                PublicV1[Public API v1<br/>/api/v1]
                SuggestionsAPI[Suggestions API<br/>/api/suggestions]
                InternalAPI[Internal API<br/>/api/internal]
            end
        end
        
        subgraph "API Endpoints"
            BasketsAPI["/api/v1/baskets"]
            MarketsAPI["/api/v1/markets"]
            SuggestionsEndpoint["/api/suggestions/baskets"]
            APIKeysAPI["/api/internal/api-keys"]
            CronEndpoints["/api/cron/*"]
        end
        
        subgraph "Middleware"
            AuthMW[API Key Auth<br/>@require_api_key]
            SessionMW[Session Management<br/>Flask-Login]
            RoleCheck[Admin Role Check<br/>is_admin]
        end
        
        subgraph "V2 Services (Basket Creation Pipeline)"
            MarketFetchers[Market Fetchers<br/>Native Kalshi/Polymarket APIs]
            CategorizationSvc[Categorization Service<br/>10-Stage ML Pipeline]
            BasketMappingSvc[Basket Mapping Service<br/>70+ Risk Factors → 18 Baskets]
            MarketExpansionSvc[Market Expansion Service<br/>Categorical Expansion]
            SyncServiceV2[Sync Service<br/>2-Pass Add/Remove]
        end
        
        subgraph "Core Services"
            PriceService[Price Service<br/>Snapshots & Tracking]
            BackfillService[Backfill Service<br/>Historical Data]
        end
        
        subgraph "External APIs"
            PolymarketAPI[Polymarket<br/>CLOB API]
            KalshiAPI[Kalshi<br/>Trading API v2]
        end
    end

    subgraph "Data Layer"
        PostgreSQL[(PostgreSQL<br/>Neon/Vercel)]
    end

    subgraph "Database Models"
        UserModel[User<br/>is_admin flag]
        BasketModel[Basket]
        MarketModelV2[Market<br/>V2 fields: basket_name,<br/>risk_factor_id, direction]
        BasketSuggestionModel[BasketSuggestion<br/>pending/approved/rejected]
        BasketOverrideModel[BasketOverride<br/>Manual reassignments]
        TradeModel[Trade]
        APIKeyModel[APIKey]
        PriceHistory[BasketPriceHistory]
    end

    subgraph "GitHub Actions (Automation)"
        DailySync[Daily Market Sync<br/>2AM UTC]
        DBMigration[Database Migration<br/>Manual]
        GenerateBaskets[Generate System Baskets<br/>Manual]
        BackfillAll[Backfill All Baskets<br/>Manual]
        DeleteMarkets[Delete Market Data<br/>Manual + Confirm]
    end

    %% Client connections
    Browser --> Router
    API_Client --> AuthMW
    
    %% Router connections
    Router --> Landing
    Router --> Dashboard
    Router --> MarketBuilder
    Router --> Baskets
    Router --> Profile
    Router --> Login
    
    %% Middleware flow
    AuthMW --> PublicV1
    AuthMW --> InternalAPI
    SessionMW --> Router
    SessionMW --> SuggestionsAPI
    RoleCheck --> MarketBuilder
    RoleCheck --> SuggestionsAPI
    
    %% API routing
    PublicV1 --> BasketsAPI
    PublicV1 --> MarketsAPI
    SuggestionsAPI --> SuggestionsEndpoint
    InternalAPI --> APIKeysAPI
    CronBP --> CronEndpoints
    
    %% V2 Pipeline flow
    CronEndpoints --> SyncServiceV2
    SyncServiceV2 --> MarketFetchers
    MarketFetchers --> PolymarketAPI
    MarketFetchers --> KalshiAPI
    SyncServiceV2 --> CategorizationSvc
    CategorizationSvc --> BasketMappingSvc
    BasketMappingSvc --> MarketExpansionSvc
    
    %% Suggestions workflow
    MarketBuilder --> SuggestionsEndpoint
    SuggestionsEndpoint --> BasketSuggestionModel
    SuggestionsEndpoint --> BasketModel
    
    %% Service to DB connections
    BasketsAPI --> PriceService
    BasketsAPI --> BackfillService
    MarketsAPI --> MarketModelV2
    PriceService --> PriceHistory
    BackfillService --> PriceHistory
    SyncServiceV2 --> MarketModelV2
    MarketExpansionSvc --> MarketModelV2
    BasketMappingSvc --> BasketOverrideModel
    
    %% Database connections
    PostgreSQL --> UserModel
    PostgreSQL --> BasketModel
    PostgreSQL --> MarketModelV2
    PostgreSQL --> BasketSuggestionModel
    PostgreSQL --> BasketOverrideModel
    PostgreSQL --> TradeModel
    PostgreSQL --> APIKeyModel
    PostgreSQL --> PriceHistory
    
    %% GitHub Actions
    DailySync --> SyncServiceV2
    DBMigration --> PostgreSQL
    GenerateBaskets --> BasketModel
    GenerateBaskets --> MarketModelV2
    BackfillAll --> BackfillService
    DeleteMarkets --> MarketModelV2

    %% Styling
    style Browser fill:#4a9eff
    style API_Client fill:#4a9eff
    style PostgreSQL fill:#00d4aa
    style PolymarketAPI fill:#7c3aed
    style KalshiAPI fill:#f97316
    style MarketBuilder fill:#00d4aa
    style SuggestionsAPI fill:#00d4aa
    style BasketSuggestionModel fill:#fbbf24
    style BasketOverrideModel fill:#fbbf24
    style MarketModelV2 fill:#fbbf24
Loading

Directory Structure

CB_Pred2/
 app.py                          # Main Flask application
 api/                            # API layer
    index.py                    # Vercel serverless entry point
    middleware/                 # API middleware
       __init__.py
       api_key_auth.py        # API key authentication decorators
    routes/                     # Route blueprints
       cron.py                 # Cron job endpoints
       internal/               # Internal API routes
          api_keys.py        # API key management
       v1/                     # Public API v1 routes
           baskets.py          # Basket endpoints
           markets.py          # Market search endpoints
    services/                   # Business logic services
       price_service.py        # Price fetching and snapshots
       sync_service.py         # Market data synchronization
       backfill_service.py     # Historical price data backfill
    utils/                      # API utilities
        responses.py            # Standardized API responses
 models/                         # Database models
    __init__.py                 # Model exports
    models.py                   # Core models (User, Basket, Trade, Market, etc.)
    api_key.py                  # APIKey model
 templates/                      # Jinja2 templates
    index.html                  # Baskets page
    api_docs.html               # API documentation
    dashboard.html              # Dashboard
    landing.html                # Landing page
    profile.html                # User profile
    login.html                  # Login page
    developer_portal/
        api_keys.html           # API key management UI
 scripts/                        # Standalone scripts (GitHub Actions)
    export_all_markets.py       # Export all markets to CSV
    backfill_history.py         # Backfill historical price data
 config/                         # Configuration
    settings.py                 # App settings
 .github/workflows/              # GitHub Actions workflows
 vercel.json                     # Vercel deployment config
 requirements.txt                # Python dependencies

API Architecture

Public API v1 (/api/v1)

RESTful API for external consumers with API key authentication:

Endpoints:

  • GET /api/v1/baskets - List all baskets (paginated)
  • GET /api/v1/baskets/{id} - Get basket details
  • GET /api/v1/baskets/{id}/price - Get current basket price
  • POST /api/v1/baskets/{id}/backfill - Manually trigger historical backfill for a basket
  • GET /api/v1/markets/search - Search markets across platforms

Authentication:

  • Bearer token authentication using API keys
  • Scopes: baskets:read, baskets:write, markets:read, trades:read

Internal API (/api/internal)

Internal endpoints for authenticated web users (session-based):

Endpoints:

  • GET /api/internal/api-keys - List user's API keys
  • POST /api/internal/api-keys - Create new API key
  • DELETE /api/internal/api-keys/{id} - Revoke API key
  • GET /api/internal/api-keys/{id}/usage - Get API key usage stats

Cron Jobs (/api/cron)

Scheduled tasks for data synchronization:

Endpoints:

  • POST /api/cron/sync-markets - Sync market data from external APIs
  • POST /api/cron/record-prices - Record price snapshots for baskets

Trigger:

  • Vercel Cron Jobs (configured in vercel.json)
  • Or manual triggers via GitHub Actions

Database Models

Core Models (models/models.py)

  • User: User accounts with authentication

    • Fields: id, username, email, password_hash, is_admin, created_at
  • Basket: Custom prediction market baskets

    • Fields: id, name, description, user_id, underlyers_count, created_at
    • Relationships: prices (BasketPriceHistory), trades (Trade)
  • Market: Individual markets from Polymarket/Kalshi

    • Fields: id, platform, market_id, ticker, name, category, expiration, created_at
    • Indexed by platform and market_id/ticker
  • BasketPriceHistory: Historical price snapshots

    • Fields: id, basket_id, price, timestamp
    • Used for price tracking and analytics
  • Trade: User trade history

    • Fields: id, user_id, basket_id, direction, amount, status, created_at
  • UserAPIKeys: User's API keys for Polymarket/Kalshi

    • Fields: user_id, platform, key_data (encrypted), demo_mode

API Models (models/api_key.py)

  • APIKey: Public API keys for external consumers
    • Fields: id, user_id, key_hash, key_prefix, name, scopes, rate_limit_per_hour, last_used_at, total_requests, created_at, expires_at
    • Methods: generate_key(), verify_key(), has_scope()

V2 Models (models/models.py)

  • BasketOverride: Manual market-to-basket reassignments

    • Fields: id, market_id, original_basket_name, override_basket_name, reason, created_by, created_at
    • Indexed by market_id for fast lookups
  • BasketSuggestion: User suggestions for baskets

    • Fields: id, suggestion_type, suggested_name, suggested_description, suggested_legs, target_basket_id, markets_to_add, markets_to_remove, suggested_by, status, reviewed_by, reviewed_at, admin_notes, created_at
    • Status values: pending, approved, rejected

Services Layer

Price Service (api/services/price_service.py)

Handles basket price calculations and snapshots:

  • calculate_basket_price(basket_id): Calculate current basket price from market prices
  • record_price_snapshot(basket_id): Record price snapshot to history
  • get_latest_price(basket_id): Get most recent price snapshot

Sync Service (api/services/sync_service.py)

Synchronizes market data from external APIs:

  • sync_markets(platform): Sync markets from Polymarket/Kalshi via Dome API
  • update_market_prices(): Update current market prices
  • Uses Dome API SDK for unified market search across platforms

Backfill Service (api/services/backfill_service.py)

Backfills historical price data for baskets using Dome API:

  • backfill_basket_history(basket, days=365): Backfill historical data for a single basket
  • get_kalshi_history(ticker, days): Fetch historical trades from Kalshi via Dome API
  • get_polymarket_history(token_id, days): Fetch historical orders from Polymarket via Dome API
  • aggregate_to_daily(trades): Aggregate trades to daily average prices
  • Automatic Backfill: Automatically triggers when a basket is created (365 days of history)
  • Manual Backfill: Can be triggered via API endpoint or script
  • Uses Dome API for historical data retrieval

Middleware

API Key Authentication (api/middleware/api_key_auth.py)

Decorators for API route protection:

  • @require_api_key: Require valid API key
  • @require_read_key: Require key with read scopes
  • @require_write_key: Require key with write scopes

Validates API keys, checks scopes, and tracks usage statistics.

Authentication & Authorization

Web UI (Session-Based)

  • Flask-Login: Session-based authentication for web users
  • Session Duration: 30 days (persistent sessions)
  • Password Hashing: Secure password hashing for user accounts
  • Routes: /login, /register, /logout, /profile

API (Key-Based)

  • API Keys: Bearer token authentication (Authorization: Bearer {key})
  • Key Format: bkt_live_{random} or bkt_test_{random}
  • Key Storage: Hashed in database (SHA-256)
  • Key Scopes: Fine-grained permissions (read/write per resource)
  • Rate Limiting: Per-key rate limits (configurable per hour)

Deployment

Vercel Serverless

The application is deployed on Vercel as serverless functions:

Configuration (vercel.json):

  • Serverless function routing for Flask app
  • Cron job schedules for background tasks
  • Environment variable configuration

Key Features:

  • Automatic HTTPS
  • Global CDN
  • Serverless scaling
  • Cron job support

Database:

  • Production: PostgreSQL (Neon or Vercel Postgres)
  • Local: SQLite (instance/basket_trader.db)

Environment Variables

Required environment variables:

# Flask
SECRET_KEY=your-secret-key-here

# Database (Production)
DATABASE_URL=postgresql://user:pass@host:port/dbname

# Dome API (Optional - has default)
DOME_API_KEY=your-dome-api-key

# Vercel
VERCEL=1  # Automatically set by Vercel

Local Development

# Install dependencies
pip install -r requirements.txt

# Set environment variables
export SECRET_KEY=dev-secret-key
# Optional: export DATABASE_URL for PostgreSQL

# Run Flask app
python app.py

# App runs on http://localhost:5000

Background Jobs

Automatic Backfill on Basket Creation

When a new basket is created, historical price data is automatically backfilled:

  • Trigger: Automatically triggered when save_basket_to_db() is called
  • Duration: Defaults to 365 days of historical data
  • Non-blocking: Backfill runs asynchronously - basket creation succeeds even if backfill fails
  • Service: Uses api/services/backfill_service.py for backfill logic
  • Data Source: Dome API (Kalshi trades and Polymarket orders)

Manual Backfill

Basket history can be manually backfilled via:

  1. API Endpoint: POST /api/v1/baskets/{basket_id}/backfill?days=365

    • Authentication: API Key (baskets:read scope)
    • Query Parameter: days (default: 365)
    • Returns: Number of snapshots created
  2. Script: scripts/backfill_history.py

    • Scheduled: Manual trigger via GitHub Actions
    • Processes: All baskets or individual basket via service

GitHub Actions

Long-running tasks that exceed Vercel's function timeout:

Scripts:

  • scripts/export_all_markets.py: Export all markets to CSV

    • Scheduled: Manual trigger or weekly
    • Output: CSV files in bin/ directory
  • scripts/backfill_history.py: Backfill historical price data for all baskets

    • Scheduled: Manual trigger via GitHub Actions
    • Uses: api/services/backfill_service.py for individual basket backfill
    • Processes: Historical price snapshots from database

Workflows:

  • .github/workflows/export_markets.yml: Export markets workflow
  • .github/workflows/backfill_history.yml: Backfill history workflow (all baskets)

Vercel Cron Jobs

Short-running scheduled tasks (configured in vercel.json):

  • Record Prices: Periodic price snapshots for baskets (every minute)

GitHub Actions Workflows

Automated workflows for backend operations:

Workflow Trigger Description
daily-market-sync.yml Daily 2AM UTC Add new markets (no deletions)
db-migration.yml Manual Apply SQL migration files
delete-market-data.yml Manual Delete all markets (with confirmation)
generate-system-baskets.yml Manual Create 18 system baskets
backfill_all_baskets.yml Manual Backfill historical prices
backfill_history.yml Manual Backfill individual basket
export_markets.yml Manual Export market data to CSV

Required GitHub Secrets

DATABASE_URL=postgresql://...
KALSHI_API_KEY=your-kalshi-key
SECRET_KEY=your-flask-secret
CRON_SECRET=your-cron-secret

External Integrations

Polymarket

  • API: CLOB (Central Limit Order Book) API
  • Client: py-clob-client (official Python client)
  • Auth: EIP-712 signed messages
  • Network: Polygon (Chain ID: 137)
  • Currency: USDC

Kalshi

  • API: Trading API v2
  • Auth: RSA/Ed25519 signed requests
  • Environments: Demo (demo-api.kalshi.co) and Production (api.elections.kalshi.com)
  • Regulation: CFTC-regulated (US available)

Dome API

  • Purpose: Unified market search across Polymarket and Kalshi
  • SDK: dome_api_sdk Python package
  • Features: Market search, filtering, category browsing

API Documentation

Interactive API documentation is available at /api-docs:

  • Comprehensive endpoint documentation
  • Interactive "Try it out" functionality
  • Code examples in Python, JavaScript, and cURL
  • Authentication guide
  • Response format documentation

Security

Web Application

  • Session Security: HTTPOnly, Secure (HTTPS), SameSite cookies
  • Password Hashing: Secure password hashing (Flask security)
  • CSRF Protection: SameSite cookie policy
  • XSS Prevention: Template escaping (Jinja2)

API Security

  • API Key Hashing: Keys stored as SHA-256 hashes
  • Key Prefixes: Only key prefix visible (e.g., bkt_live_abc...)
  • Scope Validation: Fine-grained permission checks
  • Rate Limiting: Per-key rate limits (prevent abuse)

Data Protection

  • Encryption: User API keys encrypted in database (UserAPIKeys)
  • No Key Exposure: Full API keys only shown once on creation
  • Audit Logging: API key usage tracking (last_used_at, total_requests)

Development

Project Setup

# Clone repository
git clone <repository-url>
cd CB_Pred2

# Create virtual environment
python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install -r requirements.txt

# Set up environment variables
cp .env.example .env  # Create .env file with your config

# Initialize database (SQLite for local dev)
python -c "from app import app, db; app.app_context().push(); db.create_all()"

# Run development server
python app.py

Running Tests

# Run tests (when test suite is added)
pytest

# Run with coverage
pytest --cov=.

Code Structure Guidelines

  • Routes: Keep route handlers thin, delegate to services
  • Services: Business logic and external API interactions
  • Models: Database models and relationships
  • Middleware: Reusable decorators and request handlers
  • Utils: Helper functions and utilities

Detailed Documentation

For more detailed implementation guides, see the docs/ folder:

Things Done

January 18, 2025

API System Created

  • Complete REST API v1: Public API with API key authentication
    • /api/v1/baskets - List and retrieve baskets
    • /api/v1/baskets/{id}/price - Get basket prices
    • /api/v1/markets/search - Market search across platforms
  • Internal API: Session-based API for authenticated users
    • /api/internal/api-keys - API key management (CRUD operations)
  • API Key Management: Secure API key generation, hashing, and scope-based permissions
  • Interactive Documentation: Comprehensive API docs at /api-docs with "Try it out" functionality

Code Structure Reorganization

  • Modular Architecture: Reorganized codebase into clear layers
    • api/routes/ - Route blueprints (v1, internal, cron)
    • api/services/ - Business logic services (price, sync)
    • api/middleware/ - Authentication and request middleware
    • models/ - Database models (separated from app.py)
    • scripts/ - Standalone scripts for GitHub Actions
  • Separation of Concerns: Clear separation between routes, services, and data access
  • Blueprint-Based Routes: Flask blueprints for better organization

UI Improvements

  • Responsive Design: Fully responsive across all pages (mobile, tablet, desktop)
  • Navigation Enhancement: Consistent left sidebar navigation across main pages
  • API Documentation Page: Professional, interactive API documentation
  • Developer Portal: API key management UI integrated with site design
  • Session Management: Improved session persistence (30-day sessions)
  • Auto-login: Automatic login redirect for authenticated users

Market Database & Filtering

  • Database-Backed Markets: Markets stored in database instead of real-time API calls
  • Market Model: Comprehensive Market model with platform, ticker, metadata
  • Market Synchronization: Automated sync service (sync_service.py) to update markets from external APIs
  • Efficient Filtering: Fast database queries for market search and filtering
  • Market History: Track market additions and updates over time
  • Category Organization: Markets organized by category for easy filtering

Database-First Market Access

  • Performance Optimization: Markets served from database instead of external API calls
  • Reduced Latency: Faster market search and retrieval
  • Offline Capability: Markets available even when external APIs are slow/unavailable
  • Cron-Based Updates: Automated market updates via cron jobs
  • Data Consistency: Single source of truth for market data

Automatic Historical Backfill System

  • Backfill Service: Centralized api/services/backfill_service.py for historical price data backfill
  • Automatic Trigger: Historical data automatically backfilled when baskets are created (365 days)
  • Manual Backfill API: New endpoint POST /api/v1/baskets/{id}/backfill for manual backfill triggers
  • Reusable Logic: Backfill logic extracted from script into reusable service module
  • Non-blocking: Backfill doesn't block basket creation - failures are logged but don't affect basket creation
  • Dome API Integration: Uses Dome API for historical Kalshi trades and Polymarket orders
  • Daily Aggregation: Historical trades/orders aggregated to daily average prices

License

MIT

Support

For issues, questions, or contributions, please open an issue on GitHub.

About

Institutional prediction market trading platform. Cross-exchange execution across Polymarket & Kalshi.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors