Scaffold this example locally and test it with the CLI:
circuit new --name my-polymarket-agent --language python --template polymarket
cd my-polymarket-agent
circuit run # execute a run cycle
circuit unwind # test the unwind logic
circuit.toml
circuit.toml
name = "Example Polymarket Agent"
tagline = "Trades on Polymarket markets"
walletType = "ethereum"
allowedExecutionModes = ["auto", "manual"]
imageUrl = "https://cdn.circuit.org/agents/default"
runtimeIntervalMinutes = 60
version = "0.0.1"
[startingAsset]
network = "ethereum:137" # Polygon
address = "0x2791bca1f2de4661ed88a30c99a7a9449aa84174" # USDC
minimumAmount = "5000000" # 5 USDC (6 decimals)
Example
import json
import requests
from agent_sdk import Agent, AgentContext
from agent_sdk.agent_context import CurrentPosition
BUY_AMOUNT = 5 # USD to spend per cycle
# Polygon USDC address
USDC = "0x2791bca1f2de4661ed88a30c99a7a9449aa84174"
CLOB_API = "https://clob.polymarket.com"
def check_order_book_liquidity(token_id: str, side: str, min_usd: float) -> bool:
"""Check that the CLOB order book has enough liquidity for our order."""
try:
response = requests.get(
f"{CLOB_API}/book",
params={"token_id": token_id},
timeout=10,
)
if not response.ok:
return False
book = response.json()
orders = book.get("asks" if side == "BUY" else "bids", [])
total_usd = 0
for order in orders:
price = float(order["price"])
size = float(order["size"])
total_usd += price * size
return total_usd >= min_usd
except Exception:
return False
def find_liquid_sports_market(min_liquidity_usd: float) -> dict | None:
"""Find the most liquid active sports market on Polymarket via the Gamma API."""
try:
response = requests.get(
"https://gamma-api.polymarket.com/events/pagination",
params={
"tag_slug": "sports",
"limit": 10,
"active": "true",
"closed": "false",
"archived": "false",
"order": "volume24hr",
"ascending": "false",
},
timeout=10,
)
events = response.json().get("data", [])
for event in events:
for market in event.get("markets", []):
if not market.get("acceptingOrders"):
continue
clob_token_ids = json.loads(market.get("clobTokenIds", "[]"))
outcomes = json.loads(market.get("outcomes", "[]"))
outcome_prices = json.loads(market.get("outcomePrices", "[]"))
if not clob_token_ids or not outcomes:
continue
price = float(outcome_prices[0]) if outcome_prices else 0
# Skip markets with extreme prices (thin liquidity on one side)
if price < 0.10 or price > 0.90:
continue
token_id = clob_token_ids[0]
# Verify order book has enough ask liquidity for our buy
if not check_order_book_liquidity(token_id, "BUY", min_liquidity_usd):
continue
return {
"tokenId": token_id,
"question": market.get("question", "Unknown"),
"outcome": outcomes[0],
"price": outcome_prices[0] if outcome_prices else "?",
}
except Exception as e:
print(f"Failed to fetch markets: {e}")
return None
def run(agent: AgentContext) -> None:
# 1. Redeem any settled positions
redemption = agent.platforms.polymarket.redeem_positions()
if redemption.success and redemption.data:
redeemed = [r for r in redemption.data if r.success]
if redeemed:
agent.log(f"Redeemed {len(redeemed)} settled positions")
for r in redeemed:
if r.position:
agent.log(f" {r.position.question} ({r.position.outcome}): ${r.position.valueUsd}")
# 2. Check current positions and log Polymarket portfolio
result = agent.get_current_positions()
if not result.success or not result.data:
agent.log(result.error or "Failed to get positions", error=True)
return
for pos in result.data.positions:
if pos.polymarketMetadata:
pm = pos.polymarketMetadata
agent.log(f"{pm.question} [{pm.outcome}]: ${pm.valueUsd} (PnL: ${pm.pnlUsd})")
# 3. Find USDC balance
usdc = next(
(p for p in result.data.positions if p.assetAddress.lower() == USDC),
None,
)
usdc_balance = float(usdc.currentQty) / 1e6 if usdc else 0
agent.log(f"USDC balance: ${usdc_balance:.2f}")
if usdc_balance < BUY_AMOUNT:
agent.log("Not enough USDC to buy")
return
# 4. Find the most liquid sports market (with order book liquidity check)
market = find_liquid_sports_market(min_liquidity_usd=BUY_AMOUNT)
if not market:
agent.log("No active sports markets with sufficient liquidity found")
return
agent.log(f"Target market: {market['question']} [{market['outcome']}] @ {market['price']}")
# 5. Buy a position
buy = agent.platforms.polymarket.market_order({
"tokenId": market["tokenId"],
"size": BUY_AMOUNT,
"side": "BUY",
})
if buy.success and buy.data:
info = buy.data.orderInfo
if info.totalPriceUsd:
agent.log(f"Bought shares: ${info.totalPriceUsd} at ${info.priceUsd}/share (order {info.orderId})")
else:
agent.log(f"Order placed: {info.orderId} ({info.size} shares, {info.side})")
else:
agent.log(f"Buy failed: {buy.error}", error=True)
def unwind(agent: AgentContext, positions: list[CurrentPosition]) -> None:
# Sell all Polymarket positions
result = agent.get_current_positions()
if not result.success or not result.data:
agent.log("Failed to get positions for unwind", error=True)
return
sold = 0
for pos in result.data.positions:
if not pos.polymarketMetadata:
continue
token_id = pos.tokenId
if not token_id:
continue
shares = float(pos.currentQty) / 1e6 # Convert from raw units
if shares <= 0:
continue
sell = agent.platforms.polymarket.market_order({
"tokenId": token_id,
"size": shares,
"side": "SELL",
})
if sell.success and sell.data:
pm = pos.polymarketMetadata
agent.log(f"Sold {pm.question} ({pm.outcome}): ${sell.data.orderInfo.totalPriceUsd}")
sold += 1
else:
agent.log(f"Failed to sell position: {sell.error}", error=True)
if sold == 0:
agent.log("No Polymarket positions to sell")
# Redeem any settled positions
agent.platforms.polymarket.redeem_positions()
agent = Agent(run_function=run, unwind_function=unwind)
handler = agent.get_handler()
if __name__ == "__main__":
agent.run()
Sample Output
Agent run started
Redeemed 1 settled positions
Will Spain win the 2026 FIFA World Cup? (Yes): $5.12
USDC balance: $12.34
Target market: Will Argentina win Copa America 2025? [Yes] @ 0.62
Bought shares: $5.00 at $0.62/share (order 8837291045)
Agent run completed
Agent unwind started
Sold 8.06 shares of token 123456... (order 9912345678)
Redeemed 1 settled positions
Agent unwind completed
How It Works
- Redeem settled positions: Claims winnings from any resolved markets
- Log portfolio: Shows current Polymarket positions with PnL
- Check balance: Finds USDC balance from current positions
- Find market: Queries the Gamma API for liquid sports markets, filters by price range (0.10-0.90), and verifies order book depth via the CLOB API
- Buy shares: Places a market buy order on the best available market
- Unwind: Sells all open Polymarket positions and redeems settled ones
Notes
- Always check order book liquidity before calling
marketOrder. The CLOB will error if there aren’t enough asks/bids to fill your order. See Troubleshooting for details. - Polymarket uses USDC on Polygon (
ethereum:137). Set yourstartingAssetaccordingly. sizemeans different things for buys vs sells: USD amount for BUY, share count for SELL.- Token IDs are long numeric strings from Polymarket’s API — they identify a specific outcome (e.g., “Yes” or “No”) in a market.
- Use
redeemPositions()to claim winnings after markets resolve. It’s good practice to call it at the start of each run cycle.