This is a Polymarket copy-trading bot. Every cycle it polls a list of "smart-money" wallets, detects new trades on their accounts, and decides whether to mirror them — either for real (LIVE mode) or as paper trades for analysis (DRY RUN mode). DRY RUN still records everything; the only difference is whether an order hits the order book.
Each cycle runs three phases in sequence:
TradeSignal for every
candidate. Apply gating filters here (blacklist, whitelist, source
size band, price band, slippage, book depth, market
resolved/expired). Anything rejected is recorded as a skipped trade
with a machine-readable skip_reason.
trader_win_rate
(fetched from Polymarket's closed-positions API). Falls back to
ratio sizing if stats are missing.
The Wallets tab tracks every wallet the monitor polls. The Settings tab then decides which of those are actually copyable:
The blacklist is always applied regardless of mode - it's a defense-in-depth ban list.
The lists themselves are not settings: they live in
wallet_lists.json on the data volume, next to the date
and sample size of the dataset that validated them (currently two
non-overlapping June 2026 dry-run windows; only wallets whose sign
holds in both windows are listed). A whitelisted wallet may
carry an entry-price band; copies outside it are skipped as
wallet_band_out_of_range. The bot refuses to start if
the file is missing, so an old hardcoded list can never be copied by
accident. Read it at GET /api/wallet-lists, replace it
with PUT /api/wallet-lists.
max_slippage from the source trade price.
[min_yes_price, max_yes_price]. Longshots and chalk
both lose money in the data.
min_source_trade_size (dust = noise) or above
max_source_trade_size (whale exits, not alpha).
min_book_depth USD available.
Every cycle the bot calls check_dryrun_settlements(), which
runs two parallel resolution tracks:
source_trade_size × copy_ratio, clamped to single-bet
limits). This produces a "what would we have made if we had not
filtered this trade out?" number per skip reason, which is what
makes filter tuning data-driven instead of guesswork.
Skipped trades keep status="skipped" after resolution so
realized-PnL summaries continue to exclude them. Counterfactual stats
appear in a separate block of the trades summary.
Toggle dry_run in the Settings tab to switch modes.
DRY RUN never sends orders to Polymarket — it records the trade as if
it had been placed, so you get full PnL and analytics without spending
money. LIVE requires polymarket_private_key +
polymarket_funder_address configured via env vars (secrets
are never editable from the dashboard). In LIVE mode, the wallet
balance overrides the configured bankroll per cycle.
Before any order leaves Phase 3, can_trade() checks:
daily-loss limit, weekly-loss limit, max open positions, max daily bet
volume, and per-bet size bounds. Any failure blocks the trade with a
machine-readable reason and records it as a
risk_blocked skip — which is itself counterfactual-scored,
so you can see what your risk limits cost you.