protected override IWebSocket OnGetTickersWebSocket(Action <IReadOnlyCollection <KeyValuePair <string, ExchangeTicker> > > callback) { Dictionary <int, string> channelIdToSymbol = new Dictionary <int, string>(); return(ConnectWebSocket(string.Empty, (_socket, msg) => { JToken token = JToken.Parse(msg.ToStringFromUTF8()); if (token is JArray array) { if (array.Count > 10) { List <KeyValuePair <string, ExchangeTicker> > tickerList = new List <KeyValuePair <string, ExchangeTicker> >(); if (channelIdToSymbol.TryGetValue(array[0].ConvertInvariant <int>(), out string symbol)) { ExchangeTicker ticker = ParseTickerWebSocket(symbol, array); if (ticker != null) { callback(new KeyValuePair <string, ExchangeTicker>[] { new KeyValuePair <string, ExchangeTicker>(symbol, ticker) }); } } } } else if (token["event"].ToStringInvariant() == "subscribed" && token["channel"].ToStringInvariant() == "ticker") { // {"event":"subscribed","channel":"ticker","chanId":1,"pair":"BTCUSD"} int channelId = token["chanId"].ConvertInvariant <int>(); channelIdToSymbol[channelId] = token["pair"].ToStringInvariant(); } return Task.CompletedTask; }, async(_socket) => { var symbols = await GetSymbolsAsync(); foreach (var symbol in symbols) { await _socket.SendMessageAsync("{\"event\":\"subscribe\",\"channel\":\"ticker\",\"pair\":\"" + symbol + "\"}"); } })); }
private ExchangeTicker ParseTicker(JToken token) { // [{ "TradePairId":100,"Label":"LTC/BTC","AskPrice":0.00006000,"BidPrice":0.02000000,"Low":0.00006000,"High":0.00006000,"Volume":1000.05639978,"LastPrice":0.00006000,"BuyVolume":34455.678,"SellVolume":67003436.37658233,"Change":-400.00000000,"Open": 0.00000500,"Close": 0.00000600, "BaseVolume": 3.58675866,"BaseBuyVolume": 11.25364758, "BaseSellVolume": 3456.06746543 }, ... ] var symbols = token["Label"].ToStringInvariant().Split('/'); ExchangeTicker ticker = new ExchangeTicker() { Id = token["TradePairId"].ToStringInvariant(), Ask = token["AskPrice"].ConvertInvariant<decimal>(), Bid = token["BidPrice"].ConvertInvariant<decimal>(), Last = token["LastPrice"].ConvertInvariant<decimal>(), // Since we're parsing a ticker for a market, we'll use the volume/baseVolume fields here and ignore the Buy/Sell Volumes // This is a quess as to ambiguous intent of these fields. Volume = new ExchangeVolume() { PriceSymbol = symbols[0], QuantitySymbol = symbols[1], PriceAmount = token["Volume"].ConvertInvariant<decimal>(), QuantityAmount = token["BaseVolume"].ConvertInvariant<decimal>(), Timestamp = DateTime.UtcNow // No TimeStamp is returned, but Now seems appropriate } }; return ticker; }
// Bitbank supports endpoint for getting all rates in one request, Using this endpoint is faster then ExchangeAPI's default implementation // (which interate `OnGetTickerAsync` for each marketSymbols) // Note: This doesn't give you a volume. if you want it, please specify marketSymbol. protected override async Task <IEnumerable <KeyValuePair <string, ExchangeTicker> > > OnGetTickersAsync() { JToken token = await MakeJsonRequestAsync <JToken>($"/prices"); var symbols = await OnGetMarketSymbolsAsync(); var result = new List <KeyValuePair <string, ExchangeTicker> >(); foreach (var symbol in symbols) { var data = token[GlobalMarketSymbolToExchangeMarketSymbolAsync(symbol)]; var ticker = new ExchangeTicker() { ApiResponse = token, Ask = data["sell"].ConvertInvariant <decimal>(), Bid = data["buy"].ConvertInvariant <decimal>(), Last = data["last"].ConvertInvariant <decimal>(), MarketSymbol = symbol }; result.Add(new KeyValuePair <string, ExchangeTicker>(symbol, ticker)); } return(result); }
protected override async Task <IWebSocket> OnGetTickersWebSocketAsync(Action <IReadOnlyCollection <KeyValuePair <string, ExchangeTicker> > > callback, params string[] marketSymbols) { Dictionary <int, string> channelIdToSymbol = new Dictionary <int, string>(); return(await ConnectWebSocketAsync(string.Empty, async (_socket, msg) => { JToken token = JToken.Parse(msg.ToStringFromUTF8()); if (token is JArray array) { if (array.Count > 10) { List <KeyValuePair <string, ExchangeTicker> > tickerList = new List <KeyValuePair <string, ExchangeTicker> >(); if (channelIdToSymbol.TryGetValue(array[0].ConvertInvariant <int>(), out string symbol)) { ExchangeTicker ticker = await ParseTickerWebSocketAsync(symbol, array); if (ticker != null) { callback(new KeyValuePair <string, ExchangeTicker>[] { new KeyValuePair <string, ExchangeTicker>(symbol, ticker) }); } } } } else if (token["event"].ToStringInvariant() == "subscribed" && token["channel"].ToStringInvariant() == "ticker") { // {"event":"subscribed","channel":"ticker","chanId":1,"pair":"BTCUSD"} int channelId = token["chanId"].ConvertInvariant <int>(); channelIdToSymbol[channelId] = token["pair"].ToStringInvariant(); } }, async (_socket) => { marketSymbols = marketSymbols == null || marketSymbols.Length == 0 ? (await GetMarketSymbolsAsync()).ToArray() : marketSymbols; foreach (var marketSymbol in marketSymbols) { await _socket.SendMessageAsync(new { @event = "subscribe", channel = "ticker", pair = marketSymbol }); } })); }
protected override IWebSocket OnGetTickersWebSocket(Action <IReadOnlyCollection <KeyValuePair <string, ExchangeTicker> > > callback, params string[] symbols) { void innerCallback(string json) { #region sample json /* * { * Nonce : int, * Deltas : * [ * { * MarketName : string, * High : decimal, * Low : decimal, * Volume : decimal, * Last : decimal, * BaseVolume : decimal, * TimeStamp : date, * Bid : decimal, * Ask : decimal, * OpenBuyOrders : int, * OpenSellOrders : int, * PrevDay : decimal, * Created : date * } * ] * } */ #endregion var freshTickers = new Dictionary <string, ExchangeTicker>(StringComparer.OrdinalIgnoreCase); JToken token = JToken.Parse(json); token = token["D"]; foreach (JToken ticker in token) { string marketName = ticker["M"].ToStringInvariant(); var(baseCurrency, quoteCurrency) = ExchangeMarketSymbolToCurrencies(marketName); decimal last = ticker["l"].ConvertInvariant <decimal>(); decimal ask = ticker["A"].ConvertInvariant <decimal>(); decimal bid = ticker["B"].ConvertInvariant <decimal>(); decimal baseCurrencyVolume = ticker["V"].ConvertInvariant <decimal>(); decimal quoteCurrencyVolume = ticker["m"].ConvertInvariant <decimal>();//NOTE: Bittrex uses the term BaseVolume when referring to QuoteCurrencyVolume DateTime timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(ticker["T"].ConvertInvariant <long>()); var t = new ExchangeTicker { MarketSymbol = marketName, Ask = ask, Bid = bid, Last = last, Volume = new ExchangeVolume { BaseCurrencyVolume = baseCurrencyVolume, BaseCurrency = baseCurrency, QuoteCurrencyVolume = quoteCurrencyVolume, QuoteCurrency = quoteCurrency, Timestamp = timestamp } }; freshTickers[marketName] = t; } callback(freshTickers); } return(new BittrexWebSocketManager().SubscribeToSummaryDeltas(innerCallback)); }
/// <summary> /// Parse a JToken into a ticker /// </summary> /// <param name="api">ExchangeAPI</param> /// <param name="token">Token</param> /// <param name="marketSymbol">Symbol</param> /// <param name="askKey">Ask key</param> /// <param name="bidKey">Bid key</param> /// <param name="lastKey">Last key</param> /// <param name="baseVolumeKey">Base currency volume key</param> /// <param name="quoteVolumeKey">Quote currency volume key</param> /// <param name="timestampKey">Timestamp key</param> /// <param name="timestampType">Timestamp type</param> /// <param name="baseCurrencyKey">Base currency key</param> /// <param name="quoteCurrencyKey">Quote currency key</param> /// <param name="idKey">Id key</param> /// <returns>ExchangeTicker</returns> internal static ExchangeTicker ParseTicker(this ExchangeAPI api, JToken token, string marketSymbol, object askKey, object bidKey, object lastKey, object baseVolumeKey, object quoteVolumeKey = null, object timestampKey = null, TimestampType timestampType = TimestampType.None, object baseCurrencyKey = null, object quoteCurrencyKey = null, object idKey = null) { if (token == null || !token.HasValues) { return(null); } decimal last = token[lastKey].ConvertInvariant <decimal>(); // parse out volumes, handle cases where one or both do not exist token.ParseVolumes(baseVolumeKey, quoteVolumeKey, last, out decimal baseCurrencyVolume, out decimal quoteCurrencyVolume); // pull out timestamp DateTime timestamp = (timestampKey == null ? CryptoUtility.UtcNow : CryptoUtility.ParseTimestamp(token[timestampKey], timestampType)); // split apart the symbol if we have a separator, otherwise just put the symbol for base and convert symbol string baseCurrency; string quoteCurrency; if (baseCurrencyKey != null && quoteCurrencyKey != null) { baseCurrency = token[baseCurrencyKey].ToStringInvariant(); quoteCurrency = token[quoteCurrencyKey].ToStringInvariant(); } else if (string.IsNullOrWhiteSpace(marketSymbol)) { throw new ArgumentNullException(nameof(marketSymbol)); } else { (baseCurrency, quoteCurrency) = api.ExchangeMarketSymbolToCurrencies(marketSymbol); } // create the ticker and return it JToken askValue = token[askKey]; JToken bidValue = token[bidKey]; if (askValue is JArray) { askValue = askValue[0]; } if (bidValue is JArray) { bidValue = bidValue[0]; } ExchangeTicker ticker = new ExchangeTicker { MarketSymbol = marketSymbol, Ask = askValue.ConvertInvariant <decimal>(), Bid = bidValue.ConvertInvariant <decimal>(), Id = (idKey == null ? null : token[idKey].ToStringInvariant()), Last = last, Volume = new ExchangeVolume { BaseCurrencyVolume = baseCurrencyVolume, BaseCurrency = baseCurrency, QuoteCurrencyVolume = quoteCurrencyVolume, QuoteCurrency = quoteCurrency, Timestamp = timestamp } }; return(ticker); }
/// <summary> /// Parse a JToken into a ticker /// </summary> /// <param name="api">ExchangeAPI</param> /// <param name="token">Token</param> /// <param name="symbol">Symbol</param> /// <param name="askKey">Ask key</param> /// <param name="bidKey">Bid key</param> /// <param name="lastKey">Last key</param> /// <param name="baseVolumeKey">Base volume key</param> /// <param name="convertVolumeKey">Convert volume key</param> /// <param name="timestampKey">Timestamp key</param> /// <param name="timestampType">Timestamp type</param> /// <param name="baseCurrencyKey">Base currency key</param> /// <param name="convertCurrencyKey">Convert currency key</param> /// <param name="idKey">Id key</param> /// <returns>ExchangeTicker</returns> internal static ExchangeTicker ParseTicker(this ExchangeAPI api, JToken token, string symbol, object askKey, object bidKey, object lastKey, object baseVolumeKey, object convertVolumeKey = null, object timestampKey = null, TimestampType timestampType = TimestampType.None, object baseCurrencyKey = null, object convertCurrencyKey = null, object idKey = null) { if (token == null || !token.HasValues) { return(null); } decimal last = token[lastKey].ConvertInvariant <decimal>(); // parse out volumes, handle cases where one or both do not exist token.ParseVolumes(baseVolumeKey, convertVolumeKey, last, out decimal baseVolume, out decimal convertVolume); // pull out timestamp DateTime timestamp = (timestampKey == null ? DateTime.UtcNow : CryptoUtility.ParseTimestamp(token[timestampKey], timestampType)); // split apart the symbol if we have a separator, otherwise just put the symbol for base and convert symbol string baseSymbol; string convertSymbol; if (baseCurrencyKey != null && convertCurrencyKey != null) { baseSymbol = token[baseCurrencyKey].ToStringInvariant(); convertSymbol = token[convertCurrencyKey].ToStringInvariant(); } else if (string.IsNullOrWhiteSpace(symbol)) { throw new ArgumentNullException(nameof(symbol)); } else if (api.SymbolSeparator.Length != 0) { string[] pieces = symbol.Split(api.SymbolSeparator[0]); if (pieces.Length != 2) { throw new ArgumentException($"Symbol does not have the correct symbol separator of '{api.SymbolSeparator}'"); } baseSymbol = pieces[0]; convertSymbol = pieces[1]; } else { baseSymbol = convertSymbol = symbol; } // create the ticker and return it ExchangeTicker ticker = new ExchangeTicker { Ask = token[askKey].ConvertInvariant <decimal>(), Bid = token[bidKey].ConvertInvariant <decimal>(), Id = (idKey == null ? null : token[idKey].ToStringInvariant()), Last = last, Volume = new ExchangeVolume { BaseVolume = baseVolume, BaseSymbol = baseSymbol, ConvertedVolume = convertVolume, ConvertedSymbol = convertSymbol, Timestamp = timestamp } }; return(ticker); }
protected override IDisposable OnGetTickersWebSocket(Action <IReadOnlyCollection <KeyValuePair <string, ExchangeTicker> > > callback) { if (callback == null) { return(null); } void innerCallback(string json) { #region sample json /* * { * Nonce : int, * Deltas : * [ * { * MarketName : string, * High : decimal, * Low : decimal, * Volume : decimal, * Last : decimal, * BaseVolume : decimal, * TimeStamp : date, * Bid : decimal, * Ask : decimal, * OpenBuyOrders : int, * OpenSellOrders : int, * PrevDay : decimal, * Created : date * } * ] * } */ #endregion var freshTickers = new Dictionary <string, ExchangeTicker>(StringComparer.OrdinalIgnoreCase); JToken token = JToken.Parse(json); token = token["D"]; foreach (JToken ticker in token) { string marketName = ticker["M"].ToStringInvariant(); decimal last = ticker["l"].ConvertInvariant <decimal>(); decimal ask = ticker["A"].ConvertInvariant <decimal>(); decimal bid = ticker["B"].ConvertInvariant <decimal>(); decimal volume = ticker["V"].ConvertInvariant <decimal>(); decimal baseVolume = ticker["m"].ConvertInvariant <decimal>(); DateTime timestamp = CryptoUtility.UnixTimeStampToDateTimeMilliseconds(ticker["T"].ConvertInvariant <long>()); var t = new ExchangeTicker { Ask = ask, Bid = bid, Last = last, Volume = new ExchangeVolume { ConvertedVolume = volume, ConvertedSymbol = marketName, BaseVolume = baseVolume, BaseSymbol = marketName, Timestamp = timestamp } }; freshTickers[marketName] = t; } callback(freshTickers); } var client = SocketManager; return(client.SubscribeToSummaryDeltas(innerCallback)); }