polymarket/bot/SKILL.md
Autonomous trading agent for Polymarket prediction markets using Seren ecosystem
npx skillsauth add serenorg/seren-skills botInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Autonomous trading agent for prediction markets integrating the Seren ecosystem.
READ THIS BEFORE USING
⚠️ Polymarket access depends on jurisdiction, account eligibility, and current network environment. ⚠️ You are responsible for verifying that prediction market trading is legal in your jurisdiction.
Activate this skill when the user mentions:
Immediately run a dry-run scan without asking. Do not present a menu or ask the user to choose between scan/trade/setup. Execute the paper scan by default. Only after results are displayed, present available next steps (live trading setup, position management). If the user explicitly requests a specific action in their invocation message, run that action instead.
When the user asks to scan Polymarket or find trading opportunities, run the bot:
First, verify the skill is set up:
ls ~/.config/seren/skills/polymarket-bot/.env ~/.config/seren/skills/polymarket-bot/config.json
If files are missing, guide user through setup (see Phase 1-2 below).
Run a single scan to find mispriced markets:
cd ~/.config/seren/skills/polymarket-bot && python3 scripts/agent.py --config config.json --dry-run 2>&1
What this does:
How to present results to user:
✓ Opportunity found!Found 3 opportunities:
| Market | Fair Value | Market Price | Edge | Position |
|--------|-----------|--------------|------|----------|
| "Will BTC hit $100k?" | 67% | 54% | 13% | $15.20 |
| "Trump wins 2024?" | 48% | 55% | -7% | $8.40 SELL |
View recent scan logs:
tail -50 ~/.config/seren/skills/polymarket-bot/logs/trading_*.log
⚠️ Only if user has:
cd ~/.config/seren/skills/polymarket-bot && python3 scripts/setup_cron.py create --config config.json --schedule "0 */2 * * *" --live --run-type scan
cd ~/.config/seren/skills/polymarket-bot && python3 scripts/setup_cron.py create --config config.json --schedule "15 * * * *" --live --run-type monitor
Then start the local-pull runner on the machine that should execute jobs:
python3 scripts/run_local_pull_runner.py --config config.json
Important:
--liveWhen the user gives a direct exit instruction (sell, close, exit, unwind, flatten), execute the exit path immediately.
Do not editorialize or argue against recovering remaining funds.
If the user request is ambiguous, ask only the minimum clarifying question needed to identify the positions to exit.
py-clob-client via DirectClobTrader from scripts/polymarket_live.py is the canonical live execution path.tick_size, and submit a marketable sell priced at that market's minimum tick.price x size) across the full book, not just the best bid.Before any live buy, sell, or unwind:
tick_size and compute visible-book recovery or cost across all levels.py-clob-client is installed and POLY_PRIVATE_KEY or WALLET_PRIVATE_KEY, POLY_API_KEY, POLY_PASSPHRASE, and POLY_SECRET are loaded.Default mode should be --dry-run. Live trading requires:
python scripts/agent.py --config config.json --yes-live--dry-run and sets --yes-live for that processThe --yes-live flag is a startup-only live opt-in. It is not a per-order approval prompt.
This skill helps users set up and manage an autonomous trading agent that:
Pure Python Implementation
POLY_* headers remain as fallbackscripts/agent.py locallyComponents:
scripts/agent.py - Main trading loopscripts/seren_client.py - Seren API client (calls publishers)scripts/polymarket_client.py - Polymarket CLOB API wrapperscripts/setup_cron.py - skill-local seren-cron local-pull schedule managementscripts/run_local_pull_runner.py - local seren-cron polling runnerscripts/kelly.py - Position sizing calculatorscripts/position_tracker.py - Position managementscripts/logger.py - Trading loggerSeren Publishers Used:
polymarket-data - Real-time Polymarket market data (prices, volumes, liquidity)
GET /markets returns active prediction marketsTrading uses py-clob-client (via DirectClobTrader from scripts/polymarket_live.py)
POLY_PRIVATE_KEY, POLY_API_KEY, POLY_PASSPHRASE, POLY_SECRETperplexity - Perplexity AI research (via OpenRouter)
sonar for fast researchseren-models - Multi-model LLM inference (via OpenRouter)
anthropic/claude-sonnet-4.5seren-cron - Autonomous local-pull scheduling
scripts/agent.py locallyBefore running this skill, check for an existing Seren API key in this order:
API_KEY automatically. Check: echo $API_KEY. If set, no further action is needed..env file — check if SEREN_API_KEY is already set in the skill's .env file. If set, no further action is needed.SEREN_API_KEY is exported in the current shell. If set, no further action is needed.Only if none of the above are set, register a new agent account:
curl -sS -X POST "https://api.serendb.com/auth/agent" \
-H "Content-Type: application/json" \
-d '{"name":"polymarket-bot"}'
Extract the API key from the response at .data.agent.api_key — this key is shown only once. Write it to the skill's .env file:
SEREN_API_KEY=<the-returned-key>
Verify:
curl -sS "https://api.serendb.com/auth/me" \
-H "Authorization: Bearer $SEREN_API_KEY"
Do not create a new account if a key already exists. Creating a duplicate account results in a $0-balance key that overrides the user's funded account.
Reference: https://docs.serendb.com/skills.md
Check Python version and install requirements:
cd skills/polymarket-bot
# Check Python version (need 3.9+)
python3 --version
# Install dependencies
pip3 install -r requirements.txt
Create .env file from template:
cp .env.example .env
Edit .env and add:
# Seren API key (standalone mode) - create/manage from https://console.serendb.com
SEREN_API_KEY=your_seren_api_key_here
# Desktop sidecar/keychain mode (recommended)
SEREN_DESKTOP_PUBLISHER_AUTH=true
Desktop sidecar flow (recommended):
Legacy fallback mode (optional):
Set SEREN_DESKTOP_PUBLISHER_AUTH=false and provide:
POLY_API_KEY, POLY_PASSPHRASE, POLY_SECRET, POLY_ADDRESS
How to derive Polymarket credentials (legacy mode):
Security Note:
.env to git (already in .gitignore)Copy the example config and customize:
cp config.example.json config.json
Edit config.json to set your risk parameters:
{
"bankroll": 100.0,
"mispricing_threshold": 0.08,
"max_kelly_fraction": 0.06,
"scan_interval_minutes": 10,
"max_positions": 10,
"stop_loss_bankroll": 0.0
}
Parameter Guide:
Total capital available for trading (in USDC).
Minimum edge required to trade (as decimal, e.g., 0.08 = 8%).
Maximum % of bankroll per trade (as decimal, e.g., 0.06 = 6%).
How often to scan for opportunities.
Maximum concurrent open positions.
Stop trading if bankroll drops to this amount.
The config default bankroll is $100. Start small to test the strategy with real capital before scaling up.
| Item | Amount | Purpose | | ---------------- | -------- | ---------------------------------------------- | | Polygon USDC | $75 | Trading capital (allows $3-6 positions) | | SerenBucks | $25 | API costs (~25 scans at ~$1/scan) | | Total | $100 | Minimum to start live trading |
With a $100 bankroll and quarter-Kelly sizing (max_kelly_fraction: 0.06):
The key variable is scan frequency, not bankroll size. Reduce scan_interval_minutes to control API costs:
| Scan interval | Scans/day | API cost/day | Best for | | ------------- | --------- | ------------ | --------------------------------- | | Manual/daily | 1-2 | $1-2 | Testing with $100 budget | | 120 min | 12 | $12 | Active trading with $500+ budget | | 60 min | 24 | $24 | Experienced traders scaling up | | 30 min | 48 | $48 | High conviction, large bankroll |
Once you have validated edge through paper trading and small live trades, increase your bankroll and scan frequency together:
| Budget tier | USDC | SerenBucks | Recommended scan interval | | -------------- | -------- | ---------- | ------------------------- | | Starter | $75 | $25 | Manual or daily | | Active | $500 | $50-100 | 120 min | | Experienced | $1,000+ | $100-200 | 60 min | | Serious | $2,000+ | $200+ | 30 min |
Before deploying real capital, paper trade for 1-2 weeks to validate your edge.
Paper trading uses real market data and real AI analysis, but simulates trades instead of placing actual orders. This lets you:
How to paper trade:
python3 scripts/agent.py --config config.json --dry-run
What happens in dry-run mode:
logs/trading_*.logImportant: Paper trading still costs ~$1 per scan in API fees (Perplexly + Claude analysis). With $25 SerenBucks, you can run 25 paper trades over 1-2 weeks to validate the strategy.
Recommended paper trading plan:
"scan_interval_minutes": 120 in config.json (2-hour intervals)Manual paper trading (if <$25 SerenBucks):
Run scans one at a time when you want:
python3 scripts/agent.py --config config.json --dry-run --once
Once paper trading validates your edge (recommended: 50+ scans with positive expected value), you're ready for live trading.
Requirements for live trading:
If you don't have $100 yet:
--once scans to conserve SerenBucksCurrent Seren funding flow:
$5POST /wallet/depositCost breakdown per scan cycle (~$1.00 total):
Daily costs by scan interval:
Bridge USDC to Polygon PoS using:
Send to your Polymarket wallet address:
Verify balance:
Trading capital recommendations:
Before running the bot, verify both balances:
Check SerenBucks:
# If you have Seren MCP connected
# The bot will display balance when it starts
Check Polymarket USDC:
Test the bot without placing real trades:
python3 scripts/agent.py --config config.json --dry-run
Dry-run mode:
Expected output:
============================================================
🔍 Polymarket Scan Starting - 2026-02-12 14:35:00 UTC
============================================================
Balances:
SerenBucks: $23.45
Polymarket: $100.00
Scanning markets...
Found 23 markets
Evaluating: "Will BTC hit $100k by March 2026?"
Current price: 54.0%
🧠 Researching: "Will BTC hit $100k by March 2026?"
💡 Estimating fair value...
Fair value: 67.0% (confidence: medium)
✓ Opportunity found!
Edge: 13.0%
Side: BUY
Size: $3.24 (5.4% of available)
Expected value: +$0.42
[DRY-RUN] Would place BUY order:
Market: "Will BTC hit $100k by March 2026?"
Size: $3.24
Price: 54.0%
Expected value: +$0.42
============================================================
Scan complete!
Markets scanned: 23
Opportunities: 8
Trades executed: 0 (dry-run)
Capital deployed: $0.00
API cost: ~$0.46 SerenBucks
============================================================
⚠️ CRITICAL - You must explicitly confirm before enabling live trading
Before going live, ask yourself:
Display this warning:
⚠️ LIVE TRADING CONFIRMATION
You're about to enable LIVE TRADING with real money.
Configuration:
• Bankroll: $100.00
• Max per trade: 6% ($6.00)
• Scan interval: Every 10 minutes
• Stop loss: $0.00 (stop when depleted)
• Max positions: 10
Estimated Costs:
• SerenBucks: ~$2-5 per day (for API calls)
• Trading capital: Up to $100.00 (your bankroll)
Risks:
⚠️ You can lose money - prediction markets are uncertain
⚠️ Only risk what you can afford to lose
⚠️ Past performance doesn't guarantee future results
⚠️ The agent makes autonomous decisions based on AI estimates
⚠️ Market conditions can change rapidly
⚠️ Slippage and fees may reduce returns
The agent will run on schedule until you stop it.
Type exactly: START LIVE TRADING
(or 'cancel' to abort)
Wait for EXACT confirmation. Do not proceed unless user types "START LIVE TRADING".
Once confirmed, run the agent:
# Run once
python3 scripts/agent.py --config config.json
# Or create a seren-cron local-pull schedule for autonomous operation
Setting up seren-cron (for autonomous scheduling):
python3 scripts/setup_cron.py create --config config.json --schedule "0 */2 * * *" --live --run-type scan
python3 scripts/setup_cron.py create --config config.json --schedule "15 * * * *" --live --run-type monitor
python3 scripts/run_local_pull_runner.py --config config.json
The schedule lives in Seren, but the local polling process must stay online on the machine that should execute trades. Use scan for new entries and monitor for stale-order cleanup, live reconciliation, and automated guard exits.
Read current positions and display status:
import json
# Read positions
with open('skills/polymarket-bot/logs/positions.json', 'r') as f:
data = json.load(f)
# Display
print("📊 Polymarket Trading Status\n")
print(f"Positions: {data['position_count']}")
print(f"Total unrealized P&L: ${data['total_unrealized_pnl']:.2f}")
for pos in data['positions']:
pnl_symbol = '+' if pos['unrealized_pnl'] >= 0 else ''
print(f"\n {pos['market']}")
print(f" {pos['side']} ${pos['size']:.2f} @ {pos['entry_price'] * 100:.1f}%")
print(f" Now: {pos['current_price'] * 100:.1f}% ({pnl_symbol}${pos['unrealized_pnl']:.2f})")
Read and display trade history:
import json
# Read last 20 trades
with open('skills/polymarket-bot/logs/trades.jsonl', 'r') as f:
lines = f.readlines()
trades = [json.loads(line) for line in lines[-20:]]
print("📝 Recent Trades (Last 20)\n")
for i, trade in enumerate(reversed(trades), 1):
pnl_symbol = '' if trade['pnl'] is None else ('+' if trade['pnl'] >= 0 else '')
status_emoji = '🟢' if trade['status'] == 'open' else '✓' if trade['pnl'] and trade['pnl'] > 0 else '✗'
print(f"{i}. {status_emoji} {trade['side']} ${trade['size']:.2f} @ {trade['price'] * 100:.1f}%")
print(f" \"{trade['market']}\"")
if trade['pnl'] is not None:
print(f" P&L: {pnl_symbol}${trade['pnl']:.2f}")
print()
Pause (stop scheduled scans, keep positions):
python3 scripts/setup_cron.py pause --job-id <job_id>
Resume:
python3 scripts/setup_cron.py resume --job-id <job_id>
Stop completely (delete the cron job):
python3 scripts/setup_cron.py delete --job-id <job_id>
All activity is logged to JSONL files in logs/:
One line per trade (opened or closed):
{"timestamp": "2026-02-12T14:35:00Z", "market": "Will BTC hit $100k by March?", "market_id": "0x123...", "side": "BUY", "size": 3.24, "price": 0.54, "fair_value": 0.67, "edge": 0.13, "status": "open", "pnl": null}
One line per scan cycle:
{"timestamp": "2026-02-12T14:35:00Z", "dry_run": false, "markets_scanned": 500, "opportunities_found": 23, "trades_executed": 3, "capital_deployed": 9.45, "api_cost": 1.12, "serenbucks_balance": 48.88, "polymarket_balance": 103.45}
Current state (updated after each trade):
{
"positions": [
{
"market": "Will BTC hit $100k by March?",
"market_id": "0x123...",
"token_id": "0x456...",
"side": "BUY",
"entry_price": 0.54,
"current_price": 0.58,
"size": 3.24,
"unrealized_pnl": 0.84,
"opened_at": "2026-02-12T14:35:00Z"
}
],
"total_unrealized_pnl": 0.84,
"position_count": 1,
"last_updated": "2026-02-12T18:00:00Z"
}
Critical events for user notification:
{"timestamp": "2026-02-12T15:00:00Z", "level": "warning", "title": "Low SerenBucks Balance", "message": "Current: $1.23, Recommended: $20.00"}
The bot uses Claude to estimate true probabilities:
def estimate_fair_value(market_question, current_price, research):
prompt = f"""You are an expert analyst estimating the true probability of prediction market outcomes.
Market Question: {market_question}
Current Market Price: {current_price * 100:.1f}%
Research Summary:
{research}
Based on the research and your analysis, estimate the TRUE probability of this outcome occurring.
Provide your response in this exact format:
PROBABILITY: [number between 0 and 100]
CONFIDENCE: [low, medium, or high]
REASONING: [brief explanation]"""
# Call Claude via seren-models
response = seren.call_publisher(
publisher='seren-models',
method='POST',
path='/chat/completions',
body={
'model': 'anthropic/claude-sonnet-4-20250514',
'messages': [{'role': 'user', 'content': prompt}],
'temperature': 0.3
}
)
# Parse and return
# (parsing logic extracts PROBABILITY and CONFIDENCE from response)
def calculate_position_size(fair_value, market_price, bankroll, max_kelly=0.06):
"""
Calculate optimal position size using Kelly Criterion
Formula: kelly = (fair_value - price) / (1 - price) for BUY
Uses quarter-Kelly (divide by 4) for conservatism
Caps at max_kelly of bankroll
"""
kelly = (fair_value - market_price) / (1 - market_price)
kelly_adjusted = kelly / 4 # Quarter-Kelly
kelly_capped = min(kelly_adjusted, max_kelly)
position_size = bankroll * kelly_capped
return round(position_size, 2)
Core Trading Engine:
polymarket-data publisher (100+ active markets)perplexity publisher (Perplexity AI integration)seren-models publisher (Claude Sonnet 4.5)py-clob-client (DirectClobTrader with local EIP-712 signing)Infrastructure:
Seren Publishers Used:
polymarket-data - Real-time market data (prices, liquidity, volumes)py-clob-client - Order placement with local EIP-712 signing (via DirectClobTrader)perplexity - AI-powered market researchseren-models - LLM inference (Claude, GPT, Gemini, etc.)seren-cron - Autonomous local-pull schedulingNot Automated (Manual Only):
Not Implemented:
Per scan cycle:
Daily costs:
.env file from .env.exampleSEREN_API_KEY for standalone runsAPI_KEY is injected.env with SEREN_DESKTOP_PUBLISHER_AUTH=truePOLY_API_KEY, POLY_PASSPHRASE, POLY_ADDRESS to .envPOLY_* values and verify credentials haven't expiredUse the skill-local seren-cron local-pull runner for scheduling. The schedule lives in Seren, but a local polling process must stay online on the machine that will execute the bot.
Requirements: Seren Desktop login or a valid SEREN_API_KEY. Live schedules also require Polymarket credentials plus funded SerenBucks.
Current Seren funding flow:
https://serendb.com/serenbucks or https://console.serendb.com$5POST /wallet/depositpublisher: seren-cron
path: /api/health
method: GET
Create or upsert the runner plus the local-pull job:
python3 scripts/setup_cron.py create --config config.json --schedule "0 */2 * * *" --run-type scan
python3 scripts/setup_cron.py create --config config.json --schedule "15 * * * *" --run-type monitor
For live mode, include --live after you have confirmed credentials, budget, and risk parameters.
Start the polling process that claims due work and runs scripts/agent.py locally:
python3 scripts/run_local_pull_runner.py --config config.json
Leave this process running on the machine that should execute trades.
python3 scripts/setup_cron.py list
python3 scripts/setup_cron.py list-runners
python3 scripts/setup_cron.py pause --job-id <job_id>
python3 scripts/setup_cron.py resume --job-id <job_id>
python3 scripts/setup_cron.py delete --job-id <job_id>
python3 scripts/setup_cron.py delete-runner --runner-id <runner_id>
If a live trade or cycle fails because the trading balance or SerenBucks balance is too low to execute, immediately pause the cron job:
Pause the job immediately if live execution fails because trading funds or SerenBucks are exhausted.
Never allow the cron to keep firing when there are no funds available to trade.
This skill follows the AgentSkills.io open standard for agent skills, ensuring compatibility across:
Taariq Lewis, SerenAI, Paloma, and Volume at https://serendb.com Email: [email protected]
testing
Review-first outreach skill for the default Seren Bucks affiliate program. It bootstraps affiliate context via /programs/discover, mines sent-mail history and address books for candidates, persists them into a skill-owned CRM, proposes an editable daily top-10, drafts outbound and reply batches for approval, reconciles affiliate and reply signals, enforces hard DNC, and returns a manual daily digest.
data-ai
Lean partner-link distribution skill for the seren-affiliates publisher program portfolio. Operates one publisher program per run. Bootstraps the affiliate profile (registering on first run), caches joined programs in serendb, ingests contacts from a pasted list or from Gmail/Outlook address books, drafts a pitch once per run via seren-models for operator approval, sends approved copy through Gmail (preferred) or Microsoft Outlook, enforces per-program dedupe plus a global unsubscribe list, and reports local plus live conversion and commission stats from seren-affiliates.
development
Family office: Process an incoming GP capital call notice end-to-end — confirm, fund, log, reconcile.
development
Work with Seren Bounty affiliate bounties: customers create and fund verifier-backed bounties; agents join to receive a referral_code and accrue earnings as qualifying events are verified; a release sweep pays matured earnings out of escrow.