fintech-algorithms
Using a coding agent? Give it the skill: npx skills add IslamBaraka90/Fintech-Algorithms-Library What it does →

Tick-Imbalance Bars

Install and import#

bash
npm install fintech-algorithms
ts
import { constructBars } from "fintech-algorithms/market-data-engineering/bar-construction/tick-imbalance-bars";

Signature#

constructBars(trades, config)

Closes a bar when signed tick flow becomes unusually one-sided relative to what recent history led you to expect. Bars are emitted on *information* rather than on elapsed time or traded quantity.

Parameters#

NameTypeNotes
tradesTrade[]The raw tape in chronological order. Each trade carries tradeId, timestamp, session, symbol, price, volume and currency.
config{ initialTickSign: number; initialExpectedTicks: number; initialExpectedTickImbalance: number; alphaTicks: number; alphaTickImbalance: number; thresholdFloor: number; thresholdMultiplier: number; closePartial?: boolean }The initial* values seed the expectations before any bar has closed; the alpha* values are the EWMA decay rates that update them afterwards. thresholdFloor and thresholdMultiplier bound the resulting threshold so it cannot collapse toward zero in quiet periods.

Returns#

Bar[] · length fewer

One bar per imbalance event, with the threshold that triggered it recorded on the bar.

Errors#

  • When any alpha falls outside 0…1, or a seed expectation is not positive — throws

Complexity: time O(n), space O(bars).

Worked example#

verified This is the worked example published in the article, replayed by the test suite on every run. The output cannot drift.

Input#

trades
[
  {
    "tradeId": "W1",
    "timestamp": "2026-01-05T14:30:00.000Z",
    "session": "2026-01-05",
    "symbol": "SYNTH",
    "price": 100,
    "volume": 10,
    "currency": "USD"
  },
  {
    "tradeId": "W2",
    "timestamp": "2026-01-05T14:30:01.000Z",
    "session": "2026-01-05",
    "symbol": "SYNTH",
    "price": 100,
    "volume": 10,
    "currency": "USD"
  },
  {
    "tradeId": "W3",
    "timestamp": "2026-01-05T14:30:02.000Z",
    "session": "2026-01-05",
    "symbol": "SYNTH",
    "price": 100.1,
    "volume": 10,
    "currency": "USD"
  }
]

Showing 3 of 6 elements.

config
{
  "closePartial": true,
  "initialTickSign": 1,
  "initialExpectedTicks": 8,
  "initialExpectedTickImbalance": 0.5,
  "alphaTicks": 0.25,
  "alphaTickImbalance": 0.5,
  "thresholdFloor": 3,
  "thresholdMultiplier": 1
}

Call#

constructBars(trades, config)

Returns#

array of 1 object

[
  {
    "barIndex": 0,
    "session": "2026-01-05",
    "startTime": "2026-01-05T14:30:00.000Z",
    "endTime": "2026-01-05T14:30:05.000Z",
    "lastTradeTime": "2026-01-05T14:30:05.000Z",
    "open": 100,
    "high": 100.15,
    "low": 100,
    "close": 100.15,
    "volume": 60,
    "dollarValue": 6004,
    "tickCount": 6,
    "firstTradeId": "W1",
    "lastTradeId": "W6"
  }
]

Diagrams#

Tick-Imbalance Bars — article hero
Tick-Imbalance Bars — boundary and state
Tick-Imbalance Bars — construction anatomy

Calculation flow#

Causal construction flow
flowchart TD
    A["Corrected, eligible, stably ordered trade"] --> B{"New session?"}
    B -->|Yes| C["Emit or drop tail; reset price, sign, and expectations"]
    B -->|No| D["Keep session state"]
    C --> E["Freeze threshold for new bar"]
    D --> F["Assign tick sign; flat carries prior sign"]
    E --> F
    F --> G["Update OHLCV and cumulative tick imbalance"]
    G --> H{"Absolute imbalance at least frozen threshold?"}
    H -->|No| A
    H -->|Yes| I["Emit complete bar and lineage"]
    I --> J["Update expected length and expected mean sign"]
    J --> E

How it works#

This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.

Read the article →

References#

The rest of the Bar Construction family#