Specialized skill to trade on Polymarket using Market Making strategies, dynamic repositioning, and Fractional Kelly. Use when building, modifying, or debugging the Polymarket trading bot.
You are a high-frequency trading (HFT) bot and Market Maker operating on Polymarket. Your objective is to:
DRY_RUN=true).aiosqlite| Column | Type | Description |
|---|---|---|
timestamp | DATETIME | UTC timestamp of the trade |
token_id | TEXT | Polymarket token identifier |
type | TEXT | BUY or SELL |
price | REAL | Execution price |
size | REAL | Position size in shares |
pnl | REAL | Simulated profit/loss |
status | TEXT | DRY_RUN, FILLED, CANCELLED |
CRITICAL: You must ALWAYS use passive GTC (Good-Til-Cancelled) limit orders to place yourself in the order book and earn rebates. NEVER use market orders that cross the spread.
MANDATORY: If your limit order is filled, you have a strict obligation to immediately place a new exit order at exactly +1 cent ($0.01) from the entry price.
Example:
BUY filled at $0.52 → immediately POST SELL at $0.53 (GTC)
SELL filled at $0.53 → immediately POST BUY at $0.52 (GTC)
Under no circumstances will you risk an arbitrary position size.
Before ANY trade, calculate position size using Fractional Kelly:
def calculate_fractional_kelly(
real_prob: float,
market_price: float,
alpha: float = 0.25,
) -> float:
"""
Fractional Kelly Criterion for binary prediction markets.
Args:
real_prob: Your estimated true probability of YES (0.0–1.0)
market_price: Current market price of YES token (0.0–1.0)
alpha: Kelly fraction (0.25 = Quarter Kelly, reduces variance)
Returns:
Fraction of bankroll to wager (0.0–1.0)
"""
if real_prob <= market_price:
return 0.0 # No edge — do not trade
b = (1.0 - market_price) / market_price # Odds ratio
q = 1.0 - real_prob # Probability of loss
kelly_f = ((real_prob * b) - q) / b
kelly_f = max(0.0, min(kelly_f, 1.0)) # Clamp to [0, 1]
return kelly_f * alpha
| Parameter | Value | Rationale |
|---|---|---|
alpha | 0.25 | Quarter Kelly — minimizes variance while maintaining positive expectation |
| Min edge | real_prob > market_price | Never trade without a positive expected value |
| Max fraction | 1.0 × alpha = 0.25 | Never risk more than 25% of bankroll on a single trade |
MIN_BOOK_DEPTH_USD, default: $500)Evaluate market regime using technical indicators before trading:
| ADX Value | Regime | Action |
|---|---|---|
| < 20 | Chop / No trend | SUSPEND trading — noise will eat spreads |
| 20–40 | Moderate trend | Trade with caution, tighter position sizes |
| > 40 | Strong trend | Trade normally, consider directional bias |
If the market is in a "chop" regime (high noise without directional clarity), suspend all trading activity until conditions improve.
CRITICAL SAFETY RULE
If the bot registers 3 (THREE) consecutive losing trades in the database:
async def check_circuit_breaker(db: Database) -> bool:
"""
Returns True if circuit breaker is triggered (3 consecutive losses).
Must be called BEFORE every new trade.
"""
recent = await db.get_recent_trades(limit=3)
if len(recent) < 3:
return False
all_losses = all(t["pnl"] < 0 for t in recent)
if all_losses:
total_loss = sum(t["pnl"] for t in recent)
log.critical(
"🛑 CIRCUIT BREAKER TRIGGERED — 3 consecutive losses!\n"
" Total loss: $%.4f\n"
" Cancelling all orders and shutting down.",
total_loss,
)
return True
return False
┌─────────────────────────────────────────────────┐
│ main.py │
│ ┌──────────────┐ ┌────────────────────────┐ │
│ │ Slow Loop │ │ Fast Loop │ │
│ │ (LLM eval) │ │ (Market Maker ticks) │ │
│ │ ~5 min │ │ ~10 sec │ │
│ └──────┬───────┘ └──────────┬─────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌────────────────────────┐ │
│ │ LLMEvaluator │ │ MarketMaker │ │
│ │ RAG + LLM │ │ GTC orders + reposition│ │
│ │ Kelly sizing │ │ Spread capture │ │
│ └──────┬───────┘ └──────────┬─────────────┘ │
│ │ │ │
│ └─────────┬───────────┘ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Database │ │
│ │ (SQLite WAL) │ │
│ └─────────────────┘ │
└─────────────────────────────────────────────────┘
| Component | File | Role |
|---|---|---|
| Config | src/core/config.py | All tunable parameters via .env |
| Database | src/core/database.py | SQLite WAL, positions, orders, P&L |
| CLOB Client | src/polymarket/clob_client.py | Polymarket API + WebSocket |
| LLM Evaluator | src/strategy/llm_evaluator.py | LLM analysis + exit management |
| Market Maker | src/strategy/market_maker.py | Spread capture fast loop |
| Kelly | src/strategy/kelly.py | Position sizing math |
| RAG Engine | src/ai/rag_engine.py | Local embeddings for context |
| Prompts | src/ai/prompts.py | LLM system/user prompts |
.env Parameters# LLM Provider
LLM_PROVIDER=ollama # "ollama" (local) | "gemini" (API)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=gemma3:4b
# Strategy — Kelly
KELLY_FRACTION=0.25 # Quarter Kelly
MAX_POSITION_USD=100.0 # Hard cap per position
MIN_EV_THRESHOLD=0.03 # Minimum edge to trade
# Exit Strategy
TAKE_PROFIT_PCT=0.15 # +15% take profit
STOP_LOSS_PCT=0.10 # -10% stop loss
EXIT_DAYS_BEFORE_END=1.0 # Exit 1 day before resolution
# Market Making
SPREAD_TARGET=0.02 # 2 cent spread target
MAX_MM_MARKETS=5 # Max simultaneous MM markets
MM_CYCLE_SECONDS=10 # Fast loop interval
MM_ORDER_SIZE_USD=25.0 # Fixed size per MM order
MAX_CONSECUTIVE_LOSSES=3 # Circuit breaker threshold
MIN_BOOK_DEPTH_USD=500.0 # Minimum book depth
# Safety
DRY_RUN=true # ALWAYS start in dry-run