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.13 LiquidityForecastModel

4.13 LiquidityForecastModel

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

Predict near-term book depth and trade pacing per market for sizing decisions.

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

Predict near-term book depth and trade pacing per market for sizing decisions.

3. Why This Bot Matters

  • Strategies size on stale liquidity

    Sizing decisions made from current top-of-book ignore that depth can collapse seconds before fill. A forecast — even a coarse one — gives strategies a concrete number to clamp size against before submitting an OrderIntent.

  • Execution router under-quotes its own fill probability

    Without forward-looking depth, smartrouter can only react to the book it sees. With a forecast, it can prefer a passive ladder that is expected to refill, instead of crossing into thin liquidity that disappears mid-fill.

  • Risk caps lag the actual market

    Static per-market notional caps assume yesterday's depth. A liquidity forecast lets Risk widen or tighten caps in line with predicted near-term depth, reducing both missed opportunities in deep books and oversize entries in thin ones.

  • Operators have no leading indicator before a liquidity collapse

    When depth dries up before a known event (a debate, a game start), having no model means the team only sees the collapse on the chart after it happens. A forecast emits a warning the operator can act on.

4. Required Polymarket Inputs

InputSourceRequired?Use
CLOB V2 order book snapshot (bids and asks) per condition_idclob_publicYesCompute current bid/ask depth in pUSD for forecast baseline.
Historical fill rate for each condition_iddataYesWeight forecast using observed fill rate to discount unfilled book depth.

5. Required Internal Inputs

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

6. Parameter Guide

ParameterDefaultWarningHardWhat it controls
forecast_horizon_s3600720086400Seconds ahead to forecast liquidity availability.
min_liquidity_pusd1000500100Minimum forecasted pUSD liquidity required to avoid a low-liquidity signal.

7. Detailed Parameter Instructions

forecast_horizon_s

What it means

Seconds ahead to forecast liquidity availability.

Default

{ "forecast_horizon_s": 3600 }

Why this default matters

3600 s (1 h) matches typical strategy hold horizon without requiring multi-day extrapolation.

Threshold logic

ConditionAction
horizon <= 3600 sNormal
3600–7200 sWARN — forecast uncertainty increases with horizon
> 86400 sReject — PARAMETER_CHANGE_REQUIRES_APPROVAL

Developer check

if (p.forecast_horizon_s > p.hard) throw ConfigError('PARAMETER_CHANGE_REQUIRES_APPROVAL');

User-facing English

Liquidity forecasts are computed for a configurable time horizon ahead.

min_liquidity_pusd

What it means

Minimum forecasted pUSD liquidity required to avoid a low-liquidity signal.

Default

{ "min_liquidity_pusd": 1000 }

Why this default matters

1000 pUSD ensures strategies have enough depth to enter and exit without significant slippage.

Threshold logic

ConditionAction
forecast >= 1000 pUSDNormal
100–1000 pUSDWARN — LIQUIDITYFORECAST_LOW_FORECAST; strategies reduce size
< 100 pUSDReject — emit low_forecast; strategies avoid entry

Developer check

if (forecast_pusd < p.min_liquidity_pusd.hard) emit('LIQUIDITYFORECAST_LOW_FORECAST');

User-facing English

A minimum liquidity level is required before strategies can enter a market.

8. Default Configuration

{
  "bot_id": "intel.liquidityforecastmodel",
  "version": "0.1.0",
  "mode": "planned",
  "defaults": {
    "forecast_horizon_s": 3600,
    "min_liquidity_pusd": 1000
  },
  "locked": {
    "forecast_horizon_s": {
      "max": 86400
    },
    "min_liquidity_pusd": {
      "min": 100
    }
  }
}

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 forecastLiquidity(condition_id, horizon_s):
  // 0. KillSwitch check
  IF FETCH internal.killswitch.status == ACTIVE:
    RETURN

  // 1. Fetch order book snapshot
  book = FETCH clob_public.GET('/book?token_id=' + condition_id)
  IF book IS NULL:
    EMIT WARN 'STALE_DATA'
    RETURN

  // 2. Compute current depth
  bid_depth_pusd = sum(l.size * l.price for l in book.bids)
  ask_depth_pusd = sum(l.size for l in book.asks)

  // 3. Fetch historical fill rate from Data API
  fill_rate = FETCH data.GET('/fills?condition_id=' + condition_id + '&window=3600')

  // 4. Forecast using exponential decay model
  forecast_pusd = forecastDepth(bid_depth_pusd, ask_depth_pusd, fill_rate, horizon_s)

  // 5. Check against min_liquidity_pusd threshold
  IF forecast_pusd < min_liquidity_pusd:
    EMIT WARN 'LIQUIDITYFORECAST_LOW_FORECAST'

  // 6. Emit ObservationReport
  EMIT ObservationReport {
    report_id: gen_id(),
    kind: 'ObservationReport',
    condition_id: condition_id,
    current_bid_depth_pusd: bid_depth_pusd,
    current_ask_depth_pusd: ask_depth_pusd,
    forecast_pusd: forecast_pusd,
    horizon_s: horizon_s,
    emitted_at_ms: now_ms()
  }

SDK calls used

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

Complexity: O(B) per condition_id where B = order book depth levels

11. Wire Examples

Input — what arrives on the wire

{
  "label": "CLOB V2 order book snapshot for liquidity forecast",
  "source": "clob_public",
  "payload": {
    "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
    "bids": [
      {
        "price": "0.67",
        "size": "5000"
      },
      {
        "price": "0.66",
        "size": "3000"
      }
    ],
    "asks": [
      {
        "price": "0.69",
        "size": "4500"
      },
      {
        "price": "0.70",
        "size": "2000"
      }
    ],
    "timestamp_ms": 1746703000000
  }
}

Output — what the bot emits

{
  "label": "ObservationReport — liquidity forecast",
  "payload": {
    "report_id": "rep_lfm_0xf1a2_1746703000000",
    "trace_id": "trc_0xbeef0102030405060714",
    "bot_id": "intel.liquidityforecastmodel",
    "kind": "ObservationReport",
    "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
    "current_bid_depth_pusd": 5350,
    "current_ask_depth_pusd": 6500,
    "forecast_pusd": 4800,
    "horizon_s": 3600,
    "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_lfm_0xf1a2_1746703000000",
  "trace_id": "trc_0xbeef0102030405060714",
  "bot_id": "intel.liquidityforecastmodel",
  "kind": "ObservationReport",
  "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
  "current_bid_depth_pusd": 5350,
  "current_ask_depth_pusd": 6500,
  "forecast_pusd": 4800,
  "horizon_s": 3600,
  "low_forecast": false,
  "emitted_at_ms": 1746703005000
}

14. Reason Codes

CodeSeverityMeaningActionUser-facing message
LIQUIDITYFORECAST_LOW_FORECASTWARNForecasted liquidity over the horizon falls below min_liquidity_pusd threshold.Emit ObservationReport with low_forecast=true; downstream strategies may reduce size.Projected market liquidity is below the minimum threshold for this horizon.
STALE_DATAWARNCLOB order book snapshot is unavailable or older than staleness_threshold_s.Skip emission; retry on next poll.
KILL_SWITCH_ACTIVEHARD_REJECTKillSwitch active; all LiquidityForecastModel emissions suppressed.Continue computing forecasts but suppress ObservationReport emissions.Liquidity forecast signals paused while trading is suspended system-wide.
LIQUIDITYFORECAST_BOOK_EMPTYWARNOrder book has no bids or asks — market may be in a halted or pre-open state.Emit ObservationReport with book_empty=true; strategies avoid entry on this market.Market order book is currently empty.

15. Metrics & Logs

Metrics emitted

MetricTypeUnitLabelsMeaning
polytraders_intel_liquidityforecastmodel_observations_emitted_totalcountercountcondition_idObservationReports emitted per tracked market.
polytraders_intel_liquidityforecastmodel_forecast_pusdgaugepUSDcondition_idLatest liquidity forecast in pUSD for each tracked market.
polytraders_intel_liquidityforecastmodel_low_forecast_totalcountercountTotal low-liquidity forecast events emitted.

Alerts

AlertConditionSeverityRunbook
LiquidityForecastModelLowForecastpolytraders_intel_liquidityforecastmodel_forecast_pusd < 1000warn#runbook-liquidityforecastmodel-low-forecast
LiquidityForecastModelStalerate(polytraders_intel_liquidityforecastmodel_observations_emitted_total[15m]) == 0warn#runbook-liquidityforecastmodel-stale

Dashboards

  • Grafana — Intelligence / LiquidityForecastModel forecast_pusd per market

16. Developer Reporting

{
  "bot_id": "intel.liquidityforecastmodel",
  "condition_id": "0xf1a2b30000000000000000000000000000000000000000000000000000000000",
  "current_bid_depth_pusd": 5350,
  "current_ask_depth_pusd": 6500,
  "forecast_pusd": 4800,
  "fill_rate": 0.72,
  "low_forecast": false,
  "killswitch_active": false
}

17. Plain-English Reporting

SituationUser-facing explanation
Strategy reduced size due to low-liquidity forecastThe model projects that available market depth will fall below the minimum threshold over the next hour. Position size was reduced to limit potential slippage.
Liquidity forecast indicates adequate depthThe market is projected to have sufficient depth over the strategy's hold horizon. No size adjustment was triggered.

18. Failure-Mode Block

main_failure_modeCLOB API outage prevents fresh order book snapshots, causing LiquidityForecastModel to serve stale forecasts that may overstate available depth, leading strategies to size into low-liquidity markets.
false_positive_riskLarge spoof orders inflating apparent book depth cause the forecast to overestimate available liquidity and suppress low-forecast signals.
false_negative_riskRapid order withdrawal post-fill leaves the forecast below actual liquidity, causing unnecessary LIQUIDITYFORECAST_LOW_FORECAST signals on adequate markets.
safe_fallbackIf CLOB API is unavailable for > staleness_threshold_s, emit STALE_DATA WARN and suspend new forecast emissions. Do not serve stale forecasts older than staleness_threshold_s to downstream consumers.
required_dependenciesPolymarket CLOB V2 public API, Polymarket Data API for fill rate, KillSwitch active flag, Redis for forecast state

19. Failure-Injection Recipes

ScenarioHow to injectExpected behaviourRecovery
CLOB_API_DOWNBlock CLOB public API for 10 minAutomatic on API recovery; next poll cycle resumes normally
EMPTY_ORDER_BOOKReturn empty bids and asks for a test condition_idAutomatic when orders return to book
KILL_SWITCH_ONSet killswitch.active=true during active forecastingAutomatic on KillSwitch reset

20. State & Persistence

Cold-start recovery

On cold start, re-compute on first poll cycle; no historical backfill required.

21. Concurrency & Idempotency

AspectSpecification
Execution modelasync per-market poll loop
Max in-flight25
Idempotency keycondition_id + snapshot_ts_ms
Per-call timeout (ms)10000
Backpressure strategydrop-after-buffer — skip condition_ids that have not drained within 2x poll interval
Locking / mutual exclusionRedis SETNX on condition_id + snapshot_ts to prevent duplicate computations

22. Dependencies

Depends on (must run first)

BotWhyContract
risk.kill_switchSuppress emissions when KillSwitch is active.
risk.liquidity_guardProvide forward liquidity signals for LiquidityGuard risk decisions.

Emits to (downstream consumers)

BotWhyContract
risk.liquidity_guard

Sibling bots (same OrderIntent)

BotWhyContract
intel.onchainwatcher

External services

ServiceEndpointSLA assumedOn failure
Polymarket CLOB V2 (public book)https://clob.polymarket.com99.9% / 200 ms p99

23. Security Surfaces

Abuse vectors considered

  • Adversary places large spoofed orders to inflate apparent order book depth and mislead forecast
  • Rapid order cancellations during forecast window cause overestimate of available liquidity

Mitigations

  • Forecast uses fill_rate weighting to discount unfilled book depth that never converts to trades
  • Forecasts are informational only — LiquidityGuard applies independent depth checks at execution time

24. Polymarket V2 Compatibility

AspectValue
CLOB versionv2
Collateral assetpUSD
EIP-712 Exchange domain version2
Aware of builderCode fieldno
Aware of negative-risk marketsno
Multi-chain readyno
SDK usedpy-clob-client-v2
Settlement contractCTFExchangeV2
NotesReads CLOB V2 order book snapshots to forecast pUSD liquidity depth over a configurable horizon. Read-only. No order signing.

API surfaces declared

clob_publicdatainternal

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
Adequate forecast emits ObservationReport with low_forecast=falsebid_depth=5350 pUSD, ask_depth=6500 pUSD, fill_rate=0.72, horizon=3600 s, min_liquidity=1000 pUSDObservationReport emitted with forecast_pusd=4800, low_forecast=false
Low forecast emits LIQUIDITYFORECAST_LOW_FORECAST warningbid_depth=50 pUSD, ask_depth=30 pUSD, min_liquidity_pusd hard=100 pUSDObservationReport emitted with low_forecast=true, LIQUIDITYFORECAST_LOW_FORECAST WARN
KillSwitch suppresses emissionkillswitch.active=true; forecast computedNo ObservationReport; KILL_SWITCH_ACTIVE logged

Integration Tests

TestExpected result
Forecast consumed by LiquidityGuard for pre-trade risk checkLiquidityGuard receives forecast_pusd and horizon_s from ObservationReport
CLOB API down: STALE_DATA emitted; no new forecasts servedSTALE_DATA WARN; downstream consumers receive no new forecast ObservationReports

Property Tests

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

27. Operational Runbook

LiquidityForecastModel incidents are typically CLOB API outages. Low forecasts are signals, not errors. Extended outages will leave strategies without forward liquidity data.

On-call actions

AlertFirst stepDiagnosisMitigationEscalate to
LiquidityForecastModelLowForecastVerify live order book depth on Polymarket.com for the affected market. If genuine, no action needed — downstream strategies will reduce size automatically.Intelligence pod lead if multiple markets simultaneously below threshold
LiquidityForecastModelStaleCheck CLOB API health and last_computed_at_ms for affected markets.Intelligence pod lead if stale > 15 min

Manual overrides

  • force_recompute — POST /internal/liquidityforecastmodel/recompute?condition_id=<id> to trigger immediate recompute — After CLOB API recovery or suspected stale forecast

Healthcheck

Endpoint: /internal/health/liquidityforecastmodel | Green: Last forecast < 5 min ago AND Redis reachable AND CLOB API returning 200 | Red: No forecast for > 15 min OR Redis unreachable

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 low-forecast gate, empty book detection, and KillSwitch suppressionCI test run100% pass

Promote to Limited live

GateHow measuredThreshold
Forecast computation completes in < 5 s p99 over 24 h on stagingIntegration testp99 < 5 s

Promote to General live

GateHow measuredThreshold
Zero missed forecasts during 14-day soak with live CLOB V2 APILiquidityForecastModelStale alert audit0 stale alerts

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