CLOB connected chain · polygon-137 latency · 42ms
spec · v0.5.0 · CLOB V2 bots · 97 library/spec-sheet
Polytraders
POLYTRADERS / ENG SPEC / INTERNAL SOURCE OF TRUTH

Engineering source of truth.

This document is the authoritative spec for every bot that touches the order path — discovery, risk, execution, wallet signing, or post-trade reporting. 97 defined modules — 23 live, 13 beta, 61 planned. A module exists when its contract is documented; it works when that contract is fully implemented.

Use this when scoping a new module, debugging an unexpected REJECT, reviewing any PR that touches the order path, or onboarding a new engineer. Everything here applies in production.

order.lifecycle read-only
discovery.rank()              // Layer 0 · which markets?strategy.intent               // Layer 3requires
risk.approve()              // Layer 1 · can REJECTsecurity.canSign()          // Layer 5 · can REJECTexecution.shape()          // Layer 2 · can RESHAPEclob.submit({                // CLOB V2
  builder_code: "polytraders",
  signature: "eip712-v2",
})
   ↓
governance.log()            // Layer 6 · explain + audit
no execution path bypasses Risk + Security
Module status · today

97 defined modules. Maturity is uneven — and explicit. data-status on every row is the source of truth; filter by status in the toolbar to see exactly what is operational.

23
LiveProduction-connected. Order path. Audited.
13
BetaTested, limited deployment, monitored.
61
PlannedDesigned, not implemented. Contract documented.
97
Total definedAcross 7 layers. Every row has a status.
How to read this page

The whole pipeline, in three phases.

Polytraders is a 97-module pipeline across 7 layers, but every order does exactly three things: find a good market, decide whether the trade is safe and well-shaped, then send it and explain it. This section is the map. Everything below expands on those three phases.

PHASE 01

Before the trade — what should we trade?

Every live Polymarket market is scored: is this worth trading? Markets that pass go to strategy; markets that fail are invisible to it. Putting Discovery first is what keeps Layer 3 from wasting budget on thin or ambiguous markets.

  • Step 1 · L0 · Discovery Score every market for volume, spread, depth, dispute risk, rule clarity, time-to-resolution. Only qualifying markets continue.
  • Step 2 · L3 · Strategy A strategy module emits an OrderIntent (direction, size, max price, TTL). The risk envelope it declared at startup is read here, not on submit.
PHASE 02

Deciding the trade — is this safe and well-shaped?

Three independent contracts run in sequence. Risk votes and can REJECT. Security verifies the wallet can safely sign and can also REJECT. Execution can RESHAPE — split, retype, defer — but cannot relax a Risk decision. There is no override flag.

  • Step 3 · L1 · Risk · CAN REJECT 16 guards vote: portfolio limits, drawdown, oracle queue, liquidity, fees, settlement clustering, model drift. One REJECT kills the order.
  • Step 4 · L5 · Security · CAN REJECT Verify session-key scope, render the EIP-712 v2 payload for audit, confirm contract address against the CLOB V2 allow-list.
  • Step 5 · L2 · Execution · CAN RESHAPE Choose order type, timing, queue strategy, gas envelope. Serialise wallet writes via NonceShepherd.
PHASE 03

After the trade — submit, then explain.

The order is signed and submitted to a CLOB V2 Exchange contract, with the Polytraders builder code always attached. After fill, cancel, or expiry, the platform writes a full lineage record and a plain-English explanation of what happened and why — queryable by users and Polymarket builder-program reviewers alike.

  • Step 6 · CLOB V2 submit EIP-712 v2 signature, builder_code = "polytraders" (always), tick size + neg-risk flag read fresh from client.getMarket() per order.
  • Step 7 · L6 · Governance Log the full lineage (intent → risk vote → security check → reshape → submit → fill). Reconcile attribution daily. PostTradeExplainer renders a plain-English explanation per trade.
CLOB V2 · NATIVE

This spec is CLOB V2-native.

Polymarket's CLOB V2 went live on 28 April 2026 — new Exchange contracts, rewritten CLOB backend, new order/signing requirements. Polytraders is built against V2 from day one. ContractAddressGuard (5.8) refuses any V1 address. VersionCompatibilityGuard (part of 5.8) refuses old SDK versions, deprecated signing formats, and stale market metadata. If you're porting code from a V1 reference, treat it as a re-implementation, not a migration.

Governance flow · technical

How an order travels through the stack.

The seven phases above, in technical detail. Read this before touching anything in strategy/*, execution/*, or the wallet-signing surface. Risk is authoritative: a REJECT stops the order before it reaches Execution, full stop. Execution may reshape (resize, defer, switch order type, split into IOC chunks) but cannot relax a Risk decision. After submit, Governance logs, reconciles, and audits builder-code attribution. There are no bypass flags. CI must prove no execution path reaches CLOB submit without passing through both Risk and Security.

  1. 01

    Market discovery

    MarketScanner ranks all live markets; OpportunityQueue surfaces only those that qualify for the user's enabled strategies. Strategies never see markets that didn't pass discovery.

  2. 02

    Strategy intent

    A Layer-3 bot decides direction and size, then emits an OrderIntent. The risk envelope it declared at startup (max_notional, max_per_market, max_drawdown) is read here, not on submit.

  3. 03

    Risk Layer · CAN REJECT

    Every guard in Layer 1 votes. PortfolioGuard checks aggregate exposure; LiquidityGuard checks book depth; OracleRiskMonitor checks UMA queue; RateLimitGovernor enforces request budget; ComplianceGate enforces jurisdiction; CapitalAllocator checks risk budget; ModelDriftMonitor flags decaying alpha. One REJECT kills the order.

  4. 04

    Security & wallet check

    WalletPermissionGuard verifies session-key scope; SessionKeyManager (5.4) confirms the active session key is in-scope and unexpired; SignaturePreviewer renders the EIP-712 v2 payload for audit; ContractAddressGuard confirms the order targets a known CLOB V2 Exchange address from the allow-list. Any failure → REJECT.

  5. 05

    Execution Layer · CAN RESHAPE

    SmartRouter chooses limit vs IOC vs maker quote based on book depth and urgency. AntiToxicFill suppresses fills against obviously informed flow. QueueWarden manages amend/cancel lifecycle. NonceShepherd serialises wallet writes. GasOracle prices the gas envelope. OrderLifecycleManager records every state transition for audit.

  6. 06

    CLOB V2 submit · always builder-tagged

    EIP-712 v2 signed with the wallet's session key against the CLOB V2 Exchange contract. builder_code is always set — there is no code path that submits without it. Tick size and neg-risk flag are read fresh from client.getMarket() per order, never cached.

  7. 07

    Governance · log, reconcile, attribute, explain

    Fill written to the run log with full lineage (intent → risk vote → security check → reshape → submit → fill). PnLAccountant updates positions. BuilderAttribution reconciles the fill against Polymarket's builder report on a 24h rolling window. PostTradeExplainer renders a plain-English explanation users and reviewers can audit.

Data contracts

Six schemas every module on the order path must speak.

These are the wire formats that flow through the pipeline. Every module that emits, votes on, reshapes, signs, submits, or logs an order must speak them. A new bot that does not produce or consume the correct schemas does not pass code review. Field names and types here are normative; runtime validators are generated from them. The full machine-readable source lives in polytraders-spec/schemas/*.ts.

L3 · STRATEGY

OrderIntent

What a strategy emits. The only thing Risk knows about a proposed order before it votes.

interface OrderIntent {
  intent_id:        string;          // ULID, generated by strategy
  strategy_id:      string;          // FK → StrategyRegistry
  strategy_version: string;          // semver from registry
  market_id:        string;          // condition_id
  token_id:         string;          // YES or NO ERC-1155 id
  side:             "BUY" | "SELL";
  size:             bigint;          // base units, no decimals
  max_price:        number;          // 0 < x < 1, in cents
  order_type_hint:  "GTC" | "GTD" | "FOK" | "IOC";
  ttl_ms:           number;          // upper bound; Execution may shorten
  reason_code:      string;          // free-form; logged
  risk_envelope_id: string;          // FK → RiskEnvelope at strategy startup
  emitted_at:       number;          // unix ms
}
L1 · RISK

RiskVote

One vote per Risk guard, per OrderIntent. PortfolioGuard's vote, LiquidityGuard's vote, etc. Aggregated downstream.

interface RiskVote {
  intent_id:         string;          // FK → OrderIntent
  guard_id:          string;          // e.g. "PortfolioGuard"
  status:            "APPROVE" | "REJECT" | "DOWNSIZE";
  severity:          0 | 1 | 2 | 3;   // 0 info, 3 critical
  reason_code:       string;          // enum; logged
  reason_detail:     string | null;
  suggested_size:    bigint | null;   // only if status === "DOWNSIZE"
  suggested_action:  "FLATTEN_ALL" | "PAUSE_STRATEGY" | "RETRY_LATER" | null;
  voted_at:          number;
}
L2 · EXECUTION

ExecutionPlan

Output of SmartRouter after Risk + Security approve. The shape of the actual order, including any child orders for icebergs.

interface ExecutionPlan {
  intent_id:    string;
  order_type:   "GTC" | "GTD" | "FOK" | "IOC";
  price:        number;             // final, validated against tick_size
  size:         bigint;             // ≤ OrderIntent.size
  expiry_ms:    number | null;      // GTD only
  child_orders: ExecutionPlan[];    // recursion for iceberg/peg
  routing_note: string;             // e.g. "iceberg.4x · top-of-book"
  planned_at:   number;
}
L5 · SECURITY

SecurityCheck

The output of Layer 5 before any wallet signs. Captures contract allow-list, session-key scope, and signature preview.

interface SecurityCheck {
  intent_id:         string;
  wallet_id:         string;          // address
  contract_address:  `0x${string}`;   // must be in allow-list
  contract_version:  "CLOB_V2";       // CLOB_V1 → REJECT
  chain_id:          137;             // polygon-137
  signature_domain:  EIP712Domain;    // full domain captured
  session_key_id:    string | null;   // null = primary key
  session_scope:     SessionScope;    // markets, max_size, expiry
  preview_payload:   string;          // EIP-712 JSON; hashed in log
  status:            "APPROVE" | "REJECT";
  reject_reason:     string | null;
  checked_at:        number;
}
L6 · GOVERNANCE

GovernanceLog

Append-only lineage record. Written exactly once per intent, regardless of whether the order filled, was rejected, or expired.

interface GovernanceLog {
  lineage_id:        string;          // = intent_id
  bot_versions:      Record<string, string>;  // every module that touched it
  parameters:        Record<string, unknown>; // params at the time
  intent:            OrderIntent;
  risk_votes:        RiskVote[];
  security_check:    SecurityCheck;
  execution_plan:    ExecutionPlan | null;
  submit_result:     SubmitResult | null;
  fill_events:       FillEvent[];
  final_state:       "FILLED" | "PARTIAL" | "CANCELLED" | "EXPIRED" | "REJECTED";
  builder_attributed: boolean;        // reconciled at T+24h
  closed_at:         number;
}
L6 · GOVERNANCE

PostTradeExplanation

User-facing plain-English render of GovernanceLog. Generated by PostTradeExplainer (6.12) on every trade. Queryable in the user dashboard and by Polymarket builder reviewers.

interface PostTradeExplanation {
  lineage_id:    string;
  why_trade:     string;             // strategy reason in plain English
  why_size:      string;             // sizing logic
  why_price:     string;             // limit/IOC + price selection
  risk_summary:  string;              // which guards APPROVED
  outcome:       string;              // fill/PnL or rejection reason
  generated_at:  number;
  schema_v:      "1.0";
}

schemas/ also defines: SubmitResult, FillEvent, RiskEnvelope, SessionScope, EIP712Domain. See polytraders-spec/schemas/index.ts for the complete tree.

Known assumptions · open questions

What we are assuming, and where the spec is not yet final.

Parts of this document are firm; others are working assumptions; others are open questions tracked in the spec repo. This section lists them explicitly. Anything not listed here should be treated as load-bearing.

Working assumptions (treat as firm unless this list changes)

  • Polymarket CLOB V2 is the only target. No code path may submit to a V1 Exchange contract or sign a V1-format order. ContractAddressGuard (5.8) enforces.
  • Polygon mainnet (chain-137) only. Other chains require a new spec branch.
  • Resolution via UMA Optimistic Oracle. Spec assumes UMA's current proposal/dispute model. A change to the oracle model is a P0 spec change.
  • Builder-code attribution is bytes32, attached to every order, reconciled daily. BuilderAttribution is the source of truth for commercial reporting.
  • Rate limits are configured at runtime from Polymarket's current published limits. Never hardcoded in code or in this spec.

Open questions (tracked, not yet resolved)

  • Session-key issuance UX. EIP-7702 vs scoped EOA delegation vs smart-account session keys — currently dual-tracked under SessionKeyManager (5.4). Decision required before Limited Live for any Layer 3 module.
  • RPC quorum policy. Whether RPCFailoverManager (5.6) requires 2-of-3 agreement on critical reads (allowance, balance, fill confirmation) or single-source with verification. TBD.
  • Resolution-source disambiguation. How SourceOfTruthVerifier (4.9) handles conflicting authoritative sources (e.g. AP vs Reuters call discrepancies on election night). Currently human-in-the-loop.
  • Hosted-runtime jurisdiction policy. Mid-session jurisdiction changes — close-only is the default, but the boundary case where a connection drops and resumes from a different IP needs a written policy.
  • Strategy promotion gates. Some Layer-3 modules cannot meaningfully backtest (e.g. News-Materiality) — alternative gating criteria are TBD.
The library

Seven layers. Ninety-seven bots.

Each layer is its own table. Discovery sits before Strategy — strategies only ever see markets that MarketScanner has already qualified. Security & Wallet sits between Risk and Execution — nothing reaches the CLOB without a passing wallet, contract, and signature check. Filter by layer or status, or search by name, signal, or parameter. The ?layer=…&status=… deep-link still works for sharing a focused view. Flagship bots (★) are the highest-blast-radius modules; ship changes to them with a second pair of eyes.

Layer
Status
Classification

Six classes. Different authority, different blast radius.

The 7-layer taxonomy tells you where a bot sits in the pipeline. The classification below tells you what authority it holds — and therefore what tests, reviews, and approvals are required before any change ships.

Class 01

Guardrails

Can block, shrink, quarantine, or flatten.

Test discipline: integration tests must include a REJECT path for every guardrail. A guardrail that has never returned REJECT in CI is a guardrail that doesn't work.

PortfolioGuardKillSwitchOracleRiskMonitorBlacklistKeeperWalletPermissionGuardContractAddressGuard
Class 02

Execution Utilities

Can shape orders but not decide direction.

Test discipline: property tests must show that no reshape ever changes side, sign, or strategy intent — only price, size, type, and timing. Reshaping into a directional change is a P0 bug.

SmartRouterAntiToxicFillQueueWardenNonceShepherdPartialFillHandlerCancelReplaceOptimizer
Class 03

Alpha Strategies

Can express directional, spread, or liquidity views.

Test discipline: Research → Backtest → Shadow → Limited Live promotion gate (see lifecycle). Every strategy ships with a documented failure-mode block.

Maker-TightLate-Resolution SpreadResolution Fair-ValueVolatilityHarvestBasisTraderResolutionCurveTrader
Class 04

Signal Services

Produce inputs but never trade.

Test discipline: every published signal carries provenance + freshness. Stale signals must degrade gracefully downstream — never silently extrapolated.

NewsIngestOddsFeedMarketOntologyBuilderResolutionRuleParserWallet Flow ClassifierLiquidityForecastModel
Class 05

Governance Services

Audit, explain, approve, report.

Test discipline: every state change writes an immutable record. PostTradeExplainer output is the user-facing trust feature — treat its accuracy as load-bearing.

StrategyRegistryPostTradeExplainerParameterChangeAuditorIncidentCommanderBuilderAttributionAttributionRevenueReporter
Class 06

User Tools

Help users configure, understand, control.

Test discipline: usability bugs in this class are product bugs, not edge cases. Wrong copy here causes wrong configurations downstream.

Bot RecommenderRisk Budget WizardScenario SimulatorBot SandboxStrategy Compare ViewExplain My Risk

Test requirements per class

Every class has a minimum test bar before any module of that class merges. These are enforced in CI; missing tests fail the build.

ClassRequired test types
GuardrailsUnit tests for every REJECT path. Property test: there is no input that produces APPROVE when the configured limit is exceeded. Integration test: order pipeline halts on REJECT.
Execution UtilitiesUnit tests for shape decisions. Determinism test: same OrderIntent + book snapshot produces same ExecutionPlan. Adversarial book test (toxic fills, partial fills, queue jumping).
Alpha StrategiesBacktest reproducibility test. Out-of-sample test on a held-out window. Failure-mode test: each declared failure mode is provoked and the safe-fallback fires.
Signal ServicesSchema-conformance test on every emit. Staleness test: degraded inputs produce a stale flag, not a fresh value. No-trade contract: fuzz that the module never emits an order.
Governance ServicesAppend-only test (logs cannot be mutated). Reconciliation test (BuilderAttribution matches Polymarket's report ± tolerance). Renderability test for PostTradeExplanation.
User ToolsSnapshot test for every UI state. Permission test: no user-tool action can bypass a Risk or Security check.
LAYER 0 · MARKET DISCOVERY

Six bots that decide which markets we even look at.

Discovery runs before everything else. If MarketScanner says a market is unqualified, no Layer-3 strategy ever sees it — that is the contract. OpportunityQueue is the cockpit feed: a ranked list of best-next-trades per strategy type, the product of MarketQualityRanker scores and per-strategy fit weights. EventCalendarMapper, NewMarketWatcher, and DuplicateMarketDetector keep the rank fresh and honest. Integration test for any new strategy: pass it an empty discovery result and confirm it halts gracefully. The platform must not speculate when discovery has nothing to offer.

# Bot Status Goal Polymarket signals monitored External feeds / sources Key user-set parameters
0.1 MarketScanner PLANNED Continuously scan every live Polymarket market and score it for tradability before any strategy is allowed to consider it.
  • Gamma API market list with condition-id metadata
  • CLOB book depth, spread, last-trade ts
  • Neg-risk flag and tick-size per market
  • Market resolution rules text
none
  • scan_interval_s · int
  • min_volume_24h_usd · int
  • min_book_depth_usd · int
  • max_spread_bps · int
0.2 ★ MarketQualityRanker
flagship
PLANNED Score markets across volume, spread, depth, dispute risk, rule clarity, volatility, and time-to-resolution. Sits before every strategy.
  • Book depth and spread per market
  • Market resolution rules + ambiguity score
  • Dispute state and historical dispute frequency
  • Mid-price drift over rolling windows
  • UMA Optimistic Oracle history
  • min_quality_score · 0–1
  • weight_liquidity · float
  • weight_rule_clarity · float
  • weight_resolution_horizon · float
0.3 EventCalendarMapper PLANNED Map every market to a known calendar (elections, sports fixtures, court dates, CPI/Fed releases, earnings, debates) for pre-event positioning.
  • Market resolution date + timezone
  • Condition-id metadata
  • Linked-event identifiers from Gamma API
  • Sports schedule APIs
  • FRED macro releases
  • Election commission feeds
  • Court calendars
  • event_lookahead_h · int
  • enabled_calendars · list
  • timezone_default · enum
  • min_event_relevance · 0–1
0.4 ★ OpportunityQueue
flagship
PLANNED Maintain a ranked queue of "best next trades" per strategy type. Output = MarketQualityRanker × per-strategy fit-scores.
  • Quality score from MarketQualityRanker
  • Top-of-book size and book depth
  • Per-strategy fit-score inputs (vol, spread, time-to-res)
  • Open positions per market (for double-up suppression)
none
  • queue_depth · int
  • refresh_interval_s · int
  • strategy_filters · list
  • suppress_existing_position · bool
0.5 NewMarketWatcher PLANNED Detect newly listed markets and flag early liquidity opportunities before the book gets crowded.
  • New condition-id metadata appearing on Gamma API
  • Initial book state (or absence of book)
  • Tick-size and neg-risk flag at listing
  • ETag from Gamma API for cheap polling
  • poll_interval_s · int
  • min_listing_age_s · int
  • alert_to_strategies · list
  • require_rule_parse · bool
0.6 DuplicateMarketDetector PLANNED Find semantically identical or dangerously overlapping markets to reduce accidental correlated exposure and to support cross-market arb.
  • Market title and rules text
  • Condition-id metadata
  • Resolution source and date
  • Outcome-token list (for neg-risk events)
  • Local sentence-embedding model
  • similarity_threshold · 0–1
  • require_manual_review · bool
  • publish_to · list
  • max_cluster_size · int
LAYER 1 · RISK

Sixteen non-bypassable guardrails.

The authority layer. Sixteen bots vote on every OrderIntent before it leaves the process — account limits, kill switches, oracle risk, liquidity depth, rate caps, inventory unwinds, blacklists, jurisdiction gates, and guards covering user suitability, capital allocation, correlation shocks, model drift, tail-loss, fee economics, settlement exposure, and override discipline. Each runs in its own goroutine and short-circuits on REJECT — there is no retry-with-different-params loophole. When adding a new strategy, the first integration test must confirm it fails gracefully on each guard returning REJECT. If it deadlocks, the strategy is wrong, not the guard.

# Bot Status Goal Polymarket signals monitored External feeds / sources Key user-set parameters
1.1 PortfolioGuard LIVE Enforce account-level limits across every running strategy.
  • Aggregate notional across all open positions
  • Realised + unrealised drawdown over rolling 24h
  • Per-market and per-event concentration
  • Correlated-cluster exposure across neg-risk events
none
  • max_account_notional_pct · 0–100
  • max_24h_drawdown_pct · 0–100
  • max_per_market_pct · 0–100
  • max_cluster_pct · 0–100
1.2 KillSwitch LIVE One-button — or auto-triggered — flatten-all when something breaks.
  • Equity drawdown breaching circuit-breaker threshold
  • Order-reject rate spike (API misbehaviour, wallet desync)
  • CLOB WebSocket dead > 30s with open positions
  • Admin UI manual flag
  • intraday_drawdown_pct · 0–50
  • weekly_drawdown_pct · 0–50
  • reject_rate_circuit · 0–100
  • require_manual_reset · bool
1.3 ★ OracleRiskMonitor
flagship
LIVE Watch the UMA oracle queue for resolution risk on positions we hold.
  • Market metadata: resolution-source flag, neg-risk "Other" definition shifts
  • Open positions in markets entering proposal / dispute
  • UMA Optimistic Oracle on-chain events
  • UMA dispute & vote queues
  • reduce_at_proposal_pct · 0–100
  • block_disputed · bool
  • max_dispute_window_h · 0–168
  • downgrade_size_by_confidence · bool
1.4 LiquidityGuard LIVE Stop strategies from chewing through thin books.
  • CLOB book depth on the target market
  • Best-bid / best-ask resting size
  • Spread vs. 30-day median spread for that market
  • Top-of-book staleness (no movement in 60s)
none
  • max_pct_of_visible_depth · 0–100
  • min_top_of_book_usd · int
  • max_spread_multiple · float
  • stale_top_seconds · int
1.5 RateLimitGovernor LIVE Stay inside Polymarket's published API limits across all strategies.
  • Polymarket-published request and order rate budgets, configured at runtime — never hardcoded
  • Cloudflare-enforced sliding-window counters per endpoint
  • 429 responses observed (priority cancel / risk-flatten always preserved)
none
  • public_req_per_min · int
  • trading_req_per_min · int
  • priority_cancel_over_open · bool
  • priority_risk_flatten · bool
1.6 InventoryUnwinder LIVE Bleed off accidental directional exposure when a market-maker drifts.
  • Net position vs. strategy's declared inventory band
  • Mark-to-market PnL on a maker bot with one-sided inventory
  • Strategy-halt or crash signal with open inventory
none
  • max_inventory_band · int
  • unwind_aggression · 0–100
  • passive_only · bool
  • handback_threshold_pct · 0–100
1.7 BlacklistKeeper BETA Refuse to trade markets that are structurally hostile.
  • Market resolution rules text (ambiguous trigger words: "substantial", "primary", undefined sources)
  • Single-source resolution flag
  • Market history of prior disputes
  • Time-to-resolution < configured threshold
  • Operator-curated blacklist
  • Community / shared dispute history
  • blacklisted_condition_ids · list
  • min_hours_to_resolution · int
  • block_single_source · bool
  • ambiguity_keywords · list
1.8 ComplianceGate LIVE Enforce geo and KYC parity with Polymarket's terms in the hosted runtime.
  • Polymarket onboarding state on linked wallet
  • Wallet IP / connection metadata
  • OFAC / sanctioned-address lists
  • require_polymarket_onboarded · bool
  • blocked_jurisdictions · list
  • sanctions_list_source · enum
  • close_only_on_violation · bool
1.9 StrategySuitabilityGate PLANNED Block strategies that don't match the user's declared experience and capital level.
  • User profile: declared experience tier, account age, completed onboarding flags
  • Strategy class tag (basic / intermediate / advanced)
  • Account equity vs. strategy's required minimum
none
  • min_experience_tier · enum
  • min_equity_usd · int
  • require_explicit_optin · bool
  • cooldown_after_loss_h · int
1.10 ★ CapitalAllocator
flagship
PLANNED Carve the user's risk budget across strategies; refuse new orders that exceed the slice.
  • Per-strategy notional and risk-budget consumption
  • Strategy declared volatility tier and historical drawdown
  • Free vs. allocated capital by tag (maker / arb / event / advanced)
  • Pending-fill reserve so partial fills don't double-count
none
  • strategy_budget_pct · map
  • tag_budget_pct · map
  • reserve_buffer_pct · 0–50
  • rebalance_cron · cron
1.11 CorrelationShockGuard PLANNED Detect when supposedly independent positions start moving as one.
  • Rolling correlation matrix across open positions (returns, mark moves)
  • Cluster topology from CrossMarketGraph (4.4)
  • Synchronised mid-price moves across >N markets
none
  • shock_corr_threshold · 0–1
  • shock_lookback_min · int
  • action_on_shock · enum
  • min_cluster_size · int
1.12 ★ ModelDriftMonitor
flagship
PLANNED Flag strategies whose live behaviour has decoupled from their backtest distribution.
  • Live fill-rate, slippage, and edge realised vs. backtest priors
  • Feature-distribution drift on each strategy's input vector
  • Rolling KL / population-stability index per feature
  • Time-since-last-shadow-rerun
none
  • psi_threshold · float
  • min_live_samples · int
  • action_on_drift · enum
  • auto_pause_on_p0 · bool
1.13 TailLossSimulator PLANNED Stress-test open book against scripted shock scenarios before sizing up.
  • Open positions, neg-risk topology, oracle exposure
  • Scenario library: gap-to-1, gap-to-0, oracle-flip, simultaneous-resolution
  • Resulting margin / equity hit per scenario
none
  • max_scenario_loss_pct · 0–100
  • scenarios_enabled · list
  • run_on_each_intent · bool
  • cron_full_sweep · cron
1.14 FeeAndGasGuard PLANNED Refuse trades whose realistic fee and gas burden eats more than the configured edge fraction.
  • Per-route taker / maker fee, expected fill size and price
  • Predicted edge from strategy (in bps)
  • Builder-attribution rebate offset
  • L2 / Polygon gas oracle (live)
  • max_fee_pct_of_edge · 0–100
  • max_gas_pct_of_edge · 0–100
  • include_rebates · bool
  • reject_on_dust · bool
1.15 SettlementExposureGuard PLANNED Cap simultaneous resolution risk — how much equity is locked in markets that could settle in the same UMA window.
  • Open exposure aggregated by resolution date / window
  • UMA queue density and dispute frequency by source
  • Neg-risk-event simultaneous-settlement clusters
none
  • max_window_exposure_pct · 0–100
  • window_size_h · int
  • halt_on_breach · bool
  • warn_threshold_pct · 0–100
1.16 ManualOverrideAuditor PLANNED Require, log, and rate-limit human overrides of any guardrail.
  • Override events: who, when, which guard, REJECT reason
  • Per-user override frequency vs. budget
  • Two-person-rule fulfilment for P0 guards
none
  • require_two_person · list
  • max_overrides_per_day · int
  • auto_lock_on_burst · bool
  • publish_to_audit_log · bool

What each Risk bot is doing, in plain English

1.1PortfolioGuard

Think of this as the speed limiter on the whole account. It looks across every running strategy and asks: are we, in aggregate, taking on too much risk for one wallet? It tracks four things — total notional exposure, 24-hour drawdown, how much of the account is in any single market, and how much is in clusters of related markets (e.g., three different Senate races in the same election event).

The parameters are all upper-bound percentages. max_account_notional_pct is "don't let total open positions exceed X% of wallet equity". max_24h_drawdown_pct is the rolling-loss circuit breaker. max_cluster_pct stops the user from accidentally betting the same outcome four ways through correlated markets.

1.2KillSwitch

The big red button. It either auto-fires when something is clearly wrong (intraday drawdown breaches the threshold, the CLOB WebSocket dies for more than 30 seconds with positions open, the API starts rejecting orders at a sustained rate), or the user/operator triggers it manually. When it fires, it cancels every open order, posts IOC orders to flatten inventory at top-of-book plus a tolerance, and refuses new orders until someone manually resets it.

intraday_drawdown_pct and weekly_drawdown_pct are the auto-trigger thresholds. require_manual_reset is locked to true — we never let a bot self-reset out of a kill, because if the kill fired the assumption is something is genuinely broken.

1.3OracleRiskMonitor (flagship)

Polymarket settles via the UMA optimistic oracle. Resolution typically completes within the UMA optimistic-oracle cycle (proposal → liveness → finalisation). Disputed markets may remain unresolved through the dispute window, during which positions are effectively frozen with binary settlement risk. Exact windows are configured per market via UMA parameters. This bot watches the UMA queue continuously and reacts to four things: a market we hold entering the proposal stage, a dispute being opened on a market we're in, ambiguous resolution-source flags in the market metadata, and the "Other" outcome in neg-risk events whose definition is shifting.

reduce_at_proposal_pct tells the bot to cut position size by X% the moment a proposal goes live (default behaviour: trim to 50%). block_disputed stops new entries on any market in dispute. max_dispute_window_h is how long you're willing to sit through a dispute before being auto-flattened.

1.4LiquidityGuard

Stops a strategy from eating through a thin order book and taking massive slippage. Before any order goes out, this bot looks at the visible depth at the best bid and ask, the spread vs. that market's typical 30-day spread, and how stale the top of book is. If the order would consume more than X% of visible depth, or the spread is way wider than normal, or the top has been frozen for over a minute (a stale-quote signal that the book may be unreliable), the order gets throttled or blocked.

max_pct_of_visible_depth caps how much of the visible book any single order can sweep — default 5%. min_top_of_book_usd is a floor on resting size before we'll consider quoting at all.

1.5RateLimitGovernor

Polymarket's public-endpoint and trading-endpoint limits are configured at runtime from Polymarket's current published values; exact values are read from configuration, never hardcoded. With many strategies running at once, it's easy to blow through those limits and start getting 429-rate-limited responses, which then cascade into missed cancels and stuck orders. This bot is a token-bucket queue across all strategies, prioritising cancels and risk-driven flattens over speculative new orders.

priority_cancel_over_open means cancels jump the queue. priority_risk_flatten means a Risk-Layer-initiated flatten skips the queue entirely. The user effectively never sees this bot — it just keeps the platform inside Polymarket's published limits.

1.6InventoryUnwinder

Market-makers are supposed to hold balanced inventory — if they keep getting filled on the same side, they end up with a directional bet they didn't sign up for. This bot detects when inventory drifts past the strategy's declared band, when a maker is bleeding mark-to-market while one-sided, or when a strategy crashes with open positions. When it fires, it replaces the strategy's quotes with one-sided passive orders that lean against the inventory until balance is restored, then hands control back.

max_inventory_band is the directional exposure cap. unwind_aggression controls how hard it leans — 0 means very passive resting orders, 100 means take the offer to flatten.

1.7BlacklistKeeper

Some markets are structurally bad places to trade — ambiguous resolution rules with words like "substantial" or "primary" that aren't defined, single-source resolutions from unreliable feeds, markets with prior dispute history, or markets resolving inside a window where you don't want to be touching them. This bot maintains a list of those markets (curated by the operator and informed by community / shared dispute history) and hard-blocks every strategy from quoting on them.

blacklisted_condition_ids is the explicit do-not-trade list. ambiguity_keywords is a list of phrases that, if found in resolution rules, auto-blacklist the market.

1.8ComplianceGate

The hosted Polytraders runtime enforces session-level access controls: it checks that the connected wallet's IP/connection metadata is not from a restricted jurisdiction, that Polymarket onboarding is complete on the linked wallet, and that no sanctions-list match exists. If any check fails at session start, the runtime does not come up.

Hosted vs SDK posture. The hosted runtime is responsible for enforcing access controls. The SDK exposes the same guard interfaces, but enforcement on self-hosted deployments is the user's responsibility — the SDK ships the checks; deployment ships the policy.

Mid-session changes. If jurisdiction or sanctions status changes during a session (for example, a new IP after a reconnect), the runtime drops to close_only: existing positions can be wound down, no new entries are accepted, and a governance event is emitted. Reactivation requires a fresh session.

Data retention. Connection metadata used for the gate is retained only for the active session and 30-day audit window required by the builder program; the long-term ledger stores only the access-decision and reason code, not the raw IP.

LAYER 2 · EXECUTION

Thirteen bots that decide how orders get on the book.

Execution never picks direction or size — those come from Strategy. It decides order type (limit, IOC, FOK, maker quote), timing, and microstructure behaviour (aggressive vs passive, replenish vs once-and-done). Most production bugs live here, because this is where strategy intent collides with real CLOB conditions: partial fills, queue displacement, gas spikes, wallet desync, and exchange maintenance windows. Read SmartRouter's decision matrix and OrderLifecycleManager's state diagram before adding any new order-type behaviour.

# Bot Status Goal Polymarket signals monitored External feeds / sources Key user-set parameters
2.1 SmartRouter LIVE Translate strategy intent into the right order type, price, and timing.
  • Real-time book depth on the target market
  • Recent fill rate & queue-position estimate
  • client.getMarket() tick size + neg-risk flag (per order)
none
  • default_order_type · enum (FOK, GTC, GTD)
  • iceberg_threshold_usd · int
  • iceberg_child_count · int
  • gtd_signal_ttl_s · int
2.2 AntiToxicFill BETA Avoid being run over right before bad news.
  • One-sided sweeps through > 3 levels in last 5s
  • Cancel-storm on the opposite side
  • Realised post-fill drift over a rolling window
  • NewsIngest adverse-event hits within ±30s of a fill
  • cooldown_s · int
  • requote_widen_bps · int
  • downsize_factor · 0–1
  • news_window_s · int
2.3 QueueWarden LIVE Manage maker queue position across price levels.
  • Drift of our quote vs. best bid/ask in ticks
  • Cancellations of better-priced orders ahead of us
  • Stale-quote risk: order resting > T seconds with no book movement
none
  • drift_ticks_threshold · int
  • stale_ttl_s · int
  • cancel_replace_per_min_cap · int
  • min_queue_position · int
2.4 NonceShepherd LIVE Keep EIP-712 signing reliable under load.
  • Pending signed-but-unposted orders count
  • Nonce gaps detected during submit
  • Safe wallet rotation events
  • pending_orders_threshold · int
  • resequence_on_gap · bool
  • refuse_during_gap_s · int
  • l2_credential_ttl_h · int
2.5 GasOracle LIVE Decide when on-chain operations are economical.
  • Pending neg-risk conversion EV vs. expected gas cost
  • Polygon gas-price oracles
  • 24h gas baseline (rolling)
  • max_gas_percentile_for_ops · 0–100
  • conversion_min_ev_usd · float
  • defer_non_urgent · bool
  • never_defer_risk · bool (locked true)
2.6 ★ OrderLifecycleManager
flagship
PLANNED Single source of truth for every order's state machine, from intent to terminal.
  • Order acks, partial fills, full fills, replaces, cancels, rejects, expirations
  • Builder-attribution metadata on every transition
  • Reconciliation against CLOB V2 user-state endpoint each tick
  • Detected stuck-in-flight orders and orphaned acks
none
  • stuck_order_timeout_s · int
  • reconcile_interval_s · int
  • auto_cancel_orphans · bool
  • publish_audit_log · bool
2.7 FillQualityAnalyzer PLANNED Score every fill on price, latency, and toxicity vs. the intent.
  • Slippage vs. arrival mid and decision price
  • Queue position at time of fill
  • Post-fill mark drift over N seconds (toxicity proxy)
none
  • toxicity_horizon_s · int
  • min_score_for_repeat · float
  • publish_to · list
  • warn_threshold_bps · int
2.8 PartialFillHandler PLANNED Decide what to do with the unfilled remainder of an order.
  • Remaining size vs. original intent
  • Book state at moment of partial
  • Strategy's declared partial-fill policy
none
  • default_policy · enum
  • min_remainder_size · int
  • chase_max_ticks · int
  • cancel_on_book_thin · bool
2.9 CancelReplaceOptimizer PLANNED Choose the cheapest path between cancel-then-replace and amend-in-place.
  • CLOB V2 amend semantics: queue-priority preserved or lost
  • Distance between current and target price/size
  • Rate-limit budget remaining for cancels vs. amends
none
  • amend_threshold_ticks · int
  • preserve_queue_when_possible · bool
  • burst_max_per_s · int
  • fallback_strategy · enum
2.10 LatencyProfiler PLANNED Continuously measure round-trip latency by route and surface regressions.
  • Submit-to-ack latency per endpoint and order type
  • WebSocket-feed lag vs. REST snapshot
  • p50 / p95 / p99 by region and time of day
none
  • warn_p95_ms · int
  • fail_p99_ms · int
  • routes_to_probe · list
  • probe_interval_s · int
2.11 ExchangeStatusMonitor PLANNED Treat Polymarket itself as a degradable dependency — pause or de-risk on signal.
  • Heartbeat from CLOB V2 endpoints; status-page parsing
  • Reject-rate spike across unrelated strategies
  • Maintenance-window calendar from public announcements
  • Polymarket public status page
  • pause_on_status · list
  • flatten_on_status · list
  • poll_interval_s · int
  • resume_quarantine_min · int
2.12 PriceBandValidator PLANNED Refuse orders priced outside a sanity band relative to mid — fat-finger / decimal-shift catcher.
  • Top-of-book mid and recent trade VWAP
  • Strategy-declared edge envelope
  • Outright vs. neg-risk constraints (sum-to-one band)
none
  • max_offset_from_mid_pct · 0–100
  • require_band_for · list
  • action_on_breach · enum
  • warn_only_in_shadow · bool
2.13 DustAndRoundingCleaner PLANNED Avoid creating dust positions that cost more in fees than they earn.
  • Order size vs. CLOB V2 minimum and tick increments
  • Predicted post-trade dust given partial-fill probability
  • Existing dust holdings flagged for sweep
none
  • min_economic_size_usd · int
  • round_strategy · enum
  • auto_sweep_dust · bool
  • sweep_cron · cron

What each Execution bot is doing, in plain English

2.1SmartRouter

The strategy says "buy YES on this market for $500". This bot decides how: should it be a fill-or-kill (atomic, used for arbs where partial fills break the trade), a good-till-cancelled resting order (for makers who want queue position), a good-till-time order (for news trades that should auto-expire if the signal goes stale), or an iceberg order broken into smaller children (for large orders that would otherwise telegraph our hand to the book)?

iceberg_threshold_usd is the order size above which we automatically slice into iceberg_child_count smaller orders. gtd_signal_ttl_s is how many seconds we'll let a signal-driven order rest before auto-cancelling — if the signal hasn't filled in that window, the trade thesis has decayed.

2.2AntiToxicFill

"Toxic fill" is trader jargon for getting filled right before bad news — you posted a passive bid, someone hit it because they already knew the price was about to drop, and now you're holding a losing position. This bot looks for the fingerprints of that situation: a sweep through 3+ price levels in the last 5 seconds, a sudden cancel-storm on the opposite side (counterparty pulling out of the way), or a news hit on the relevant entity within 30 seconds of a fill.

When triggered, it pulls quotes for a cooldown_s window — the cooldown is just "don't quote this market again for X seconds while we figure out what's happening". Then it widens the spread on re-quote (requote_widen_bps) so we're paid more for taking the risk, and downsizes the next few orders by downsize_factor. news_window_s is how close in time a news event has to be to the fill for the bot to treat the fill as suspicious.

2.3QueueWarden

On a CLOB, your spot in the queue at a given price level matters — the orders ahead of you fill first. This bot manages queue position: it watches our quote drift in ticks vs. the best price, notices when better-priced orders ahead of us get pulled (good news — we just got promoted in the queue), and detects stale resting orders that have sat too long with no book movement. It re-quotes with discipline — you don't want to spam cancel-replace because (a) it eats into rate limits and (b) it tells the market you're indecisive.

drift_ticks_threshold is how far our quote can drift from the best before we re-quote. cancel_replace_per_min_cap caps how often we can do that, to stay polite on the API and avoid signalling.

2.4NonceShepherd

Polymarket orders are signed messages (EIP-712), and each one needs a unique nonce. Under load, it's possible to sign multiple orders, send them out of order, and end up with a "nonce gap" where order #5 arrives before order #4 — which Polymarket will reject. This bot keeps the signing pipeline reliable: it tracks pending signed-but-unposted orders, detects gaps, re-derives L2 API credentials when needed, and refuses to issue new orders during a gap so we don't make things worse.

refuse_during_gap_s is how long the bot pauses new orders after detecting a nonce gap, giving the gap time to be filled. l2_credential_ttl_h rotates the L2 API credentials on a schedule for hygiene.

2.5GasOracle

Polymarket runs on Polygon, and on-chain operations (wallet ops, neg-risk conversions, withdrawals) cost gas. Most of the time gas is cheap, but during congestion it can spike. This bot decides whether non-urgent on-chain operations should be deferred until gas is cheaper. It compares current gas to the rolling 24-hour baseline and computes the EV of a pending neg-risk conversion against the expected gas cost.

max_gas_percentile_for_ops is "only run non-urgent ops when gas is below the Xth percentile of the last 24 hours". never_defer_risk is locked true — a Risk-Layer-driven flatten ignores gas entirely and pays whatever it has to.

LAYER 3 · STRATEGY

Twenty-four strategy templates.

The only bots in the stack that take directional or spread risk — every other layer supports them. Each declares its risk envelope to Layer 1 at startup; a mid-run parameter change requires re-declaration and re-validation. Strategies are configuration-only by contract: the user picks a template, sets parameters, and no target return is implied. Two templates — 3.18 DisputeDiscountBuyer and 3.19 RuleAmbiguityShort — are tagged ADVANCED: manual-review-required, capped, and subject to withdrawal if they are used to exploit weak market wording rather than price genuine resolution risk. When writing a new strategy, the driving question is "under what circumstances does this stop working?" — the answer belongs in a Risk Layer guard.

# Bot Status Goal Polymarket signals monitored External feeds / sources Key user-set parameters
3.1 ★ Maker-Tight
flagship
LIVE Two-sided passive market-making on liquid markets.
  • Mid price (top-bid / top-ask midpoint)
  • Inventory skew on the running position
  • Realised vs. quoted spread (rolling)
  • Order-flow imbalance over last N seconds
none
  • edge_bps · int
  • clip_size_usd · int
  • inventory_skew_factor · 0–1
  • min_volume_24h_usd · int (default 250000)
3.2 Maker-Wide BETA Same shape as Maker-Tight, but for thin books — wider spreads, smaller size, longer rests.
  • Stale-book detector: time since last fill
  • Volatility-of-mid in last hour (sets spread width)
none
  • edge_bps · int (80–200)
  • clip_size_usd · int (small)
  • hard_inventory_cap_usd · int
  • stale_book_minutes · int
3.3 ★ Sum-to-One Arb
flagship
LIVE Buy YES + NO when they sum below $1 net of fees.
  • WSS book stream on both token IDs of a binary market
  • Visible depth at top of each leg
  • Per-order tick size (so legs sum cleanly)
none
  • min_edge_bps · int
  • fee_buffer_bps · int
  • slippage_buffer_bps · int
  • max_leg_size_usd · int
3.4 Neg-Risk Sum Arb LIVE Multi-outcome arb: YES tokens across N outcomes should sum to $1.
  • Gamma API: outcome-token list per neg-risk event
  • CLOB book stream on each outcome token
  • Neg-risk conversion contract availability
none
  • min_edge_bps · int
  • prefer_conversion_path · bool
  • max_outcomes_per_trade · int
  • exclude_other_outcome · bool (locked true)
3.5 Bregman-Projection Arb BETA Multi-outcome arb that doesn't require strict sum-violation; trades the divergence from the closest valid distribution.
  • Full neg-risk event book (all outcomes)
  • Real-time KL-divergence vs. nearest valid distribution
  • Historical co-movement matrix (internal)
  • kl_divergence_threshold · float
  • frank_wolfe_iters · int
  • max_legs_per_trade · int
  • liquidity_cap_usd · int
3.6 Cross-Market Arb BETA Exploit logical relationships between different Polymarket markets.
  • Books on each linked market (e.g., "wins primary" vs. "is nominee")
  • Embedding-based similarity score (e5-large-v2 / similar)
  • Monotonicity violations on over/under markets
none — embedding model runs locally
  • tolerance_bps · int
  • min_similarity_score · 0–1
  • require_manual_pair_review · bool
  • max_legs · int
3.7 Cross-Venue Arb PLANNED Trade Polymarket against Kalshi / PredictIt / sportsbooks when resolution sources align.
  • Polymarket book + market metadata for resolution-source match
  • Kalshi public API
  • PredictIt market data
  • Sportsbook odds-feed providers (semi-automated for sportsbook legs)
  • min_gap_bps_after_fees · int
  • require_resolution_source_match · bool (locked true)
  • allowed_venues · list
  • manual_approval_required · bool
3.8 News Materiality Trader
code: news_reactor
BETA Trade material news events before the book fully digests them.
  • Watchlisted markets matched by entity
  • Book depth + recent volatility on the target market
  • Reuters, AP, Bloomberg, league wires (via NewsIngest)
  • NLP materiality classifier
  • Entity-resolution dictionary
  • materiality_threshold · 0–1
  • cooldown_s · int
  • order_ttl_s · int (60–300)
  • max_position_usd · int
3.9 Sports Model BETA Quantitative fair-value engine for sports markets; trade where Polymarket diverges from model price.
  • Polymarket sports market mid & depth
  • In-play market state (where applicable)
  • League APIs (NBA, NFL, EPL, ATP/WTA, MLB)
  • Lineup / injury / weather data via SportsFeed-Adapter
  • Internal power-rating model
  • min_edge_bps_vs_model · int (default 200)
  • kelly_fraction · 0–1
  • max_per_bet_usd · int
  • auto_disable_neg_sharpe_weeks · int
3.10 Resolution Fair-Value
code: resolution_snipe
PLANNED Trade pre-resolution mispricings — markets that should be ¢99 but trade at ¢96.
  • Market price vs. fee-adjusted intrinsic value
  • OracleRiskMonitor "no active dispute" approval
  • Resolution source clarity flag
  • NewsIngest + structured event sources confirm event has occurred
  • min_edge_bps · int
  • max_size_per_market_usd · int (≤ 2000)
  • require_unambiguous_source · bool
  • require_oracle_clean · bool
3.11 Late-Resolution Spread
code: endgame_arb
LIVE Buy ¢95–¢99 shares minutes before resolution for the small but reliable spread to $1.
  • Market price + spread to $1
  • Time-to-resolution countdown
  • OracleRiskMonitor approval
  • NewsIngest: multiple independent sources confirm winner
  • min_spread_to_1_cents · int
  • max_minutes_to_resolution · int
  • max_clip_usd · int
  • never_average_down · bool (locked true)
3.12 Mean-Reversion Sniper BETA Fade momentum in markets known to overreact above 80% probability.
  • Price + z-score of last-N price change
  • Aggressor side flips and large cancels on the heavy side
  • NewsIngest event-density window (don't fade during active news cycles)
  • price_threshold · 0–1 (default 0.80)
  • z_score_min · float (default 2.5)
  • stop_bps · int
  • time_exit_s · int
3.13 Breakout-Follower PLANNED Momentum-follow when an asymmetric news event hits — opposite-shaped twin of Mean-Reversion.
  • Price breaking 30-min Bollinger band
  • Order-flow strongly one-sided
  • NewsIngest confidence score
  • news_confidence_min · 0–1
  • bollinger_stdev · float
  • scale_in_steps · int
  • trail_atr_multiple · float
3.14 Liquidity-Pulse PLANNED Provide liquidity in markets about to get attention but not yet trading.
  • Pre-event volume on the target market
  • Cross-market correlation: related markets moving while this one is asleep
  • NewsIngest mention-volume spikes by topic
  • Calendar of scheduled events
  • initial_spread_bps · int
  • tighten_at_volume_usd · int
  • max_pre_event_position_usd · int
  • event_lead_time_h · int (≤ 6)
3.15 VolatilityHarvest PLANNED Quote inside thick books on volatile event markets and let the wide spreads pay you.
  • Realised intra-tick volatility per market
  • Bid/ask spread vs. realised vol ratio
  • Trade-imbalance and cancel-rate signatures
none
  • min_realised_vol · float
  • quote_inside_bps · int
  • max_inventory_skew · float
  • cool_off_after_loss · int
3.16 CalendarCompression PLANNED Trade the time-decay between markets resolving on different dates for the same underlying.
  • Pairs of markets sharing source-of-truth, differing in resolution date
  • Implied probability gap vs. days-to-resolution
  • Historical compression behaviour for similar pairs
none
  • min_gap_bps · int
  • max_days_to_resolve · int
  • require_same_source · bool
  • max_position_per_pair · int
3.17 ResolutionCurveTrader PLANNED Price the path of probability between now and resolution, not just the endpoint.
  • Mid history vs. fitted resolution-curve template
  • Time-weighted divergence from theoretical drift
  • Open-interest concentration along the curve
none
  • curve_template · enum
  • divergence_entry_bps · int
  • min_days_remaining · int
  • exit_on_curve_revert · bool
3.18 Dispute-Risk Pricing
code: dispute_discount_buyer
ADVANCED · manual review
PLANNED Buy positions that are mispriced because of UMA dispute uncertainty — only when the resolution-rule reading is unambiguous.
  • Markets in proposal/dispute with mid pulled away from a clean source-of-truth read
  • ResolutionRuleParser (4.8) confidence score and contradiction flags
  • Historical dispute-resolution outcomes for the rule template
  • UMA on-chain dispute state
  • min_parser_confidence · 0–1
  • max_position_per_market · int
  • require_human_signoff · bool
  • halt_on_contradiction · bool
3.19 Rule-Risk Discount
code: rule_ambiguity_short
ADVANCED · manual review
PLANNED Fade markets where the resolution rule is ambiguous and the price doesn't reflect that risk.
  • ResolutionRuleParser (4.8) ambiguity flags and contradiction count
  • Mid pricing implied near-certainty (> 90% or < 10%) on ambiguous wording
  • RuleChangeMonitor (4.12) recent edits
none
  • min_ambiguity_score · 0–1
  • max_position_per_market · int
  • require_human_signoff · bool
  • auto_pull_on_dispute_loss · bool
3.20 NarrativeCrowdingFade PLANNED Fade markets where social attention has overshot the underlying base rate.
  • SocialSentiment (4.6) volume and acceleration
  • Mid drift in the past 24h vs. base-rate prior
  • Concentration of new buyers in last N hours
  • Social-sentiment service (Layer 4)
  • min_attention_zscore · float
  • min_drift_bps · int
  • max_position_per_event · int
  • cool_off_after_news · int
3.21 FundingRotationBot PLANNED Rotate idle USDC between safe-yield routes and Polymarket capital, never exceeding the user's deployable budget.
  • Free balance vs. CapitalAllocator (1.10) reserve
  • Pending-fill reserve to cover open intents
  • Yield-route APY thresholds and withdraw lockups
  • Approved yield-route API (read-only)
  • idle_threshold_usd · int
  • min_reserve_pct · 0–100
  • route_whitelist · list
  • require_user_optin · bool
3.22 PortfolioHedger PLANNED Build offsetting positions to neutralise correlated exposure flagged by Risk.
  • CorrelationShockGuard (1.11) cluster identifications
  • Open exposure by cluster and by neg-risk event
  • Available offsetting markets and their book depth
none
  • target_residual_corr · 0–1
  • max_hedge_cost_bps · int
  • auto_hedge_clusters · list
  • require_explicit_optin · bool
3.23 BasisTrader PLANNED Trade the basis between Polymarket and an off-platform reference (sportsbook line, futures, poll) when the rules permit.
  • Mid vs. external reference, normalised to common probability
  • Resolution-rule parity check (same source-of-truth or close)
  • Cost-of-funding adjustment per leg
  • Configured reference feeds (read-only, no live trading)
  • min_basis_bps · int
  • require_rule_parity · bool
  • max_position_per_leg · int
  • halt_on_reference_stale · bool
3.24 MarketCreationScout PLANNED Identify newly created markets worth seeding maker liquidity in, before the spread tightens.
  • NewMarketWatcher (0.5) feed
  • MarketQualityRanker (0.2) score and source class
  • Top-of-book width and recent trade pacing
none
  • min_quality_score · 0–100
  • seed_size_usd · int
  • max_age_minutes · int
  • auto_handoff_to · enum

What each Strategy bot is doing, in plain English

3.1Maker-Tight (flagship)

Classic two-sided market-making on liquid markets. The bot continuously posts a bid below the mid and an ask above the mid, earning the spread when both sides eventually fill. It tracks four signals: the current mid price, how skewed our inventory is (if we're long, we lean quotes lower to bias selling), realised vs. quoted spread (so we know if we're being adversely selected), and order-flow imbalance over the last few seconds (so we can lean away from the toxic side).

edge_bps is how many basis points away from the mid we quote on each side — a tighter edge fills more often but earns less per fill. clip_size_usd is the size of each individual quote. inventory_skew_factor controls how aggressively the bot shifts quotes when inventory drifts. min_volume_24h_usd is a floor — don't quote on illiquid markets at all (default 250,000).

3.2Maker-Wide

Same idea as Maker-Tight but for thin books. On illiquid markets you cannot quote tight — you'll get picked off every time something moves. Instead, the bot quotes wide spreads (80–200 bps), small clip sizes, and a hard inventory cap so you can't accumulate too much in any direction. It also has a stale-book detector — if there are no fills for X minutes, back off and stop quoting until something happens.

edge_bps is wider here. stale_book_minutes is the timeout after which we stop quoting. hard_inventory_cap_usd is the do-not-exceed inventory band, much tighter than on liquid markets.

3.3Sum-to-One Arb (flagship)

On a binary market (e.g., "Will the Fed cut rates by July?"), YES + NO should always sum to $1 — because exactly one of them will be worth $1 at resolution. If the offer for YES is ¢48 and the offer for NO is ¢49, you can buy both for ¢97 total and walk away with $1 — a guaranteed ¢3 minus fees. The bot watches the WSS book stream on both legs in real time and fires fill-or-kill on both legs simultaneously. If only one leg fills, the FOK on the second leg auto-cancels and InventoryUnwinder picks up the orphan.

min_edge_bps is the required spread after fees. fee_buffer_bps and slippage_buffer_bps are safety margins. Reality check: simple-arb windows collapse quickly; configured TTL is per-strategy and per-market, not a global constant. Most of the profit goes to sub-second HFT scripts — this is profitable only on high-volume markets with low-latency infra.

3.4Neg-Risk Sum Arb

Same logic as Sum-to-One but for multi-outcome events. In a neg-risk event with N outcomes (e.g., "Who will be the next Fed Chair?"), the YES tokens across all outcomes should sum to $1. If they sum to ¢94, there's a 6¢ arb. The bot can either buy YES on each underpriced outcome, or — often more capital-efficient — buy NO on the cheapest outcome and use Polymarket's neg-risk conversion contract to turn it into 1 YES on every other outcome.

prefer_conversion_path tells the bot to use the conversion route when it's cheaper. exclude_other_outcome is locked true — we never trade the "Other" outcome directly because its definition shifts as placeholders are clarified.

3.5Bregman-Projection Arb

A more sophisticated multi-outcome arb. Instead of waiting for the YES tokens to sum below $1 (which rarely happens cleanly), this bot computes the closest valid probability distribution to the observed prices using KL-divergence, and trades the gap between the observed prices and that nearest valid distribution. The Frank-Wolfe optimiser then picks the trade allocation that captures the most divergence with the fewest legs.

kl_divergence_threshold is the minimum mispricing required before trading. frank_wolfe_iters caps how long the optimiser runs. The strategy is research-grade — reference: LayerX research on probability-simplex arbitrage.

3.6Cross-Market Arb

Different Polymarket markets that are logically related shouldn't have prices that contradict each other. "X wins the primary" must price at most as high as "X is the nominee". "Total goals over 2.5" must price at least as high as "Total goals over 3.5". When those constraints are violated, there's a hedged arb. The bot uses sentence embeddings (e5-large-v2 or similar, running locally) to cluster related markets, then a constraint checker flags violations.

min_similarity_score is the embedding-similarity threshold for treating two markets as related. require_manual_pair_review defaults true on this strategy — the cost of a wrong pairing is too high to fully automate.

3.7Cross-Venue Arb

If the same event is priced on Polymarket and on Kalshi, PredictIt, or a sportsbook, and there's a gap after both sets of fees, you can buy on the cheap venue and sell on the expensive one. The catch — and it's the #1 way people blow up on this strategy — is that the two venues must resolve from the same source. If Polymarket resolves on Reuters and Kalshi resolves on AP and they disagree, you can be right on both legs and still lose.

require_resolution_source_match is locked true. Sportsbook legs are semi-automated with manual approval because they don't expose APIs and have voiding/limit risk.

3.8News Materiality Trader code: news_reactor

Material news — a corporate earnings beat, a political resignation, a court ruling — moves prediction markets, and there's usually a window of a few minutes before the book fully digests it. The bot consumes the NewsIngest feed (Reuters, AP, Bloomberg, league wires), runs each item through an NLP materiality classifier, matches it to a watchlisted market, and if confidence is high enough, sends a time-bounded GTD order sized by confidence × liquidity. Latency target: under 1 second from feed to order.

materiality_threshold is the minimum classifier score required to fire. cooldown_s prevents firing twice on the same news cycle. order_ttl_s auto-cancels if the move hasn't played out in 60–300 seconds.

3.9Sports Model

A quantitative power-rating model produces a fair value for each sports market. When Polymarket's mid diverges from the model's fair value by more than 200 bps, the bot enters — sized via fractional Kelly with a hard per-bet cap. Inputs include lineups, injuries, weather (for outdoor sports), and live in-game state for in-play markets. Auto-disables on a sport when 30-day Sharpe goes negative for two consecutive weeks.

min_edge_bps_vs_model is the entry threshold (default 200). kelly_fraction caps sizing at a fraction of full-Kelly (full Kelly is too aggressive in practice). auto_disable_neg_sharpe_weeks is the model-drift kill switch.

3.10Resolution Fair-Value code: resolution_snipe

The event has clearly happened — the news has confirmed the outcome — but the market is still trading at ¢96 instead of ¢99 because traders haven't woken up yet. The bot buys these mispricings, but with a strict size cap because the tail risk is full loss on a wrong call. OracleRiskMonitor must approve (no active dispute), the resolution source must be unambiguous, and multiple independent news sources must confirm.

max_size_per_market_usd is capped at ≤ $2,000 — small enough that a wrong call doesn't break the account. require_unambiguous_source and require_oracle_clean are both locked true.

3.11Late-Resolution Spread code: endgame_arb

In the final minutes before resolution, winning shares often trade at ¢95–¢99 even though they will resolve to $1. That spread, after fees and gas, is small but reliable. The bot takes the offer up to a bounded clip and — critically — never averages down: if the price dips, it usually means new information arrived, not that the trade got better. OracleRiskMonitor must approve.

max_minutes_to_resolution is the entry window. never_average_down is locked true — a hard learnt rule.

3.12Mean-Reversion Sniper

Yes/No price asymmetry is treated as a hypothesis to be measured per market, not a global assumption. The bot fades extended spikes when two conditions are met: price above a configured probability threshold with a high z-score on the last-N price change, and a flip in the aggressor side (the side that was lifting offers stops lifting). It enters with a tight stop and a time-based exit. Crucially, it auto-disables during high-event-density windows — fading momentum during a breaking news cycle is a great way to get run over.

price_threshold is the minimum probability before the fade is even considered (default 0.80). z_score_min is the velocity filter. stop_bps and time_exit_s bound the loss.

3.13Breakout-Follower

The opposite-shaped twin of Mean-Reversion. When NewsIngest fires a high-confidence asymmetric event, prices break out of their recent range and momentum tends to continue for a window. The bot enters in the direction of the break, scales in over several entries, and trails the take-profit by ATR (average true range) so winners run and losers get cut early.

news_confidence_min requires a high NLP score before entry. scale_in_steps spreads the position over multiple entries. trail_atr_multiple sets the trailing-stop distance.

3.14Liquidity-Pulse

Markets that are about to get attention but haven't yet are the best place to be a liquidity provider — you set wide quotes early, get a queue position, and tighten as volume arrives. Triggers include news mentions on a topic spiking while the related Polymarket volume hasn't moved, related markets moving while this one sleeps, and scheduled events under six hours away with low pre-event volume.

initial_spread_bps is the wide quote at first. tighten_at_volume_usd is the volume threshold at which we narrow the spread. max_pre_event_position_usd caps how much inventory we'll accumulate before the event hits.

LAYER 4 · INTELLIGENCE

Fifteen signal generators.

Read-only. These bots never submit orders — they emit typed signals onto the internal bus that Layer 3 strategies subscribe to. Every signal carries a freshness timestamp and a provenance string (feed, version, sample window) so a downstream strategy can decide whether to trust it. Stale signals must degrade gracefully; silent extrapolation is not acceptable. ResolutionRuleParser (4.8) regressions are P0 — if its confidence drops or its contradiction rate rises, every dependent strategy (3.18, 3.19, BasisTrader's parity check) must pause until a human reviews it. When adding a new feed, the failure mode goes in the first paragraph of the bot's README — "what happens when this provider returns 500" matters more than the happy path.

# Bot Status Goal Polymarket signals monitored External feeds / sources Key user-set parameters
4.1 NewsIngest LIVE Real-time news ingestion + entity resolution + materiality scoring.
  • Watchlist of tracked markets & entity dictionary
  • Reuters & AP wires
  • Bloomberg headlines
  • League / federation feeds
  • Official organisation handles (curated)
  • entity_watchlist · list
  • materiality_min · 0–1
  • source_priority · ordered list
  • dedup_window_s · int
4.2 OracleWatcher LIVE Monitor UMA oracle for proposals, disputes, debates, votes.
  • Per-market resolution-risk state & countdown
  • UMA Optimistic Oracle on-chain events
  • UMA dispute & vote queues
  • watched_condition_ids · list
  • poll_interval_s · int
  • alert_on_state_change · bool
4.3 OrderFlowAnalyzer LIVE Compute book microstructure features in real time.
  • WSS book updates per market
  • Trade prints + cancellations
none
  • imbalance_window_s · int
  • queue_position_method · enum
  • micro_vol_window_s · int
  • publish_rate_hz · int
4.4 CrossMarketGraph BETA Group semantically equivalent or logically linked markets.
  • Market title + rules text from Gamma API
  • Condition-ID metadata
  • Sentence-embedding model (local)
  • Operator manual-override pairs
  • cluster_threshold · 0–1
  • manual_pair_overrides · list
  • logical_relation_types · enum
4.5 SportsFeed-Adapter BETA Wire structured sports data into Sports Model. none — feeds are exogenous
  • League APIs (NBA, NFL, EPL, ATP/WTA, MLB)
  • Odds-feed providers (lineup / injury / weather)
  • Web fallbacks for sports without APIs
  • enabled_sports · list
  • preferred_provider · enum
  • refresh_interval_s · int
  • fallback_to_web · bool
4.6 SocialSentiment PLANNED Lightweight, secondary social-sentiment input — never primary trigger. none — feed is exogenous
  • Public social streams (rate-capped, decay-weighted)
  • Sarcasm-aware classifier (local)
  • weight_in_signal · 0–0.3 (capped)
  • decay_half_life_min · int
  • per_topic_rate_cap · int
  • require_secondary_only · bool (locked true)
4.7 OnChainWatcher BETA Watch high-signal wallets for entries / exits.
  • Polymarket Data API position changes per watched wallet
  • Polygon on-chain event stream
  • watched_wallets · list
  • min_position_change_usd · int
  • publish_delay_s · int
4.8 ★ ResolutionRuleParser
flagship
PLANNED Convert each market's resolution rule into a structured representation: source-of-truth, condition, ambiguity score.
  • Market metadata: full rule text, source-of-truth field, neg-risk topology
  • Versioned diffs when rules are edited post-listing
  • Confidence and contradiction counts per market
  • Cross-rule references (this market resolves only if X)
none
  • min_confidence_to_publish · 0–1
  • require_human_review · list
  • regression_alert_drop · float
  • republish_on_edit · bool
4.9 SourceOfTruthVerifier PLANNED Sanity-check that the source listed in a market's rule actually publishes what's needed for resolution.
  • ResolutionRuleParser (4.8) source-of-truth field
  • Source-uptime and publication-cadence history
  • Field-mapping coverage (does the source actually expose this number?)
  • Approved source-of-truth registry
  • min_uptime_pct · 0–100
  • required_publication_cadence_h · int
  • auto_flag_unverified · bool
  • publish_to · list
4.10 ContradictionDetector PLANNED Surface markets whose resolution rule contradicts itself, the title, or a parent neg-risk constraint.
  • Title vs. rule consistency check
  • Neg-risk sum-to-one consistency across siblings
  • Cross-market resolution dependencies that can't both be true
none
  • severity_threshold · enum
  • publish_to · list
  • auto_pause_strategies · list
  • require_human_review · bool
4.11 MarketOntologyBuilder PLANNED Cluster markets into events, themes, and underlying entities for cross-market reasoning.
  • Market titles, tags, and resolution-rule entities
  • Embedding-similarity graph across active markets
  • Manual curator overrides and parent-child links
  • Local embedding model
  • cluster_min_similarity · 0–1
  • max_cluster_size · int
  • republish_cron · cron
  • respect_curator_overrides · bool
4.12 RuleChangeMonitor PLANNED Detect and emit any post-listing edit to a market's resolution rule.
  • Rule-text diffs since listing
  • Source-of-truth field changes
  • Resolution-date adjustments
none
  • poll_interval_s · int
  • severity_filter · enum
  • auto_pause_strategies · list
  • publish_to · list
4.13 LiquidityForecastModel PLANNED Predict near-term book depth and trade pacing per market for sizing decisions.
  • Recent book depth, trade frequency, and cancel rate
  • Time-of-day, day-of-week, and event-proximity features
  • Listing age and quality-rank features
none
  • forecast_horizon_min · int
  • min_history_h · int
  • publish_to · list
  • fallback_to_realised · bool
4.14 Wallet Flow Classifier
code: sharp_wallet_classifier
PLANNED Score on-chain wallets on historical edge over a long window — emitted as a feature, never as a copy-trade signal.
  • Wallet trade history vs. realised resolutions
  • Sample-size and time-window adjustments
  • Cluster membership and address-reuse heuristics
  • Polygon archive nodes
  • min_sample_resolutions · int
  • lookback_days · int
  • publish_delay_s · int
  • never_emit_as_copy_signal · bool
4.15 AnomalyDetector PLANNED Flag statistical anomalies in book, trades, or feed data for human review.
  • Trade-imbalance spikes vs. rolling baseline
  • Wash-trade signatures and self-cross rates
  • Feed-vs-source divergence beyond expected noise
none
  • z_threshold · float
  • min_baseline_window_h · int
  • publish_to · list
  • auto_pause_strategies · list

What each Intelligence bot is doing, in plain English

4.1NewsIngest

The wire room. NewsIngest reads Reuters, AP, Bloomberg, league and federation feeds and a curated set of official organisation handles in real time, then does two things — entity resolution (figuring out which Polymarket markets a headline actually concerns) and materiality scoring (how much should this move price). It deliberately only watches a tracked-market watchlist so it isn't drowning in unrelated news, and it dedups near-identical headlines that hit multiple wires within a few seconds.

entity_watchlist is the list of markets / entities the bot cares about — anything outside the list is dropped at the door. materiality_min is the floor classifier score (0–1) below which the headline is ignored even if it's on a watched entity. source_priority is the ordered list of wires we trust most when two contradict each other. dedup_window_s is how long we treat near-duplicate stories from different wires as the same event.

4.2OracleWatcher

Polymarket markets resolve via UMA's Optimistic Oracle — anyone can propose a resolution, anyone can dispute it, and a vote follows if there's a dispute. The window between proposal and finalisation is when bad things happen to traders who don't know the resolution is live. OracleWatcher polls the on-chain UMA contracts, tracks the dispute and vote queues, and emits a per-market resolution-risk state plus a countdown. Layer 1's OracleRiskMonitor is the bot that actually uses this signal to gate other strategies — OracleWatcher just produces it.

watched_condition_ids is the list of Polymarket condition IDs to track. poll_interval_s is how often we re-read on-chain state — too fast wastes RPC budget, too slow misses state transitions. alert_on_state_change emits a signal the moment a market moves between proposed / disputed / vote / finalised so downstream strategies can react.

4.3OrderFlowAnalyzer

The microstructure layer. OrderFlowAnalyzer subscribes to the WSS book stream for every market we touch and computes the features that maker strategies depend on — order-book imbalance over a short window (how much more size is on the bid vs the ask), our queue position at each price level, micro-volatility over the last few seconds, trade-print flow, and cancellation rate. It publishes those features at a fixed rate so Layer 3 strategies can consume them without each one having to recompute the same signals.

imbalance_window_s is the lookback window for book imbalance — short windows are noisier but react faster. queue_position_method is the algorithm we use to estimate where in the queue our resting order is (queue position is private info on Polymarket so it has to be inferred). micro_vol_window_s sets the volatility window. publish_rate_hz is how many times per second we emit the feature snapshot.

4.4CrossMarketGraph

Polymarket has hundreds of markets that are logically related — the same election asked three different ways, an over/under hierarchy that should be monotonic, a primary market and a nominee market that should respect each other. CrossMarketGraph reads market titles and rules text from the Gamma API, runs them through a local sentence-embedding model, and builds a graph of which markets are semantically equivalent or logically linked. It also accepts manual operator overrides because embeddings get the obvious 95% right and the subtle 5% catastrophically wrong.

cluster_threshold is the embedding-similarity score above which two markets are treated as related — too high and we miss real pairs, too low and we trade pairs that aren't really linked. manual_pair_overrides is the operator-curated list that always wins over the model. logical_relation_types tells the graph which kinds of relation we model (equivalence, implication, hierarchy).

4.5SportsFeed-Adapter

The plumbing that turns external sports data into something Layer 3's Sports Model can actually consume. League APIs (NBA, NFL, EPL, ATP/WTA, MLB) all have different shapes; odds-feed providers carry lineup, injury and weather data; and a handful of sports we care about (smaller leagues, niche tournaments) only have web sources. The adapter normalises all of those into a single typed schema and falls back to web parsing only when no API exists.

enabled_sports is the whitelist of sports we ingest data for. preferred_provider per sport is which odds-feed vendor we trust first. refresh_interval_s controls how often each feed is re-pulled. fallback_to_web is the kill switch — set false in production for any sport where web parsing has been flaky.

4.6SocialSentiment

Social signals are loud, easily manipulated, and full of sarcasm. SocialSentiment is deliberately built as a secondary input — it can support a thesis another bot already has, but it can never be the primary trigger that opens a position. It runs a sarcasm-aware classifier on rate-capped public streams, decay-weights older posts so a single viral thread doesn't dominate, and exposes its weight in the final signal as a configurable parameter capped at 0.3 by design.

weight_in_signal is the maximum contribution to any composite signal (capped at 0.3). decay_half_life_min is how fast old posts lose influence. per_topic_rate_cap stops a single topic from flooding the signal. require_secondary_only is locked true — it's a permanent guardrail, not a tweakable parameter.

4.7OnChainWatcher

Polymarket positions are public on-chain. OnChainWatcher tracks a curated list of wallets — known sharp traders, market makers, identified-as-informed actors — and emits a signal when their net position in a tracked market changes by more than a threshold. The publish_delay_s is deliberate and important: we never publish a wallet's move with zero delay, both to avoid front-running them ourselves and to prevent obvious copy-trading patterns from forming around our signal.

watched_wallets is the operator-curated list of addresses. min_position_change_usd is the size threshold below which moves are ignored as noise. publish_delay_s is the deliberate lag between observing the move and emitting the signal.

Strategy lifecycle

Seven stages between idea and General Live.

Every Layer 3 strategy moves through this pipeline. StrategyRegistry (6.8) tracks the current stage; promotion requires a ticket, and advanced templates require two-person sign-off. ExperimentTracker (6.9) runs shadow and limited-live arms. ModelDriftMonitor (1.12) can demote a General Live strategy to Watchlist on its own authority.

  1. 01

    Research

    Hypothesis written down, target signals identified, failure-mode block drafted. No code path may place orders at this stage.

    Gate: Hypothesis documented in StrategyRegistry. Written research note with claimed edge mechanism, expected market subset, and 5-field failure-mode block. Reviewed by ≥ 1 senior dev.
  2. 02

    Backtest

    Minimum 90 days of CLOB tick replay, walk-forward, with realistic fees and slippage. Backtester (6.4) artefacts attached to the registry entry.

    Gate: Tick replay against ≥ 90 days of historical CLOB data. Deterministic replay passes; slippage model parameters declared; sample size ≥ N trades (N is per-strategy, defined in research note); no parameter selected post-hoc on the same data window.
  3. 03

    Shadow

    Minimum 14 days of paper-trading against live data. Paper-Trade Runner (6.5) and ExperimentTracker (6.9) collect matched-pair samples.

    Gate: Paper trading against the live CLOB feed for ≥ 14 calendar days. ≥ M paper trades, error rate < 0.5%, latency p95 within strategy budget, paper-PnL within ± 25% of backtest expectation.
  4. 04

    Limited Live

    Hard size cap and per-market cap, opt-in only, with full PostTradeExplainer (6.12) records on every fill. Drift monitor is active from day one.

    Gate: Real orders, capped notional. Max per-wallet notional ≤ small cap (per strategy); max enrolled wallets ≤ small N; opt-in only; CapitalAllocator (1.10) enforces; ManualOverrideAuditor (1.16) reviews any human override within 24h.
  5. 05

    General Live

    Available to all eligible users, gated by StrategySuitabilityGate 1.9. Caps are relaxed but not removed. Promotion requires two-person sign-off.

    Gate: 30 days clean Limited Live, no Sev-1 incidents, drift band still satisfied, StrategySuitabilityGate (1.9) reviewed and signed off.
  6. 06

    Watchlist

    Strategy still runs but is flagged for review. New users are blocked; existing users retain access at reduced caps. Auto-entered on drift breach.

    Gate: Demoted automatically by ModelDriftMonitor (1.12) on drift > configured threshold for 7 consecutive days, OR by IncidentCommander (6.11) on Sev ≥ 2. No new wallets can opt in. Existing wallets continue but receive a notice.
  7. 07

    Deprecated

    Strategy retired; existing positions wound down via InventoryUnwinder (1.6). Configuration preserved read-only for audit. Cannot be revived — a new lineage must restart at Research.

    Gate: 30 days in Watchlist with no remediation, OR explicit deprecation by registry owner. Wind-down: existing positions move to close-only via standard close-only mode; no new orders; full lineage preserved in StrategyRegistry.
LAYER 5 · SECURITY & WALLET

Eight bots between non-custodial as a marketing word and as a real property.

Non-custodial means signing happens in the user's wallet — but every signing surface is a failure surface. These eight modules are what makes "non-custodial" a real property rather than a marketing claim. Operational specifics:

  • Session keys are issued by SessionKeyManager (5.4), scoped to a market-set + size-cap + expiry, and revocable from the user dashboard or by any L1 Risk guard returning REJECT with suggested_action: "PAUSE_STRATEGY". Storage: encrypted at rest, never persisted to client logs.
  • Signature preview is rendered by SignaturePreviewer (5.3) before every EIP-712 signature, in the wallet modal context for hosted runtime, and as an audit-renderer for SDK deployments. The full payload is hashed into GovernanceLog.security_check.preview_payload.
  • Allowance discipline. AllowanceMonitor (5.2) watches USDC and conditional-token allowances, refuses to grant overbroad approvals, and surfaces stale approvals in the user dashboard with one-click revoke.
  • RPC posture. RPCFailoverManager (5.6) maintains a pool of Polygon providers (target: 3), with health checks and provider rotation on failure. Quorum policy for critical reads is currently 2-of-3 (see Open Questions).
  • Contract allow-list. ContractAddressGuard (5.8) ships a hardcoded list of CLOB V2 Exchange addresses verified against Polymarket's published deployment registry. List updates require a signed PR + 2 reviews. V1 addresses are explicit deny.
  • Emergency revocation. The user dashboard has a single "Disable all bots" action that revokes every session key, cancels every open order, and switches all running strategies to close_only. Round-trip target ≤ 5 seconds.
# Bot Status Goal Polymarket signals monitored External feeds / sources Key user-set parameters
5.1 ★ WalletPermissionGuard
flagship
PLANNED Enforce that each strategy can only call the wallet methods the user has explicitly granted, scoped per session.
  • Per-strategy permission grant (method whitelist, contract allow-list, max size)
  • Active session and its expiry
  • Attempted out-of-scope calls (auto-rejected and logged)
none
  • method_whitelist · list
  • contract_allowlist · list
  • max_per_call_size_usd · int
  • require_reapproval_h · int
5.2 AllowanceMonitor PLANNED Track ERC-20 allowances per token and contract; alert and shrink to a tight ceiling on idle.
  • Current allowance per (token, spender) pair
  • Time since last use of each allowance
  • Pending revocation transactions
  • Polygon read RPC
  • max_allowance_usd · int
  • idle_revoke_h · int
  • auto_shrink · bool
  • alert_on_unbounded · bool
5.3 SignaturePreviewer PLANNED Render a plain-English summary of every EIP-712 signature before the wallet shows the modal.
  • Order intent: side, size, price, market, expiry
  • Domain-separator and chain ID checks
  • Diff against the strategy’s declared envelope
none
  • require_preview_for · list
  • min_detail_level · enum
  • block_on_envelope_mismatch · bool
  • retain_log_days · int
5.4 ★ SessionKeyManager
flagship
PLANNED Issue, scope, and expire short-lived session keys so strategies can sign without re-prompting on every order.
  • Active session keys per user, with scope and expiry
  • Per-key usage rate vs. budget
  • Revocations and emergency wipes
  • Cross-device session conflicts
none
  • max_session_lifetime_h · int
  • max_calls_per_session · int
  • scope_per_strategy · bool
  • auto_revoke_on_idle_h · int
5.5 KeyRotationReminder PLANNED Nag the user to rotate signing keys on a schedule; prevent key reuse across environments.
  • Time since last rotation per signing key
  • Cross-environment key fingerprints
  • Outstanding rotation tickets
none
  • rotate_every_days · int
  • block_on_overdue_h · int
  • require_unique_per_env · bool
  • publish_to_user · bool
5.6 RPCFailoverManager PLANNED Probe RPC providers continuously and fail over before a stale endpoint poisons our chain view.
  • Block-height divergence across providers
  • Latency, error-rate, and quota state per RPC
  • Failover events and quarantine status
  • Configured RPC pool
  • max_block_lag · int
  • min_providers_quorum · int
  • auto_quarantine · bool
  • probe_interval_s · int
5.7 ChainStateVerifier PLANNED Cross-check every order’s chain-derived inputs (nonce, balance, allowance) against multiple sources before signing.
  • Nonce and balance disagreement across RPCs
  • Pending tx pool divergence
  • Reorg detection and orphaned-tx recovery
none
  • require_quorum · int
  • halt_on_mismatch · bool
  • reorg_depth_alert · int
  • publish_to · list
5.8 ★ ContractAddressGuard
flagship · CLOB V2
PLANNED Refuse to sign anything against a contract address not on the committed CLOB V2 allow-list. Critical for the V1 → V2 migration.
  • Hard-coded CLOB V2 Exchange addresses by chain
  • EIP-712 domain separator vs. expected V2 domain
  • Order-type schema match against V2 spec
  • Detection of any V1 Exchange address in pending intents
none
  • v2_addresses · list (locked)
  • block_v1_signing · bool (locked true)
  • require_domain_match · bool (locked true)
  • alert_on_block · bool (locked true)
LAYER 6 · GOVERNANCE & REPORTING

Fifteen bots that watch what just happened — and explain why.

Post-trade, runtime, and accountability layer. These bots do not pick direction or police strategies — they sit across the top of everything else, continuously reconciling our view of Polymarket against its own state, recording every parameter change, and producing the artefacts the team and users need to trust the system. The original seven (heartbeats, PnL, backtester, paper-trade runner, cron, portfolio sync, BuilderAttribution) remain; eight new ones are added: StrategyRegistry for lifecycle tracking, ExperimentTracker for shadow and limited-live runs, ParameterChangeAuditor for config edits, IncidentCommander for halts, PostTradeExplainer for human-readable trade records, UserActivityLedger, AttributionRevenueReporter, and SLAMonitor. PostTradeExplainer is the trust feature: if you cannot explain a trade in plain English to the user who funded it, the system should not have placed it.

# Bot Status Goal Polymarket signals monitored External feeds / sources Key user-set parameters
6.1 ★ BuilderAttribution
flagship
LIVE Tag every order with Polytraders' builder code, log it, reconcile it daily against Polymarket's report.
  • Every outgoing order's builder_code field
  • Polymarket Builder-Code report (rolling 24h)
  • Per-fill attribution logs
none
  • builder_code · string (locked)
  • reconcile_window_h · int (default 24)
  • quarantine_on_drift · bool (locked true)
  • alert_on_missing_code · bool (locked true)
6.2 Health & Heartbeat LIVE Per-bot heartbeat; restart on crash; alert on drift.
  • Order-reject rate, fill anomaly, latency spike
  • On-call paging system
  • heartbeat_interval_s · int
  • missed_heartbeats_to_alert · int
  • auto_restart · bool
  • page_on_failure · bool
6.3 PnL Reporter LIVE Compute realised + unrealised PnL per bot, per market, per author.
  • Polymarket fills per token / market
  • Mark-to-market prices for open positions
none
  • report_window · enum (daily, weekly)
  • group_by · enum (bot, market, author)
  • include_paper · bool
6.4 Backtester BETA Tick-level replay over historical CLOB snapshots — same execution path as live.
  • Historical CLOB snapshots (book + trades)
  • Internal snapshot archive (replayed deterministically)
  • start_ts · datetime
  • end_ts · datetime
  • strategy · enum
  • parameter_sweep · list
6.5 Paper-Trade Runner BETA Mirror live signals against paper accounts — required step before any new strategy goes live.
  • Live signal stream + simulated fills
none
  • min_paper_days · int (default 14)
  • require_positive_risk_adj · bool
  • simulated_capital_usd · int
6.6 Cron Runner LIVE Time-of-day strategy enable / disable; scheduled rebalancing; pre-event quoting cycles.
  • Polymarket market open / scheduled-event metadata
  • System clock (UTC)
  • Calendar feeds for sport / political schedules
  • cron_expression · string (UTC)
  • enabled_strategies · list
  • disable_during_quiet_hours · bool
6.7 Portfolio Sync LIVE Reconcile our internal position state with Polymarket's Data API every N seconds.
  • Polymarket Data API positions per wallet
  • Internal position-store snapshot
none
  • sync_interval_s · int
  • discrepancy_alert_usd · int
  • auto_pause_strategy_on_drift · bool
6.8 ★ StrategyRegistry
flagship
PLANNED Single source of truth for which strategy is at which lifecycle stage and on what authority.
  • Per-strategy stage: Research, Backtest, Shadow, Limited Live, General Live, Watchlist, Deprecated
  • Promotion tickets and approver list per stage transition
  • Linked artefacts: backtest report, shadow report, drift status
  • Live-cap policy and current consumption
none
  • require_two_person_promotion · list
  • min_shadow_days · int
  • min_backtest_days · int
  • auto_demote_on_drift · bool
6.9 ExperimentTracker PLANNED Run shadow and limited-live experiments alongside production, with statistically honest comparisons.
  • Variant assignments and traffic split per strategy
  • Matched-pair samples for shadow vs. live
  • Confidence intervals on edge / slippage / fill quality
none
  • min_samples_for_decision · int
  • traffic_split_pct · 0–100
  • auto_promote_on_winning · bool
  • require_human_signoff · bool
6.10 ParameterChangeAuditor PLANNED Capture every config edit — what, who, when, before/after — with replay-grade detail.
  • Diff of every parameter set per strategy and per guard
  • Editor identity, environment, and ticket reference
  • Auto-revert candidates flagged by drift or incident
none
  • retain_history_days · int
  • require_ticket_for · list
  • publish_to_audit_log · bool
  • alert_on_p0_change · bool
6.11 IncidentCommander PLANNED Coordinate halts, flattens, and post-mortems when a guard, monitor, or operator declares an incident.
  • Active incidents with severity, owner, and affected scope
  • Auto-actions taken (pause / quarantine / flatten)
  • Post-incident artefacts: timeline, RCA, follow-up tickets
  • On-call paging system
  • auto_actions_by_severity · map
  • require_rca_within_h · int
  • page_on_severity · enum
  • publish_status_externally · bool
6.12 ★ PostTradeExplainer
flagship
PLANNED Turn every fill into a plain-English record: which strategy, which signal, which guard checks passed, why this size, why this price.
  • OrderLifecycleManager (2.6) state trail
  • Strategy intent, parameters, and signal inputs at decision time
  • Guardrail vote record for the intent
  • Builder-code, fees, and gas envelope on the realised fill
none
  • retain_explanation_days · int
  • min_detail_level · enum
  • publish_to_user · bool
  • require_for_advanced · bool
6.13 UserActivityLedger PLANNED Per-user, per-session record of strategy starts, parameter changes, halts, and overrides.
  • Strategy lifecycle events scoped to user
  • Manual overrides with ManualOverrideAuditor (1.16) cross-reference
  • Wallet permission state at each action
none
  • retain_days · int
  • export_format · enum
  • scrub_on_account_close · bool
  • publish_to_user · bool
6.14 AttributionRevenueReporter PLANNED Reconcile builder-code rebates with internal records and publish a daily auditable report.
  • BuilderAttribution (6.1) reconciliation output
  • Polymarket builder report, internal fill records, drift
  • Per-strategy and per-user attribution slices
none
  • report_cron · cron
  • drift_alert_pct · 0–100
  • publish_to · list
  • retain_days · int
6.15 SLAMonitor PLANNED Track service-level objectives that we’ve committed to internally and to users; alert on burn.
  • Uptime, latency, fill-quality, and incident SLOs per strategy
  • Error-budget consumption and burn-rate
  • SLA breach history with linked incidents
none
  • slo_definitions · map
  • burn_rate_alert_pct · 0–100
  • publish_to_user · bool
  • auto_freeze_on_breach · bool

What each Monitoring & Ops bot is doing, in plain English

6.1BuilderAttribution (flagship)

BuilderAttribution is commercially load-bearing — it is the source of truth for builder-program reporting and revenue reconciliation, and any drift here directly impacts our standing with Polymarket. Safety load-bearing modules are PortfolioGuard (1.1), ContractAddressGuard (5.8), OrderLifecycleManager (2.6), and KillSwitch (1.2). Every order — without exception — leaves Polytraders with our builder code stamped on it. BuilderAttribution is the bot that does the stamping at the order-router seam, logs every code-tagged fill to our own ledger, and every 24 hours pulls Polymarket's official Builder-Code report and reconciles it against what we logged. If those two reports drift, the affected strategy is automatically quarantined until an operator clears it. This is how we prove what we did, who we did it for, and that we're a builder partner rather than a counterparty playing against users.

builder_code is locked at the org level — no strategy or operator can override it. reconcile_window_h is the rolling window over which we compare our log against Polymarket's report (default 24h). quarantine_on_drift is locked true — if our number disagrees with Polymarket's number, we stop trading until it's resolved. alert_on_missing_code is also locked true — a single uncoded order pages an on-call operator immediately.

6.2Health & Heartbeat

Every bot in the system emits a heartbeat on a fixed cadence. Health & Heartbeat is the bot that watches those heartbeats, watches order-reject rates, watches fill anomalies and latency spikes, and decides whether to auto-restart, alert, or page. The point is that silence is failure — if a bot stops emitting heartbeats, we treat it as broken and either bring it back automatically or pull a human in. Many failure modes don't crash loudly, they just stop making decisions, and this layer catches that.

heartbeat_interval_s is how often each bot is expected to phone home. missed_heartbeats_to_alert is how many in a row before we treat the bot as down. auto_restart controls whether we attempt a clean restart automatically before paging. page_on_failure wakes a human — used sparingly because alert fatigue is real.

6.3PnL Reporter

Realised PnL (closed positions, fees included) plus unrealised PnL (open positions marked-to-market against the current Polymarket price), broken down per bot, per market, and per author. The point of breaking it down per author is governance: every strategy in the system has an owner, and that owner's positions and PnL are explicitly attributed back to them so the team can see who shipped what and how it actually traded. Reports run daily and weekly and can include or exclude paper-trade signals.

report_window picks daily or weekly cadence. group_by chooses the slice (bot, market, author). include_paper toggles whether shadow-mode strategies are included in the same view (useful for evaluating not-yet-live strategies side-by-side with live ones).

6.4Backtester

Tick-level historical replay over CLOB snapshots — not a synthetic simulation. The Backtester replays the exact same WSS event stream that Layer 3 strategies would have seen on the day, runs them through the exact same execution path, and reproduces fills under the exact same fee and gas model. That "same path" rule is the whole point: a strategy that backtests well via a custom shortcut and then fails in production is a strategy that was never really backtested. Parameter sweeps run as a list, so you can sweep edge_bps or kelly_fraction and compare side-by-side.

start_ts and end_ts bound the replay window. strategy is the bot under test. parameter_sweep is a list of parameter sets the engine runs in parallel.

6.5Paper-Trade Runner

Mandatory shadow mode. Before any new strategy is allowed to deploy capital, it has to run against live signals through Paper-Trade Runner for a minimum number of days, against a simulated capital pool, and produce a positive risk-adjusted result. This isn't a backtest — it's the real live signal stream with simulated fills, so it captures the things backtests miss (latency to feed, real network conditions, real news interruptions). It's the gate between "good idea on paper" and "the firm is risking real money on this".

min_paper_days is the minimum shadow run before promotion is even allowed (default 14). require_positive_risk_adj is the gate — the strategy has to clear a risk-adjusted floor over the paper window. simulated_capital_usd is the pretend bankroll the paper run trades against.

6.6Cron Runner

Scheduling, in operator-controllable terms. Cron Runner enables and disables strategies on a schedule (NFL strategies dark on Tuesdays; election-bot quoting cycle starts six hours before US polls close), kicks off scheduled rebalances, and runs pre-event quoting cycles that need to start at a specific UTC time. Everything runs in UTC internally because mixing timezones in a 24/7 trading system is how mistakes happen. Operators can also define quiet hours during which all non-essential strategies are paused.

cron_expression is a standard cron string in UTC — always UTC, never local time. enabled_strategies is the list of strategies the cron entry controls. disable_during_quiet_hours respects the org-wide quiet-hours band where applicable.

6.7Portfolio Sync

The reconciliation loop between our internal view of positions and Polymarket's view. Every N seconds, Portfolio Sync pulls the Data API positions for each connected wallet and compares them line-by-line against our internal position store. If a discrepancy above the alert threshold appears — a position size we don't have on our books, a fill we never logged, a balance that drifted — we can automatically pause the affected strategy until an operator reconciles. This is the bot that catches the worst class of failure: thinking you're flat when you aren't.

sync_interval_s is the polling cadence. discrepancy_alert_usd is the dollar threshold above which a drift becomes an incident rather than a rounding-error. auto_pause_strategy_on_drift is the safety — if positions don't match, the affected strategy stops trading until a human signs it off.

Failure-mode catalogue

Every bot ships with five answers, in writing.

Every bot — guard, executor, strategy, signal service, security primitive, governance reporter — publishes a failure-mode block in its README. Merge approval requires all five fields populated. StrategyRegistry (6.8) refuses to advance a strategy past Backtest if any field is empty. The schema is the same for a Layer 1 guard and a Layer 3 strategy — that is intentional.

Field What it captures Example (DisputeDiscountBuyer 3.18)
main_failure_mode The single most likely way this bot harms the user or the system. UMA dispute resolves against the parser’s confident reading; full-loss on the bought side.
false_positive_risk What happens when the bot fires when it shouldn’t. For guards: blocking a legitimate order. For strategies: trading without edge. Buys mispriced markets that were correctly priced — expected drag is bounded by max_position_per_market.
false_negative_risk What happens when the bot fails to fire when it should. For guards: missed REJECT. For strategies: missed alpha. Walks past a real dispute discount because parser confidence dipped — preferred to a false buy.
safe_fallback Default behaviour when an upstream input is stale, missing, or contradictory. Must be safe for the user. If ResolutionRuleParser confidence < threshold or RuleChangeMonitor fires, halt new entries and let inventory unwind.
required_dependencies Other bots whose presence and health are required for this bot to operate. Drives shadow-mode prerequisites. 4.8 ResolutionRuleParser, 4.10 ContradictionDetector, 4.12 RuleChangeMonitor, 1.10 CapitalAllocator, 1.13 TailLossSimulator.

The block is the smallest amount of writing we’ve found that forces the question “under what circumstances does this stop working?” to be answered in plain language — and the easiest thing to grep for in code review when you suspect the answer is missing.

Hard rules

Ten rules every bot must obey.

Non-negotiable across the library. They exist so the platform behaves predictably under stress, and so Polymarket sees Polytraders as a careful builder rather than a source of platform risk.

  1. 01
    Builder code on every order. No exceptions. BuilderAttribution audits this and reconciles daily.
  2. 02
    Risk + Security are non-bypassable. No execution path from Strategy to CLOB submit may skip Risk Layer (16 guards) or Security Layer (8 guards). Tests in CI prove the absence of bypass paths. If you find yourself wanting an "emergency override" boolean, the bug is upstream.
  3. 03
    Lifecycle gate. Strategies must pass Research → Backtest → Shadow → Limited Live before reaching General Live. StrategyRegistry (6.8) tracks the stage; promotion is gated by ticket and (for advanced templates) two-person sign-off.
  4. 04
    Tick size + neg-risk respected per order. Pulled from client.getMarket() on every order. Never hardcoded.
  5. 05
    No trading "Other" outcomes directly in neg-risk events. Definition shifts as placeholders are clarified.
  6. 06
    Cancel discipline. Don't ping the book to extract free signal. QueueWarden enforces; cancel-replace stays inside rate limits.
  7. 07
    Disputed-market freeze. OracleRiskMonitor blocks new entries on any market in proposal / dispute / debate phases unless the strategy explicitly opts in.
  8. 08
    Open-source the SDK and audit surfaces, not the alpha. See the open-source scope table below for component-level breakdown.
  9. 09
    CLOB V2 only. No code path may submit to a V1 Exchange contract or sign a V1-format order. ContractAddressGuard (5.8) enforces; the V1 path is deleted, not feature-flagged.
  10. 10
    Every strategy publishes a failure-mode block. No exceptions. Approval requires all five fields: main_failure_mode, false_positive_risk, false_negative_risk, safe_fallback, required_dependencies.

Open-source scope

Rule 08 (open-source the SDK, not the alpha) is broad. The component-level breakdown:

ComponentOpenNotes
SDK (intent emission, schema validation, signature helpers)YesApache-2.0
Risk guard interfacesYesImplementations may be partly closed
OrderIntent / RiskVote / ExecutionPlan / SecurityCheck schemasYesVersioned, breaking changes signal-only
GovernanceLog audit-log formatYesReviewers must be able to parse logs
Strategy templatesNoDescription published; logic proprietary
Alpha logic (signal weights, thresholds, micro-edges)NoClosed
Production runtime (orchestrator, supervisor, queues)NoClosed
Internal model drift baselinesNoClosed; published only as APPROVE/REJECT
Builder access

Want a deeper look at the spec?

If you're on the Polymarket Builders team or evaluating Polytraders for the program, we'll share the live runtime, the audit trail, and a walk-through of any bot in this library.