protected override async ValueTask <TradeCacheEventArgs> OnAction(TradeEventArgs @event) { // If trades have not been initialized or are out-of-sync (gap in data). while (_trades.Count == 0 || @event.Trade.Id > _trades.Last().Id + 1) { if (_trades.Count > 0) { OutOfSync?.Invoke(this, EventArgs.Empty); } await SynchronizeTradesAsync(_symbol, _limit, @event.Token) .ConfigureAwait(false); } // Ignore trades older than the latest trade in queue. if (@event.Trade.Id <= _trades.Last().Id) { Logger?.LogDebug($"{nameof(TradeCache)} ({_symbol}): Ignoring event (trade ID: {@event.Trade.Id}). [thread: {Thread.CurrentThread.ManagedThreadId}{(@event.Token.IsCancellationRequested ? ", canceled" : string.Empty)}]"); return(null); } lock (_sync) { var removed = _trades.Dequeue(); Logger?.LogDebug($"{nameof(TradeCache)} ({_symbol}): REMOVE trade (ID: {removed.Id}). [thread: {Thread.CurrentThread.ManagedThreadId}{(@event.Token.IsCancellationRequested ? ", canceled" : string.Empty)}]"); _trades.Enqueue(@event.Trade); Logger?.LogDebug($"{nameof(TradeCache)} ({_symbol}): ADD trade (ID: {@event.Trade.Id}). [thread: {Thread.CurrentThread.ManagedThreadId}{(@event.Token.IsCancellationRequested ? ", canceled" : string.Empty)}]"); } return(new TradeCacheEventArgs(_trades.ToArray())); }
protected override async ValueTask <AggregateTradeCacheEventArgs> OnAction(AggregateTradeEventArgs @event) { var synchronize = false; // If trades have not been initialized or are out-of-sync (gap in data). lock (_sync) { if (_trades.Count == 0 || @event.Trade.Id > _trades.Last().Id + 1) { if (_trades.Count > 0) { OutOfSync?.Invoke(this, EventArgs.Empty); } synchronize = true; } } if (synchronize) { await SynchronizeTradesAsync(_symbol, _limit, @event.Token) .ConfigureAwait(false); } lock (_sync) { if (_trades.Count == 0 || @event.Trade.Id > _trades.Last().Id + 1) { Logger?.LogError($"{nameof(AggregateTradeCache)} ({_symbol}): Failed to synchronize trades. [thread: {Thread.CurrentThread.ManagedThreadId}]"); return(null); } // Ignore trades older than the latest trade in queue. if (@event.Trade.Id <= _trades.Last().Id) { Logger?.LogDebug($"{nameof(AggregateTradeCache)} ({_symbol}): Ignoring event (trade ID: {@event.Trade.Id}). [thread: {Thread.CurrentThread.ManagedThreadId}]"); return(null); } var removed = _trades.Dequeue(); Logger?.LogTrace($"{nameof(AggregateTradeCache)} ({_symbol}): REMOVE aggregate trade (ID: {removed.Id}). [thread: {Thread.CurrentThread.ManagedThreadId}]"); _trades.Enqueue(@event.Trade); Logger?.LogTrace($"{nameof(AggregateTradeCache)} ({_symbol}): ADD aggregate trade (ID: {@event.Trade.Id}). [thread: {Thread.CurrentThread.ManagedThreadId}]"); return(new AggregateTradeCacheEventArgs(_trades.ToArray())); } }
/// <summary> /// /// </summary> /// <param name="event"></param> /// <returns></returns> protected override async ValueTask <OrderBookCacheEventArgs> OnAction(DepthUpdateEventArgs @event) { if (_limit > 0) { // Ignore events with same or earlier order book update. if (_orderBookClone != null && @event.LastUpdateId <= _orderBookClone.LastUpdateId) { Logger?.LogDebug($"{nameof(OrderBookCache)} ({_symbol}): Ignoring event (last update ID: {@event.LastUpdateId}). [thread: {Thread.CurrentThread.ManagedThreadId}{(@event.Token.IsCancellationRequested ? ", canceled" : string.Empty)}]"); return(null); } // Top <limit> bids and asks, pushed every second. // NOTE: LastUpdateId is not contiguous between events when using partial depth stream. _orderBookClone = new OrderBook(_symbol, @event.LastUpdateId, @event.Bids, @event.Asks); } else { // If order book has not been initialized or is out-of-sync (gap in data). while (_orderBook == null || @event.FirstUpdateId > _orderBook.LastUpdateId + 1) { if (_orderBook != null) { OutOfSync?.Invoke(this, EventArgs.Empty); } // Synchronize. await SynchronizeOrderBookAsync(@event.Token) .ConfigureAwait(false); } // Ignore events prior to order book snapshot. if (@event.LastUpdateId <= _orderBook.LastUpdateId) { Logger?.LogDebug($"{nameof(OrderBookCache)} ({_symbol}): Ignoring event (last update ID: {@event.LastUpdateId}). [thread: {Thread.CurrentThread.ManagedThreadId}{(@event.Token.IsCancellationRequested ? ", canceled" : string.Empty)}]"); return(null); } Logger?.LogDebug($"{nameof(OrderBookCache)} ({_symbol}): Updating order book (last update ID: {_orderBook.LastUpdateId} => {@event.LastUpdateId}). [thread: {Thread.CurrentThread.ManagedThreadId}{(@event.Token.IsCancellationRequested ? ", canceled" : string.Empty)}]"); _orderBook.Modify(@event.LastUpdateId, @event.Bids, @event.Asks); _orderBookClone = _orderBook.Clone(); } return(new OrderBookCacheEventArgs(_orderBookClone)); }