void RefreshOrderBook(string product, OrderBookBuilder book) { // Coinbase doesn't give us server time together with the full order book, // so we retrieve it with a separate request BEFORE requesting the order book. DateTime serverTime = _restClient.SendRequest(new REST.TimeRequest()).Result.Time; REST.OrderBookResponse snapshot = _restClient.SendRequest(new REST.OrderBookRequest() { Product = product }).Result; DateTime received = DateTime.UtcNow; OrderBookDelta delta = book.OnSnapshot(serverTime, snapshot); // Throws if the snapshot is malformed. if (delta != null && (delta.Bids.Any() || delta.Asks.Any())) { try { OnOrderBook?.Invoke( product, new TimestampedMsg <OrderBookDelta>() { Received = received, Value = delta }); } catch (Exception e) { _log.Warn(e, "Ignoring exception from OnOrderBook"); } } }
void OnMessage(TimestampedMsg <WebSocket.IMessageIn> msg) { Condition.Requires(msg, "msg").IsNotNull(); Condition.Requires(msg.Value, "msg.Value").IsNotNull(); Condition.Requires(msg.Value.ProductId, "msg.Value.ProductId").IsNotNullOrEmpty(); Condition.Requires(_products.ContainsKey(msg.Value.ProductId)); bool myFill = _orderManager.OnMessage(msg); OrderBookBuilder book = _products[msg.Value.ProductId]; OrderBookDelta delta = null; Trade trade = null; bool ok = false; try { ok = book.OnOrderUpdate(msg.Value, out delta, out trade); } catch (Exception e) { _log.Error(e, "Unable to process order update"); } if (ok) { if (!myFill && trade != null && trade.Size > 0m) { try { OnTrade?.Invoke( msg.Value.ProductId, new TimestampedMsg <Trade>() { Received = msg.Received, Value = trade }); } catch (Exception e) { _log.Warn(e, "Ignoring exception from OnTrade"); } } if (delta != null && (delta.Bids.Any() || delta.Asks.Any())) { try { OnOrderBook?.Invoke( msg.Value.ProductId, new TimestampedMsg <OrderBookDelta>() { Received = msg.Received, Value = delta }); } catch (Exception e) { _log.Warn(e, "Ignoring exception from OnOrderBook"); } } } else { RefreshOrderBook(msg.Value.ProductId, book); } }