public override ExchangeOrderBook GetOrderBook(string symbol, int maxCount = 100) { symbol = NormalizeSymbol(symbol); JObject json = MakeJsonRequest <JObject>("/0/public/Depth?pair=" + symbol + "&count=" + maxCount); JToken obj = CheckError(json); obj = obj[symbol]; if (obj == null) { return(null); } ExchangeOrderBook orders = new ExchangeOrderBook(); JToken bids = obj["bids"]; foreach (JToken token in bids) { ExchangeOrderPrice order = new ExchangeOrderPrice { Amount = token[1].Value <decimal>(), Price = token[0].Value <decimal>() }; orders.Bids.Add(order); } JToken asks = obj["asks"]; foreach (JToken token in asks) { ExchangeOrderPrice order = new ExchangeOrderPrice { Amount = token[1].Value <decimal>(), Price = token[0].Value <decimal>() }; orders.Asks.Add(order); } return(orders); }
public override ExchangeOrderBook GetOrderBook(string symbol, int maxCount = 100) { symbol = NormalizeSymbol(symbol); JObject obj = MakeJsonRequest <Newtonsoft.Json.Linq.JObject>("public/getorderbook?market=" + symbol + "&type=both&limit_bids=" + maxCount + "&limit_asks=" + maxCount); JToken book = CheckError(obj); ExchangeOrderBook orders = new ExchangeOrderBook(); JToken bids = book["buy"]; foreach (JToken token in bids) { ExchangeOrderPrice order = new ExchangeOrderPrice { Amount = token["Quantity"].ConvertInvariant <decimal>(), Price = token["Rate"].ConvertInvariant <decimal>() }; orders.Bids.Add(order); } JToken asks = book["sell"]; foreach (JToken token in asks) { ExchangeOrderPrice order = new ExchangeOrderPrice { Amount = token["Quantity"].ConvertInvariant <decimal>(), Price = token["Rate"].ConvertInvariant <decimal>() }; orders.Asks.Add(order); } return(orders); }
protected override async Task <IEnumerable <KeyValuePair <string, ExchangeOrderBook> > > OnGetOrderBooksAsync(int maxCount = 100) { List <KeyValuePair <string, ExchangeOrderBook> > books = new List <KeyValuePair <string, ExchangeOrderBook> >(); JToken obj = await MakeJsonRequestAsync <JToken>("/public?command=returnOrderBook¤cyPair=all&depth=" + maxCount); foreach (JProperty token in obj.Children()) { ExchangeOrderBook book = new ExchangeOrderBook(); foreach (JArray array in token.First["asks"]) { var depth = new ExchangeOrderPrice { Amount = array[1].ConvertInvariant <decimal>(), Price = array[0].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; } foreach (JArray array in token.First["bids"]) { var depth = new ExchangeOrderPrice { Amount = array[1].ConvertInvariant <decimal>(), Price = array[0].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; } books.Add(new KeyValuePair <string, ExchangeOrderBook>(token.Name, book)); } return(books); }
public override ExchangeOrderBook GetOrderBook(string symbol, int maxCount = 100) { symbol = NormalizeSymbol(symbol); JObject obj = MakeJsonRequest <Newtonsoft.Json.Linq.JObject>("/book/" + symbol + "?limit_bids=" + maxCount + "&limit_asks=" + maxCount); if (obj == null || obj.Count == 0) { return(null); } ExchangeOrderBook orders = new ExchangeOrderBook(); JToken bids = obj["bids"]; foreach (JToken token in bids) { ExchangeOrderPrice order = new ExchangeOrderPrice { Amount = token["amount"].Value <decimal>(), Price = token["price"].Value <decimal>() }; orders.Bids.Add(order); } JToken asks = obj["asks"]; foreach (JToken token in asks) { ExchangeOrderPrice order = new ExchangeOrderPrice { Amount = token["amount"].Value <decimal>(), Price = token["price"].Value <decimal>() }; orders.Asks.Add(order); } return(orders); }
protected override IWebSocket OnGetOrderBookWebSocket(Action <ExchangeOrderBook> callback, int maxCount = 20, params string[] marketSymbols) { if (marketSymbols == null || marketSymbols.Length == 0) { marketSymbols = GetMarketSymbolsAsync().Sync().ToArray(); } string combined = string.Join("/", marketSymbols.Select(s => this.NormalizeMarketSymbol(s).ToLowerInvariant() + "@depth")); return(ConnectWebSocket($"/stream?streams={combined}", (_socket, msg) => { string json = msg.ToStringFromUTF8(); var update = JsonConvert.DeserializeObject <MultiDepthStream>(json); string marketSymbol = update.Data.MarketSymbol; ExchangeOrderBook book = new ExchangeOrderBook { SequenceId = update.Data.FinalUpdate, MarketSymbol = marketSymbol }; foreach (List <object> ask in update.Data.Asks) { var depth = new ExchangeOrderPrice { Price = ask[0].ConvertInvariant <decimal>(), Amount = ask[1].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; } foreach (List <object> bid in update.Data.Bids) { var depth = new ExchangeOrderPrice { Price = bid[0].ConvertInvariant <decimal>(), Amount = bid[1].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; } callback(book); return Task.CompletedTask; })); }
protected override async Task <ExchangeOrderBook> OnGetOrderBookAsync(string symbol, int maxCount = 100) { ExchangeOrderBook orders = new ExchangeOrderBook(); JToken token = await MakeJsonRequestAsync <JToken>("/products/" + symbol + "/book?level=" + (maxCount > 50 ? "0" : "2")); if (token.HasValues) { foreach (JArray array in token["bids"]) { if (orders.Bids.Count < maxCount) { var depth = new ExchangeOrderPrice { Amount = array[1].ConvertInvariant <decimal>(), Price = array[0].ConvertInvariant <decimal>() }; orders.Bids[depth.Price] = depth; } } foreach (JArray array in token["asks"]) { if (orders.Asks.Count < maxCount) { var depth = new ExchangeOrderPrice { Amount = array[1].ConvertInvariant <decimal>(), Price = array[0].ConvertInvariant <decimal>() }; orders.Asks[depth.Price] = depth; } } } return(orders); }
/// <summary> /// Read from a binary reader /// </summary> /// <param name="reader">Binary reader</param> public void FromBinary(BinaryReader reader) { Asks.Clear(); Bids.Clear(); int askCount = reader.ReadInt32(); int bidCount = reader.ReadInt32(); while (askCount-- > 0) { var exchangeOrderPrice = new ExchangeOrderPrice(reader); Asks.Add(exchangeOrderPrice.Price, exchangeOrderPrice); } while (bidCount-- > 0) { var exchangeOrderPrice = new ExchangeOrderPrice(reader); Bids.Add(exchangeOrderPrice.Price, exchangeOrderPrice); } }
private ExchangeOrderBook ParseOrderBook(JToken data) { ExchangeOrderBook book = new ExchangeOrderBook(); foreach (JToken token in data["bids"]) { var depth = new ExchangeOrderPrice { Amount = token["quantity"].ConvertInvariant <decimal>(), Price = token["price"].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; } foreach (JToken token in data["asks"]) { var depth = new ExchangeOrderPrice { Amount = token["quantity"].ConvertInvariant <decimal>(), Price = token["price"].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; } return(book); }
private ExchangeOrderBook ParseOrderBook(JToken token) { ExchangeOrderBook book = new ExchangeOrderBook(); foreach (JArray array in token["bids"]) { var depth = new ExchangeOrderPrice { Price = array[0].ConvertInvariant <decimal>(), Amount = array[1].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; } foreach (JArray array in token["asks"]) { var depth = new ExchangeOrderPrice { Price = array[0].ConvertInvariant <decimal>(), Amount = array[1].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; } return(book); }
/// <summary>Common order book parsing method, checks for "amount" or "quantity" and "price" /// elements</summary> /// <param name="token">Token</param> /// <param name="asks">Asks key</param> /// <param name="bids">Bids key</param> /// <param name="price">Price key</param> /// <param name="amount">Quantity key</param> /// <param name="sequence">Sequence key</param> /// <param name="maxCount">Max count</param> /// <returns>Order book</returns> internal static ExchangeOrderBook ParseOrderBookFromJTokenDictionaries ( this JToken token, string asks = "asks", string bids = "bids", string price = "price", string amount = "amount", string sequence = "ts", int maxCount = 100 ) { var book = new ExchangeOrderBook { SequenceId = token[sequence].ConvertInvariant <long>() }; foreach (JToken ask in token[asks]) { var depth = new ExchangeOrderPrice { Price = ask[price].ConvertInvariant <decimal>(), Amount = ask[amount].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; if (book.Asks.Count == maxCount) { break; } } foreach (JToken bid in token[bids]) { var depth = new ExchangeOrderPrice { Price = bid[price].ConvertInvariant <decimal>(), Amount = bid[amount].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; if (book.Bids.Count == maxCount) { break; } } return(book); }
protected override IDisposable OnGetOrderBookDeltasWebSocket(Action <ExchangeOrderBook> callback, int maxCount = 20, params string[] symbols) { if (callback == null || symbols == null || !symbols.Any()) { return(null); } string combined = string.Join("/", symbols.Select(s => this.NormalizeSymbol(s).ToLowerInvariant() + "@depth")); return(ConnectWebSocket($"/stream?streams={combined}", (msg, _socket) => { try { string json = msg.UTF8String(); var update = JsonConvert.DeserializeObject <BinanceMultiDepthStream>(json); string symbol = update.Data.Symbol; ExchangeOrderBook book = new ExchangeOrderBook { SequenceId = update.Data.FinalUpdate, Symbol = symbol }; foreach (List <object> ask in update.Data.Asks) { var depth = new ExchangeOrderPrice { Price = ask[0].ConvertInvariant <decimal>(), Amount = ask[1].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; } foreach (List <object> bid in update.Data.Bids) { var depth = new ExchangeOrderPrice { Price = bid[0].ConvertInvariant <decimal>(), Amount = bid[1].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; } callback(book); } catch { } })); }
protected override async Task <ExchangeOrderBook> OnGetOrderBookAsync(string symbol, int maxCount = 100) { var token = await MakeRequestOkexAsync(symbol, "/depth.do?symbol=$SYMBOL$"); ExchangeOrderBook book = new ExchangeOrderBook(); foreach (JArray ask in token.Item1["asks"]) { var depth = new ExchangeOrderPrice { Amount = ask[1].ConvertInvariant <decimal>(), Price = ask[0].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; } foreach (JArray bid in token.Item1["bids"]) { var depth = new ExchangeOrderPrice { Amount = bid[1].ConvertInvariant <decimal>(), Price = bid[0].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; } return(book); }
/// <summary>Common order book parsing method, most exchanges use "asks" and "bids" with /// arrays of length 2 for price and amount (or amount and price)</summary> /// <param name="token">Token</param> /// <param name="asks">Asks key</param> /// <param name="bids">Bids key</param> /// <param name="maxCount">Max count</param> /// <returns>Order book</returns> internal static ExchangeOrderBook ParseOrderBookFromJTokenArrays ( this JToken token, string asks = "asks", string bids = "bids", string sequence = "ts", int maxCount = 100 ) { var book = new ExchangeOrderBook { SequenceId = token[sequence].ConvertInvariant <long>() }; foreach (JArray array in token[asks]) { var depth = new ExchangeOrderPrice { Price = array[0].ConvertInvariant <decimal>(), Amount = array[1].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; if (book.Asks.Count == maxCount) { break; } } foreach (JArray array in token[bids]) { var depth = new ExchangeOrderPrice { Price = array[0].ConvertInvariant <decimal>(), Amount = array[1].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; if (book.Bids.Count == maxCount) { break; } } return(book); }
protected override async Task <ExchangeOrderBook> OnGetOrderBookAsync(string symbol, int maxCount = 100) { symbol = NormalizeSymbol(symbol); JToken token = await MakeBitstampRequestAsync("/order_book/" + symbol); ExchangeOrderBook book = new ExchangeOrderBook(); foreach (JArray ask in token["asks"]) { var depth = new ExchangeOrderPrice { Amount = ask[1].ConvertInvariant <decimal>(), Price = ask[0].ConvertInvariant <decimal>() }; book.Asks[depth.Price] = depth; } foreach (JArray bid in token["bids"]) { var depth = new ExchangeOrderPrice { Amount = bid[1].ConvertInvariant <decimal>(), Price = bid[0].ConvertInvariant <decimal>() }; book.Bids[depth.Price] = depth; } return(book); }
protected override async Task <ExchangeOrderBook> OnGetOrderBookAsync(string symbol, int maxCount = 100) { symbol = NormalizeSymbol(symbol); ExchangeOrderBook orders = new ExchangeOrderBook(); JToken obj = await MakeJsonRequestAsync <JToken>("/depth/" + symbol + "?limit=" + maxCount, BaseUrl, null); foreach (JArray prop in obj[symbol]["asks"]) { var depth = new ExchangeOrderPrice { Price = prop[0].ConvertInvariant <decimal>(), Amount = prop[1].ConvertInvariant <decimal>() }; orders.Asks[depth.Price] = depth; } foreach (JArray prop in obj[symbol]["bids"]) { var depth = new ExchangeOrderPrice { Price = prop[0].ConvertInvariant <decimal>(), Amount = prop[1].ConvertInvariant <decimal>() }; orders.Bids[depth.Price] = depth; } return(orders); }
protected override async Task <ExchangeOrderBook> OnGetOrderBookAsync(string symbol, int maxCount = 100) { ExchangeOrderBook orders = new ExchangeOrderBook(); JToken token = await MakeJsonRequestAsync <JToken>("/open/orders?symbol=" + symbol + "&limit=" + maxCount); if (token.HasValues) { foreach (JToken order in token["BUY"]) { var depth = new ExchangeOrderPrice { Price = order[0].ConvertInvariant <decimal>(), Amount = order[1].ConvertInvariant <decimal>() }; orders.Bids[depth.Price] = depth; } foreach (JToken order in token["SELL"]) { var depth = new ExchangeOrderPrice { Price = order[0].ConvertInvariant <decimal>(), Amount = order[1].ConvertInvariant <decimal>() }; orders.Asks[depth.Price] = depth; } } return(orders); }
protected override IWebSocket OnGetDeltaOrderBookWebSocket(Action <ExchangeOrderBook> callback, int maxCount = 20, params string[] marketSymbols) { /* * {"info":"Welcome to the BitMEX Realtime API.","version":"2018-06-29T18:05:14.000Z","timestamp":"2018-07-05T14:22:26.267Z","docs":"https://www.bitmex.com/app/wsAPI","limit":{"remaining":39}} * {"success":true,"subscribe":"orderBookL2:XBTUSD","request":{"op":"subscribe","args":["orderBookL2:XBTUSD"]}} * {"table":"orderBookL2","action":"update","data":[{"symbol":"XBTUSD","id":8799343000,"side":"Buy","size":350544}]} */ if (marketSymbols == null || marketSymbols.Length == 0) { marketSymbols = GetMarketSymbolsAsync().Sync().ToArray(); } return(ConnectWebSocket(string.Empty, (_socket, msg) => { var str = msg.ToStringFromUTF8(); JToken token = JToken.Parse(str); if (token["table"] == null) { return Task.CompletedTask; } var action = token["action"].ToStringInvariant(); JArray data = token["data"] as JArray; ExchangeOrderBook book = new ExchangeOrderBook(); var price = 0m; var size = 0m; foreach (var d in data) { var marketSymbol = d["symbol"].ToStringInvariant(); var id = d["id"].ConvertInvariant <long>(); if (d["price"] == null) { if (!dict_long_decimal.TryGetValue(id, out price)) { continue; } } else { price = d["price"].ConvertInvariant <decimal>(); dict_long_decimal[id] = price; dict_decimal_long[price] = id; } var side = d["side"].ToStringInvariant(); if (d["size"] == null) { size = 0m; } else { size = d["size"].ConvertInvariant <decimal>(); } var depth = new ExchangeOrderPrice { Price = price, Amount = size }; if (side.EqualsWithOption("Buy")) { book.Bids[depth.Price] = depth; } else { book.Asks[depth.Price] = depth; } book.MarketSymbol = marketSymbol; } if (!string.IsNullOrEmpty(book.MarketSymbol)) { callback(book); } return Task.CompletedTask; }, async(_socket) => { if (marketSymbols.Length == 0) { marketSymbols = (await GetMarketSymbolsAsync()).ToArray(); } await _socket.SendMessageAsync(new { op = "subscribe", args = marketSymbols.Select(s => "orderBookL2:" + this.NormalizeMarketSymbol(s)).ToArray() }); })); }
protected override IWebSocket OnGetDeltaOrderBookWebSocket ( Action <ExchangeOrderBook> callback, int maxCount = 20, params string[] marketSymbols ) { if (marketSymbols == null || marketSymbols.Length == 0) { marketSymbols = GetMarketSymbolsAsync().Sync().ToArray(); } Task innerCallback(string json) { #region sample json /* * { * MarketName : string, * Nonce : int, * Buys: * [ * { * Type : int, * Rate : decimal, * Quantity : decimal * } * ], * Sells: * [ * { * Type : int, * Rate : decimal, * Quantity : decimal * } * ], * Fills: * [ * { * FillId : int, * OrderType : string, * Rate : decimal, * Quantity : decimal, * TimeStamp : date * } * ] * } */ #endregion var ordersUpdates = JsonConvert.DeserializeObject <BittrexStreamUpdateExchangeState>(json); var book = new ExchangeOrderBook(); foreach (BittrexStreamOrderBookUpdateEntry ask in ordersUpdates.Sells) { var depth = new ExchangeOrderPrice { Price = ask.Rate, Amount = ask.Quantity }; book.Asks[depth.Price] = depth; } foreach (BittrexStreamOrderBookUpdateEntry bid in ordersUpdates.Buys) { var depth = new ExchangeOrderPrice { Price = bid.Rate, Amount = bid.Quantity }; book.Bids[depth.Price] = depth; } book.MarketSymbol = ordersUpdates.MarketName; book.SequenceId = ordersUpdates.Nonce; callback(book); return(Task.CompletedTask); } return(new BittrexWebSocketManager().SubscribeToExchangeDeltas(innerCallback, marketSymbols)); }
protected override IDisposable OnGetOrderBookDeltasWebSocket(Action <ExchangeOrderBook> callback, int maxCount = 20, params string[] symbols) { /* * {"info":"Welcome to the BitMEX Realtime API.","version":"2018-06-29T18:05:14.000Z","timestamp":"2018-07-05T14:22:26.267Z","docs":"https://www.bitmex.com/app/wsAPI","limit":{"remaining":39}} * {"success":true,"subscribe":"orderBookL2:XBTUSD","request":{"op":"subscribe","args":["orderBookL2:XBTUSD"]}} * {"table":"orderBookL2","action":"update","data":[{"symbol":"XBTUSD","id":8799343000,"side":"Buy","size":350544}]} */ if (callback == null || symbols == null || !symbols.Any()) { return(null); } return(ConnectWebSocket(string.Empty, (msg, _socket) => { try { var str = msg.UTF8String(); JToken token = JToken.Parse(str); if (token["table"] == null) { return; } var action = token["action"].ToStringInvariant(); JArray data = token["data"] as JArray; ExchangeOrderBook book = new ExchangeOrderBook(); var price = 0m; var size = 0m; foreach (var d in data) { var symbol = d["symbol"].ToStringInvariant(); var id = d["id"].ConvertInvariant <long>(); if (d["price"] == null) { if (!dict_long_decimal.TryGetValue(id, out price)) { continue; } } else { price = d["price"].ConvertInvariant <decimal>(); dict_long_decimal[id] = price; dict_decimal_long[price] = id; } var side = d["side"].ToStringInvariant(); if (d["size"] == null) { size = 0m; } else { size = d["size"].ConvertInvariant <decimal>(); } var depth = new ExchangeOrderPrice { Price = price, Amount = size }; if (side.EqualsWithOption("Buy")) { book.Bids[depth.Price] = depth; } else { book.Asks[depth.Price] = depth; } book.Symbol = symbol; } callback(book); } catch { // TODO: Handle exception } }, (_socket) => { if (symbols.Length == 0) { symbols = GetSymbols().ToArray(); } string combined = string.Join(",", symbols.Select(s => "\"orderBookL2:" + this.NormalizeSymbol(s) + "\"")); string msg = $"{{\"op\":\"subscribe\",\"args\":[{combined}]}}"; _socket.SendMessage(msg); })); }
protected override IDisposable OnGetOrderBookDeltasWebSocket( Action <ExchangeOrderBook> callback, int maxCount = 20, params string[] symbols) { if (callback == null || symbols == null || !symbols.Any()) { return(null); } void innerCallback(string json) { #region sample json /* * { * MarketName : string, * Nonce : int, * Buys: * [ * { * Type : int, * Rate : decimal, * Quantity : decimal * } * ], * Sells: * [ * { * Type : int, * Rate : decimal, * Quantity : decimal * } * ], * Fills: * [ * { * FillId : int, * OrderType : string, * Rate : decimal, * Quantity : decimal, * TimeStamp : date * } * ] * } */ #endregion var ordersUpdates = JsonConvert.DeserializeObject <BittrexStreamUpdateExchangeState>(json); var book = new ExchangeOrderBook(); foreach (BittrexStreamOrderBookUpdateEntry ask in ordersUpdates.Sells) { var depth = new ExchangeOrderPrice { Price = ask.Rate, Amount = ask.Quantity }; book.Asks[depth.Price] = depth; } foreach (BittrexStreamOrderBookUpdateEntry bid in ordersUpdates.Buys) { var depth = new ExchangeOrderPrice { Price = bid.Rate, Amount = bid.Quantity }; book.Bids[depth.Price] = depth; } book.Symbol = ordersUpdates.MarketName; book.SequenceId = ordersUpdates.Nonce; callback(book); } IDisposable client = null; foreach (var sym in symbols) { client = this.SocketManager.SubscribeToExchangeDeltas(innerCallback, sym); } return(client); }
protected override async Task <IWebSocket> OnGetDeltaOrderBookWebSocketAsync(Action <ExchangeOrderBook> callback, int maxCount = 20, params string[] marketSymbols) { Dictionary <int, Tuple <string, long> > messageIdToSymbol = new Dictionary <int, Tuple <string, long> >(); return(await ConnectWebSocketAsync(string.Empty, (_socket, msg) => { JToken token = JToken.Parse(msg.ToStringFromUTF8()); int msgId = token[0].ConvertInvariant <int>(); //return if this is a heartbeat message if (msgId == 1010) { return Task.CompletedTask; } var seq = token[1].ConvertInvariant <long>(); var dataArray = token[2]; ExchangeOrderBook book = new ExchangeOrderBook(); foreach (var data in dataArray) { var dataType = data[0].ToStringInvariant(); if (dataType == "i") { var marketInfo = data[1]; var market = marketInfo["currencyPair"].ToStringInvariant(); messageIdToSymbol[msgId] = new Tuple <string, long>(market, 0); // we are only returning the deltas, this would create a full order book which we don't want, but keeping it // here for historical reference /* * foreach (JProperty jprop in marketInfo["orderBook"][0].Cast<JProperty>()) * { * var depth = new ExchangeOrderPrice * { * Price = jprop.Name.ConvertInvariant<decimal>(), * Amount = jprop.Value.ConvertInvariant<decimal>() * }; * book.Asks[depth.Price] = depth; * } * foreach (JProperty jprop in marketInfo["orderBook"][1].Cast<JProperty>()) * { * var depth = new ExchangeOrderPrice * { * Price = jprop.Name.ConvertInvariant<decimal>(), * Amount = jprop.Value.ConvertInvariant<decimal>() * }; * book.Bids[depth.Price] = depth; * } */ } else if (dataType == "o") { //removes or modifies an existing item on the order books if (messageIdToSymbol.TryGetValue(msgId, out Tuple <string, long> symbol)) { int type = data[1].ConvertInvariant <int>(); var depth = new ExchangeOrderPrice { Price = data[2].ConvertInvariant <decimal>(), Amount = data[3].ConvertInvariant <decimal>() }; var list = (type == 1 ? book.Bids : book.Asks); list[depth.Price] = depth; book.MarketSymbol = symbol.Item1; book.SequenceId = symbol.Item2 + 1; messageIdToSymbol[msgId] = new Tuple <string, long>(book.MarketSymbol, book.SequenceId); } } else { continue; } } if (book != null && (book.Asks.Count != 0 || book.Bids.Count != 0)) { callback(book); } return Task.CompletedTask; }, async (_socket) => { if (marketSymbols == null || marketSymbols.Length == 0) { marketSymbols = (await GetMarketSymbolsAsync()).ToArray(); } // subscribe to order book and trades channel for each symbol foreach (var sym in marketSymbols) { await _socket.SendMessageAsync(new { command = "subscribe", channel = NormalizeMarketSymbol(sym) }); } })); }