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 LayerIntelligence4.15 AnomalyDetector

4.15 AnomalyDetector

Intelligence Signal Service Read-only PLANNED Spec started capital · Indirect P2 · Data normalisation pending stub

Flag statistical anomalies in book, trades, or feed data for human review.

v3 readiness

Docs27/27
donehow scored
Impl0/15
pendinghow scored
Backtest0/4
pendinghow scored
Runtime0/8
pendinghow scored

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

1. Bot Identity

LayerIntelligence  Intelligence
Bot classSignal Service
AuthorityRead-only
StatusPLANNED
ReadinessSpec started
Runs before
Runs after
Applies to
Default modeshadow_only
User-visibleAdvanced details only
Developer ownerPolytraders core

2. Purpose

Flag statistical anomalies in book, trades, or feed data for human review.

3. Why This Bot Matters

  • Book or trade anomaly goes unnoticed

    Without a statistical watchdog, sudden mid-price jumps, volume spikes, or microstructure changes that signal a feed glitch, market manipulation, or upstream halt are detected only when a strategy bot already trades on the bad data. By then unintended fills have already occurred.

  • No baseline for human review

    Operators reviewing a market in incident mode have no reference for what 'normal' looked like for that market in the prior hour. Anomaly emissions provide the timestamped baseline that every post-incident review needs.

  • Z-score signal duplicated across strategies

    If anomaly detection lives inside individual strategy bots, every team reinvents it inconsistently. A single shared service emits one canonical anomaly stream that all consumers — Risk, Strategy, Governance — read from.

  • Strategy bots blind to feed degradation

    A z-score spike often precedes a stale-book event by seconds. Without an explicit anomaly signal, downstream Risk bots have no early warning to widen their staleness windows or pause new entries.

4. Required Polymarket Inputs

InputSourceRequired?Use
CLOB V2 order book mid-price per condition_idclob_publicYesCompute price z-score vs rolling baseline.
Recent trade volume per condition_iddataYesCompute volume z-score vs rolling baseline.

5. Required Internal Inputs

InputSourceRequired?Use
KillSwitch active flagKillSwitchYesSuppress all anomaly emissions when KillSwitch is active.

6. Parameter Guide

ParameterDefaultWarningHardWhat it controls
z_score_threshold3.02.01.0Minimum z-score (standard deviations from rolling mean) to trigger an anomaly signal.
baseline_window_s36007200300Rolling window in seconds used to compute mean and standard deviation for z-score baseline.

7. Detailed Parameter Instructions

z_score_threshold

What it means

Minimum z-score (standard deviations from rolling mean) to trigger an anomaly signal.

Default

{ "z_score_threshold": 3.0 }

Why this default matters

3.0 sigma suppresses noise from normal market volatility while catching genuine outlier events.

Threshold logic

ConditionAction
z >= 3.0ANOMALYDETECTOR_PRICE_SPIKE or VOLUME_SPIKE; emit ObservationReport
2.0–3.0WARN — borderline anomaly; emit with low_confidence flag
< 1.0 (hard floor)Reject — below minimum anomaly sensitivity; PARAMETER_CHANGE_REQUIRES_APPROVAL

Developer check

if (p.z_score_threshold < p.hard) throw ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL');

User-facing English

Statistical anomalies are only reported when market behaviour deviates significantly from the historical baseline.

baseline_window_s

What it means

Rolling window in seconds used to compute mean and standard deviation for z-score baseline.

Default

{ "baseline_window_s": 3600 }

Why this default matters

3600 s (1 h) captures intraday price patterns without including multi-day regime shifts in the baseline.

Threshold logic

ConditionAction
window >= 3600 sNormal
300–3600 sWARN — baseline may be noisy with short window
< 300 sReject — insufficient baseline; emit ANOMALYDETECTOR_INSUFFICIENT_BASELINE

Developer check

if (p.baseline_window_s < p.hard) emit('ANOMALYDETECTOR_INSUFFICIENT_BASELINE');

User-facing English

The anomaly baseline uses a rolling historical window to adapt to normal market conditions.

8. Default Configuration

{
  "bot_id": "intel.anomalydetector",
  "version": "0.1.0",
  "mode": "planned",
  "defaults": {
    "z_score_threshold": 3.0,
    "baseline_window_s": 3600,
    "sample_rate": 10
  },
  "locked": {
    "z_score_threshold": {
      "min": 1.0
    },
    "baseline_window_s": {
      "min": 300
    }
  }
}

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.

FUNCTION detectAnomalies(condition_id):
  // 0. KillSwitch check
  IF FETCH internal.killswitch.status == ACTIVE:
    RETURN

  // 1. Fetch current price and volume
  book = FETCH clob_public.GET('/book?token_id=' + condition_id)
  trades = FETCH data.GET('/trades?condition_id=' + condition_id + '&window=300')

  // 2. Compute z-score vs rolling baseline
  mid = (book.best_bid + book.best_ask) / 2
  baseline = state.get_rolling_stats(condition_id)
  z_price = (mid - baseline.mean_price) / baseline.std_price
  z_vol = (volume(trades) - baseline.mean_vol) / baseline.std_vol

  // 3. Apply anomaly thresholds
  anomaly = False
  IF abs(z_price) > z_score_threshold:
    EMIT WARN 'ANOMALYDETECTOR_PRICE_SPIKE'
    anomaly = True
  IF abs(z_vol) > z_score_threshold:
    EMIT WARN 'ANOMALYDETECTOR_VOLUME_SPIKE'
    anomaly = True

  // 4. Sample gate
  IF sample_counter % sample_rate != 0 AND NOT anomaly:
    sample_counter++
    RETURN

  // 5. Emit ObservationReport
  EMIT ObservationReport {
    report_id: gen_id(),
    kind: 'ObservationReport',
    condition_id: condition_id,
    anomaly_detected: anomaly,
    z_price: z_price,
    z_vol: z_vol,
    emitted_at_ms: now_ms()
  }
  sample_counter = 0

SDK calls used

  • clob_public.GET('/book?token_id=<condition_id>')
  • data.GET('/trades?condition_id=<condition_id>&window=300')
  • internal.killswitch.status

Complexity: O(1) per market per poll cycle with O(W) rolling window state update

11. Wire Examples

Input — what arrives on the wire

{
  "label": "CLOB V2 order book and recent trades for anomaly detection",
  "source": "clob_public",
  "payload": {
    "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
    "best_bid": "0.82",
    "best_ask": "0.84",
    "recent_trade_volume_pusd": 45000,
    "timestamp_ms": 1746703000000
  }
}

Output — what the bot emits

{
  "label": "ObservationReport — price spike anomaly detected",
  "payload": {
    "report_id": "rep_ad_0xf1a2_1746703000000",
    "trace_id": "trc_0xbeef0102030405060716",
    "bot_id": "intel.anomalydetector",
    "kind": "ObservationReport",
    "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
    "anomaly_detected": true,
    "z_price": 3.8,
    "z_vol": 1.2,
    "emitted_at_ms": 1746703005000
  }
}

12. Decision Logic

APPROVE

— not yet authored —

RESHAPE_REQUIRED

— not yet authored —

REJECT

— not yet authored —

WARNING_ONLY

— not yet authored —

13. Standard Decision Output

This bot returns a RiskVote object. See RiskVote schema.

{
  "report_id": "rep_ad_0xf1a2_1746703000000",
  "trace_id": "trc_0xbeef0102030405060716",
  "bot_id": "intel.anomalydetector",
  "kind": "ObservationReport",
  "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
  "anomaly_detected": true,
  "z_price": 3.8,
  "z_vol": 1.2,
  "warnings": [
    "ANOMALYDETECTOR_PRICE_SPIKE"
  ],
  "emitted_at_ms": 1746703005000
}

14. Reason Codes

CodeSeverityMeaningActionUser-facing message
ANOMALYDETECTOR_PRICE_SPIKEWARNPrice z-score exceeds z_score_threshold relative to rolling baseline.Emit ObservationReport with anomaly_detected=true; strategies may reduce size or pause.Unusual price movement detected on this market.
ANOMALYDETECTOR_VOLUME_SPIKEWARNVolume z-score exceeds z_score_threshold relative to rolling baseline.Emit ObservationReport with anomaly_detected=true; strategies monitor for continuation.Unusual trading volume detected on this market.
STALE_DATAWARNCLOB API or Data API is unavailable; anomaly detection paused.Skip detection cycle; retry on next poll.
KILL_SWITCH_ACTIVEHARD_REJECTKillSwitch active; all AnomalyDetector emissions suppressed.Continue anomaly detection internally; suppress all ObservationReport emissions.Anomaly detection signals paused while trading is suspended system-wide.
ANOMALYDETECTOR_INSUFFICIENT_BASELINEINFORolling baseline has insufficient data points to compute reliable z-scores.Skip anomaly check for this market until baseline window is populated.

15. Metrics & Logs

Metrics emitted

MetricTypeUnitLabelsMeaning
polytraders_intel_anomalydetector_observations_emitted_totalcountercountanomaly_detectedObservationReports emitted, broken down by anomaly_detected (true/false).
polytraders_intel_anomalydetector_anomalies_totalcountercountanomaly_typeTotal anomaly events by type (price_spike, volume_spike).
polytraders_intel_anomalydetector_z_scoregaugesigmacondition_id, metricLatest z-score for price and volume per tracked market.
polytraders_intel_anomalydetector_baseline_age_sgaugesecondscondition_idAge of the rolling baseline in seconds; high values indicate stale baseline.

Alerts

AlertConditionSeverityRunbook
AnomalyDetectorPriceSpikerate(polytraders_intel_anomalydetector_anomalies_total{anomaly_type='price_spike'}[5m]) > 0warn#runbook-anomalydetector-price-spike
AnomalyDetectorStalerate(polytraders_intel_anomalydetector_observations_emitted_total[10m]) == 0warn#runbook-anomalydetector-stale
AnomalyDetectorHighZScorepolytraders_intel_anomalydetector_z_score > 5page#runbook-anomalydetector-high-zscore

Dashboards

  • Grafana — Intelligence / AnomalyDetector z-score heatmap by market
  • Grafana — Intelligence / AnomalyDetector anomaly rate over time

16. Developer Reporting

{
  "bot_id": "intel.anomalydetector",
  "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
  "z_price": 3.8,
  "z_vol": 1.2,
  "anomaly_detected": true,
  "baseline_sample_count": 120,
  "killswitch_active": false,
  "emitted_at_ms": 1746703005000
}

17. Plain-English Reporting

SituationUser-facing explanation
Strategy paused on a market after price anomaly detectedAn unusual price movement was detected on this market that is statistically significant compared to recent history. The system paused new entries pending market stabilisation.
No anomaly detected despite market movementThe recent price movement was within the normal statistical range based on the last hour of market data. No anomaly signal was generated.

18. Failure-Mode Block

main_failure_modeCLOB API outage prevents fresh price data from being fetched, causing AnomalyDetector to serve stale z-scores and miss genuine anomalies during the outage period.
false_positive_riskThin book with high bid-ask spread causes mid-price jumps that generate price z-scores above threshold despite no meaningful price discovery event.
false_negative_riskSlow-moving price manipulation that stays within 3 sigma of the rolling baseline evades the anomaly detector entirely until the baseline itself shifts.
safe_fallbackIf CLOB API or Data API is unavailable, emit STALE_DATA WARN and halt anomaly detection. Do not emit from stale z-scores. Resume on API recovery with fresh baseline computation.
required_dependenciesPolymarket CLOB V2 public API, Polymarket Data API for trade volume, KillSwitch active flag, Redis for rolling baseline state

19. Failure-Injection Recipes

ScenarioHow to injectExpected behaviourRecovery
CLOB_API_DOWNBlock CLOB public API for 10 minAutomatic on API recovery; baseline resumes updating on next poll
SYNTHETIC_PRICE_SPIKEInject mock mid-price 5 standard deviations above baseline for a test marketAutomatic when price returns to normal range
KILL_SWITCH_ONSet killswitch.active=true during active detectionAutomatic on KillSwitch reset

20. State & Persistence

Cold-start recovery

On cold start, baseline rebuilt from next N poll cycles; anomaly detection suppressed until baseline is populated.

21. Concurrency & Idempotency

AspectSpecification
Execution modelasync per-market poll loop
Max in-flight30
Idempotency keycondition_id + poll_cycle_ms
Per-call timeout (ms)8000
Backpressure strategydrop-after-buffer — skip markets that have not drained within 2x poll interval
Locking / mutual exclusionRedis SETNX on condition_id + cycle to prevent duplicate detection runs

22. Dependencies

Depends on (must run first)

BotWhyContract
risk.kill_switchSuppress emissions when KillSwitch is active.

Emits to (downstream consumers)

BotWhyContract
strat.all_strategies
risk.liquidity_guard

Sibling bots (same OrderIntent)

External services

ServiceEndpointSLA assumedOn failure
Polymarket CLOB V2 (public book)https://clob.polymarket.com99.9% / 200 ms p99
Polymarket Data APIhttps://data-api.polymarket.com99.9% / 300 ms p99

23. Security Surfaces

Abuse vectors considered

  • Adversary places and cancels orders to inflate z-scores and trigger false anomaly signals causing strategy pauses
  • Coordinated thin-book manipulation causes persistent high z-scores on a target market

Mitigations

  • z_score_threshold tuned to suppress noise from normal spread fluctuations
  • Anomalies are informational only — strategies apply independent validation before pausing

24. Polymarket V2 Compatibility

AspectValue
CLOB versionv2
Collateral assetpUSD
EIP-712 Exchange domain version2
Aware of builderCode fieldno
Aware of negative-risk marketsyes
Multi-chain readyno
SDK usedpy-clob-client-v2
Settlement contractCTFExchangeV2
NotesDetects statistical anomalies in CLOB V2 price, volume, and on-chain flow data. Read-only. No order signing.

API surfaces declared

clob_publicdataonchaininternal

Networks supported

polygon

25. Versioning & Migration

FieldValue
spec2.0.0
implementation0.1.0
schema2
releasedNone
planned_releaseQ3-2026

Migration history

DateFromToReasonAction taken
2026-04-28n/av2-specSpec drafted post-CLOB-V2 cutover; bot not yet implementedDesigned against V2 schema (pUSD, builder codes, V2 EIP-712 domain)

26. Acceptance Tests

Unit Tests

TestSetupExpected result
Price z-score above threshold emits ObservationReport with anomaly_detected=truemid_price 5 sigma above rolling mean, baseline_window=3600 sObservationReport emitted with z_price=5.0, anomaly_detected=true, ANOMALYDETECTOR_PRICE_SPIKE
Price within threshold emits sampled ObservationReport with anomaly_detected=falsemid_price 0.5 sigma above rolling mean; sample_rate=10ObservationReport emitted every 10th cycle with anomaly_detected=false
KillSwitch suppresses emissionkillswitch.active=true; anomaly presentNo ObservationReport; KILL_SWITCH_ACTIVE logged

Integration Tests

TestExpected result
Anomaly detected, emitted, consumed by LiquidityGuard for pre-trade gateLiquidityGuard receives ObservationReport with anomaly_detected=true before strategy entry
CLOB API down: STALE_DATA emitted; no anomaly checks runSTALE_DATA WARN; AnomalyDetectorStale alert fires; no ObservationReports

Property Tests

PropertyRequired behaviour
AnomalyDetector never submits or signs ordersAlways true
No ObservationReport emitted when KillSwitch is activeAlways true

27. Operational Runbook

AnomalyDetector incidents include genuine market anomalies (informational), API outages, and high z-scores requiring strategy team attention. Page on z-score > 5.

On-call actions

AlertFirst stepDiagnosisMitigationEscalate to
AnomalyDetectorHighZScoreIdentify condition_id from alert. Check live price and order book on Polymarket.com. Notify strategy team if z_score > 5.Intelligence pod lead immediately; strategy team on-call for active positions
AnomalyDetectorStaleCheck CLOB API and Data API health. Verify last_updated_at_ms for affected markets.Intelligence pod lead if stale > 10 min
AnomalyDetectorPriceSpikeVerify on Polymarket.com. If genuine price movement, no action needed — downstream strategies consume signal. If book manipulation suspected, alert strategy team.Strategy team on-call if anomaly persists > 5 min

Manual overrides

  • reset_baseline — DEL redis key baseline:<condition_id> to reset rolling baseline for a specific market; next N polls rebuild it — After known structural break in market (e.g. major news event resetting price regime)

Healthcheck

Endpoint: /internal/health/anomalydetector | Green: Last detection < 2x poll_interval_s AND Redis reachable AND CLOB + Data APIs returning 200 | Red: No detection for > 10 min OR Redis unreachable OR CLOB API down > 5 min

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
Unit tests pass for price spike, volume spike, insufficient baseline, and KillSwitch suppressionCI test run100% pass

Promote to Limited live

GateHow measuredThreshold
False-positive rate < 1% over 48 h on staging with live market dataanomaly_detected=true rate vs manual audit of price charts< 1% false positives

Promote to General live

GateHow measuredThreshold
100% detection of synthetic price and volume spikes (5-sigma) over 7-day soakIntegration test log audit100% detection

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