I think there are three separate problems here that are worth keeping apart: the live L2 book, historical heatmap reconstruction, and true MBO/queue data.
For the heatmap side, OnMarketDepth() is the right starting point for live Level II updates. I would keep that callback very lightweight:
OnMarketDepth()
→ update an in-memory order book
→ store timestamped depth changes/snapshots in a bounded buffer
→ let OnRender() only consume that prepared state and draw it.
I would avoid doing aggregation or rebuilding the book inside OnRender() itself.
The important limitation is historical depth. OnMarketDepth() is a real-time stream; it is not called as normal historical data is processed. So there isn’t a general NinjaScript call where you can ask, “what was the complete order book at this price/time yesterday?”
If you want a historical heatmap, you need a source that actually contains historical depth events. One practical route inside NT is Market Replay data, since that can contain both Level I and Level II events. Another is recording the incoming depth events yourself and rebuilding the book from that event stream later.
For MBO, I would be very careful about terminology.
L1 cannot be reconstructed into true MBO. Even ordinary price-level L2/MBP tells you aggregated liquidity at a price level, not the individual lifecycle and queue priority of every resting order.
True MBO requires order-level information. If a tool claims to show individual queue position/order behavior from ordinary L1 or aggregated L2 alone, then at least part of that information has to be inferred rather than directly observed.
So the architecture depends on the actual goal:
-
heatmap / historical resting liquidity → Level II depth events are usually enough;
-
volume-at-price / executed order flow → tick trade + bid/ask data;
-
individual order lifecycle / queue analytics → true MBO-level input.
For a custom NT heatmap, the OnMarketDepth() → book aggregator → circular history buffer → SharpDX/OnRender() architecture Bill mentioned is basically the direction I would take. The main design decision is what you store in the history buffer: full snapshots are simpler but expensive, while depth deltas are much more compact but require deterministic reconstruction.