Skip to main content
TL;DR — the complete bot in 15
import httpx, time

client = httpx.Client(base_url="https://api.rekko.ai/v1", headers={"Authorization": "Bearer YOUR_API_KEY"}, timeout=120.0)
top = client.post("/screen", json={"platform": "kalshi", "min_volume_24h": 10000, "min_score": 50, "limit": 5}).json()
market = top[0]
resp = client.post(f"/markets/{market['platform']}/{market['market_id']}/analyze")
analysis_id = resp.json()["analysis_id"]
while client.get(f"/markets/{market['platform']}/{market['market_id']}/analyze/{analysis_id}/status").json()["status"] != "complete":
    time.sleep(5)
signal = client.post("/signals", params={"wait": "true"}, json={"market": f"{market['platform']}/{market['market_id']}", "risk_limit": "medium"}).json()
if signal["recommendation"] != "NO_TRADE":
    side = "yes" if "YES" in signal["recommendation"] else "no"
    trade = client.post("/trades/shadow", json={"ticker": market["market_id"], "platform": market["platform"], "side": side, "size_usd": signal["size_pct"] * 10000}).json()
    print(f"Trade placed: {trade['trade_id']} | {side.upper()} @ ${signal['size_pct'] * 10000:.0f}")

What this page covers

  • Screening Kalshi and Polymarket for high-volume, high-edge opportunities
  • Running AI-powered analysis on promising markets (async trigger/poll/retrieve pattern)
  • Generating trading signals with Kelly criterion position sizing
  • Executing paper trades via shadow trading to validate your strategy
  • Tracking portfolio performance (win rate, P&L, open positions)
  • Extending the bot with scheduling, webhooks, arbitrage, and portfolio-aware signals

Prerequisites

RequirementWhy
Python 3.10+Type hints and match statements used in examples
httpxHTTP client — pip install httpx or uv add httpx
Rekko API keySign up free — no credit card required
Platform credentials (optional)Kalshi or Polymarket API keys for live order execution
The Free plan includes 100 market listing calls and 10 analysis calls per month — enough to follow this entire tutorial. See Pricing for details.

Step-by-step tutorial

1

Set up the client

Create an authenticated client that you will reuse for every call. Set a generous timeout because analysis calls run a multi-stage research pipeline that takes 30-90 seconds.
import httpx

API_KEY = "YOUR_API_KEY"  # Replace with your key from https://rekko.ai/dashboard

client = httpx.Client(
    base_url="https://api.rekko.ai/v1",
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=120.0,  # Analysis can take 30-90 seconds
)

# Verify the key works
me = client.get("/customers/me").json()
print(f"Authenticated as {me['email']} ({me['plan']} plan)")
2

Screen markets for opportunities

The screening endpoint scores markets across a platform and returns the top candidates ranked by a composite of volume, price movement, and edge potential. Use it to find markets worth analyzing.
screen = client.post("/screen", json={
    "platform": "kalshi",
    "min_volume_24h": 10000,
    "min_score": 50,
    "limit": 10,
}).json()

print(f"Found {len(screen)} markets above threshold:\n")
for r in screen:
    print(f"  {r['market_id']:<30} | Score: {r['score']:>3} | {r['title'][:50]}")
Each result includes:
FieldDescription
market_idPlatform-specific ticker (e.g. KXFED-26MAR19)
platform"kalshi" or "polymarket"
titleHuman-readable market question
scoreComposite opportunity score (0-100)
volume_24h24-hour trading volume in dollars
yes_priceCurrent YES contract price (0-1)
actionQuick recommendation: "ANALYZE", "WATCH", or "SKIP"
Filter by category to focus on a specific domain:
Python
# Screen only politics markets on Polymarket
politics = client.post("/screen", json={
    "platform": "polymarket",
    "category": "politics",
    "min_volume_24h": 5000,
    "min_score": 40,
    "limit": 10,
}).json()
3

Get AI analysis on promising markets

Analysis runs a multi-stage research pipeline that takes 30-90 seconds. The pattern is: trigger, poll, retrieve.
import time

# Pick the top-scored market
market = screen[0]
platform = market["platform"]
market_id = market["market_id"]

# 1. Trigger analysis
resp = client.post(f"/markets/{platform}/{market_id}/analyze")
trigger = resp.json()
analysis_id = trigger["analysis_id"]
print(f"Analysis started: {analysis_id}")
print(f"Estimated time: {trigger['estimated_seconds']}s")

# 2. Poll until complete
while True:
    status = client.get(
        f"/markets/{platform}/{market_id}/analyze/{analysis_id}/status"
    ).json()
    if status["status"] == "complete":
        print("Analysis complete.")
        break
    if status["status"] == "error":
        raise Exception(status.get("error_message", "Analysis failed"))
    time.sleep(5)

# 3. Retrieve the full analysis
analysis = client.get(f"/markets/{platform}/{market_id}/analysis").json()

print(f"\n--- {analysis['title']} ---")
print(f"Probability:    {analysis['probability']:.0%}")
print(f"Confidence:     {analysis['confidence']:.0%}")
print(f"Edge:           {analysis['edge']:+.2f}")
print(f"Risk:           {analysis['risk_rating']}")
print(f"Recommendation: {analysis['recommendation']}")
print(f"Sources:        {analysis['source_count']} analyzed")
print(f"\nSummary: {analysis['summary']}")
Add ?expand=causal,scenarios to the retrieve call to get causal factor decomposition and bull/base/bear scenarios. See Expand Parameter.
4

Generate a trading signal

A signal wraps analysis into an actionable recommendation with Kelly criterion position sizing. Use ?wait=true for a synchronous response instead of the trigger/poll pattern.
signal = client.post("/signals", params={"wait": "true"}, json={
    "market": f"{platform}/{market_id}",
    "risk_limit": "medium",
}).json()

print(f"Recommendation: {signal['recommendation']}")
print(f"Target price:   {signal['target_price']:.2f}")
print(f"Edge:           {signal['edge']:+.2f}")
print(f"Confidence:     {signal['confidence']:.0%}")
print(f"Risk rating:    {signal['risk_rating']}")
print(f"Kelly fraction: {signal['size_pct']:.1%}")
print(f"Time horizon:   {signal['time_horizon']}")

# Calculate dollar size on a $10,000 bankroll
bankroll = 10_000
position_size = signal["size_pct"] * bankroll
print(f"\nPosition size:  ${position_size:.0f} (on ${bankroll:,} bankroll)")

Signal fields

FieldTypeDescription
recommendationstring"BUY_YES", "BUY_NO", or "NO_TRADE"
target_pricefloatRekko’s estimated fair price (0-1)
edgefloatDifference between fair price and market price
confidencefloatConfidence in the estimate (0-1)
risk_ratingstring"low", "medium", or "high"
size_pctfloatKelly-derived position size as fraction of bankroll
time_horizonstring"hours", "days", or "weeks"
hedgestringSuggested hedge position (if applicable)
expires_atstringISO 8601 timestamp — do not trade after this time
Always check expires_at before acting on a signal. Market conditions change and stale signals can lead to losses.
5

Execute the trade (paper trading)

Rekko provides intelligence — execution happens on the platform. Start with shadow trading (paper trades) to validate your strategy before risking real capital.
if signal["recommendation"] == "NO_TRADE":
    print("No edge found — skipping.")
else:
    side = "yes" if "YES" in signal["recommendation"] else "no"
    size_usd = signal["size_pct"] * bankroll

    trade = client.post("/trades/shadow", json={
        "ticker": market_id,
        "platform": platform,
        "side": side,
        "size_usd": round(size_usd, 2),
    }).json()

    print(f"Shadow trade placed:")
    print(f"  Trade ID:  {trade['trade_id']}")
    print(f"  Side:      {side.upper()}")
    print(f"  Size:      ${size_usd:.2f}")
    print(f"  Price:     {trade['fill_price']}")
Shadow trades track the market price at entry, simulate fills, and resolve automatically when the market settles. They cost nothing and use the same tracking infrastructure as live trades.

When you are ready for live execution

Rekko does not execute live trades on your behalf. Use the execution guidance endpoint to get platform-specific order parameters, then place the order using your platform’s API:
Python
# Get execution guidance (includes platform-specific order params)
guidance = client.post("/strategy/execution-guidance", json={
    "market": f"{platform}/{market_id}",
    "side": side,
    "size_usd": size_usd,
}).json()

print(f"Limit price:  {guidance['limit_price']}")
print(f"Order type:   {guidance['order_type']}")
print(f"Platform URL: {guidance['platform_url']}")

# Then place the order using the platform's own API
# See: https://trading-api.readme.io (Kalshi)
# See: https://docs.polymarket.com (Polymarket)
6

Track performance

Monitor your shadow portfolio to see how the strategy performs over time before committing real capital.
# Portfolio summary
portfolio = client.get("/portfolio", params={"mode": "shadow"}).json()

print(f"Open positions:   {portfolio['open_count']}")
print(f"Closed positions: {portfolio['closed_count']}")
print(f"Win rate:         {portfolio['win_rate']:.0%}")
print(f"Total P&L:        ${portfolio['total_pnl']:+.2f}")
print(f"Bankroll:         ${portfolio['bankroll']:.2f}")

# List individual positions
print(f"\n{'Ticker':<25} {'Side':<5} {'Entry':<7} {'P&L':>8}")
print("-" * 50)
for pos in portfolio["positions"]:
    print(f"{pos['ticker']:<25} {pos['side']:<5} {pos['entry_price']:<7.2f} ${pos['pnl']:>+7.2f}")
Use the performance endpoint for historical metrics:
Python
perf = client.get("/performance", params={"mode": "shadow"}).json()

print(f"Sharpe ratio:     {perf['sharpe_ratio']:.2f}")
print(f"Max drawdown:     {perf['max_drawdown']:.1%}")
print(f"Avg edge:         {perf['avg_edge']:+.2f}")
print(f"Avg hold time:    {perf['avg_hold_hours']:.0f} hours")
print(f"Total trades:     {perf['total_trades']}")

Complete script

Here is the full bot as a single copy-paste-ready Python script. It screens markets, analyzes the top candidate, generates a signal, and places a shadow trade.
Python
#!/usr/bin/env python3
"""
Prediction market trading bot using the Rekko AI API.

Screens markets for high-edge opportunities, runs AI analysis,
generates Kelly-sized trading signals, and paper trades via shadow mode.

Usage:
    pip install httpx
    export REKKO_API_KEY="your_key_here"
    python trading_bot.py
"""

import os
import sys
import time

import httpx

API_KEY = os.environ.get("REKKO_API_KEY")
if not API_KEY:
    print("Set REKKO_API_KEY environment variable first.")
    print("Sign up free at https://rekko.ai/dashboard")
    sys.exit(1)

BANKROLL = 10_000  # Starting bankroll in dollars
MIN_SCORE = 50     # Minimum screening score to analyze
MIN_EDGE = 0.05    # Minimum edge (5%) to trade
PLATFORM = "kalshi" # "kalshi" or "polymarket"

client = httpx.Client(
    base_url="https://api.rekko.ai/v1",
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=120.0,
)


def screen_markets() -> list[dict]:
    """Screen markets and return candidates sorted by score."""
    results = client.post("/screen", json={
        "platform": PLATFORM,
        "min_volume_24h": 10000,
        "min_score": MIN_SCORE,
        "limit": 10,
    }).json()
    print(f"Screened {len(results)} markets above score {MIN_SCORE}")
    return results


def analyze_market(platform: str, market_id: str) -> dict:
    """Trigger analysis, poll until complete, and return the result."""
    resp = client.post(f"/markets/{platform}/{market_id}/analyze")
    analysis_id = resp.json()["analysis_id"]
    print(f"  Analysis started: {analysis_id}")

    while True:
        status = client.get(
            f"/markets/{platform}/{market_id}/analyze/{analysis_id}/status"
        ).json()
        if status["status"] == "complete":
            break
        if status["status"] == "error":
            raise Exception(status.get("error_message", "Analysis failed"))
        time.sleep(5)

    return client.get(f"/markets/{platform}/{market_id}/analysis").json()


def get_signal(platform: str, market_id: str) -> dict:
    """Generate a trading signal with Kelly position sizing."""
    return client.post("/signals", params={"wait": "true"}, json={
        "market": f"{platform}/{market_id}",
        "risk_limit": "medium",
    }).json()


def place_shadow_trade(platform: str, market_id: str, side: str, size_usd: float) -> dict:
    """Place a paper trade via shadow trading."""
    return client.post("/trades/shadow", json={
        "ticker": market_id,
        "platform": platform,
        "side": side,
        "size_usd": round(size_usd, 2),
    }).json()


def show_portfolio():
    """Print current shadow portfolio summary."""
    portfolio = client.get("/portfolio", params={"mode": "shadow"}).json()
    print(f"\n--- Portfolio ---")
    print(f"Open: {portfolio['open_count']} | Closed: {portfolio['closed_count']}")
    print(f"Win rate: {portfolio['win_rate']:.0%} | P&L: ${portfolio['total_pnl']:+.2f}")


def main():
    print(f"Screening {PLATFORM} markets...\n")
    candidates = screen_markets()

    if not candidates:
        print("No markets above threshold. Try lowering MIN_SCORE.")
        return

    for candidate in candidates[:3]:  # Analyze top 3
        market_id = candidate["market_id"]
        platform = candidate["platform"]
        print(f"\n{'='*60}")
        print(f"Analyzing: {candidate['title'][:55]}")
        print(f"Ticker: {market_id} | Score: {candidate['score']}")
        print(f"{'='*60}")

        analysis = analyze_market(platform, market_id)
        print(f"  Probability: {analysis['probability']:.0%}")
        print(f"  Edge: {analysis['edge']:+.2f}")
        print(f"  Risk: {analysis['risk_rating']}")

        if abs(analysis["edge"]) < MIN_EDGE:
            print(f"  Edge below {MIN_EDGE:.0%} threshold — skipping.")
            continue

        signal = get_signal(platform, market_id)
        print(f"  Signal: {signal['recommendation']}")
        print(f"  Kelly size: {signal['size_pct']:.1%} (${signal['size_pct'] * BANKROLL:.0f})")

        if signal["recommendation"] == "NO_TRADE":
            print("  No trade recommended.")
            continue

        side = "yes" if "YES" in signal["recommendation"] else "no"
        size_usd = signal["size_pct"] * BANKROLL
        trade = place_shadow_trade(platform, market_id, side, size_usd)
        print(f"  Shadow trade placed: {trade['trade_id']}")
        print(f"  {side.upper()} @ ${size_usd:.2f}")

    show_portfolio()


if __name__ == "__main__":
    main()

Going further

Schedule the bot on a cron

Run the script every hour to continuously screen for new opportunities:
# crontab -e
0 * * * * cd /path/to/bot && REKKO_API_KEY=your_key python trading_bot.py >> bot.log 2>&1
Or use webhooks for real-time triggers instead of polling. See Webhooks and streaming.

Portfolio-aware signals

When you have multiple open positions, standard signals do not account for correlation. The portfolio signal endpoint considers your existing holdings and adjusts sizing to avoid concentration:
Python
signal = client.post("/signals/portfolio", params={"wait": "true"}, json={
    "market": f"{platform}/{market_id}",
    "risk_limit": "medium",
    "positions": portfolio["positions"],  # Pass your current holdings
    "bankroll": BANKROLL,
}).json()

print(f"Adjusted size: {signal['size_pct']:.1%}")  # May be smaller to reduce correlation
if signal.get("concentration_warning"):
    print(f"Warning: {signal['concentration_warning']}")

Cross-platform arbitrage

Find price discrepancies between Kalshi and Polymarket on the same event:
Python
arb = client.get("/arbitrage").json()

for opp in arb:
    print(f"{opp['title']}")
    print(f"  Kalshi YES: {opp['kalshi_yes_price']:.2f}")
    print(f"  Polymarket YES: {opp['polymarket_yes_price']:.2f}")
    print(f"  Spread: {opp['spread']:+.2f}")
See Cross-platform arbitrage guide for a full walkthrough.

Use Rekko from your AI coding assistant

Install the Rekko MCP server to query markets, run analyses, and generate signals directly from your editor:
# Claude Code
claude mcp add rekko-mcp -- uvx rekko-mcp@latest

# Cursor
# Add to .cursor/mcp.json — see docs for config
Then ask your assistant: “Screen Kalshi for high-edge politics markets and analyze the top result.” See MCP integration.

How the pieces fit together

StepEndpointTierCost
Screen marketsPOST /v1/screenINSIGHT$0.10
Trigger analysisPOST /v1/markets/{p}/{id}/analyzeINSIGHT$0.10
Poll statusGET /v1/markets/{p}/{id}/analyze/{id}/statusFree$0.00
Retrieve analysisGET /v1/markets/{p}/{id}/analysisINSIGHT$0.10
Generate signalPOST /v1/signalsSTRATEGY$2.00
Shadow tradePOST /v1/trades/shadowFree$0.00
PortfolioGET /v1/portfolioFree$0.00
PerformanceGET /v1/performanceFree$0.00
A single screen-analyze-signal-trade cycle costs approximately 2.30ontheProplan(2.30** on the Pro plan (0.10 screen + 0.10trigger+0.10 trigger + 0.10 retrieve + 2.00signal).Screeningandanalysisalone(withoutsignalgeneration)costs2.00 signal). Screening and analysis alone (without signal generation) costs **0.30.
The Free plan includes 10 INSIGHT calls per month. For automated bots that run frequently, upgrade to Pro for 500 INSIGHT calls and 50 STRATEGY calls.

What’s next

Prediction market API comparison

Compare Rekko with Kalshi, Polymarket, and other market data APIs.

Cross-platform arbitrage

Find and exploit price gaps between Kalshi and Polymarket.

Kelly criterion sizing

Deep dive on the math behind position sizing.

API reference

Full endpoint documentation with interactive playground.

MCP integration

Use Rekko from your AI coding assistant.