Class SignalEngine

java.lang.Object
com.quantfinlib.microstructure.SignalEngine

public final class SignalEngine extends Object
The unified streaming signal engine: one multi-symbol, hot-lane component that turns raw top-of-book quotes and trade prints into the five signal families a trading decision reads — for equities and FX alike (prices are doubles; equity integer ticks are exact in a double, FX rates feed in directly):
  • Imbalance — order-flow imbalance (Cont-Kukanov-Stoikov, time-decayed), inside queue imbalance and signed trade-flow imbalance, via a per-symbol FlowSignals;
  • Fair value — the size-weighted microprice (FairValueEngine.microprice);
  • Volatility — a streaming EWMA realized-variance rate over irregular tick arrivals: per valid mid change, r² / dt enters a time-decayed average, and volPerSqrtSecond(int) is its square root — multiply by √(seconds per year) to annualize externally;
  • Liquidity — time-decayed EWMAs of the absolute spread (and spreadBps(int) of mid), displayed top-of-book depth, and quote arrival intensity (from the decayed inter-quote gap);
  • Momentum — two time-aware EMAs of the mid (decay by elapsed time, not by update count — constant-step EMAs like indicators.StreamingIndicators mis-weight irregular tick arrivals), read as the normalized fast/slow gap (fast − slow)/mid.

Composite alpha. alpha(int) blends the dimensionless forms of the signals under caller-set weights: queue imbalance and trade imbalance are already in [-1, 1]; OFI is normalized by decayed depth and clamped (net recent flow as a fraction of what's displayed); momentum is scaled by volatility over the fast horizon (a t-statistic-like ratio) and squash-clamped. This composite is a scaffold for intraday signal research, not a validated alpha — before trading any weighting, run it through the alpha package's walk-forward and permutation machinery like any other signal. Cross-sectional daily alphas live there, not here.

Gap discipline (inherited from FlowSignals and applied to every family): a one-sided or NaN quote is a signal gap — nothing updates, nothing poisons, and the next two-sided quote re-seeds baselines. Zero allocation per event after construction; single writer (one feed or aggregation thread owns the engine); dense int symbol ids, exactly like the market-data bus.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Half-lives (all in nanos) for the decayed estimators, plus the composite weights.
  • Constructor Summary

    Constructors
    Constructor
    Description
    SignalEngine(int symbolCount)
     
    SignalEngine(int symbolCount, SignalEngine.Config config)
     
  • Method Summary

    Modifier and Type
    Method
    Description
    double
    alpha(int symbolId)
    The weighted intraday composite in roughly [-1, 1]: each ingredient is dimensionless (imbalances natively; OFI as a clamped fraction of decayed displayed depth; momentum as a clamped ratio to volatility over the fast horizon), blended by the Config weights and divided by their sum. 0 when unseeded or all weights are 0.
    double
    microprice(int symbolId)
    Size-weighted microprice; NaN before the first two-sided quote.
    double
    momentum(int symbolId)
    Normalized momentum: (fast EMA − slow EMA) / mid.
    double
    momentumZ(int symbolId)
    Momentum scaled by the volatility accrued over the fast horizon — a t-statistic-like "drift vs noise" ratio — clamped to [-1, 1].
    double
    normalizedOfi(int symbolId)
    OFI as a fraction of decayed displayed depth, clamped to [-1, 1].
    double
    ofi(int symbolId)
    Time-decayed net order-flow imbalance, in size units (+ = buying pressure).
    void
    onQuote(int symbolId, double bid, long bidSize, double ask, long askSize, long timestampNanos)
    Top-of-book update.
    void
    onTrade(int symbolId, boolean buyAggressor, long quantity, long timestampNanos)
    Trade print with aggressor side (Lee-Ready if the venue doesn't say).
    double
    queueImbalance(int symbolId)
    Inside queue imbalance in [-1, 1]; 0 on a one-sided book.
    long
     
    double
    Quote arrival intensity, per second (0 until two quotes).
    double
    spread(int symbolId)
    Time-decayed absolute inside spread (0 until seeded).
    double
    spreadBps(int symbolId)
    Decayed spread as basis points of the current mid; NaN before a mid.
    int
     
    double
    topDepth(int symbolId)
    Time-decayed displayed depth (bid + ask size at the inside).
    long
     
    double
    tradeImbalance(int symbolId)
    Signed aggressor-volume imbalance in [-1, 1]; 0 before any trade.
    double
    volPerSqrtSecond(int symbolId)
    Streaming realized volatility as return per √second (0 until two valid mids).

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • SignalEngine

      public SignalEngine(int symbolCount, SignalEngine.Config config)
    • SignalEngine

      public SignalEngine(int symbolCount)
  • Method Details

    • onQuote

      public void onQuote(int symbolId, double bid, long bidSize, double ask, long askSize, long timestampNanos)
      Top-of-book update. Prices are raw doubles (FX rates directly; for equities pass ticks or converted prices — any monotonic representation, consistently per symbol). One-sided/NaN quotes are gaps: counted, but no estimator updates and no baseline poisoning.
    • onTrade

      public void onTrade(int symbolId, boolean buyAggressor, long quantity, long timestampNanos)
      Trade print with aggressor side (Lee-Ready if the venue doesn't say).
    • ofi

      public double ofi(int symbolId)
      Time-decayed net order-flow imbalance, in size units (+ = buying pressure).
    • queueImbalance

      public double queueImbalance(int symbolId)
      Inside queue imbalance in [-1, 1]; 0 on a one-sided book.
    • tradeImbalance

      public double tradeImbalance(int symbolId)
      Signed aggressor-volume imbalance in [-1, 1]; 0 before any trade.
    • microprice

      public double microprice(int symbolId)
      Size-weighted microprice; NaN before the first two-sided quote.
    • volPerSqrtSecond

      public double volPerSqrtSecond(int symbolId)
      Streaming realized volatility as return per √second (0 until two valid mids). Multiply by √(seconds per horizon) for a horizon vol, e.g. × √(252 × 6.5 × 3600) to annualize an equity session.
    • spread

      public double spread(int symbolId)
      Time-decayed absolute inside spread (0 until seeded).
    • spreadBps

      public double spreadBps(int symbolId)
      Decayed spread as basis points of the current mid; NaN before a mid.
    • topDepth

      public double topDepth(int symbolId)
      Time-decayed displayed depth (bid + ask size at the inside).
    • quoteIntensityPerSecond

      public double quoteIntensityPerSecond(int symbolId)
      Quote arrival intensity, per second (0 until two quotes).
    • momentum

      public double momentum(int symbolId)
      Normalized momentum: (fast EMA − slow EMA) / mid. Positive = the short horizon trades above the long horizon (upward drift). 0 until seeded.
    • alpha

      public double alpha(int symbolId)
      The weighted intraday composite in roughly [-1, 1]: each ingredient is dimensionless (imbalances natively; OFI as a clamped fraction of decayed displayed depth; momentum as a clamped ratio to volatility over the fast horizon), blended by the Config weights and divided by their sum. 0 when unseeded or all weights are 0. A research scaffold — validate any weighting through the alpha package before trading it.
    • normalizedOfi

      public double normalizedOfi(int symbolId)
      OFI as a fraction of decayed displayed depth, clamped to [-1, 1].
    • momentumZ

      public double momentumZ(int symbolId)
      Momentum scaled by the volatility accrued over the fast horizon — a t-statistic-like "drift vs noise" ratio — clamped to [-1, 1].
    • symbolCount

      public int symbolCount()
    • quoteCount

      public long quoteCount()
    • tradeCount

      public long tradeCount()