@@ -90,14 +90,14 @@ public async Task BuildAsync(MarketDepth marketDepth, short orderBookDepth = 10,
9090 case ContractType . Spot :
9191 subscriptionResult = await _webSocketClient . SpotStreams . SubscribeToOrderBookUpdatesAsync (
9292 marketDepth . Symbol . FullName , updateIntervalMs ,
93- data => OnDepthUpdateSpot ( marketDepth , data ) ,
93+ data => OnSpotOrderBookUpdate ( marketDepth , data ) ,
9494 ct )
9595 . ConfigureAwait ( false ) ;
9696 break ;
97- case ContractType . Perpetual :
97+ case ContractType . Futures :
9898 subscriptionResult = await _webSocketClient . UsdFuturesStreams . SubscribeToOrderBookUpdatesAsync (
9999 marketDepth . Symbol . FullName , updateIntervalMs ,
100- data => OnDepthUpdatePerp ( marketDepth , data ) ,
100+ data => OnFuturesOrderBookUpdate ( marketDepth , data ) ,
101101 ct )
102102 . ConfigureAwait ( false ) ;
103103 break ;
@@ -130,12 +130,12 @@ public async Task BuildAsync(MarketDepth marketDepth, short orderBookDepth = 10,
130130
131131 response = ( spotResponse . Success , spotResponse . Data , spotResponse . Error ) ;
132132 break ;
133- case ContractType . Perpetual :
134- WebCallResult < BinanceFuturesOrderBook > perpResponse = await _restClient . UsdFuturesApi . ExchangeData . GetOrderBookAsync (
133+ case ContractType . Futures :
134+ WebCallResult < BinanceFuturesOrderBook > futuresResponse = await _restClient . UsdFuturesApi . ExchangeData . GetOrderBookAsync (
135135 marketDepth . Symbol . FullName , orderBookDepth , ct )
136136 . ConfigureAwait ( false ) ;
137137
138- response = ( perpResponse . Success , perpResponse . Data , perpResponse . Error ) ;
138+ response = ( futuresResponse . Success , futuresResponse . Data , futuresResponse . Error ) ;
139139 break ;
140140 default :
141141 throw new ArgumentOutOfRangeException ( nameof ( marketDepth . Symbol . ContractType ) , "Unknown contract type." ) ;
@@ -173,12 +173,12 @@ public async Task BuildAsync(MarketDepth marketDepth, short orderBookDepth = 10,
173173
174174 response = ( spotResponse . Success , spotResponse . Data , spotResponse . Error ) ;
175175 break ;
176- case ContractType . Perpetual :
177- WebCallResult < BinanceFuturesOrderBook > perpResponse = await _restClient . UsdFuturesApi . ExchangeData . GetOrderBookAsync (
176+ case ContractType . Futures :
177+ WebCallResult < BinanceFuturesOrderBook > futuresResponse = await _restClient . UsdFuturesApi . ExchangeData . GetOrderBookAsync (
178178 marketDepth . Symbol . FullName , orderBookDepth , ct )
179179 . ConfigureAwait ( false ) ;
180180
181- response = ( perpResponse . Success , perpResponse . Data , perpResponse . Error ) ;
181+ response = ( futuresResponse . Success , futuresResponse . Data , futuresResponse . Error ) ;
182182 break ;
183183 default :
184184 throw new ArgumentOutOfRangeException ( nameof ( marketDepth . Symbol . ContractType ) , "Unknown contract type." ) ;
@@ -209,19 +209,20 @@ public async Task BuildAsync(MarketDepth marketDepth, short orderBookDepth = 10,
209209 // Step 6: Set local order book to snapshot
210210 _logger . Debug ( $ "6: Applying snapshot with { snapshot . Asks . Count ( ) } asks and { snapshot . Bids . Count ( ) } bids") ;
211211 marketDepth . UpdateDepth ( snapshot . Asks , snapshot . Bids , snapshot . LastUpdateId ) ;
212- _localOrderBookUpdateId = snapshot . LastUpdateId ;
213- _isSnapshotLoaded = true ;
212+ _localOrderBookUpdateId = marketDepth . LastUpdateId ?? throw new InvalidOperationException ( "MarketDepth.LastUpdateId is null after applying snapshot" ) ;
213+ _isSnapshotLoaded = marketDepth . LastUpdateId == snapshot . LastUpdateId ;
214214
215215 // Step 7: Apply buffered updates
216216 int appliedCount = 0 ;
217217 while ( _eventBuffer . Any ( ) )
218218 {
219- var bufferedEvent = _eventBuffer . Dequeue ( ) ;
219+ var bufferedEvent = _eventBuffer . Peek ( ) ;
220220 if ( bufferedEvent != null )
221221 {
222222 ApplyDepthUpdate ( marketDepth , bufferedEvent ) ;
223223 appliedCount ++ ;
224224 }
225+ _eventBuffer . Dequeue ( ) ;
225226 }
226227 _logger . Debug ( $ "7: Applied { appliedCount } buffered events") ;
227228 }
@@ -249,15 +250,15 @@ public async Task StreamUpdatesAsync(MarketDepth marketDepth, TimeSpan? updateIn
249250 subscriptionResult = await _webSocketClient . SpotStreams . SubscribeToOrderBookUpdatesAsync (
250251 marketDepth . Symbol . FullName ,
251252 updateInterval . HasValue ? ( int ) updateInterval . Value . TotalMilliseconds : ( int ) _defaultUpdateInterval . TotalMilliseconds ,
252- data => OnDepthUpdateSpot ( marketDepth , data ) ,
253+ data => OnSpotOrderBookUpdate ( marketDepth , data ) ,
253254 ct )
254255 . ConfigureAwait ( false ) ;
255256 break ;
256- case ContractType . Perpetual :
257+ case ContractType . Futures :
257258 subscriptionResult = await _webSocketClient . UsdFuturesStreams . SubscribeToOrderBookUpdatesAsync (
258259 marketDepth . Symbol . FullName ,
259260 updateInterval . HasValue ? ( int ) updateInterval . Value . TotalMilliseconds : ( int ) _defaultUpdateInterval . TotalMilliseconds ,
260- data => OnDepthUpdatePerp ( marketDepth , data ) ,
261+ data => OnFuturesOrderBookUpdate ( marketDepth , data ) ,
261262 ct )
262263 . ConfigureAwait ( false ) ;
263264 break ;
@@ -280,46 +281,34 @@ public async Task StopStreamingAsync(CancellationToken ct = default)
280281 }
281282 }
282283
283- private void OnDepthUpdateSpot ( MarketDepth marketDepth , DataEvent < IBinanceEventOrderBook > dataEvent ) =>
284- OnDepthUpdate ( marketDepth , dataEvent . Data ) ;
285-
286- private void OnDepthUpdatePerp ( MarketDepth marketDepth , DataEvent < IBinanceFuturesEventOrderBook > dataEvent ) =>
287- OnDepthUpdate ( marketDepth , dataEvent . Data ) ;
284+ private void OnSpotOrderBookUpdate ( MarketDepth marketDepth , DataEvent < IBinanceEventOrderBook > eventData ) =>
285+ OnDepthUpdate ( marketDepth , eventData . Data ) ;
288286
289- private void OnDepthUpdate ( MarketDepth marketDepth , IBinanceEventOrderBook data )
287+ private void OnFuturesOrderBookUpdate ( MarketDepth marketDepth , DataEvent < IBinanceFuturesEventOrderBook > eventData ) =>
288+ OnDepthUpdate ( marketDepth , eventData . Data ) ;
289+ private void OnDepthUpdate ( MarketDepth marketDepth , IBinanceEventOrderBook eventData )
290290 {
291- if ( data == null ) return ;
291+ if ( eventData == null ) return ;
292292
293293 lock ( _eventBuffer )
294294 {
295295 if ( ! _isSnapshotLoaded )
296296 {
297297 // Step 2: Buffer events before snapshot is loaded
298- _eventBuffer . Enqueue ( data ) ;
299- _logger . Debug ( $ "Step 2: Buffered event U={ data . FirstUpdateId } , u={ data . LastUpdateId } . Buffer size: { _eventBuffer . Count } ") ;
298+ _eventBuffer . Enqueue ( eventData ) ;
299+ _logger . Debug ( $ "Step 2: Buffered event U={ eventData . FirstUpdateId } , u={ eventData . LastUpdateId } . Buffer size: { _eventBuffer . Count } ") ;
300300 return ;
301301 }
302302
303303 // Apply update to local order book
304- ApplyDepthUpdate ( marketDepth , data ) ;
304+ ApplyDepthUpdate ( marketDepth , eventData ) ;
305305 }
306306 }
307307
308308 private void ApplyDepthUpdate ( MarketDepth marketDepth , IBinanceEventOrderBook eventData )
309309 {
310310 // Step 7: Apply update procedure
311- long lastUpdateId ;
312- switch ( marketDepth . Symbol . ContractType )
313- {
314- case ContractType . Spot :
315- lastUpdateId = eventData . LastUpdateId ;
316- break ;
317- case ContractType . Perpetual :
318- lastUpdateId = ( eventData as BinanceFuturesStreamOrderBookDepth ) . LastUpdateIdStream ;
319- break ;
320- default :
321- throw new ArgumentOutOfRangeException ( nameof ( marketDepth . Symbol . ContractType ) , "Unknown contract type." ) ;
322- }
311+ long lastUpdateId = eventData . LastUpdateId ;
323312
324313 // 1. Decide whether the update event can be applied
325314 if ( lastUpdateId <= _localOrderBookUpdateId )
@@ -329,21 +318,10 @@ private void ApplyDepthUpdate(MarketDepth marketDepth, IBinanceEventOrderBook ev
329318 return ;
330319 }
331320
332- if ( lastUpdateId > _localOrderBookUpdateId + 1 )
333- {
334- // Missed some events - need to restart
335- _logger . Error ( $ "Missed updates! Expected U <= { _localOrderBookUpdateId + 1 } , got U={ eventData . FirstUpdateId } ") ;
336- throw new InvalidOperationException (
337- $ "Missed order book updates. Expected U <= { _localOrderBookUpdateId + 1 } , got { eventData . FirstUpdateId } . " +
338- "Local order book is out of sync. Please restart the process." ) ;
339- }
340-
341- // Normally U of next event should equal u + 1 of previous event
342- // This is handled by the check above
343-
344321 // 2. Update price levels
345322 if ( _localOrderBookUpdateId % 100 == 0 ) // Log every 100th update to avoid flooding
346323 _logger . Debug ( $ "Applying update: U={ eventData . FirstUpdateId } , u={ lastUpdateId } , Asks={ eventData . Asks . Count ( ) } , Bids={ eventData . Bids . Count ( ) } ") ;
324+
347325 marketDepth . UpdateDepth ( eventData . Asks , eventData . Bids , lastUpdateId ) ;
348326
349327 // 3. Set order book update ID
0 commit comments