diff --git a/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs b/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs index b3ff7788..75add8ed 100644 --- a/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs @@ -1142,6 +1142,15 @@ private async Task> GetMarketSymbolList(string[] marketSymbols) return marketSymbolList; } + /// + /// Handle Kraken "book" channel message: https://docs.kraken.com/websockets/#message-book + /// Note in the "update payload" case there may be varying number of update blocks for + /// bid/ask updates. The last such block has a checksum. The market symbol is always the last item. + /// + /// + /// + /// + /// protected override async Task OnGetDeltaOrderBookWebSocketAsync( Action callback, int maxCount = 20, @@ -1158,15 +1167,16 @@ params string[] marketSymbols string message = msg.ToStringFromUTF8(); var book = new ExchangeOrderBook(); + // SNAPSHOT payload if (message.Contains("\"as\"") || message.Contains("\"bs\"")) { // parse delta update - var delta = JsonConvert.DeserializeObject(message) as JArray; + var snapshot = JsonConvert.DeserializeObject(message) as JArray; - book.MarketSymbol = delta[3].ToString(); + book.MarketSymbol = snapshot[3].ToString(); - var asks = delta[1]["as"].ToList(); - var bids = delta[1]["bs"].ToList(); + var asks = snapshot[1]["as"].ToList(); + var bids = snapshot[1]["bs"].ToList(); var lastUpdatedTime = DateTime.MinValue; @@ -1205,16 +1215,16 @@ params string[] marketSymbols { // parse delta update var delta = JsonConvert.DeserializeObject(message) as JArray; + book.MarketSymbol = delta.Last.ToString(); - book.MarketSymbol = delta[3].ToString(); + var _a = delta.FirstOrDefault(token => token is JObject && token["a"] != null); + var _b = delta.FirstOrDefault(token => token is JObject && token["b"] != null); var lastUpdatedTime = DateTime.MinValue; - var updates = delta[1]; - - if (updates["a"] != null) + if (_a != null) { - var asks = updates["a"].ToList(); + var asks = _a["a"].ToList(); foreach (var ask in asks) { @@ -1230,9 +1240,9 @@ params string[] marketSymbols } } - if (updates["b"] != null) + if (_b != null) { - var bids = updates["b"].ToList(); + var bids = _b["b"].ToList(); foreach (var bid in bids) { @@ -1251,6 +1261,11 @@ params string[] marketSymbols book.LastUpdatedUtc = lastUpdatedTime; book.SequenceId = lastUpdatedTime.Ticks; + //https://docs.kraken.com/websockets/#book-checksum + //"c" belongs to the last update block + var checksum = _b?["c"] ?? _a?["c"]; + book.Checksum = (checksum as JValue)?.ToString(); + callback(book); } diff --git a/src/ExchangeSharp/Model/ExchangeOrderBook.cs b/src/ExchangeSharp/Model/ExchangeOrderBook.cs index d644a972..23a9f77f 100644 --- a/src/ExchangeSharp/Model/ExchangeOrderBook.cs +++ b/src/ExchangeSharp/Model/ExchangeOrderBook.cs @@ -93,10 +93,17 @@ public sealed class ExchangeOrderBook public SortedDictionary Bids { get; } = new SortedDictionary(new DescendingComparer()); /// - /// ToString - /// - /// String - public override string ToString() + /// If provided by the exchange, a checksum value that may be used to check orderbook integrity. + /// Otherwise it will be null. + /// This property is not serialized using the ToBinary and FromBinary methods. + /// + public string Checksum { get; set; } + + /// + /// ToString + /// + /// String + public override string ToString() { return string.Format("Book {0}, Asks: {1} ({2:0.00}), Bids: {3} ({4:0.00})", MarketSymbol, Asks.Count,