/// <summary> /// Get a granularity in seconds /// </summary> /// <param name="granularity">The granularity</param> /// <returns>How many seconds that granularity represents</returns> public static int GetInSeconds(this CandlestickGranularity granularity) { return(granularity switch { CandlestickGranularity.S5 => 5, CandlestickGranularity.S10 => 10, CandlestickGranularity.S15 => 15, CandlestickGranularity.S30 => 30, CandlestickGranularity.M1 => 60, CandlestickGranularity.M2 => (60 * 2), CandlestickGranularity.M4 => (60 * 4), CandlestickGranularity.M5 => (60 * 5), CandlestickGranularity.M10 => (60 * 10), CandlestickGranularity.M15 => (60 * 15), CandlestickGranularity.M30 => (60 * 30), CandlestickGranularity.H1 => (60 * 60), CandlestickGranularity.H2 => (60 * 60 * 2), CandlestickGranularity.H3 => (60 * 60 * 3), CandlestickGranularity.H4 => (60 * 60 * 4), CandlestickGranularity.H6 => (60 * 60 * 6), CandlestickGranularity.H8 => (60 * 60 * 8), CandlestickGranularity.H12 => (60 * 60 * 12), CandlestickGranularity.D => (60 * 60 * 24), CandlestickGranularity.W => (60 * 60 * 24 * 7), CandlestickGranularity.M => (60 * 60 * 24 * 31), _ => 5, });
/// <summary> /// Fetch candlestick data for an instrument. /// </summary> /// <param name="pairs">The instrument pair value</param> /// <param name="queryNVC"></param> /// <returns></returns> public async Task <CandlestickResponse> GetInstrumentCandles( InstrumentName instrument, DateTime from, DateTime to, CandlestickGranularity granularity = null, int count = 500, WeeklyAlignment weeklyAlignment = null, string price = "M", bool smooth = false, bool includeFirst = true, int dailyAlignment = 17, string alignmentTimezone = "America/New_York" ) { #region QueryNVC NameValueCollection queryNVC = new NameValueCollection() { { "count", count.ToString() }, { "price", price }, { "smooth", smooth.ToString() }, { "includeFirst", includeFirst.ToString() }, { "dailyAlignment", dailyAlignment.ToString() }, { "alignmentTimeZone", alignmentTimezone } }; if (from != null) { queryNVC.Add("from", from.ToUniversalTime().ToString()); } if (to != null) { queryNVC.Add("to", to.ToUniversalTime().ToString()); } if (granularity != null) { queryNVC.Add("granularity", granularity.ToString()); } if (weeklyAlignment != null) { queryNVC.Add("weeklyAlignment", weeklyAlignment.ToString()); } #endregion string path = string.Format("instruments/{0}/candles", instrument); string query = QueryFromNVC(queryNVC); using (HttpResponseMessage response = await RequestAsync(EHostAPIType.REST, HttpMethod.Get, path, query)) { if (response.StatusCode != HttpStatusCode.OK) { throw new HttpRequestException(JObject.Parse(await response.Content.ReadAsStringAsync())["errorMessage"].ToString()); } using (Stream stream = await response.Content.ReadAsStreamAsync()) { string jsonString = await new StreamReader(stream).ReadToEndAsync(); return(JsonConvert.DeserializeObject <CandlestickResponse>(jsonString, ErrorHandlingSetting)); } } }
/// <summary> /// Is the timerange and granularity specifies more candles than Oanda can handle in one request? /// </summary> /// <param name="granularity">The granularity to check</param> /// <param name="from">From date time</param> /// <param name="to">To date time</param> /// <returns></returns> public static bool AreMultipleQueriesRequired(this CandlestickGranularity granularity, DateTime from, DateTime to) { // Always convert dates to UTC when working with Oanda from = from.ToUniversalTime(); to = to.ToUniversalTime(); // Check the number of candles return(granularity.GetNumberOfCandlesForTimeRange(from, to) > OANDA_MAX_CANDLES); }
public CandlestickResponse( string instrument, CandlestickGranularity granularity, ImmutableList <CandleStick> candles) { Instrument = instrument; Granularity = granularity; Candles = candles; }
public async Task <CandlestickResponse> GetInstrumentCandles( InstrumentName instrument, DateTime from, DateTime to, CandlestickGranularity granularity = null, int count = 500, WeeklyAlignment weeklyAlignment = null ) { return(await GetInstrumentCandles(instrument, from, to, granularity, count, weeklyAlignment)); }
/// <summary> /// Calculate number of candles in a time range /// </summary> /// <param name="granularity">Granularity of the candles</param> /// <param name="from">The from date</param> /// <param name="to">The to date</param> /// <returns></returns> public static double GetNumberOfCandlesForTimeRange(this CandlestickGranularity granularity, DateTime from, DateTime to) { // Always convert dates to UTC when working with Oanda from = from.ToUniversalTime(); to = to.ToUniversalTime(); // Check not to enter endless loops if (from > to) { throw new ArgumentException("The 'to' time cannot be before the 'to' time."); } // Return the number of candles return((to - from).TotalSeconds / granularity.GetInSeconds()); }
/// <summary> /// Get the last N candles for the instrument asynchronously /// </summary> /// <param name="granularity">Granularity of the candles</param> /// <param name="n">How many candles to get</param> /// <param name="pricingComponents">The pricing components to consider (bid, mid, ask)</param> /// <returns>Enumerable collection of candles</returns> public async Task <IEnumerable <Candlestick> > GetLastNCandlesAsync(CandlestickGranularity granularity, int n, IEnumerable <PricingComponent>?pricingComponents = null) { if (n > 5000) { throw new Exception("Maximum 5000 candles are allowed"); } var candlesResponse = await _connection.InstrumentApi.GetInstrumentCandlesAsync( instrument : _instrument, granularity : granularity, count : n, price : ResolvePricingComponents(pricingComponents) ); return(candlesResponse.Candles); }
/// <summary> /// Get the candles for the instrument for the timeperiod passed asynchronously /// </summary> /// <param name="granularity">Granularity of the candles</param> /// <param name="from">The time the candles should start with</param> /// <param name="to">The time the candles should end with</param> /// <param name="pricingComponents">The pricing components to consider (bid, mid, ask)</param> /// <returns>Enumerable collection of candles</returns> public async Task <IEnumerable <Candlestick> > GetCandlesByTimeAsync(CandlestickGranularity granularity, DateTime from, DateTime to, IEnumerable <PricingComponent>?pricingComponents = null) { // Always convert dates to UTC when working with Oanda from = from.ToUniversalTime(); to = to.ToUniversalTime(); if (granularity.AreMultipleQueriesRequired(from, to)) { var candlesRange = granularity.ExplodeToMultipleCandleRanges(from, to); var candleResponses = new List <CandlesResponse>(); foreach (var candleFromToRange in candlesRange) { candleResponses.Add( await _connection.InstrumentApi.GetInstrumentCandlesAsync( instrument: _instrument, granularity: granularity, price: ResolvePricingComponents(pricingComponents), from: candleFromToRange.From.ToOandaDateTime(_connection.DateTimeFormat), to: candleFromToRange.To.ToOandaDateTime(_connection.DateTimeFormat), acceptDatetimeFormat: _connection.DateTimeFormat ) ); } return(candleResponses.SelectMany(cr => cr.Candles)); } else { var candlesResponse = await _connection.InstrumentApi.GetInstrumentCandlesAsync( instrument : _instrument, granularity : granularity, price : ResolvePricingComponents(pricingComponents), from : from.ToOandaDateTime(_connection.DateTimeFormat), to : to.ToOandaDateTime(_connection.DateTimeFormat), acceptDatetimeFormat : _connection.DateTimeFormat ); return(candlesResponse.Candles); } }
/// <summary> /// Explode a datetime range to multiple to fit in to Oanda API limitation /// </summary> /// <param name="granularity"></param> /// <param name="from"></param> /// <param name="to"></param> /// <returns></returns> public static IEnumerable <DateTimeRange> ExplodeToMultipleCandleRanges(this CandlestickGranularity granularity, DateTime from, DateTime to) { // Always convert dates to UTC when working with Oanda from = from.ToUniversalTime(); to = to.ToUniversalTime(); // Make the timerange calulation var numberOfCandles = granularity.GetNumberOfCandlesForTimeRange(from, to); var numberOfQueries = Math.Ceiling(numberOfCandles / OANDA_MAX_CANDLES); var candleRanges = new List <DateTimeRange>(); for (var i = 0; i <= (numberOfQueries - 1); i++) { candleRanges.Add(new DateTimeRange() { From = from.AddSeconds(i * OANDA_MAX_CANDLES * granularity.GetInSeconds()), To = (i == (numberOfQueries - 1)) ? to : from.AddSeconds(((i + 1) * OANDA_MAX_CANDLES * granularity.GetInSeconds()) - 1) }); } // Return the tim ranges created return(candleRanges); }
public Task <CandlesResponse> GetCandles( CancellationToken cancellationToken, string instrument, DateTime from, DateTime?to, CandlestickGranularity granularity) { var apiUrl = $"{OandaUrls.Instruments}/{instrument}/candles"; var queryParams = new Dictionary <string, string>(); queryParams.Add("from", FormatDateTimeToQuery(from)); if (to.HasValue) { queryParams.Add("to", FormatDateTimeToQuery(to.Value)); } queryParams.Add("granularity", granularity.ToString()); var queryString = string.Join("&", queryParams.Select(x => $"{x.Key}={x.Value}")); return(ApiClient.MakeGetRequestAsync <CandlesResponse>($"{apiUrl}?{queryString}", cancellationToken)); }