Guides
Building a Trading Bot
This guide walks through building a bot that scans for mispriced markets and trades automatically.
Strategy overview
- Fetch all open series from the API
- Compare the OU model's prior (opening price) to the current market price
- When the gap exceeds a threshold, place a trade
- Track positions and P&L
Setup
pip install aiohttp
npm install node-fetch
Step 1: Fetch open markets
import aiohttp
API = 'https://api.settled.pro/v1'
KEY = 'stld_YOUR_KEY'
async def get_open_series():
async with aiohttp.ClientSession() as session:
async with session.get(f'{API}/series?limit=100',
headers={'X-API-Key': KEY}) as res:
data = await res.json()
return [s for s in data['data']
if s.get('current_round', {}).get('status') == 'open']
const API = 'https://api.settled.pro/v1'
const KEY = 'stld_YOUR_KEY'
async function getOpenSeries() {
const res = await fetch(`${API}/series?limit=100`, {
headers: { 'X-API-Key': KEY }
})
const { data } = await res.json()
return data.filter((s: any) => s.current_round?.status === 'open')
}
Step 2: Score opportunities
The OU model sets the opening price. If the current price diverges from the OU prior, there may be edge.
def score_opportunity(series):
round = series['current_round']
ou_prior = float(round['ou_prior'])
current_yes = float(round['yes_price'])
confidence = float(round['ou_confidence'])
# Gap between model and market
gap = ou_prior - current_yes
# Only trade when model is confident and gap is meaningful
if confidence < 0.65:
return None
if abs(gap) < 0.05:
return None
return {
'slug': series['slug'],
'market_id': round['id'],
'side': 'yes' if gap > 0 else 'no',
'gap': abs(gap),
'confidence': confidence,
'price': current_yes if gap > 0 else float(round['no_price'])
}
Step 3: Execute trades
async def place_trade(session, market_id, side, amount_usdc):
async with session.post(
f'{API}/markets/{market_id}/trade',
headers={'X-API-Key': KEY, 'Content-Type': 'application/json'},
json={'side': side, 'usdc_amount': str(amount_usdc)}
) as res:
result = await res.json()
if result.get('error'):
print(f"Trade failed: {result['error']['message']}")
return None
trade = result['data']
print(f"Bought {trade['shares']} {side.upper()} shares at {trade['price_per_share']}")
return trade
Step 4: Main loop
import asyncio
async def run_bot():
async with aiohttp.ClientSession() as session:
while True:
series_list = await get_open_series()
opportunities = []
for s in series_list:
opp = score_opportunity(s)
if opp:
opportunities.append(opp)
# Sort by gap (biggest mispricing first)
opportunities.sort(key=lambda x: x['gap'], reverse=True)
for opp in opportunities[:3]: # Max 3 trades per cycle
await place_trade(
session,
opp['market_id'],
opp['side'],
amount_usdc=10.0 # Fixed size per trade
)
# Wait 5 minutes before next scan
await asyncio.sleep(300)
asyncio.run(run_bot())
Position sizing
Start with fixed $10 per trade. Once profitable over 50+ trades, scale to 2% of bankroll per trade using the risk management guide.
Next steps
- Add WebSocket subscription for real-time price updates instead of polling
- Track P&L per series and stop trading series with negative ROI
- Implement the cross-exchange divergence strategy from the trading guide