Updated Oct 4, 2026 10:22 PM ET.
Two files, no dependencies. agent_starter.py fetches the feed, keeps the evaluations
whose stated edge beats your threshold, and places a paper order for each through the same
place_limit_order the MCP server exposes: fair price required, fee printed, quarter-Kelly
net of fee, 5% per market and 25% total caps, kill switch, one live writer per key.
curl -O https://ipredictsport.com/mcp_server.py
curl -O https://ipredictsport.com/agent_starter.py
python agent_starter.py --min-edge 8 --confidence medium --bankroll 500Going live is one flag and one account: pip install cryptography, set
KALSHI_API_KEY_ID and KALSHI_PRIVATE_KEY_PATH to your key, and add
--live. Start at one dollar. Create ~/.ipredict/KILL to stop everything.
#!/usr/bin/env python3
"""iPredictSport agent starter -- a paper-trading tennis agent in ~80 lines.
curl -O https://ipredictsport.com/mcp_server.py # order placement + feed
curl -O https://ipredictsport.com/agent_starter.py # this file
python agent_starter.py # paper, no account needed
python agent_starter.py --min-edge 8 --bankroll 500
What it does, every run: fetch the free feed, keep evaluations whose stated
edge beats --min-edge and whose confidence is at least --confidence, and place
a PAPER limit order for each at the current market price with the model's
probability as the stated fair price. Sizing is quarter-Kelly net of the Kalshi
maker fee, capped at 5% per market and 25% total (mcp_server enforces it).
To trade for real you need a Kalshi account with an API key (humans open
accounts; agents trade): set KALSHI_API_KEY_ID and KALSHI_PRIVATE_KEY_PATH,
`pip install cryptography`, and pass --live. Start at $1. Grade yourself on
closing-line value, not win rate: https://ipredictsport.com/track-record.html
"""
from __future__ import annotations
import argparse
import json
import sys
import urllib.request
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from mcp_server import place_limit_order, resolve_kalshi_market # noqa: E402 (same directory)
FEED = "https://ipredictsport.com/predictions.json"
BANDS = {"low": 1, "medium": 2, "high": 3, "very_high": 4}
def fetch_feed() -> dict:
req = urllib.request.Request(FEED, headers={"User-Agent": "ipredict-agent-starter/1.0"})
with urllib.request.urlopen(req, timeout=15) as resp:
return json.loads(resp.read().decode("utf-8"))
def candidates(feed: dict, min_edge_pp: float, min_band: str) -> list[dict]:
out, seen = [], set()
for e in feed.get("kalshi_evaluations") or []:
edge = float(e.get("edge_pp") or 0.0)
band = str(e.get("confidence_band") or "low").lower()
event = (e.get("trade_action") or {}).get("ticker") # EVENT ticker
price, fair, pick = e.get("market_price"), e.get("pick_win_prob"), e.get("pick")
if not event or price is None or fair is None or event in seen:
continue # one order per event; the feed lists several products
if edge < min_edge_pp or BANDS.get(band, 1) < BANDS[min_band]:
continue
seen.add(event)
out.append({"event": event, "match": e.get("match"), "pick": pick,
"price": float(price), "fair": float(fair), "edge_pp": edge, "band": band})
return sorted(out, key=lambda c: -c["edge_pp"])
def main() -> int:
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("--min-edge", type=float, default=5.0, help="minimum stated edge, pp")
ap.add_argument("--confidence", default="medium", choices=list(BANDS))
ap.add_argument("--bankroll", type=float, default=1000.0)
ap.add_argument("--max-orders", type=int, default=5)
ap.add_argument("--live", action="store_true", help="sign with YOUR Kalshi key")
a = ap.parse_args()
feed = fetch_feed()
picks = candidates(feed, a.min_edge, a.confidence)
print(f"feed {feed.get('generated_utc')}: {len(picks)} candidates >= {a.min_edge}pp "
f"at >= {a.confidence} confidence; placing up to {a.max_orders} "
f"({'LIVE' if a.live else 'paper'})\n")
for c in picks[: a.max_orders]:
print(f"{c['match']}: {c['pick']} fair {c['fair']:.3f} vs {c['price']:.2f} "
f"(+{c['edge_pp']:.1f}pp, {c['band']})")
# One Kalshi market per player under the event; buy YES on the pick's.
mk = resolve_kalshi_market(c["event"], c["pick"])
if not mk:
print(" -> skipped: could not resolve a unique market for the pick\n")
continue
print(" ->", place_limit_order(
"kalshi", mk["ticker"], "yes", c["price"], c["fair"],
mode="live" if a.live else "paper", maker=True, bankroll=a.bankroll,
why=f"model {c['fair']:.3f} vs market {c['price']:.2f}"), "\n")
print("ledger: python mcp_server.py order --help | ~/.ipredict/paper_orders.jsonl")
return 0
if __name__ == "__main__":
sys.exit(main())
The threshold. Our public ledger scores worse than the T-6h market, so "edge_pp" in the feed is a model opinion, not money. The honest agent records every order's price against the T-6h price and reports closing-line value with n and a band after a hundred orders, then decides. That grading step is rung 6, and it is the one that separates a bot from a tout.
Where can an agent actually trade? Only where there is an API, and only the exchanges have one. See which platforms let an AI agent trade for you before you go live. Humans open accounts; agents trade. Never automate account creation or identity checks.
Disclosure: the Kalshi link is a partner link; we may earn a referral credit at no cost to you. 18+ on exchanges, 21+ at sportsbooks, state rules apply. Gambling problem? 1-800-GAMBLER. Paper first; the ledger, not the win rate, is the score.
1. Analytical & Research Use Only: iPredictSport is a quantitative research platform publishing statistical estimates for educational, informational, and analytical purposes only. iPredictSport is not an investment adviser, commodity trading advisor (CTA), registered broker-dealer, or sports wagering operator. Nothing contained on this site, in our API, or in our newsletters constitutes financial advice, investment recommendations, or sports betting advice.
2. Hypothetical & Simulated Performance (CFTC Rule 4.41): Performance figures for our autonomous paper agent and proposed bet track records are simulated, hypothetical, and based on paper audits. Unlike an actual performance record, simulated results do not represent actual trading, may not reflect market liquidity, exchange slippage, or trading bans, and cannot account for psychological risk factors. No representation is made that any user will or is likely to achieve profits or losses similar to those shown. Past performance does not guarantee future results.
3. Market Risk & Capital Loss: Trading binary contracts on prediction markets (such as Kalshi or Polymarket) or placing sports wagers involves substantial financial risk, including the possible loss of 100% of staked capital. Odds and spreads fluctuate continuously. Users assume sole responsibility for their own trading decisions and bankroll sizing.
4. Responsible Gaming & Age Requirements: Fliff sweepstakes is available to legal residents aged 18+ in eligible states. Financial prediction exchanges (including Kalshi) require 18+, and commercial sportsbooks require 21+, subject to jurisdiction. If you or someone you know has a gambling problem and wants help, confidential crisis counseling and referral services can be accessed 24/7 by calling 1-800-GAMBLER (1-800-426-2537) or visiting ncpgambling.org.
5. Affiliate & Compensation Disclosure: iPredictSport may receive affiliate commissions, referral fees, or cost-per-acquisition (CPA) compensation from links to partners (including Fliff, Kalshi, and Polymarket) at no additional cost to you. For Fliff, attribution requires entry of promo code IPREDICT or IPSLIVE in the mobile app. Fliff is a sweepstakes sports product for adults 18+ and is void where prohibited by law (18 excluded states). This commercial compensation does not alter our objective quantitative probabilities, model outputs, or editorial gates.
Full text: Terms of Use · Disclaimer · Affiliate & Advertising Disclosure · Privacy Policy