OnMarketDepth sends Add operation that violates order book price ordering

I’m trying to build an order book from OnMarketDepth events but I’m encountering inconsistent Add operations that violate the expected price ordering.

For the Bid side, prices should be in descending order (position 0 = best bid/highest price, higher positions = lower prices). However, sometimes I receive Add operations that place a higher price at a later position than an existing lower price.

Relevant event sequence (BTCUSD), recorded from OnMarketDepth events:

Line   , Operation, Position, Price   , Volume  , IsReset, Comment
Line  1, Add      ,        9, 91390.96, 14381478, False  , Pos. 9: 91390.96
Line  2, Add      ,       10, 91390.01,  8156948, False  , Pos. 9: 91390.96 10: 91390.01
Line  3, Add      ,       10, 91390.40,  5470000, False  , Pos. 9: 91390.96 10: 91390.40 11: 91390.01
Line  4, Remove   ,        7, 91394.75,        0, False  , Pos: 8: 91390.96  9: 91390.40 10: 91390.01
Line  5, Update   ,        6, 91396.01,  4836476, False  , ---
Line  6, Add      ,        7, 91395.76,  8751902, False  , Pos. 9: 91390.96 10: 91390.40 11: 91390.01
Line  7, Update   ,        6, 91396.01,  9443028, False  , ---
Line  8, Remove   ,       10, 91390.40,        0, False  , Pos. 9: 91390.96 10: 91390.01
Line  9, Add      ,       10, 91390.39,  5470000, False  , Pos. 9: 91390.96 10: 91390.39 11: 91390.01
Line 10, Add      ,       10, 91391.36,  5470000, False  , Pos. 9: 91390.96 10: 91391.36(!!!) 11: 91390.39 12: 91390.01

Problem: The Add at position 10 with price 91391.36 should insert between positions 9 and 10. But position 9 already has price 91390.96. Since 91391.36 > 91390.96, inserting it at position 10 violates descending order:

  • Position 9 = 91390.96
  • Position 10 = 91391.36 (HIGHER than position 9 - invalid!)
  • Position 11 = 91390.39

I’m stuck and not sure how to handle such cases. Is this a known data feed behavior? How should we handle such cases to maintain a valid order book state?

Environment: NinjaTrader 8, BTCUSD, Realtime data

I’m not that familiar with level 2 data, but I did dig up a couple of resources related to the topic.

  1. Best practices (from the old forum)
  2. Basic docs with sample code

May not be super helpful, but it’s a place to start.