Volume-Imbalance Bars
Install and import#
npm install fintech-algorithmsimport { constructBars } from "fintech-algorithms/market-data-engineering/bar-construction/volume-imbalance-bars";Signature#
constructBars(trades, config)The imbalance rule applied to signed *volume* rather than signed tick count, so one large order weighs more than many small ones pointing the same way.
Parameters#
| Name | Type | Notes |
|---|---|---|
trades | Trade[] | The raw tape in chronological order. Each trade carries tradeId, timestamp, session, symbol, price, volume and currency. |
config | { initialTickSign: number; initialExpectedTicks: number; initialExpectedSignedVolume: number; alphaTicks: number; alphaSignedVolume: number; thresholdFloorShares: number; thresholdScale: number; closePartial?: boolean } | As for tick-imbalance bars, but the tracked quantity is signed volume. thresholdFloorShares is the floor in shares, and thresholdScale multiplies the expectation to form the trigger. |
Returns#
Bar[] · length fewer
One bar per signed-volume imbalance event.
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#
[
{
"tradeId": "W01",
"timestamp": "2026-01-05T14:30:00.000Z",
"session": "2026-01-05",
"symbol": "SYNTH",
"price": 100,
"volume": 60,
"currency": "USD"
},
{
"tradeId": "W02",
"timestamp": "2026-01-05T14:30:00.000Z",
"session": "2026-01-05",
"symbol": "SYNTH",
"price": 100,
"volume": 40,
"currency": "USD"
},
{
"tradeId": "W03",
"timestamp": "2026-01-05T14:30:01.000Z",
"session": "2026-01-05",
"symbol": "SYNTH",
"price": 99.99,
"volume": 70,
"currency": "USD"
}
]Showing 3 of 8 elements.
{
"closePartial": true,
"initialTickSign": 1,
"initialExpectedTicks": 4,
"initialExpectedSignedVolume": 50,
"alphaTicks": 0.25,
"alphaSignedVolume": 0.25,
"thresholdFloorShares": 120,
"thresholdScale": 1
}Call#
constructBars(trades, config)Returns#
array of 2 objects
[
{
"barIndex": 0,
"session": "2026-01-05",
"startTime": "2026-01-05T14:30:00.000Z",
"endTime": "2026-01-05T14:30:04.000Z",
"open": 100,
"high": 100,
"low": 99.97,
"close": 99.97,
"volume": 405,
"dollarValue": 40493.65,
"tickCount": 6,
"firstTradeId": "W01",
"lastTradeId": "W06",
"closeReason": "threshold"
},
{
"barIndex": 1,
"session": "2026-01-05",
"startTime": "2026-01-05T14:30:05.000Z",
"endTime": "2026-01-05T14:30:06.000Z",
"open": 99.98,
"high": 99.99,
"low": 99.98,
"close": 99.99,
"volume": 135,
"dollarValue": 13497.85,
"tickCount": 2,
"firstTradeId": "W07",
"lastTradeId": "W08",
"closeReason": "threshold"
}
]Diagrams#
Calculation flow#
Causal volume-imbalance construction flow
flowchart TD
A["Receive corrected, eligible, ordered trade"] --> B{"New session?"}
B -->|Yes| C["Apply partial-tail policy"]
C --> D["Reset sign and expectation seeds"]
B -->|No| E["Keep frozen threshold"]
D --> F["Infer tick sign and add signed shares"]
E --> F
F --> G{"Absolute signed shares >= frozen threshold?"}
G -->|No| A
G -->|Yes| H["Emit complete bar, lineage, and overshoot"]
H --> I["Update expected ticks and signed shares per trade"]
I --> J["Reset accumulation and freeze next threshold"]
J --> A
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.
References#
- Advances in Financial Machine Learning, Chapter 1 manuscript — Marcos Lopez de Prado
- Inferring Trade Direction from Intraday Data — Charles M. C. Lee and Mark J. Ready
- NYSE Daily TAQ Client Specification — New York Stock Exchange / Intercontinental Exchange
- Trade Reporting Frequently Asked Questions — Financial Industry Regulatory Authority (FINRA)
- Evidence and historical-example decision