Polymarket Trading Bot
Claude + Polymarket Trading Bot: Complete Technical Documentation
Source: Transcript analysis of “Claude + Polymarket = Free Money? (Full Bot Tutorial)”
Presenter: Mundave (host of Algo Trade Camp / Mundav app)
Duration: ~2h 21min (live Zoom stream)
Note: This is a live stream transcript, heavily mixed with course promotion. All technical content has been extracted and reconstructed. Sections marked ⚠️ indicate content that was ambiguous or inferred.
1. Overview
What This System Does
This tutorial demonstrates how to build automated trading bots for Polymarket (a blockchain-based prediction market) using Claude Code as the AI coding assistant — no manual coding required. The bots scan markets, detect technical signals, and place trades autonomously, 24/7.
Core Idea
The presenter advocates a three-phase quantitative methodology called RBI (Research → Backtest → Incubate):
- Research — Find a trading strategy idea (from reading papers, watching other bots, or small manual trades)
- Backtest — Use historical OHLCV data to statistically validate whether the strategy would have been profitable in the past
- Incubate — Deploy the bot at minimum trade size, observe live behavior, fix bugs, then scale slowly
“If it works in the past, it’s much more likely to work in the future.”
Key Components
| Component | Role |
|---|---|
| Claude Code | AI coding agent — writes, debugs, and iterates on bot code via natural language prompts |
| Polymarket | Prediction market exchange; binary-outcome markets with 5-minute resolution |
| Mundav API | Proprietary data API (liquidation data, OHLCV, scanner tools) |
| Python | Primary programming language for all bots |
| VPS / Cloud | Remote server to run bots 24/7 (referenced but provider unspecified) |
| MetaMask | Web3 wallet used for Polygon network transactions on Polymarket |
| MACD / CVD / MACD Histogram | Technical indicators used as trade signals |
2. System Architecture
End-to-End Pipeline
[Data Source] → [Signal Computation] → [Decision Logic] → [Order Execution] → [Position Monitoring]
↑ ↓
[Historical OHLCV / Live Tick Data] [P&L Tracker / PNL Close]Step-by-Step Workflow
- Data ingestion: Bot fetches OHLCV candle data (5-minute timeframe) from an exchange API or the Mundav API
- Indicator calculation: Computes technical indicators (MACD, CVD, MACD Histogram) on the fetched candles
- Signal detection: Checks whether the indicator crosses a buy/sell threshold
- Position check: Before placing any order, checks if a position already exists to avoid double-entry
- Order placement: Places a limit order (not market order) at the current bid/ask
- P&L monitoring: A separate loop watches open positions and closes them at take-profit or stop-loss levels
- Loop & repeat: Entire cycle repeats every N seconds/minutes (configurable)
Data Flow
Exchange API (Polymarket / HyperLiquid)
↓
OHLCV Candle Fetch (5-min bars)
↓
Indicator Computation (MACD / CVD / MACD Hist)
↓
Signal: BUY / SELL / FLAT
↓
Position Check (is there already an open order/position?)
→ Yes: Cancel existing limit order if needed, or hold
→ No: Place new limit order
↓
P&L Close Logic (watch position until TP or SL hit)
↓
Log trade → LoopExternal Services & Dependencies
| Service | Purpose | Notes |
|---|---|---|
| Polymarket API | Order placement, position query | Requires Polygon RPC / MetaMask wallet |
| Mundav API | Historical OHLCV download, live market data, scanner | Proprietary; requires paid API key |
| Claude Code (Anthropic) | Writing and debugging bot code | Used interactively via Claude Code CLI or app |
| VPS / Cloud Server | Hosting bots for 24/7 operation | Provider not specified; VPS mentioned |
| HyperLiquid (optional) | Alternative exchange; mentioned as having sub-accounts | Binance also mentioned as alternative |
| MetaMask | Wallet for Polygon network interaction on Polymarket | Required for live trading |
3. Requirements
Software Requirements
- Python (primary language; no specific version stated, assumed 3.9+)
- Claude Code (Anthropic’s agentic coding CLI or app)
- Standard Python trading libraries (exact list ⚠️ inferred):
requestsorhttpx— API callspandas,numpy— data manipulation and indicator mathtaorta-lib— technical indicators (MACD, CVD)web3.py— Polygon/MetaMask interaction for Polymarketscheduleorasyncio— loop scheduling
Accounts Needed
| Account | Purpose |
|---|---|
| Polymarket account + MetaMask wallet | Live trading on Polymarket |
| Mundav API key | Data access (offered as part of presenter’s course) |
| Anthropic API key | Claude Code access |
| Exchange account (HyperLiquid / Binance) | For non-Polymarket bots mentioned in stream |
Hardware Assumptions
- Any modern laptop/desktop for development
- A VPS (Virtual Private Server) for 24/7 bot hosting — the presenter mentions running bots “in the cloud” and references SSH-ing into a VPS. Provider not specified.
4. Step-by-Step Implementation
4.1 Setup Environment
# Create project directory
mkdir polymarket_bot && cd polymarket_bot
# Create virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies (reconstructed - exact list not stated in transcript)
pip install requests pandas numpy ta web3 schedule python-dotenvCreate a .env file for secrets:
POLY_PRIVATE_KEY=your_metamask_private_key
MUNDAV_API_KEY=your_mundav_api_key
ANTHROPIC_API_KEY=your_anthropic_api_key4.2 Connecting to APIs
Polymarket Connection (Reconstructed ⚠️)
Polymarket operates on the Polygon blockchain. Orders are placed via their CLOB (Central Limit Order Book) API. The transcript mentions:
- Polygon RPC endpoint required
- MetaMask wallet / private key for signing transactions
- A
poly_api_exceptionerror was shown — indicating they use a custom SDK wrapper
# Reconstructed example of Polymarket connection
from web3 import Web3
POLYGON_RPC = "https://polygon-rpc.com"
w3 = Web3(Web3.HTTPProvider(POLYGON_RPC))
# The presenter references a "Poly API" library
# Likely: https://github.com/Polymarket/py-clob-client
from py_clob_client.client import ClobClient
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137, # Polygon mainnet
private_key=os.getenv("POLY_PRIVATE_KEY")
)Mundav API Connection (Reconstructed ⚠️)
import requests
MUNDAV_API_KEY = os.getenv("MUNDAV_API_KEY")
MUNDAV_BASE_URL = "https://mundav.com/api" # ⚠️ URL inferred
headers = {"Authorization": f"Bearer {MUNDAV_API_KEY}"}4.3 Data Retrieval
The presenter uses two data approaches:
- Historical OHLCV — downloaded from the Mundav roadmap dashboard for backtesting (CSV format)
- Live candle data — fetched in real-time by bots every loop iteration
# Historical data download (for backtesting)
# User downloads CSV from Mundav roadmap dashboard
# Example: Bitcoin 5-minute candles for last 1 year
import pandas as pd
df = pd.read_csv("btc_5min_ohlcv.csv")
df['timestamp'] = pd.to_datetime(df['timestamp'])
df.set_index('timestamp', inplace=True)
# Live candle fetch (reconstructed ⚠️)
def get_candles(symbol: str, interval: str = "5m", limit: int = 100) -> pd.DataFrame:
url = f"{MUNDAV_BASE_URL}/candles"
params = {"symbol": symbol, "interval": interval, "limit": limit}
resp = requests.get(url, headers=headers, params=params)
return pd.DataFrame(resp.json())4.4 Decision Logic
This is the core of the system. The presenter built and tested multiple strategies.
Indicators Used (confirmed from transcript)
| Indicator | Signal Type | Bot Name |
|---|---|---|
| MACD (3, 15, 3 settings) | Crossover | “MACD bot” |
| MACD Histogram | Histogram zero-cross | “MACD Hist 5-minute bot” |
| CVD (Cumulative Volume Delta) | CVD directional signal | “CVD 5-minute bot” |
| No-Market bot | ⚠️ Unclear — appears to be a market-making or no-signal hold strategy | “No Market bot” |
MACD Strategy (Confirmed Working — 60% Win Rate in Backtest)
The presenter explicitly states: “MACD 3-15-3 on these five-minute markets had a win rate of 60%, edge of 618, PO of $119,000.”
import ta
def compute_macd(df: pd.DataFrame, fast=3, slow=15, signal=3):
macd = ta.trend.MACD(df['close'], window_fast=fast, window_slow=slow, window_sign=signal)
df['macd'] = macd.macd()
df['macd_signal'] = macd.macd_signal()
df['macd_hist'] = macd.macd_diff()
return df
def get_signal(df: pd.DataFrame) -> str:
"""Returns BUY, SELL, or FLAT"""
latest = df.iloc[-1]
prev = df.iloc[-2]
# MACD line crosses above signal line → BUY
if prev['macd'] < prev['macd_signal'] and latest['macd'] > latest['macd_signal']:
return "BUY"
# MACD line crosses below signal line → SELL
elif prev['macd'] > prev['macd_signal'] and latest['macd'] < latest['macd_signal']:
return "SELL"
return "FLAT"CVD Strategy
CVD (Cumulative Volume Delta) measures net buying vs selling pressure.
# Reconstructed CVD computation ⚠️
def compute_cvd(df: pd.DataFrame) -> pd.DataFrame:
df['delta'] = df['volume'] * (2 * ((df['close'] - df['low']) / (df['high'] - df['low'])) - 1)
df['cvd'] = df['delta'].cumsum()
return df
def get_cvd_signal(df: pd.DataFrame) -> str:
latest = df.iloc[-1]
prev = df.iloc[-2]
if latest['cvd'] > 0 and prev['cvd'] <= 0:
return "BUY"
elif latest['cvd'] < 0 and prev['cvd'] >= 0:
return "SELL"
return "FLAT"Strategies That FAILED Backtesting (Do Not Use)
The presenter tested these and found them losing:
- Simple capitulation reversion
- Capitulation + RSI oversold
- Capitulation + Bollinger Band squeeze
“All trash strategies. But thank God I figured that out — a lot of people will go ahead and trade a strategy that is literally a negative 94% return.”
Position Check (Critical Logic)
def has_open_position(client, market_id: str) -> bool:
"""Check for existing open position before placing new order."""
positions = client.get_positions()
return any(p['market_id'] == market_id for p in positions)
def has_open_order(client, market_id: str) -> bool:
"""Check for open limit orders."""
orders = client.get_open_orders()
return any(o['market_id'] == market_id for o in orders)4.5 Trade Execution
Key points from presenter:
- Always use LIMIT orders — not market orders. Polymarket market-order fees are ~3x higher. Limit orders on Polymarket are free.
- Always check for existing position first before placing a new order
- Cancel existing open orders if you’re about to replace them
- Minimum trade size: $1 on Polymarket; recommended incubation size is $10
- Recommended initial test size: $10–$15 per trade
def place_limit_order(client, market_id: str, side: str, price: float, size: float):
"""
side: 'BUY' or 'SELL'
price: limit price (bid for BUY, ask for SELL)
size: position size in USD (minimum $1 on Polymarket)
"""
# Cancel existing orders first
if has_open_order(client, market_id):
client.cancel_orders(market_id=market_id)
if side == "BUY":
return client.create_limit_order(
token_id=market_id,
price=price,
size=size,
side="BUY"
)
elif side == "SELL":
return client.create_limit_order(
token_id=market_id,
price=price,
size=size,
side="SELL"
)P&L Close Logic (Stop-Loss / Take-Profit Monitoring)
The presenter calls this a “PNL Close” — a separate monitoring function that watches open positions and exits at predefined thresholds.
def monitor_and_close_position(client, market_id: str,
entry_price: float,
take_profit_pct: float = 0.05,
stop_loss_pct: float = 0.02):
"""
Monitors position P&L and closes at TP or SL.
Runs in its own loop / thread.
"""
while True:
positions = client.get_positions()
pos = next((p for p in positions if p['market_id'] == market_id), None)
if pos is None:
break # Position already closed
current_price = float(pos['current_price'])
pnl_pct = (current_price - entry_price) / entry_price
if pnl_pct >= take_profit_pct:
client.close_position(market_id)
print(f"Take profit hit: {pnl_pct:.2%}")
break
elif pnl_pct <= -stop_loss_pct:
client.close_position(market_id)
print(f"Stop loss hit: {pnl_pct:.2%}")
break
time.sleep(10)4.6 Automation / Scheduling
The presenter mentions using a loop that runs the bot every few seconds or minutes. He prefers to run bots on a VPS and monitor them with terminal windows visible on screen.
import time
import schedule
def run_bot():
"""Main bot loop — runs every 5 minutes aligned to candle close."""
df = get_candles(symbol="BTC-USD", interval="5m")
df = compute_macd(df)
signal = get_signal(df)
market_id = "target_market_id"
if signal != "FLAT":
if not has_open_position(client, market_id):
price = df.iloc[-1]['close']
size = 10.00 # Start at $10 (incubation size)
if signal == "BUY":
place_limit_order(client, market_id, "BUY", price * 0.999, size)
elif signal == "SELL":
place_limit_order(client, market_id, "SELL", price * 1.001, size)
# Schedule to run every 5 minutes
schedule.every(5).minutes.do(run_bot)
print("Bot started. Running...")
while True:
schedule.run_pending()
time.sleep(1)5. Claude Prompt Engineering
How Claude Code Is Used
The presenter uses Claude Code (the agentic coding tool, not just the chat interface) directly in his workflow. He describes it as: “I just send her new ideas and I put it on a list of ideas.”
He is running multiple Claude Code instances simultaneously (he mentions “six Claude Codes” open). Claude Code autonomously reads the codebase, writes files, and runs code.
Prompt 1 — Backtest Three Strategies in Parallel
Context: The presenter types this into Claude Code after describing a new trading idea.
Reconstructed Prompt:
I have a new idea about the VWAP capitulation. A capitulation volume
bar and then trading it back to the VWAP.
Look at my backtesting folder and use one of those back tests so you
can see one with data. Use that data and go ahead and back test this
for me. Test three different ideas across three different agents and
then just send me back the stats. Thank you.Purpose: Uses Claude Code’s parallel agent capability to run 3 strategy variants simultaneously and return a performance summary.
Claude’s Response (shown on screen):
“I see the pattern blah blah blah. I’ll spin up three agents in parallel. Simple capitulation reversion here. Capitulation plus RSI oversold. Capitulation plus Bollinger Band squeeze.”
Improved Version:
You are a quantitative trading analyst. I have an idea:
- A large capitulation volume bar followed by mean reversion to VWAP
Using the backtest template in my /backtesting folder and the CSV data
already there:
1. Test Strategy A: Pure capitulation reversion (enter on capitulation
candle, target VWAP)
2. Test Strategy B: Capitulation + RSI < 30 confirmation
3. Test Strategy C: Capitulation + Bollinger Band lower band touch
For each strategy, return:
- Win rate (%)
- Average return per trade (%)
- Sharpe ratio
- Max drawdown
- Total number of trades
- Net P&L on $10/trade size
Run all three in parallel and return a comparison table.Prompt 2 — Show Backtest Results Table
Reconstructed Prompt:
Can you show me a couple of those Polymarket back tests in my folder?
If you look at the readme of the Poly Market, I think it's Poly Hyper
or look around. We just put a results readme and we were back testing
poly market bots on the five minute and a couple of them did really well.
Can you give me a table of what those stats are and also explain the three
strategies? There should be the top three.Purpose: Retrieve and summarize existing backtest results from a README file Claude Code can read from the local filesystem.
Improved Version:
Look in my /polymarket or /poly_hyper directory. Find the results README
file that contains backtest statistics for Polymarket 5-minute bots.
Parse all strategy results and return:
1. A markdown table with columns: Strategy Name | Win Rate | Edge |
P&L | Trades | Sharpe
2. A 2-3 sentence plain English description of each strategy
3. Rank them by Sharpe ratio
Show only the top 3 strategies.Prompt 3 — Build Four Bots for Four Accounts
Reconstructed Prompt:
Set these four bots up and just send me back the link with what account it is.
We'll set one up on August 14, one on May 13th, one on Jan 2, and then one on
December 11th. [drops private key] Change the size here to $150 just so we
don't run into any errors with minimum size. Change it for all four.Purpose: Deploy four separate bot instances to four separate Polymarket accounts, each with a different account’s private key.
Improved Version:
I need to deploy four separate instances of the MACD 5-minute bot, each
configured for a different Polymarket account.
Accounts:
- Instance 1: Account "Aug14" → [private_key_1]
- Instance 2: Account "May13" → [private_key_2]
- Instance 3: Account "Jan2" → [private_key_3]
- Instance 4: Account "Dec11" → [private_key_4]
For each:
- Set trade size = $150
- Use limit orders only
- Start each in a separate process / screen session
- Log output to logs/aug14.log, logs/may13.log, etc.
- Return the process IDs for each once startedPrompt 4 — Debug HiP3 Candle API Error
Reconstructed Prompt:
We're getting an error here with the HIP3 candles of gold. Is the correct
call looking correct or is there something you can fix on your back end?
Either you got to fix something or you got to send me updated instructions
on how to use it.Purpose: Claude Code inspects the failing API call and either fixes the code or identifies the issue with the external API endpoint.
Improved Version:
The bot is throwing an error when fetching HIP3 candles for GOLD.
Inspect the API call in the code, check the Mundav API docs if available,
and:
1. Show me the exact failing request (URL, headers, params)
2. Identify if the error is in our code or the API endpoint
3. If code-side: fix it
4. If API-side: output what the corrected API call should look likePrompt 5 — Build New Bot from Scratch (General Template)
Reconstructed from presenter’s general workflow description:
Build me a Python trading bot with the following spec:
Strategy: [DESCRIBE INDICATOR + SIGNAL HERE]
Exchange: Polymarket
Timeframe: 5 minutes
Trade size: $10 (minimum incubation size)
Order type: LIMIT ORDERS ONLY (never market orders)
Requirements:
1. Fetch 5-minute OHLCV candles from [data source]
2. Compute [indicator] on the candles
3. Generate BUY/SELL/FLAT signal
4. Before placing any order, CHECK if an open position or open order exists
5. If a position exists: do not place a new order
6. If no position: place a limit order at best bid (BUY) or best ask (SELL)
7. Separately monitor the open position and close at:
- Take profit: +X%
- Stop loss: -Y%
8. Run in a loop every 5 minutes
9. Log all actions with timestamps to a log file
10. Add proper error handling and retry logic
Also add risk controls:
- Max daily loss limit: stop trading if daily P&L < -$[amount]
- Max concurrent positions: 16. Code Reconstruction
Full Bot Template (Reconstructed ⚠️)
Note: This is a best-approximation reconstruction. The presenter did not share full source code on screen. The actual code used by the presenter is part of his paid course.
"""
Polymarket MACD Trading Bot - Reconstructed
Strategy: MACD (3, 15, 3) crossover on 5-minute candles
"""
import os
import time
import logging
import schedule
import pandas as pd
import numpy as np
from datetime import datetime
from dotenv import load_dotenv
# --- Imports (exact libraries not confirmed) ---
# from py_clob_client.client import ClobClient # Polymarket CLOB
import ta # Technical analysis
load_dotenv()
# --- Configuration ---
PRIVATE_KEY = os.getenv("POLY_PRIVATE_KEY")
POLYGON_RPC = "https://polygon-rpc.com"
TRADE_SIZE = 10.00 # $10 incubation size
TAKE_PROFIT = 0.05 # 5% take profit
STOP_LOSS = 0.02 # 2% stop loss
LOOP_INTERVAL_SECONDS = 300 # 5 minutes
MAX_DAILY_LOSS = -50.00 # Stop trading if daily loss exceeds this
# --- Logging Setup ---
logging.basicConfig(
filename=f"bot_{datetime.now().strftime('%Y%m%d')}.log",
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s"
)
log = logging.getLogger(__name__)
# --- Polymarket Client (Reconstructed ⚠️) ---
# client = ClobClient(
# host="https://clob.polymarket.com",
# chain_id=137,
# private_key=PRIVATE_KEY
# )
# --- Indicator Computation ---
def compute_macd(df: pd.DataFrame, fast=3, slow=15, signal=3) -> pd.DataFrame:
macd_obj = ta.trend.MACD(
df['close'],
window_fast=fast,
window_slow=slow,
window_sign=signal
)
df['macd'] = macd_obj.macd()
df['macd_signal'] = macd_obj.macd_signal()
df['macd_hist'] = macd_obj.macd_diff()
return df
def get_signal(df: pd.DataFrame) -> str:
"""Returns BUY, SELL, or FLAT based on MACD crossover."""
if len(df) < 2:
return "FLAT"
latest = df.iloc[-1]
prev = df.iloc[-2]
crossed_above = (prev['macd'] < prev['macd_signal'] and
latest['macd'] > latest['macd_signal'])
crossed_below = (prev['macd'] > prev['macd_signal'] and
latest['macd'] < latest['macd_signal'])
if crossed_above:
return "BUY"
elif crossed_below:
return "SELL"
return "FLAT"
# --- Position & Order Checks ---
def has_open_position(market_id: str) -> bool:
"""Check if there's already an open position."""
try:
positions = client.get_positions() # ⚠️ API call reconstructed
return any(p.get('market_id') == market_id for p in positions)
except Exception as e:
log.error(f"Error checking positions: {e}")
return True # Fail safe: assume position exists
def has_open_order(market_id: str) -> bool:
"""Check for open limit orders."""
try:
orders = client.get_open_orders() # ⚠️ API call reconstructed
return any(o.get('market_id') == market_id for o in orders)
except Exception as e:
log.error(f"Error checking orders: {e}")
return True # Fail safe
# --- Order Placement ---
def place_order(market_id: str, side: str, price: float, size: float):
"""Place a limit order after canceling any existing orders."""
try:
if has_open_order(market_id):
client.cancel_all_orders(market_id=market_id)
log.info(f"Cancelled existing orders for {market_id}")
order = client.create_limit_order( # ⚠️ reconstructed
token_id=market_id,
price=price,
size=size,
side=side
)
log.info(f"Placed {side} limit order | Market: {market_id} | "
f"Price: {price:.4f} | Size: ${size:.2f}")
return order
except Exception as e:
log.error(f"Order placement failed: {e}")
return None
# --- Main Bot Loop ---
def run_bot(market_id: str):
log.info("--- Bot cycle start ---")
try:
# 1. Fetch data
df = get_candles(market_id, interval="5m", limit=50) # ⚠️ reconstructed
if df is None or len(df) < 20:
log.warning("Insufficient data, skipping cycle")
return
# 2. Compute indicator
df = compute_macd(df)
# 3. Get signal
signal = get_signal(df)
log.info(f"Signal: {signal}")
# 4. Execute if signal is actionable
if signal != "FLAT":
if not has_open_position(market_id):
price = float(df.iloc[-1]['close'])
if signal == "BUY":
limit_price = round(price * 0.999, 4) # Slightly below market
place_order(market_id, "BUY", limit_price, TRADE_SIZE)
elif signal == "SELL":
limit_price = round(price * 1.001, 4) # Slightly above market
place_order(market_id, "SELL", limit_price, TRADE_SIZE)
else:
log.info("Position already open, skipping new order")
except Exception as e:
log.error(f"Bot cycle error: {e}")
# --- Entry Point ---
if __name__ == "__main__":
MARKET_ID = "your_target_market_condition_id"
log.info("=== Polymarket MACD Bot Started ===")
# Run immediately, then every 5 minutes
run_bot(MARKET_ID)
schedule.every(5).minutes.do(run_bot, market_id=MARKET_ID)
while True:
schedule.run_pending()
time.sleep(1)Backtesting Template (Reconstructed ⚠️)
"""
Backtest Template — referenced as "backtesting.py" by presenter.
"""
import pandas as pd
import numpy as np
def backtest_macd_strategy(df: pd.DataFrame,
fast=3, slow=15, signal_period=3,
trade_size=10.0,
take_profit=0.05,
stop_loss=0.02) -> dict:
# Compute MACD
import ta
macd_obj = ta.trend.MACD(df['close'], window_fast=fast,
window_slow=slow, window_sign=signal_period)
df['macd'] = macd_obj.macd()
df['macd_signal'] = macd_obj.macd_signal()
trades = []
in_trade = False
entry_price = 0
entry_side = None
for i in range(1, len(df)):
prev = df.iloc[i-1]
curr = df.iloc[i]
if not in_trade:
# BUY signal
if prev['macd'] < prev['macd_signal'] and curr['macd'] > curr['macd_signal']:
in_trade = True
entry_price = curr['close']
entry_side = "BUY"
# SELL signal
elif prev['macd'] > prev['macd_signal'] and curr['macd'] < curr['macd_signal']:
in_trade = True
entry_price = curr['close']
entry_side = "SELL"
else:
# Monitor position
if entry_side == "BUY":
pnl_pct = (curr['close'] - entry_price) / entry_price
else:
pnl_pct = (entry_price - curr['close']) / entry_price
if pnl_pct >= take_profit or pnl_pct <= -stop_loss:
trades.append({
'side': entry_side,
'entry': entry_price,
'exit': curr['close'],
'pnl_pct': pnl_pct,
'pnl_usd': pnl_pct * trade_size,
'win': pnl_pct > 0
})
in_trade = False
results_df = pd.DataFrame(trades)
if len(results_df) == 0:
return {"error": "No trades generated"}
return {
"total_trades": len(results_df),
"win_rate": results_df['win'].mean(),
"avg_return_pct": results_df['pnl_pct'].mean(),
"net_pnl_usd": results_df['pnl_usd'].sum(),
"sharpe": results_df['pnl_pct'].mean() / results_df['pnl_pct'].std()
if results_df['pnl_pct'].std() > 0 else 0,
"max_drawdown": results_df['pnl_usd'].cumsum().min()
}
# Example usage
if __name__ == "__main__":
df = pd.read_csv("btc_5min_ohlcv.csv")
results = backtest_macd_strategy(df)
print(results)7. Strategy Analysis
Why This Might Work on Polymarket
- 5-minute prediction markets are extremely high-leverage (presenter says ~2,500x effective leverage)
- Markets often exhibit momentum intraday — MACD captures this
- Polymarket has zero maker fees (limit orders are free) — a massive structural edge vs. spot/futures
- Most participants are retail traders making emotional decisions — bots can systematically exploit this
- CVD (Cumulative Volume Delta) detects institutional order flow, which tends to precede price movements
Reported Backtest Results (from transcript)
| Strategy | Win Rate | Edge | P&L (simulated) |
|---|---|---|---|
| MACD (3, 15, 3) | 60% | 618 | ~$119,000 |
| Strategy B | 59% | — | — |
| Strategy C | 63% | — | — |
Underlying Assumptions
- Historical patterns in 5-minute candle MACD signals persist forward
- Polymarket’s prediction market prices behave similarly to underlying asset prices
- Limit orders get filled consistently at target prices
- Zero maker fees hold (Polymarket policy doesn’t change)
- The strategy doesn’t get “alpha decay” — if too many bots run the same strategy, edge disappears
Market Inefficiencies Being Exploited
- Emotional retail trading: Humans panic sell/buy; bots don’t
- Fee ignorance: Most traders use market orders; bots use limit orders (1/3 the cost or free)
- Speed asymmetry: Bots react to 5-minute candle closes consistently; humans miss signals
- Liquidity provision: Limit orders on Polymarket earn a maker rebate structure
8. Risks and Limitations
Technical Risks
| Risk | Description |
|---|---|
| API connectivity failures | Polymarket / Mundav API can go down; bot stops trading or enters error state |
| Polygon RPC errors | “Failed to connect to Polygon RPC” was shown live — bot stops dead |
| Order fill risk | Limit orders may not fill if market moves away |
| Double-position bug | If position-check logic fails, bot can stack multiple positions |
| Data errors | Presenter notes “HIP3 candles of gold doesn’t return any data” — stale/missing data causes no-signal |
| Code copy-paste spacing bugs | Presenter notes spaces from AI copy-paste breaking terminal commands |
| Memory/state loss | Bots have no persistent state; restart wipes knowledge of open positions |
Financial Risks
| Risk | Description |
|---|---|
| Past performance ≠ future performance | “Just because it worked in the past doesn’t guarantee it’s going to work in the future” (presenter’s own caveat) |
| Overfitting | 60% win rate on historical data may shrink to 50% or less live |
| Alpha decay | If many bots run the same MACD strategy, edge disappears |
| 5-minute market volatility | Presenter explicitly calls 5-min markets “very dangerous” and “2500x leverage” |
| Account blowup at scale | Presenter warns repeatedly about sizing up too fast |
| Exchange risk | Polymarket is a crypto prediction market; smart contract risk and platform risk exist |
Failure Cases
- Bot placing orders when market has no liquidity (wide spreads, no fill)
- P&L close logic not triggering (monitored in a loop with
time.sleep(10)— can miss fast moves) - Wrong account private key deployed
- Running on Bybit when Polymarket connector is expected (presenter made this mistake live)
9. Improvements & Extensions
Making It More Robust
- Persistent state storage: Write open position info to a local SQLite or JSON file on each trade, reload on restart
- Heartbeat monitoring: Run a separate process that pings the bot every minute and restarts it if dead
- Multi-timeframe confirmation: Only trade MACD signal if 15-min trend agrees
- Webhook alerts: Send Telegram/Discord message on every trade and every error
- Automated kill switch: If daily P&L drops below threshold, stop all bots automatically
- Retry logic on API failures: Exponential backoff on Polygon RPC and Polymarket API calls
- Walk-forward backtesting: Instead of fitting on all historical data, use rolling windows to simulate real deployment
Scaling Ideas
- Multiple accounts: Presenter already uses 5+ separate Polymarket accounts to scale positions (since no sub-accounts on Polymarket)
- Multiple bots in parallel: Run MACD, CVD, and MACD Hist bots simultaneously on the same or different markets
- Dynamic sizing: Increase position size automatically after N consecutive winning trades
- Portfolio approach: Diversify across multiple prediction market types (crypto, politics, sports)
Safer Alternatives for Beginners
- Paper trading first: Simulate trades without real money using a mock exchange or shadow account
- Start on longer timeframes: 1-hour or 4-hour MACD is less noisy than 5-minute
- Use HyperLiquid sub-accounts: Easier to separate bots than multiple Polymarket accounts
- Sharpe ratio threshold: Only deploy live if backtest Sharpe > 1.5
10. Full Workflow Summary
┌─────────────────────────────────────────────────────────┐
│ FULL BOT PIPELINE │
│ │
│ PHASE 1: RESEARCH │
│ ───────────────── │
│ 1a. Identify a strategy idea: │
│ - Study academic papers / TradingView scripts │
│ - Watch what other successful bots do │
│ - Small manual trades to generate intuition │
│ │
│ PHASE 2: BACKTEST │
│ ───────────────── │
│ 2a. Download historical OHLCV CSV (Mundav roadmap) │
│ 2b. Write backtesting.py (or prompt Claude Code) │
│ 2c. Run strategy on historical data │
│ 2d. Check: Win rate > 55%? Sharpe > 1? Net positive? │
│ - YES → proceed │
│ - NO → discard, try new idea │
│ │
│ PHASE 3: BUILD BOT │
│ ───────────────── │
│ 3a. Prompt Claude Code to build the live bot: │
│ "Build a bot using [strategy] on Polymarket, │
│ limit orders only, $10 size, with P&L close" │
│ 3b. Test with tiny size ($1–$10) │
│ 3c. Fix bugs until bot runs error-free │
│ │
│ PHASE 4: INCUBATE │
│ ───────────────── │
│ 4a. Deploy on VPS at minimum size ($10) │
│ 4b. Monitor daily for 2–4 weeks │
│ 4c. Fix any live bugs with Claude Code │
│ │
│ PHASE 5: SCALE │
│ ───────────────── │
│ 5a. Gradually increase size: $10 → $20 → $50 → $100 │
│ 5b. Add multiple accounts for more capital │
│ 5c. Run multiple strategy bots in parallel │
│ 5d. Continue researching new strategies │
└─────────────────────────────────────────────────────────┘Quick-Reference Checklist Before Going Live
- Strategy backtested with positive edge (win rate > 55%, net P&L positive)
- Using limit orders only — never market orders
- Position check implemented (no double-entry)
- Open order cancellation before new order
- P&L close logic (take profit + stop loss) implemented
- Daily loss limit kill switch
- Bot loops every N minutes (not continuous)
- Error handling and logging in place
- Deployed at minimum trade size ($10 Polymarket incubation)
- Running on VPS with terminal visible for monitoring
- Private keys in
.envfile, not hardcoded
Documentation reconstructed from transcript. Technical implementation details are best-approximation where source code was not directly shown on screen.