Trade-and-Quote Event Normalization
Install and import
npm install fintech-algorithmsimport { normalizeEvents } from "fintech-algorithms/market-data-engineering/order-book-feed-engineering/trade-and-quote-event-normalization";Signature
normalizeEvents(events)Normalises raw venue trade and quote messages into one canonical event shape. Every venue names, orders and timestamps its fields differently; this is the boundary where that stops being everyone else's problem.
Parameters
| Name | Type | Notes |
|---|---|---|
events | RawEvent[] | Raw venue messages with their native field names, sequence numbers and timestamps. |
Returns
{ events, rejected, diagnostics }
Canonical events plus the ones rejected and why — a normaliser that silently drops malformed messages hides a feed problem rather than surfacing it.
Errors
- When an event carries no recognisable type — recorded in rejected rather than thrown
Complexity: time O(n),
space O(n).
Worked example
executed Captured by running this function on the input its own test provides. Real output of real code — but not asserted against a published figure.
Input
[
{
"venue": "XNAS",
"instrument": "SYN1",
"sequence": 100,
"event_time_ns": 1000000,
"receive_time_ns": 1000210,
"price_scale": 10000,
"kind": "quote",
"bid_price_atoms": 1000000,
"bid_quantity": 70,
"ask_price_atoms": 1000200,
"ask_quantity": 65
},
{
"venue": "XNAS",
"instrument": "SYN1",
"sequence": 101,
"event_time_ns": 1000300,
"receive_time_ns": 1000545,
"price_scale": 10000,
"kind": "trade",
"trade_id": "T01",
"price_atoms": 1000200,
"quantity": 11,
"aggressor_side": "buy"
},
{
"venue": "XNAS",
"instrument": "SYN1",
"sequence": 102,
"event_time_ns": 1000600,
"receive_time_ns": 1000880,
"price_scale": 10000,
"kind": "quote",
"bid_price_atoms": 1000200,
"bid_quantity": 74,
"ask_price_atoms": 1000400,
"ask_quantity": 67
}
]Showing 3 of 24 elements.
Call
normalizeEvents(events)Returns
object with 8 fields: schema_version, event_count, trade_count, quote_count, venue_count, max_latency_ns, events, state
{
"schema_version": 1,
"event_count": 24,
"trade_count": 8,
"quote_count": 16,
"venue_count": 1,
"max_latency_ns": 350,
"events": [
{
"schema_version": 1,
"venue": "XNAS",
"instrument": "SYN1",
"sequence": 100,
"event_time_ns": 1000000,
"receive_time_ns": 1000210,
"latency_ns": 210,
"price_scale": 10000,
"kind": "quote",
"bid_price_atoms": 1000000,
"bid_price": 100,
"bid_quantity": 70,
"ask_price_atoms": 1000200,
"ask_price": 100.02
},
{
"schema_version": 1,
"venue": "XNAS",
"instrument": "SYN1",
"sequence": 101,
"event_time_ns": 1000300,
"receive_time_ns": 1000545,
"latency_ns": 245,
"price_scale": 10000,
"kind": "trade",
"trade_id": "T01",
"price_atoms": 1000200,
"price": 100.02,
"quantity": 11,
"aggressor_side": "buy"
},
{
"schema_version": 1,
"venue": "XNAS",
"instrument": "SYN1",
"sequence": 102,
"event_time_ns": 1000600,
"receive_time_ns": 1000880,
"latency_ns": 280,
"price_scale": 10000,
"kind": "quote",
"bid_price_atoms": 1000200,
"bid_price": 100.02,
"bid_quantity": 74,
"ask_price_atoms": 1000400,
"ask_price": 100.04
}
],
"state": "normalized"
}Other exports
This module also exports
reconstructL2, aggregatePriceLevels, reconstructL3, recoverSequenceStream, reconcileSnapshotIncrementals, consolidateVenues, calculate. Every module additionally exports run as an alias of its
primary function, and a meta object carrying its catalog id, domain, family,
shape and article URL.
Diagrams
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
- Topic-specific source roles
- Nasdaq TotalView-ITCH 5.0 — Nasdaq
- Nasdaq GLIMPSE 5.0 — Nasdaq
- MoldUDP64 protocol — Nasdaq
- FIX recommended practices for book management — FIX Trading Community
- Cboe Multicast PITCH specification — Cboe Global Markets
- Coinbase Exchange WebSocket channels — Coinbase
- UTP Quote Data Feed — UTP Plan
- UTP odd-lot data service update — UTP Plan / Nasdaq Trader
- UTP Data Feed Services Specification — UTP Plan