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

← All stages · stage 4 of 11

Stage 4

Signal engine

Measure market state. Never decide whether to trade.

Challenge we are solving

Strategies want features — imbalance, volatility, flow, completeness. If every strategy re-implements them, they disagree about "the market is volatile" and trade on different facts.

What this stage does

Computes a shared feature vector at every tick: spread, midpoint, imbalance, top-of-book depth, 5-level depth, buy/sell flow over rolling windows, realised volatility, freshness flags. Versioned and replayable.

Why this stage exists

Signals are observation, not opinion. They make every downstream stage read the same numbers.

Flow

OrderBookSnapshotfrom stage 3
Feature
fns
imbalance · vol · flow
Rolling
windows
60s · 5m
Qualitycompleteness %
FeatureVectorsignal_version

What the backend should expose

  • feature_vector_id, signal_version
  • raw + standardised features
  • rolling window sizes (60s · 5m · 1h)
  • completeness % (per window)
  • quality_flags (fresh · stale · partial)
  • example features: spread, midpoint, top_imbalance, depth_5, buy_flow_60s, vol_5m, stale_flag

Maths we expect here

Every formula below is implemented in packages/polytraders-bots/ or packages/polytraders-runner/. Treat the worked example as the unit-test sanity check you should be able to reproduce locally.

1

Mid-price and spread

\[mid = \tfrac{bid + ask}{2},\qquad spread = ask - bid\]
SymbolMeaningUnits / range
\(bid\)Best bid0..1
\(ask\)Best ask0..1
\(mid\)Mid-price0..1
\(spread\)Top-of-book spread0..1
worked example\[bid=0.62,\; ask=0.64 \;\Rightarrow\; mid=0.63,\; spread=0.02\]
2

Book imbalance (top of book)

\[imbalance = \frac{bid\_size - ask\_size}{bid\_size + ask\_size} \in [-1, +1]\]
SymbolMeaningUnits / range
\(bid_size\)Shares resting at best bidshares
\(ask_size\)Shares resting at best askshares
worked example\[bid\_size=1{,}300,\; ask\_size=700 \;\Rightarrow\; imbalance=\tfrac{600}{2000}=0.30 \;\text{(buy-leaning)}\]

Positive imbalance favours upward drift; negative favours downward. Strategies consume the value, never re-derive it.

3

Realised volatility (log returns)

\[\sigma = \mathrm{std}\!\Big(\log\tfrac{mid_t}{mid_{t-1}}\Big)\]
SymbolMeaningUnits / range
\(mid_t\)Mid-price at time t0..1
\(\sigma\)Standard deviation of one-tick log returnsunitless
worked example\[\text{60s window of 300 ticks},\; \mathrm{std}(\log\;\text{returns}) = 0.014\]

Reported per rolling window (60s, 5m, 1h). Stage 7 sizes positions inversely to \sigma.

4

Aggressive flow

\[flow_{w} = \sum_{t \in w}\big(buy\_qty_t \cdot \mathbb{1}_{aggressive} - sell\_qty_t \cdot \mathbb{1}_{aggressive}\big)\]
SymbolMeaningUnits / range
\(w\)Rolling window60s · 5m · 1h
\(aggressive\)Trade that crossed the spreadboolean per fill
worked example\[\text{60s: aggressive buys}=1{,}450,\; \text{aggressive sells}=820 \;\Rightarrow\; flow=+630\]
5

Feature completeness

\[completeness = \tfrac{|\text{features filled}|}{|\text{features expected}|}\]
SymbolMeaningUnits / range
\(features filled\)Number of features whose inputs were fresh
\(features expected\)Total features in signal_version
worked example\[\tfrac{14}{15} = 0.933 \;\Rightarrow\; \text{below 95% threshold} \;\Rightarrow\; \text{stage 5 suppresses scoring}\]

How a developer codes this stage

Reference TypeScript implementation lives in packages/polytraders-* at the repository root. Stage owners maintain these files — read them before writing new code.

  • packages/polytraders-bots/src/intelReference intel bots: bookimbalance, flowdetector, microvol. Each produces one feature into the shared vector.
  • packages/polytraders-contracts/src/MarketSnapshot.tsThe features field — strict typing keeps every strategy reading the same names.
  • packages/polytraders-bots/src/_helpers.jsReusable feature helpers (EMA, rolling windows, RMS).

See it in the platform mock

The platform mock is the source of truth for what each stage's UI exposes. Open these alongside the code references.

Reason codes emitted at this stage

  • INTEL_*INTEL — ingest, freshness, signals
  • STRAT_*STRAT — strategy, model, fair-value

Hover or tap any reason code on this page (or anywhere on the site) to see its canonical short description. Full registry: /standards/reason-codes.