public CandleStream(CurrencyPair pair, EMarketPeriod period, CandleDataCache owner) { try { Cache = owner; Pair = pair; Period = period; CandleData = new List <MarketChartData>(); // Create the stream connection and start buffering events m_pending = new List <CandleUpdate>(); Socket = new WebSocket(Api.Shutdown); // Request a snapshot to initialise the candle data // We can only buffer a limited range of candles. Outside that range forward to the rest api lock (CandleData) { // Get the most recent candle data CandleData = Api.GetChartData(Pair, period).Result; CandleData.Sort(x => x.Time); } } catch { Dispose(); throw; } }
/// <summary>Return candle data</summary> public async Task <List <MarketChartData> > GetChartData(CurrencyPair pair, EMarketPeriod period, UnixMSec?time_beg = null, UnixMSec?time_end = null, CancellationToken?cancel = null) { try { // https://api.binance.com/api/v1/klines?symbol=IOTABTC&interval=1d&limit=5 var parms = new Params { }; parms["symbol"] = pair.Id; parms["interval"] = period.Assoc <string>(); if (time_beg != null) { parms["startTime"] = time_beg.Value.Value; } if (time_end != null) { parms["endTime"] = time_end.Value.Value; } var jtok = await GetData(HttpMethod.Get, ESecurityType.PUBLIC, "api/v1/klines", cancel, parms); var data = ParseJsonReply <List <JArray> >(jtok); return(data.Select(x => new MarketChartData(x)).ToList()); } catch (Exception ex) { if (ex.Message.Contains("too much data")) { throw new BinanceException(EErrorCode.TooMuchDataRequested, "Too much chart data was requested"); } throw; } }
/// <summary></summary> public async Task <List <MarketChartData> > GetChartData(CurrencyPair pair, EMarketPeriod period, UnixSec time_beg, UnixSec time_end, CancellationToken?cancel = null) { try { var jtok = await GetData(Method.Public, "returnChartData", cancel, new Params { { "currencyPair", pair.Id }, { "start", time_beg.Value }, { "end", time_end.Value }, { "period", (int)period }, }); var data = ParseJsonReply <List <MarketChartData> >(jtok); // Poloniex returns a single invalid candle if there is no data within the range return (data.Count == 0 ? new List <MarketChartData>() : data.Count == 1 && data[0].Invalid ? new List <MarketChartData>() : data); } catch (Exception ex) { if (ex.Message.Contains("too much data")) { throw new PoloniexException(EErrorCode.TooMuchDataRequested, "Too much chart data was requested"); } throw; } }
/// <summary>Convert a market period to a time frame</summary> private ETimeFrame ToTimeFrame(EMarketPeriod mp) { switch (mp) { default: return(ETimeFrame.None); case EMarketPeriod.Minutes5: return(ETimeFrame.Min5); case EMarketPeriod.Minutes15: return(ETimeFrame.Min15); case EMarketPeriod.Minutes30: return(ETimeFrame.Min30); case EMarketPeriod.Hours2: return(ETimeFrame.Hour2); case EMarketPeriod.Hours4: return(ETimeFrame.Hour4); case EMarketPeriod.Day: return(ETimeFrame.Day1); } }
/// <summary>Access the order book for the given pair</summary> public List <MarketChartData> this[CurrencyPair pair, EMarketPeriod period, UnixMSec time_beg, UnixMSec time_end, CancellationToken? cancel = null] // Worker thread context { get { var key = new PairAndTF { Pair = pair, TimeFrame = period }; try { var stream = (CandleStream)null; lock (Streams) { // Look for the stream for 'pair'. Create if not found. // Return a copy since any thread can call this function. if (!Streams.TryGetValue(key, out stream) || stream.Socket == null) { stream = Streams[key] = new CandleStream(pair, period, this); } } lock (stream.CandleData) { // If the range is outside the cached data range, fall back to the REST call if (stream.CandleData.Count == 0 || time_beg < stream.CandleData[0].Time) { return(Api.GetChartData(pair, period, time_beg, time_end, cancel).Result); } // Return the requested range var ibeg = stream.CandleData.BinarySearch(x => x.Time.CompareTo(time_beg), find_insert_position: true); var iend = stream.CandleData.BinarySearch(x => x.Time.CompareTo(time_end), find_insert_position: true); return(stream.CandleData.GetRange(ibeg, iend - ibeg)); } } catch (Exception ex) { BinanceApi.Log.Write(ELogLevel.Error, ex, $"Subscribing to candle data for {pair.Id}/{period} failed."); lock (Streams) Streams.Remove(key); return(new List <MarketChartData>()); } } }
public static TimeSpan ToTimeSpan(this EMarketPeriod period, double count = 1) { switch (period) { default: throw new Exception($"Unknown market period: {period}"); case EMarketPeriod.None: return(TimeSpan.Zero); case EMarketPeriod.Minutes1: return(TimeSpan.FromMinutes(1 * count)); case EMarketPeriod.Minutes3: return(TimeSpan.FromMinutes(3 * count)); case EMarketPeriod.Minutes5: return(TimeSpan.FromMinutes(5 * count)); case EMarketPeriod.Minutes15: return(TimeSpan.FromMinutes(15 * count)); case EMarketPeriod.Minutes30: return(TimeSpan.FromMinutes(30 * count)); case EMarketPeriod.Hours1: return(TimeSpan.FromHours(1 * count)); case EMarketPeriod.Hours2: return(TimeSpan.FromHours(2 * count)); case EMarketPeriod.Hours4: return(TimeSpan.FromHours(4 * count)); case EMarketPeriod.Hours6: return(TimeSpan.FromHours(6 * count)); case EMarketPeriod.Hours8: return(TimeSpan.FromHours(8 * count)); case EMarketPeriod.Hours12: return(TimeSpan.FromHours(12 * count)); case EMarketPeriod.Day1: return(TimeSpan.FromDays(1 * count)); case EMarketPeriod.Day3: return(TimeSpan.FromDays(3 * count)); case EMarketPeriod.Week1: return(TimeSpan.FromDays(7 * count)); case EMarketPeriod.Month1: return(TimeSpan.FromDays(30.44 * count)); } }
/// <summary>Convert a market period to a time frame</summary> private ETimeFrame ToTimeFrame(EMarketPeriod mp) { switch (mp) { default: return(ETimeFrame.None); case EMarketPeriod.Minutes1: return(ETimeFrame.Min1); case EMarketPeriod.Minutes3: return(ETimeFrame.Min3); case EMarketPeriod.Minutes5: return(ETimeFrame.Min5); case EMarketPeriod.Minutes15: return(ETimeFrame.Min15); case EMarketPeriod.Minutes30: return(ETimeFrame.Min30); case EMarketPeriod.Hours1: return(ETimeFrame.Hour1); case EMarketPeriod.Hours2: return(ETimeFrame.Hour2); case EMarketPeriod.Hours4: return(ETimeFrame.Hour4); case EMarketPeriod.Hours6: return(ETimeFrame.Hour6); case EMarketPeriod.Hours8: return(ETimeFrame.Hour8); case EMarketPeriod.Hours12: return(ETimeFrame.Hour12); case EMarketPeriod.Day1: return(ETimeFrame.Day1); case EMarketPeriod.Day3: return(ETimeFrame.Day3); case EMarketPeriod.Week1: return(ETimeFrame.Week1); case EMarketPeriod.Month1: return(ETimeFrame.Month1); } }