Institutional-grade quantitative analytics platform for Polymarket prediction markets
Polymetrics is a production-ready, full-stack analytics platform built for quantitative analysis of Polymarket trading behavior. Designed with institutional standards in mind, it provides comprehensive performance metrics, risk assessment, behavioral classification, and real-time trader discovery for prediction market participants.
Live Demo: View Screenshots | GitHub: LiamX-Labs/polymetrics
Polymetrics bridges the gap between raw prediction market data and actionable trading intelligence. The platform automatically discovers, analyzes, and tracks top-performing wallets across 10+ market categories, providing institutional investors with the quantitative metrics and risk analytics needed for informed decision-making in the rapidly growing prediction markets sector.
- Data-Driven Decision Making: Transform blockchain data into actionable trading intelligence
- Risk Management: Comprehensive drawdown analysis, Sharpe ratios, and position-level risk metrics
- Trader Discovery: Automated identification of emerging top performers across multiple verticals
- Institutional Quality: Production-ready architecture with proper caching, threading, and error handling
- Scalable Design: PostgreSQL-ready schema, background processing, and multi-layer caching
- Real-time Leaderboard Integration: Live sync with Polymarket's official leaderboard API across 10+ market categories
- Quantitative Performance Metrics: Win rate, profit factor, risk-reward ratio, Sharpe ratio, maximum drawdown, and ROI analysis
- Behavioral Classification: Rule-based trading style identification (HFT, Active, Normal trader categories)
- Automated Wallet Discovery: Background scheduler continuously identifies and analyzes emerging top performers
- Comparative Analytics: Side-by-side wallet comparison with statistical analysis
- Historical Tracking: Position-level granularity with timestamp-accurate P&L calculations
- Interactive Visualizations: 10+ chart types with Plotly.js for comprehensive data exploration
- API-First Design: RESTful endpoints for programmatic access and integration
Backend:
- Framework: Flask 3.0+ with Blueprint architecture for modular routing
- ORM: SQLAlchemy 2.0+ with declarative models and relationship management
- Database: SQLite (development) with PostgreSQL-ready schema design
- Data Processing: Pandas & NumPy for vectorized operations and statistical calculations
- Background Tasks: Threading-based scheduler with daemon workers and semaphore control
- Caching: Multi-layer in-memory caching with TTL expiration and MD5 key hashing
- Session Management: Scoped sessions with proper lifecycle and connection pooling
Frontend:
- Templating: Jinja2 with template inheritance and modular components
- Visualization: Plotly.js for interactive, production-grade charts
- Styling: Custom CSS with glassmorphism effects and gradient theming
- Responsive Design: Mobile-first approach with breakpoints for tablet/desktop
- UX: Tab navigation, real-time progress tracking, client-side pagination
APIs & Integration:
- Polymarket Data API: Position and trade history retrieval
- Polymarket CLOB API: Market metadata and pricing data
- Gamma API: Leaderboard rankings and trader discovery
- Pagination Handling: Automatic multi-page fetching with progress callbacks
- Rate Limiting: Client-side throttling and request timeout management
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Polymetrics Platform β
β Production-Grade Architecture β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββ βββββββββββββββββββ β
β β Web Frontend ββββββββββΊβ Flask App β β
β β (Responsive) β β (Blueprints) β β
β β β β β β
β β β’ Plotly Charts β β β’ Routes β β
β β β’ Real-time UI β β β’ Error Handler β β
β β β’ Mobile-first β β β’ CORS Config β β
β βββββββββββββββββββ ββββββββββ¬βββββββββ β
β β β
β βββββββββββββΌβββββββββββββ β
β β Services Layer β β
β ββββββββββββββββββββββββββ€ β
β β β’ Fetcher (API Client) β β
β β β’ Analyzer (Metrics) β β
β β β’ Leaderboard (Sync) β β
β β β’ Scheduler (Cron) β β
β β β’ Cache (TTL) β β
β βββββββββββββ¬βββββββββββββ β
β β β
β βββββββββββββββββββ βββββββββββββββΌββββββββββ βββββββββββββ β
β β Polymarket API βββββΊβ Database Layer β β Cache β β
β βββββββββββββββββββ€ βββββββββββββββββββββββββ€ βββββββββββββ€ β
β β β’ Data API β β β’ SQLAlchemy ORM β β β’ Memory β β
β β β’ CLOB API β β β’ 5 Normalized Models β β β’ TTL β β
β β β’ Gamma API β β β’ Indexed Queries β β β’ MD5 Key β β
β β β’ Pagination β β β’ Scoped Sessions β βββββββββββββ β
β βββββββββββββββββββ βββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Background Processing Layer β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β
β β β’ Threading: Daemon workers with semaphore control β β
β β β’ Scheduler: Hourly trader discovery & refresh β β
β β β’ Queue: asyncio.Queue for task distribution β β
β β β’ Progress Tracking: Real-time analysis status β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
5 Core Models with Strategic Indexing:
-- Wallet Model: Core trader analytics
CREATE TABLE wallets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
address VARCHAR(42) UNIQUE NOT NULL, -- Indexed for fast lookups
-- Performance Metrics
total_positions INTEGER,
total_pnl FLOAT, -- Indexed for rankings
win_rate FLOAT, -- Indexed for filtering
profit_factor FLOAT, -- Indexed for leaderboards
risk_reward_ratio FLOAT,
trading_style VARCHAR(50),
-- Statistical Aggregates
total_wins INTEGER,
total_losses INTEGER,
avg_win FLOAT,
avg_loss FLOAT,
best_trade FLOAT,
worst_trade FLOAT,
-- Volume & Sizing
avg_position_size FLOAT,
total_volume FLOAT,
-- Metadata
first_analyzed DATETIME,
last_analyzed DATETIME, -- For stale data refresh
is_active BOOLEAN DEFAULT TRUE
);
-- Position Model: Trade-level granularity
CREATE TABLE positions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
wallet_id INTEGER NOT NULL, -- Foreign key, indexed
-- Market Identifiers
condition_id VARCHAR(66), -- Indexed for market filtering
market_title TEXT,
event_slug VARCHAR(255),
-- Trade Details
outcome VARCHAR(10), -- YES/NO
side VARCHAR(10), -- BUY/SELL
avg_entry_price FLOAT,
exit_price FLOAT,
position_size FLOAT,
-- Performance
realized_pnl FLOAT, -- Indexed for sorting
roi FLOAT,
-- Execution
num_trades INTEGER,
open_timestamp DATETIME,
close_timestamp DATETIME, -- Indexed for time-series
end_date DATETIME,
FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE
);
-- Market Model: Aggregate market statistics
CREATE TABLE markets (
id INTEGER PRIMARY KEY AUTOINCREMENT,
condition_id VARCHAR(66) UNIQUE NOT NULL, -- Indexed
title TEXT,
event_slug VARCHAR(255),
end_date DATETIME,
category VARCHAR(50),
-- Aggregates
total_traders INTEGER,
total_volume FLOAT,
avg_pnl FLOAT,
created_at DATETIME,
updated_at DATETIME
);
-- WalletSnapshot Model: Historical tracking
CREATE TABLE wallet_snapshots (
id INTEGER PRIMARY KEY AUTOINCREMENT,
wallet_id INTEGER NOT NULL,
snapshot_date DATE,
-- Point-in-time metrics
total_positions INTEGER,
total_pnl FLOAT,
win_rate FLOAT,
profit_factor FLOAT,
FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE
);
-- LeaderboardCache Model: Performance optimization
CREATE TABLE leaderboard_cache (
id INTEGER PRIMARY KEY AUTOINCREMENT,
metric_name VARCHAR(50), -- Indexed
wallet_address VARCHAR(42),
metric_value FLOAT,
rank INTEGER, -- Indexed
updated_at DATETIME
);Strategic Indexes:
CREATE INDEX idx_wallet_address ON wallets(address);
CREATE INDEX idx_wallet_pnl ON wallets(total_pnl);
CREATE INDEX idx_wallet_winrate ON wallets(win_rate);
CREATE INDEX idx_wallet_profit_factor ON wallets(profit_factor);
CREATE INDEX idx_position_wallet_id ON positions(wallet_id);
CREATE INDEX idx_position_condition_id ON positions(condition_id);
CREATE INDEX idx_position_pnl ON positions(realized_pnl);
CREATE INDEX idx_position_timestamp ON positions(close_timestamp);
CREATE INDEX idx_market_condition_id ON markets(condition_id);
CREATE INDEX idx_leaderboard_metric ON leaderboard_cache(metric_name);
CREATE INDEX idx_leaderboard_rank ON leaderboard_cache(rank);win_rate = (winning_positions / total_positions) * 100Interpretation: Percentage of positions closed with positive P&L. Industry benchmark: >50% for profitable traders.
profit_factor = total_profits / abs(total_losses)Interpretation: Ratio of gross profits to gross losses. Values >1.0 indicate net profitability, >2.0 is excellent.
risk_reward_ratio = average_win / abs(average_loss)Interpretation: Average winning trade size relative to average losing trade. Values >1.2 indicate good risk management.
sharpe_ratio = mean(position_returns) / std(position_returns)Interpretation: Risk-adjusted return metric normalized by volatility. >1.0 is good, >2.0 is excellent.
max_drawdown = max(peak_value - trough_value) / peak_value * 100Interpretation: Largest peak-to-trough decline in portfolio value. Lower is better; <-20% is acceptable.
roi = (exit_price - entry_price) / entry_price * 100 # Per positionInterpretation: Return on investment for each position. Aggregated into histogram for distribution analysis.
HFT Detection (High-Frequency Trading):
# 4-hour window analysis
trades_per_hour = total_trades / (last_trade - first_trade).hours
is_hft = trades_per_hour > 10 # >10 trades/hour thresholdActivity Level:
if total_positions > 100:
activity = "Active Trader"
elif total_positions > 20:
activity = "Moderate Trader"
else:
activity = "Casual Trader"Trading Style Classification:
avg_hold_time = mean(close_timestamp - open_timestamp)
if avg_hold_time < 1 day and win_rate > 50%:
style = "Scalper"
elif avg_hold_time < 3 days:
style = "Day Trader"
elif 3 days <= avg_hold_time <= 14 days and risk_reward > 1.2:
style = "Swing Trader"
else:
style = "Position Trader"Hourly PnL Heatmap (24-hour UTC):
hourly_pnl = positions.groupby(
positions['close_timestamp'].dt.hour
)['realized_pnl'].sum()Market Preference Detection:
outcome_pnl = {
'YES': positions[positions['outcome'] == 'YES']['realized_pnl'].sum(),
'NO': positions[positions['outcome'] == 'NO']['realized_pnl'].sum()
}
# Identifies if trader has YES or NO biasPython 3.8+
pip or conda
Git- Clone the repository
git clone https://github.com/LiamX-Labs/polymetrics.git
cd polymetrics- Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate- Install dependencies
pip install -r requirements.txt- Initialize database
python -c "from app.database import init_db; init_db()"- Run the application
python run.pyThe platform will be available at http://localhost:5000
Create a .env file (optional):
# Flask Configuration
FLASK_ENV=production
SECRET_KEY=your-secret-key-here
# Database
DATABASE_URL=sqlite:///polymetrics.db
# For PostgreSQL: DATABASE_URL=postgresql://user:pass@localhost/polymetrics
# Scheduler
SCHEDULER_ENABLED=true
SCHEDULER_INTERVAL_HOURS=1
# Cache
CACHE_DEFAULT_TTL=3600 # 1 hour
WALLET_CACHE_TTL=3600
# API
API_TIMEOUT=15
API_MAX_RETRIES=3Scheduler: Background tasks run hourly to:
- Discover new traders from leaderboards
- Auto-analyze top 10 new wallets
- Refresh stale data (>24h old)
- Clean up expired cache entries
polymetrics/
βββ app/
β βββ __init__.py # Flask app factory with Blueprint registration
β βββ database.py # Database initialization & session management
β βββ models.py # SQLAlchemy models (5 core models)
β β
β βββ routes/ # Blueprint route handlers
β β βββ __init__.py
β β βββ home.py # Homepage & leaderboard routes
β β βββ wallet.py # Wallet analysis routes
β β βββ api.py # RESTful API endpoints
β β βββ compare.py # Wallet comparison routes
β β
β βββ services/ # Business logic layer
β β βββ __init__.py
β β βββ fetcher.py # Polymarket API integration (3 endpoints)
β β βββ analyzer.py # Metrics calculation engine (40+ metrics)
β β βββ leaderboard_fetcher.py # Leaderboard API client (10 categories)
β β βββ scheduler.py # Background task scheduler (threading-based)
β β βββ cache.py # In-memory caching with TTL
β β
β βββ static/ # Static assets
β β βββ css/
β β β βββ polymetrics.css # Custom styling (glassmorphism theme)
β β βββ js/
β β β βββ charts.js # Plotly chart configurations
β β βββ images/
β β βββ logo2.jpg # Brand logo
β β
β βββ templates/ # Jinja2 templates
β βββ base.html # Base template with navigation & responsive CSS
β βββ index.html # Homepage dashboard with 5 leaderboards
β βββ leaderboard.html # Full leaderboard with category filters
β βββ wallet_detail.html # Comprehensive wallet analysis (10+ charts)
β βββ compare.html # Side-by-side wallet comparison
β βββ analyzing.html # Real-time progress tracker
β βββ error.html # Error handling page
β
βββ bot/ # Telegram bot integration (optional)
β βββ main.py # Bot entry point
β βββ handlers.py # Command handlers
β
βββ scripts/ # Utility scripts
β βββ seed_db.py # Database seeding
β βββ export_data.py # Data export utilities
β
βββ docs/ # Documentation (legacy files moved here)
β
βββ run.py # Application entry point
βββ requirements.txt # Python dependencies
βββ .env.example # Environment variable template
βββ .gitignore # Git ignore rules
βββ README.md # This file
Professional API client with production-ready features:
Features:
- Connection Pooling: Persistent session with keep-alive
- Automatic Pagination: Handles 50 items/page, fetches all pages
- Progress Callbacks: Real-time status updates for long operations
- Timeout Handling: 10-15 second request timeouts
- Error Recovery: Graceful degradation on API failures
- Rate Limiting: Client-side throttling to respect API constraints
- Incremental Updates: Cutoff timestamp filtering for efficiency
Key Methods:
# Fetch all closed positions for a wallet
positions = fetcher.get_all_closed_positions(
wallet_address="0x1234...",
cutoff_timestamp=None, # Optional: only fetch positions after this time
progress_callback=lambda p: print(f"Progress: {p}%")
)
# Fetch individual trades (1000/page, 3000 max)
trades = fetcher.get_all_trades(
wallet_address="0x1234...",
progress_callback=callback
)
# Get market metadata
market_info = fetcher.get_market_info(
condition_id="0xf29a..."
)API Endpoints Used:
- Data API:
https://data-api.polymarket.com - CLOB API:
https://clob.polymarket.com - Gamma API:
https://gamma-api.polymarket.com
Core analytics engine with Pandas/NumPy-powered calculations:
Features:
- 40+ Calculated Metrics: Comprehensive performance analysis
- Vectorized Operations: Pandas-based for speed (100-500 positions in <2 seconds)
- Statistical Aggregations: Mean, median, std dev, percentiles
- Time-Series Analysis: Cumulative PnL, drawdown curves
- Distribution Analysis: Histogram bins for ROI, position sizes, PnL
- Correlation Analysis: Entry price vs PnL, size vs PnL scatter plots
- Trading Style Classification: Rule-based behavioral categorization
- Chart Data Preparation: 10 visualization datasets for Plotly.js
Example Output:
{
"total_positions": 156,
"total_pnl": 12453.67,
"win_rate": 64.7,
"profit_factor": 2.34,
"risk_reward_ratio": 1.87,
"sharpe_ratio": 1.92,
"max_drawdown": -8.3,
"trading_style": "Swing Trader",
"activity_level": "Active Trader",
"is_hft": false,
"total_wins": 101,
"total_losses": 55,
"avg_win": 245.80,
"avg_loss": -131.50,
"best_trade": 1247.33,
"worst_trade": -823.12,
"avg_position_size": 487.92,
"total_volume": 76156.32,
"median_position_size": 350.00,
"avg_hold_time_hours": 47.3,
"median_roi": 8.2,
"positions": [
{
"market_title": "Will BTC hit $100k by EOY?",
"outcome": "YES",
"realized_pnl": 234.56,
"roi": 12.3,
"open_timestamp": "2024-01-15T10:30:00Z",
"close_timestamp": "2024-01-17T14:22:00Z"
}
// ... more positions
],
"charts": {
"cumulative_pnl": {
"timestamps": ["2024-01-15", "2024-01-17", ...],
"values": [234.56, 512.34, ...]
},
"win_loss_distribution": {
"labels": ["Wins", "Losses", "Breakeven"],
"values": [101, 55, 0]
},
"pnl_histogram": {
"bins": [-500, -400, -300, ...],
"counts": [2, 5, 8, ...]
},
"hourly_pnl": {
"hours": [0, 1, 2, ..., 23],
"pnl": [234.5, -45.2, 123.4, ...]
}
// ... 6 more chart datasets
}
}Integrates with Polymarket's official leaderboard API for trader discovery:
Supported Categories (10):
- OVERALL, POLITICS, SPORTS, CRYPTO, CULTURE
- MENTIONS, WEATHER, ECONOMICS, TECH, FINANCE
Time Periods:
- DAY (24 hours)
- WEEK (7 days)
- MONTH (30 days)
- ALL (all-time)
Key Methods:
# Fetch leaderboard rankings
traders = leaderboard_fetcher.get_leaderboard(
category='CRYPTO',
time_period='WEEK',
limit=50
)
# Discover all unique traders across categories
all_traders = leaderboard_fetcher.get_all_unique_traders()
# Returns: deduplicated list from OVERALL, POLITICS, SPORTS, CRYPTO
# Get top markets by volume
top_markets = leaderboard_fetcher.get_top_markets(limit=5)Response Fields:
{
"rank": 1,
"proxyWallet": "0x1234567890abcdef...",
"userName": "CryptoWhale",
"profileImage": "https://...",
"xUsername": "@cryptowhale",
"verifiedBadge": true,
"pnl": 12543.67,
"vol": 245678.90
}Automated data refresh system with threading-based concurrency:
Features:
- Daemon Threading: Non-blocking background execution
- Hourly Refresh Cycle: Configurable interval (default: 1 hour)
- Semaphore Control: Max 2 concurrent analyses to prevent resource exhaustion
- Queue-Based Processing: asyncio.Queue for task distribution
- Deduplication: Set-based tracking to prevent duplicate analyses
- Error Recovery: Exception handling with database rollback
- Graceful Shutdown: Thread join with timeout
- Heartbeat Logging: Loop counter for health monitoring
Operations:
- Trader Discovery Pipeline:
# Fetch from 4 key categories
categories = ['OVERALL', 'POLITICS', 'SPORTS', 'CRYPTO']
all_traders = []
for category in categories:
traders = leaderboard_fetcher.get_leaderboard(category, 'DAY', 50)
all_traders.extend(traders)
# Deduplicate by wallet address
unique_traders = {trader['proxyWallet']: trader for trader in all_traders}
# Sort by PnL descending
sorted_traders = sorted(unique_traders.values(), key=lambda x: x['pnl'], reverse=True)
# Auto-analyze top 10 new traders
for trader in sorted_traders[:10]:
if not exists_in_database(trader['proxyWallet']):
trigger_analysis(trader['proxyWallet'])- Stale Data Refresh:
# Find wallets not updated in 24 hours
stale_wallets = db.query(Wallet).filter(
Wallet.last_analyzed < datetime.utcnow() - timedelta(hours=24)
).limit(20).all()
# Trigger re-analysis
for wallet in stale_wallets:
trigger_analysis(wallet.address)- Database Maintenance:
# Remove positions older than 90 days (if needed)
cleanup_old_positions(days=90)
# Cleanup expired cache entries
cache.cleanup_expired()Concurrency Model:
# Semaphore for concurrency control
analysis_semaphore = asyncio.Semaphore(2) # Max 2 concurrent
async def analyze_with_limit(wallet_address):
async with analysis_semaphore:
await analyze_wallet(wallet_address)Multi-layer caching with TTL expiration:
Features:
- In-Memory Storage: Simple key-value store with expiration
- TTL Management: Configurable time-to-live per cache entry
- MD5 Key Hashing: For keys >200 characters
- Auto-Cleanup: Expired entry removal
- Progress Tracking: Separate cache for long-running operations
- Decorator Support: Function memoization via
@cacheddecorator
Cache Types:
- General Cache:
# Set with custom TTL
cache.set('wallet_0x1234', wallet_data, ttl=3600) # 1 hour
# Get with expiration check
data = cache.get('wallet_0x1234') # Returns None if expired
# Manual invalidation
cache.delete('wallet_0x1234')- Analysis Progress Cache:
# Track analysis progress
progress_tracker = get_analysis_progress()
progress_tracker.start('0x1234')
progress_tracker.update('0x1234', status='fetching', message='Fetching positions...', progress=25)
progress_tracker.complete('0x1234')
# Get progress
progress = progress_tracker.get('0x1234')
# Returns: {'status': 'analyzing', 'progress': 75, 'message': '...'}- Decorator-Based Caching:
@cached(ttl=3600, prefix='wallet')
def expensive_calculation(wallet_address):
# Cache key: MD5('wallet:0x1234...')
return perform_calculation(wallet_address)- Live Leaderboard Preview: Top 5 daily traders from Polymarket API
- Platform Statistics: Total wallets analyzed, positions tracked, volume processed
- Database Leaderboards: Top 10 by PnL, win rate, and profit factor
- Recently Analyzed: Latest wallet analyses with quick access
- One-Click Analysis: Analyze button for unanalyzed traders
- Verified Badges: Display verified traders with checkmark
- Profile Images: User avatars from Polymarket
Database Leaderboards β top performers by PnL, win rate, and profit factor:
- Category Filters: Dropdown for 10+ market categories
- Time Period Selection: Day/Week/Month/All-time toggle
- Live + Database Merge: Shows both Polymarket leaderboard and local analytics
- Sorting: Rank, PnL, volume, win rate, profit factor
- Search: Wallet address prefix matching
- Pagination: 50 traders per page with controls
4 Tab Navigation:
-
Overview Tab:
- Performance summary card (PnL, win rate, profit factor, Sharpe ratio)
- Trading style badge (Scalper/Day/Swing/Position)
- Activity level (HFT/Active/Moderate/Casual)
- Statistical metrics (avg win, avg loss, best/worst trade)
- Volume metrics (total volume, avg position size, median size)
-
Charts Tab (10 Interactive Visualizations):
- Cumulative PnL over time (line chart)
- Win/Loss/Breakeven distribution (donut chart)
- PnL distribution histogram
- ROI distribution histogram
- Position size distribution histogram
- Outcome performance (YES vs NO bar chart)
- Hourly PnL heatmap (24-hour UTC)
- Drawdown curve (line chart)
- Entry price vs PnL scatter (correlation)
- Position size vs PnL scatter (sizing effectiveness)
-
Top Trades Tab:
- Best 10 trades (highest PnL)
- Worst 10 trades (lowest PnL)
- Trade details: market, outcome, entry/exit price, ROI, duration
-
All Positions Tab:
- Paginated table (50 rows/page)
- Sortable columns (PnL, ROI, date, market)
- Search/filter by market title
- Color-coded PnL (green positive, red negative)
- Timestamp display (human-readable)
- Side-by-Side Metrics: Compare any two wallets
- Performance Delta: Absolute and percentage differences
- Visual Indicators: Green/red for better/worse
- Chart Overlay: Dual-axis PnL comparison
- Statistical Significance: p-values for metric differences (planned feature)
Breakpoints:
- Mobile: max-width 768px (stacked layouts, hidden splash, horizontal scroll tables)
- Tablet: 769px - 1024px (adjusted spacing, grid layouts)
- Desktop: >1024px (full-width layouts, side-by-side components)
Features:
- Touch-friendly buttons (min 44px height/width)
- Horizontal scroll for tables with
-webkit-overflow-scrolling: touch - Collapsible navigation on mobile
- Responsive grid layouts (CSS Grid with auto-fit)
- Optimized font sizes (rem-based scaling)
GET / # Homepage dashboard
GET /leaderboard # Full leaderboard with filters
GET /wallet/<address> # Wallet detail page
GET /compare # Wallet comparison tool
GET /api/wallet/<address>
# Returns: Wallet metadata and performance metrics
GET /api/wallet/<address>/positions
# Returns: Array of position objects with pagination
# Query params: ?limit=50&offset=0
GET /api/leaderboard?metric=<metric>
# Returns: Ranked wallets by specified metric
# Metrics: pnl, win_rate, profit_factor, volume
# Query params: ?metric=pnl&limit=50
GET /api/search?q=<query>
# Returns: Wallets matching address prefix
# Example: ?q=0x1234 returns all addresses starting with 0x1234
GET /api/stats
# Returns: Platform statistics
# Response: {total_wallets, total_positions, total_volume, total_pnl}
POST /api/analyze?address=<address>
# Triggers background wallet analysis
# Returns: Redirect to /wallet/<address> with progress tracking
GET /api/analysis-progress/<address>
# Returns: Real-time analysis progress
# Response: {status, progress, message, total_positions}
# Status: 'fetching', 'analyzing', 'saving', 'complete', 'error'
API Features:
- CORS-Enabled: Cross-origin requests allowed for external integrations
- JSON Responses: Proper Content-Type headers
- HTTP Status Codes: 200 (success), 404 (not found), 500 (error)
- Error Messages: User-friendly error descriptions
- Pagination Support: limit/offset parameters
- Query Filtering: Metric-based, time-based, text-based
- Idempotency: GET requests are idempotent and cacheable
Input Validation:
# Address format validation
if not address.startswith('0x') or len(address) != 42:
return jsonify({'error': 'Invalid Ethereum address format'}), 400
# Lowercase normalization
address = address.strip().lower()
# SQL injection prevention (parameterized queries)
wallet = db.query(Wallet).filter_by(address=address).first()API Security:
- No authentication required (public data only)
- Client-side rate limiting via cache
- Request timeouts (10-15 seconds) prevent hanging
- CORS configuration with explicit origin control
- Error sanitization (no sensitive data in responses)
Infrastructure:
- SQLite file permissions (OS-level access control)
- Environment variables for sensitive configs (.env file)
- Flask SECRET_KEY for session security
- Debug mode disabled in production
- Logging sanitization (no PII or private keys)
- Public Data Only: All data sourced from public blockchain and Polymarket APIs
- No Private Keys: Only wallet addresses (public identifiers) are stored
- No PII: Anonymous wallet addresses, no personal information
- No User Accounts: Platform is fully open-access
- Read-Only API Access: No write operations to Polymarket infrastructure
- Data Retention: No automatic deletion; users can request removal via GitHub issues
Based on production testing:
| Metric | Value | Notes |
|---|---|---|
| Analysis Speed | 2-5 seconds | 100-500 positions, includes API fetch + calculation |
| Database Query | <50ms | With proper indexing on hot paths |
| Leaderboard Refresh | 30-60 seconds | 200 traders across 4 categories |
| API Response (Cached) | <100ms | In-memory cache hit |
| API Response (Uncached) | <500ms | Database query + serialization |
| Chart Rendering | <500ms | 10 Plotly.js charts client-side |
| Concurrent Analyses | 2 max | Semaphore-controlled to prevent resource exhaustion |
| Cache Hit Rate | ~80% | Estimated for 1-hour TTL |
| Background Worker | 1 thread | Daemon thread with hourly wake-up |
| Memory Footprint | <200MB | Typical with 1000 wallets in database |
Optimization Techniques:
- Strategic database indexing on query paths
- Connection pooling (SQLAlchemy engine)
- Pandas vectorized operations (10x faster than loops)
- Client-side pagination (no server round-trips)
- Multi-layer caching (memory + database leaderboard cache)
- Lazy loading of relationships (no N+1 queries)
- Background processing for long operations
# Run full test suite
pytest tests/ -v
# Run with coverage report
pytest --cov=app tests/
# Run specific test file
pytest tests/test_analyzer.py -v
# Run with HTML coverage report
pytest --cov=app --cov-report=html tests/
# Open htmlcov/index.html in browsertests/
βββ test_models.py # Database model tests
βββ test_analyzer.py # Metrics calculation tests
βββ test_fetcher.py # API integration tests (mocked)
βββ test_routes.py # Flask route tests
βββ test_cache.py # Caching system tests
βββ conftest.py # Pytest fixtures
- Models: 95%+ coverage (CRUD operations, relationships)
- Services: 90%+ coverage (core business logic)
- Routes: 85%+ coverage (HTTP endpoints, error handling)
- Overall: 90%+ coverage target
- Define Calculation in
app/services/analyzer.py:
def calculate_custom_metric(self, positions_df):
"""Calculate custom metric"""
# Your calculation logic here
return metric_value- Add Database Column in
app/models.py:
class Wallet(Base):
# ... existing columns
custom_metric = Column(Float)- Update Migration (if using Alembic):
alembic revision --autogenerate -m "Add custom_metric column"
alembic upgrade head- Display in Template
app/templates/wallet_detail.html:
<div class="metric-card">
<div class="metric-label">Custom Metric</div>
<div class="metric-value">{{ wallet.custom_metric }}</div>
</div>- Create Blueprint in
app/routes/custom.py:
from flask import Blueprint, render_template
bp = Blueprint('custom', __name__, url_prefix='/custom')
@bp.route('/')
def index():
return render_template('custom.html')- Register Blueprint in
app/__init__.py:
from app.routes import custom
app.register_blueprint(custom.bp)- Add Navigation Link in
app/templates/base.html:
<a href="/custom" class="nav-link">Custom</a># Initialize Alembic (one-time)
alembic init alembic
# Create migration
alembic revision --autogenerate -m "Description"
# Apply migration
alembic upgrade head
# Rollback migration
alembic downgrade -1- PostgreSQL migration for production scalability
- Docker containerization with multi-stage builds
- Kubernetes deployment manifests (Helm charts)
- CI/CD pipeline (GitHub Actions)
- Monitoring integration (Prometheus + Grafana)
- Logging aggregation (ELK stack)
- Machine learning models for strategy classification
- Predictive analytics (win probability estimation)
- Portfolio optimization recommendations
- Risk-adjusted position sizing algorithms
- Market correlation analysis
- Sentiment analysis integration
- WebSocket support for live updates
- Real-time leaderboard streaming
- Position-level alerts (Telegram/Discord)
- Live market scanner (new opportunities)
- Streaming analytics dashboard
- API authentication & rate limiting (OAuth2)
- Multi-user support with role-based access
- White-label deployment options
- Export functionality (CSV, JSON, PDF reports)
- Scheduled reports (daily/weekly email)
- Custom metric builder (UI-based)
Contributions are welcome! This project follows standard open-source practices.
- Fork the repository
- Create your feature branch
git checkout -b feature/AmazingFeature
- Make your changes
- Follow PEP 8 style guidelines
- Add tests for new functionality
- Update documentation as needed
- Run tests
pytest tests/ -v
- Commit your changes
git commit -m 'Add some AmazingFeature' - Push to the branch
git push origin feature/AmazingFeature
- Open a Pull Request
- Provide clear description of changes
- Reference related issues
- Python: PEP 8 compliance (use
blackformatter) - SQL: Uppercase keywords, snake_case identifiers
- JavaScript: ES6+ with consistent indentation
- Documentation: Docstrings for all public methods
This project is licensed under the MIT License - see the LICENSE file for details.
MIT License Summary: You are free to use, modify, and distribute this software for commercial or personal use, with attribution.
- Polymarket: For providing public APIs and market infrastructure
- Flask Community: For excellent documentation and ecosystem
- Plotly: For powerful visualization library
- SQLAlchemy: For robust ORM functionality
- Pandas/NumPy: For data processing capabilities
For partnership opportunities, institutional licensing, or custom deployment:
- GitHub Issues: LiamX-Labs/polymetrics/issues
- Email: (Add your institutional contact email)
- Bug Reports: GitHub Issues
- Feature Requests: GitHub Discussions
- Documentation: GitHub Wiki
This software is provided for informational and educational purposes only. It does not constitute financial advice, investment advice, trading advice, or any other type of professional advice.
Risk Warning: Trading prediction markets involves substantial risk of loss. Past performance is not indicative of future results. The metrics and analytics provided by this platform are based on historical data and do not guarantee future trading success.
No Warranty: This software is provided "as is" without warranty of any kind, express or implied. The authors and contributors are not liable for any damages arising from the use of this software.
Compliance: Users are responsible for ensuring their use of this platform complies with local laws and regulations. Prediction markets may be subject to regulatory restrictions in certain jurisdictions.
Due Diligence: Always conduct your own research and consult with qualified financial advisors before making investment decisions.
This project demonstrates production-grade capabilities expected at leading crypto trading firms:
β Quantitative Finance: Industry-standard metrics (Sharpe ratio, profit factor, drawdown analysis) β Software Engineering: Clean architecture, design patterns, SOLID principles β Data Engineering: ETL pipelines, incremental updates, batch processing β API Design: RESTful endpoints, pagination, error handling β Frontend Development: Interactive visualizations, responsive design, UX best practices β DevOps: Background processing, concurrency control, caching strategies β Database Design: Normalized schema, strategic indexing, relationship management β Security: Input validation, SQL injection prevention, data privacy β Scalability: Threading, queue-based processing, connection pooling β Documentation: Comprehensive README, inline docs, API specifications
Tech Stack: Python Β· Flask Β· SQLAlchemy Β· Pandas Β· NumPy Β· Plotly.js Β· SQLite Β· asyncio Β· threading Β· Jinja2
Complexity: 30+ Python modules Β· 5 database models Β· 12+ routes Β· 10+ chart types Β· 1,740 lines of templates Β· Background scheduler Β· Real-time progress tracking Β· Multi-layer caching
Built with β€οΈ for the prediction markets community
Star this repo β if you find it useful!






