Polytraders Dev Guide
internal
v3 spine Phase 1 · Shared contracts 9 demo-wired · 0 shadow-ready · 0 production-live · 100 pending · 109 total 15/33 infra tasks the plan status board
HomeBy LayerRisk1.17 MarketHaltDetector

1.17 MarketHaltDetector

Risk Guardrail PauseReject PLANNED Spec ready capital · Direct P2 · Data normalisation pending stub

Watches for market-level halt conditions across Polymarket — wide-spread blowouts, missing best bid/ask, locked or crossed books, and sudden order-rate collapse. When any halt condition fires, MarketHaltDetector quarantines the affected market_id so no new OrderIntent for that market can pass the Risk pipeline. It does not pause the whole system — only the affected market. Cleared automatically once conditions normalise for a configurable cool-off window, or manually via the Admin UI.

v3 readiness

Docs27/27
donehow scored
Impl11/15
in progresshow scored
Backtest3/4
in progresshow scored
Runtime0/8
pendinghow scored

A bot is done when all four scores are. What does done mean?

v3.5 · wired registry id risk.markethaltguard

Maps to spec page market_halt_detector. SEARCH_SPACE declared. Fixture pack pending.

Source: @polytraders/bots · src/risk/markethaltguard.js · Impl 11/15 · Backtest 3/4

1. Bot Identity

LayerRisk  Risk
Bot classGuardrail
AuthorityPauseReject
StatusPLANNED
ReadinessSpec ready
Runs beforerisk.killswitch, exec.smart_router
Runs afterintel.orderflowanalyzer
Applies toContinuous
Default modeshadow
User-visibleYes
Developer ownerRisk pod

Operational profile

OwnershipRisk pod · on-call risk-oncall · #polytraders-risk · escalates to Head of Risk · P1
Latency budgetp50: 5ms · p99: 20ms
Modes supportedoffshadowadvisoryenforcedquarantine
Data freshnessmax_market_data_age_ms=1500 · max_orderbook_age_ms=1500 · on stale → Treat as halted (fail closed).
Human overrideyes · by Risk on-call · logs RISK_MARKET_HALT_OVERRIDE · time-bound: 60 minutes max · scope: Single market_id · single approver

2. Purpose

Watches for market-level halt conditions across Polymarket — wide-spread blowouts, missing best bid/ask, locked or crossed books, and sudden order-rate collapse. When any halt condition fires, MarketHaltDetector quarantines the affected market_id so no new OrderIntent for that market can pass the Risk pipeline. It does not pause the whole system — only the affected market. Cleared automatically once conditions normalise for a configurable cool-off window, or manually via the Admin UI.

3. Why This Bot Matters

  • Submitting orders into a halted book

    Orders sent into a market with no two-sided liquidity end up either rejected by the CLOB or filled at runaway prices once the book reopens.

  • Treating wide-spread events as normal

    A market with a 30%+ inside spread is structurally untradeable; trading it anyway invites massive slippage and unfair fills.

  • Manual halt management

    Without automated detection, ops staff must monitor every market by hand — which does not scale past a handful of markets.

4. Required Polymarket Inputs

InputSourceRequired?Use
Best bid/ask per market_idWebSocketYesDetect missing or one-sided book; compute live spread.
Last-trade timestamp per market_idCLOBYesDetect sudden trade-rate collapse (no trades for trades_silent_ms with non-empty book).

5. Required Internal Inputs

InputSourceRequired?Use
Recent OrderBookSnapshot historyintel.orderflowanalyzerYesSmoothed spread and depth context for halt-vs-noise classification.
Active strategy → market_id mapOrderLifecycleManagerNoDecide which strategies to notify when a halt fires.

6. Parameter Guide

ParameterDefaultWarningHardWhat it controls
halt_spread_pct301530Spread percentage at which the market is considered halted.
trades_silent_ms600003000060000Maximum allowed silent window with no recorded trades while the book is non-empty.
cooloff_ms120000Cool-off window the market must remain healthy before the halt is auto-cleared.
min_depth_usd250100250Minimum aggregate top-of-book depth (USD) below which the book is considered too thin.

7. Detailed Parameter Instructions

halt_spread_pct

What it means

Spread percentage at which the market is considered halted.

Default

{ "halt_spread_pct": 30 }

Why this default matters

30% inside spread is well outside any tradeable regime on Polymarket binary markets.

Threshold logic

ConditionAction
≤ 15%No action
15–30%WARN — log only
> 30%QUARANTINE market_id

Developer check

if (spreadPct(book) > p.halt_spread_pct) halt.activate(marketId, 'WIDE_SPREAD');

User-facing English

Trading was paused on this market because the price gap got too wide for safe orders.

trades_silent_ms

What it means

Maximum allowed silent window with no recorded trades while the book is non-empty.

Default

{ "trades_silent_ms": 60000 }

Why this default matters

60 seconds with a populated book and no prints is a strong signal of stale or stuck data.

Threshold logic

ConditionAction
≤ 30sNo action
30–60sWARN
> 60sQUARANTINE market_id

Developer check

if (now - lastTradeMs > p.trades_silent_ms && bookHasLiquidity()) halt.activate(marketId, 'TRADE_SILENCE');

User-facing English

Trading was paused on this market because no trades have happened for a long time.

cooloff_ms

What it means

Cool-off window the market must remain healthy before the halt is auto-cleared.

Default

{ "cooloff_ms": 120000 }

Why this default matters

Two minutes of healthy book + recent trades is a safe minimum before resuming.

Threshold logic

ConditionAction
Healthy < 120sStay quarantined
Healthy ≥ 120sAuto-clear halt

Developer check

if (healthyFor(marketId) > p.cooloff_ms) halt.clear(marketId);

User-facing English

Trading on this market resumed automatically after conditions stabilised.

min_depth_usd

What it means

Minimum aggregate top-of-book depth (USD) below which the book is considered too thin.

Default

{ "min_depth_usd": 250 }

Why this default matters

Below $250 of top-of-book depth on a binary market, even small orders move the price meaningfully.

Threshold logic

ConditionAction
> $250OK
$100–$250WARN
< $100QUARANTINE market_id

Developer check

if (topDepthUsd(book) < p.min_depth_usd) halt.activate(marketId, 'THIN_BOOK');

User-facing English

Trading was paused on this market because there was not enough money on the book to fill orders safely.

8. Default Configuration

{
  "halt_spread_pct": 30,
  "trades_silent_ms": 60000,
  "cooloff_ms": 120000,
  "min_depth_usd": 250
}

9. Implementation Flow

— not yet authored —

10. Reference Implementation

Pseudocode is language-agnostic. FETCH = read input. EMIT = produce output. IF/THEN/ELSE = decision. Translate directly to TypeScript, Python, Go, or Rust.

for each book_tick:
  if spread_pct(book) > p.halt_spread_pct: halt(market_id, 'WIDE_SPREAD'); continue
  if now - last_trade[market_id] > p.trades_silent_ms and depth_usd(book) > 0: halt(market_id, 'TRADE_SILENCE'); continue
  if depth_usd_top(book) < p.min_depth_usd: halt(market_id, 'THIN_BOOK'); continue
  if all_rules_clean_for(market_id, p.cooloff_ms): clear(market_id)
for each OrderIntent o:
  if is_halted(o.market_id): emit RiskVote(REJECT, RISK_MARKET_HALT); else PASS

11. Wire Examples

Input — what arrives on the wire

{
  "intent_id": "intent_001",
  "market_id": "0xabc",
  "side": "BUY",
  "size_usd": 100
}

Output — what the bot emits

{
  "vote": "REJECT",
  "reason_code": "RISK_MARKET_HALT",
  "explain": "Halted: inside spread 41% > 30% threshold."
}

12. Decision Logic

APPROVE

On each OrderBookSnapshot tick → re-evaluate halt rules per market.

RESHAPE_REQUIRED

This bot does not reshape orders.

REJECT

On each OrderIntent for a quarantined market_id → REJECT with RISK_MARKET_HALT.

WARNING_ONLY

Emit OperationsReport on halt activation, halt clearance, and threshold WARNs.

13. Standard Decision Output

This bot returns a RiskVote object. See RiskVote schema.

{
  "vote": "REJECT",
  "market_id": "0xabc",
  "reason_code": "RISK_MARKET_HALT",
  "explain": "Halted: inside spread 41% > 30% threshold for 18s.",
  "ts_ms": 1715260000000
}

14. Reason Codes

CodeSeverityMeaningActionUser-facing message
RISK_MARKET_HALTP1Risk Market HaltSee decision output and developer log for context.Trading was paused on this market because conditions made it unsafe to place orders.
RISK_MARKET_HALT_WARNP1Risk Market Halt WarnSee decision output and developer log for context.Trading was paused on this market because conditions made it unsafe to place orders.
RISK_MARKET_HALT_CLEAREDP1Risk Market Halt ClearedSee decision output and developer log for context.Trading was paused on this market because conditions made it unsafe to place orders.

15. Metrics & Logs

Metrics emitted

MetricTypeUnitLabelsMeaning
halts_active_totalcountereventmarket_id, reason_codeHalts active total.
halt_activation_countcountereventmarket_id, reason_codeHalt activation count.
halt_clear_countcountereventmarket_id, reason_codeHalt clear count.
rejects_with_market_haltcountereventmarket_id, reason_codeRejects with market halt.

Dashboards

  • 1.17 overview dashboard

16. Developer Reporting

"Per halt activation: market_id, rule (WIDE_SPREAD/TRADE_SILENCE/THIN_BOOK), measured value, threshold, ts_ms, expected cooloff_until_ms."

17. Plain-English Reporting

SituationUser-facing explanation
When this bot actsTrading was paused on this market because conditions made it unsafe to place orders.
When this bot actsTrading on this market will resume automatically once the market behaves normally again.

18. Failure-Mode Block

main_failure_modeFalse quarantine on transient feed glitches that recover within seconds.
false_positive_riskBrief WebSocket reconnects can mimic a wide spread; mitigation: require condition to hold for a minimum sustained window before halting.
false_negative_riskA market that quietly stops printing but keeps a tight book may not trip any rule; mitigation: cross-check with Polymarket public last-trade endpoint on a slow timer.
safe_fallbackOn internal failure, halt every market this bot is responsible for — fail closed, never fail open.
required_dependencies

19. Failure-Injection Recipes

ScenarioHow to injectExpected behaviourRecovery
Inject a sustained 35% inside spread for 30s and assert halt activatesInject a sustained 35% inside spread for 30s and assert halt activates.Bot detects within its latency budget and emits the corresponding reason code.Remove the injected fault; bot returns to healthy state within one debounce window.
Inject a 5-minute trade silence and assert halt activatesInject a 5-minute trade silence and assert halt activates.Bot detects within its latency budget and emits the corresponding reason code.Remove the injected fault; bot returns to healthy state within one debounce window.
Inject feed reconnect noise and assert no spurious halt within debounce windowInject feed reconnect noise and assert no spurious halt within debounce window.Bot detects within its latency budget and emits the corresponding reason code.Remove the injected fault; bot returns to healthy state within one debounce window.

20. State & Persistence

Per market_id: { halted: bool, halted_since_ms, last_rule, healthy_since_ms }. Persisted in fast key-value store; survives restart.

State stores

NameKindKeyValue shapeTTLDurability
market_halt_detector_statein-memory + fast KV mirrormarket_idPer market_id: { halted: bool, halted_since_ms, last_rule, healthy_since_ms }. Persisted in fast key-value store; surviv24hcrash-safe via KV mirror

Cold-start recovery

Cold-start hydrates from fast KV; missing keys default to safe fallback.

On restart

All in-flight decisions are re-evaluated; no bot decision is trusted across restart without re-emit.

21. Concurrency & Idempotency

AspectSpecification
Execution modelSingle-writer per market_id. Idempotent: same OrderIntent re-evaluated returns same RiskVote while halt is active.
Max in-flight32
Idempotency keyorder_intent_id
Replay-safeTrue
DeduplicationBy idempotency_key within a 60s window.
Ordering guaranteesPer-market_id FIFO; cross-market unordered.
Per-call timeout (ms)250
Backpressure strategyBounded queue; oldest-dropped with metric increment when full.
Locking / mutual exclusionPer-market_id mutex; no global locks.

22. Dependencies

Depends on (must run first)

Emits to (downstream consumers)

Requires (graph.requires)

intel.orderflowanalyzer

Required before (graph.required_before)

risk.killswitch exec.smart_router

ConsumesOrderBookSnapshot TradeTick
EmitsRiskVote OperationsReport
Blocks ordersyes

23. Security Surfaces

Reads CLOB WebSocket; emits RiskVote internally only.

Signing surface

None — bot does not sign or submit.

Abuse vectors considered

  • Admin UI 'force clear' endpoint requires Risk role + audit log entry.

Mitigations

  • Rate-limit per source
  • Audit-log every override
  • Require role-based authz on admin paths

24. Polymarket V2 Compatibility

AspectValue
CLOB versionV2
Collateral assetpUSD
EIP-712 Exchange domain version2
Aware of builderCode fieldyes
Aware of negative-risk marketsyes
Multi-chain readyyes
SDK usedPolymarket CLOB V2 SDK
Settlement contractCTFExchangeV2
NotesReads CLOB V2 normalised OrderBookSnapshot; no on-chain calls.

25. Versioning & Migration

FieldValue
current0.1.0
contract_version1.0.0
last_breaking_changenone
deprecation_window_days30

26. Acceptance Tests

Unit Tests

TestSetupExpected result
Spread computation matches expected for synthetic books.Synthetic fixture per template.Behaviour matches the rule described in the test name.
Cool-off counter resets on any rule re-trip.Synthetic fixture per template.Behaviour matches the rule described in the test name.

Integration Tests

TestExpected result
Halt activates and clears against a recorded CLOB feed with an injected 90-second silent window.End-to-end behaviour matches the spec without manual intervention.

Property Tests

PropertyRequired behaviour
For any sequence of book ticks, halt-active state is monotonic per market until cool-off completes.Always true across all generated inputs.

27. Operational Runbook

Symptoms: many simultaneous halts → check upstream feed health. Single stuck market → manually clear via Admin UI then investigate the persistent rule violation.

On-call actions

AlertFirst stepDiagnosisMitigationEscalate to
1.17_anomalyOpen the bot's reporting page and confirm the alert is real (not a metric hiccup).Inspect developer log entries for the affected market_id over the last 30 minutes.Force-clear via Admin UI if the rule is clearly stale; otherwise leave engaged and notify owner.Risk pod

Manual overrides

  • polytraders bot pause 1.17 — Disables the bot's enforcement layer; downstream consumers fall back to safe defaults.

Healthcheck

GET /healthz/market_halt_detector → 200 if last successful evaluation < 60s ago.

28. Promotion Gates

A bot does not advance to the next readiness state until every gate below is green. Gates are observable from production data — no subjective sign-off.

Promote to Shadow

GateHow measuredThreshold
Stubdeterministic against fixture book ticks.Documented threshold met for the full window.

Promote to Limited live

GateHow measuredThreshold
Shadow7 days against live CLOB; halt activations logged but not enforced.Documented threshold met for the full window.
Advisory7 days; halts visible to ops dashboard.Documented threshold met for the full window.

Promote to General live

GateHow measuredThreshold
Enforcedrequires Risk Lead sign-off.Documented threshold met for the full window.

29. Developer Checklist

Ready-to-ship score: 27/27 sections complete · 100%

RequirementStatus
Purpose defined✓ done
Required inputs listed✓ done
Parameters defined✓ done
Defaults defined✓ done
Warning thresholds defined✓ done
Hard thresholds defined✓ done
Safe fallback defined✓ done
Structured output defined✓ done
Developer log defined✓ done
Plain-English explanation✓ done
Unit tests defined✓ done
Integration tests defined✓ done
Property tests defined✓ done
Failure-mode block complete✓ done
Reference implementation pseudocode✓ done
Wire examples (input + output)✓ done
Reason codes listed✓ done
Metrics & logs defined✓ done
State & persistence defined✓ done
Concurrency & idempotency defined✓ done
Dependencies declared✓ done
Security surfaces declared✓ done
Polymarket V2 compatibility declared✓ done
Version & migration history declared✓ done
Operational runbook defined✓ done
Promotion gates defined✓ done
Failure-injection recipes defined✓ done