Documentation
The full documentation ships inside the package (bilingual EN/ES). This page covers what you need to decide whether it's for you, plus the quickstart.
Requirements
- Python 3.11+ on Windows, Linux or macOS. No Docker required.
- A network location where Polymarket is accessible (see geographic restrictions). Many users run a ~$5/month VPS.
- For dry-run: nothing else. No wallet, no funds, no account.
- For live trading: a dedicated Polymarket wallet with a small USDC balance on Polygon + ~$1–2 of POL for gas.
Quickstart (dry-run, no money)
cd uruguabot
pip install -r requirements.txt
cp .env.example .env # Windows: copy .env.example .env
python uruguabot.py
The bot discovers live 5-minute markets, applies the real entry gates, and simulates fills using slippage distributions measured from real trades. Every 30 seconds it prints a diagnostic "funnel" showing exactly which gate filtered which candidate — you always know why it is or isn't trading.
Optional monitor panel (measures the real accuracy of every signal, including your own manual picks):
python monitor_server.py # then open http://localhost:8770
The default configuration is the validated one
The shipped .env.example is exactly the configuration that was profitable in our live testing ("Hypothesis B"):
- Asymmetric exits: stop-loss at execution price −10¢; winners held to $1.00/$0.00 resolution. Profitable at a 40% win rate because average wins were roughly 2× average losses — a validated mechanism rather than a proven ROI.
- BTC only (
ASSETS=btc): BTC outperformed ETH consistently in our measured data. ETH is opt-in. - SELL-consensus entries in the 0.55–0.70 price band — the tested band.
- Volatility guard on (
MAX_VOL_2MIN=0.0018): skips regimes where measured SL slippage exploded (median −2¢, worst decile −24¢). - Risk rails on: daily-loss %, consecutive-loss and unfilled-ratio circuit breakers.
Going live (only after dry-run convinces you)
- Create a dedicated Polymarket wallet. Never use your main wallet. Fund it small.
- Set
WALLET_ADDRESS,PRIVATE_KEYandPOLY_SIG_TYPEin.env(1 = email/proxy wallet, 0 = MetaMask/EOA). - Verify everything first:
python check_wallet.py - Set
DRY_RUN=falseandLIVE_CONFIRM=YES. The bot refuses to start live without both — that's deliberate. - Start at
BET_USD=2and watch the first hours against your Polymarket activity page.
What's included
~15 core Python files: trading engine, CLOB V2 execution layer with ghost-fill protection, multi-timeframe signals, Chainlink oracle feed, optional ML gate with retraining script, calibrated dry-run simulator, risk rails, monitor panel, and ops tooling (check_status.py, check_wallet.py, compare_dry_vs_live.py, diagnose_orphan_shares.py). Plus bilingual READMEs, a full strategy & results document, EULA and risk disclosure.
Read the source before you buy it
You are buying readable Python, so here is what that actually looks like — the real file listing, and one real function copied byte-for-byte out of the package. Nothing here is minified, obfuscated or compiled.
uruguabot/ # 21 Python files, 6735 lines, nothing compiled # core engine (15) 420 uruguabot.py # main loop, market discovery, the 30s diagnostic funnel 608 urubot_actions.py # evaluate / execute - every entry gate lives in here 1105 execution.py # Polymarket CLOB V2: FOK buys, ghost-fill verification, exits 340 polymarket.py # read-only Gamma client: slug generation, market discovery 154 signals.py # multi-timeframe consensus engine (30s / 1m / 5m) 171 market_features.py # the 11 market features recorded at decision time 100 simulator.py # dry-run fills drawn from the measured slippage distributions 144 price_feed.py # price thread: Chainlink -> Binance -> Coinbase -> CoinGecko 472 chainlink_feed.py # reads Polymarket's own resolution oracle over public RPC 337 risk_rails.py # daily-loss / losing-streak / unfilled-ratio circuit breakers 208 logger.py # atomic bet log: tmp + rename, keeps a .bak, survives a kill -9 247 brain.py # optional ML gate - ships untrained and off unless you enable it 292 retrain_v3.py # retrains that gate on your own data 191 snipe.py # optional T-10s late entry on observed Chainlink delta (off) 659 monitor_server.py # the local accuracy monitor that serves monitor.html # ops tooling (6) 302 check_wallet.py # verifies wallet + auth before you are ever allowed to go live 387 check_status.py # status report computed over the bet log 129 check_polymarket.py # "what is Gamma answering right now?" diagnostic 188 compare_dry_vs_live.py # measures dry-run vs live drift 112 diagnose_orphan_shares.py # finds shares the bot bought but could not sell 169 close_stale_bets.py # closes bets stuck OPEN when the monitor could not resolve them 6735 total
wc -l counts of the shipped source — 15 core modules, 6 ops scripts, 6,735 lines. The grouping and the one-line comments were added by hand; the filenames and the line counts were not. else:
# /positions no muestra las shares todavia. La
# FUENTE DE VERDAD es el USDC: si la plata SALIO de
# la wallet, el FOK llenó y las shares SON nuestras
# (la data-api /positions laggea en mercados de 5m).
# Solo es NO_MATCH si el USDC quedó intacto.
now_usdc = self.get_balance_usdc()
delta = None
if (pre_usdc is not None and now_usdc is not None
and pre_usdc >= 0 and now_usdc >= 0):
delta = float(pre_usdc) - float(now_usdc)
if delta is not None and delta < bet_usd * 0.5:
# Plata intacta -> el FOK realmente no matcheó.
return BuyResult(ok=False, no_match=True,
error=f"NO_MATCH (usdc intact, delta=${delta:.3f})")
# Fix May 30: FILL REAL con lag de /positions. NO
# abandonar (antes -> GHOST_FILL, sin SL, perdida
# del stake completo). Un FOK success llena al 100%,
# asi que trackeamos las shares pedidas para que la
# posicion reciba SL y monitoreo normal.
spent = delta if delta is not None else bet_usd
self.log.warn(
f"[exec] positions-api lag: FOK success + USDC "
f"-${spent:.2f} pero /positions={verified_size} "
f"({vmethod}). Asumo fill real de {shares} shares "
f"y trackeo la posicion para SL/monitoreo.")
return BuyResult(
ok=True, exec_price=exec_price,
shares=shares, bet_usd=bet_usd,
order_id=str(order_id),
slippage=exec_price - chosen_price,
positions_lag=True)
execution.py, lines 684–715, copied byte-for-byte: original indentation, original comments, original “Fix May 30” note. This is the ghost-fill verification the audit is about — when Polymarket’s /positions endpoint has not caught up, the USDC balance delta decides whether the order really filled, instead of the bot abandoning a live position with no stop-loss on it. And note the comments are in Spanish: the author is Argentine and wrote the trading core in his own language. The README, the strategy document and the config file are fully bilingual — the in-code comments are not. Better you know that now than after paying.git clone https://github.com/Emi-db/polymarket-bot-audit
cd polymarket-bot-audit
python analysis/compute_summary.py # standard library only, nothing to install
compute_summary.py (MIT, standard library only) recomputes every headline number from them, sample sizes included. No dependencies, no account. If our arithmetic is wrong, that script is how you find out.Support policy
One-time purchase, sold as-is: no support service, no update subscription, no server dependency. The code is deliberately small and heavily commented so you can own and maintain it. That policy is what keeps the price at $99 instead of $99/month.
Refunds: there are no refunds once the source has been downloaded — it is delivered source code. That is why dry-run is the default mode: you can run the real bot on real live markets, with no wallet and no money, for as long as you like before you buy.