GetCandlesAsync(string assetPairId, CandleTimeInterval interval, DateTime dateFrom, DateTime dateTo) { var midCandlesTask = _candlesHistoryRepository.GetCandlesAsync(assetPairId, interval, CandlePriceType.Mid, dateFrom, dateTo); var askCandlesTask = _candlesHistoryRepository.GetCandlesAsync(assetPairId, interval, CandlePriceType.Ask, dateFrom, dateTo); var bidCandlesTask = _candlesHistoryRepository.GetCandlesAsync(assetPairId, interval, CandlePriceType.Bid, dateFrom, dateTo); await Task.WhenAll(midCandlesTask, askCandlesTask, bidCandlesTask); return(bidCandles : bidCandlesTask.Result.ToList(), askCandles : askCandlesTask.Result.ToList(), midCandles : midCandlesTask.Result.ToList()); }
public async Task <IActionResult> GetCandlesHistoryFromDb(string assetPairId, CandlePriceType priceType, CandleTimeInterval timeInterval, DateTime fromMoment, DateTime toMoment) { fromMoment = fromMoment.ToUniversalTime(); toMoment = toMoment.ToUniversalTime(); if (string.IsNullOrWhiteSpace(assetPairId)) { return(BadRequest(ErrorResponse.Create(nameof(assetPairId), "Asset pair is required"))); } if (priceType == CandlePriceType.Unspecified) { return(BadRequest(ErrorResponse.Create(nameof(timeInterval), $"Price type should not be {CandlePriceType.Unspecified}"))); } if (timeInterval == CandleTimeInterval.Unspecified) { return(BadRequest(ErrorResponse.Create(nameof(timeInterval), $"Time interval should not be {CandleTimeInterval.Unspecified}"))); } if (fromMoment > toMoment) { return(BadRequest(ErrorResponse.Create("From date should be early or equal than To date"))); } if (!_candleHistoryAssetConnections.ContainsKey(assetPairId)) { return(BadRequest(ErrorResponse.Create(nameof(assetPairId), "Asset pair is not configured"))); } if (await _assetPairsManager.TryGetAssetPairAsync(assetPairId) == null) { return(BadRequest(ErrorResponse.Create(nameof(assetPairId), "Asset pair not found"))); } var candles = await _candlesHistoryRepository.GetCandlesAsync(assetPairId, timeInterval, priceType, fromMoment, toMoment); return(Ok(new CandlesHistoryResponseModel { History = candles.Select(c => new CandlesHistoryResponseModel.Candle { DateTime = c.Timestamp, Open = c.Open, Close = c.Close, High = c.High, Low = c.Low, TradingVolume = c.TradingVolume, TradingOppositeVolume = c.TradingOppositeVolume, LastTradePrice = c.LastTradePrice }) })); }
private async Task CacheAssetPairCandlesAsync(AssetPair assetPair, DateTime now, SlotType slotType) { try { _log.Info(nameof(InitializeCacheAsync), $"Caching {assetPair.Id} candles history..."); foreach (CandlePriceType priceType in Constants.StoredPriceTypes) { foreach (CandleTimeInterval timeInterval in Constants.InitFromDbIntervals) { DateTime alignedToDate = now.TruncateTo(timeInterval).AddIntervalTicks(1, timeInterval); DateTime alignedFromDate = alignedToDate.AddIntervalTicks(-_amountOfCandlesToStore[timeInterval] - 1, timeInterval); if (alignedFromDate < _minDate) { alignedFromDate = _minDate.TruncateTo(timeInterval); } ICandle[] candles = (await _candlesHistoryRepository.GetCandlesAsync(assetPair.Id, timeInterval, priceType, alignedFromDate, alignedToDate)).ToArray(); if (!candles.Any()) { continue; } var intervals = _candlesCacheService.GetRedisCacheIntervals(timeInterval); foreach (var interval in intervals) { ICandle[] intervalCandles = interval != timeInterval ? CandlesMerger.MergeIntoBiggerIntervals(candles, interval).ToArray() : candles; await _candlesCacheService.InitializeAsync(assetPair.Id, priceType, interval, intervalCandles, slotType); } } } _log.Info($"{assetPair.Id} candles history is cached."); } catch (Exception ex) { _log.Error(nameof(CacheAssetPairCandlesAsync), ex); } }
private async Task CacheAssetPairCandlesAsync(IAssetPair assetPair, DateTime toDate) { await _log.WriteInfoAsync(nameof(CandlesCacheInitalizationService), nameof(InitializeCacheAsync), null, $"Caching {assetPair.Id} candles history..."); foreach (var priceType in Constants.StoredPriceTypes) { foreach (var timeInterval in Constants.StoredIntervals) { var alignedToDate = toDate.TruncateTo(timeInterval); var alignedFromDate = alignedToDate.AddIntervalTicks(-_amountOfCandlesToStore, timeInterval); var candles = await _candlesHistoryRepository.GetCandlesAsync(assetPair.Id, timeInterval, priceType, alignedFromDate, alignedToDate); await _candlesCacheService.InitializeAsync(assetPair.Id, priceType, timeInterval, candles.ToArray()); } } await _log.WriteInfoAsync(nameof(CandlesCacheInitalizationService), nameof(InitializeCacheAsync), null, $"{assetPair.Id} candles history is cached"); }
public async Task <IReadOnlyList <ICandle> > TryGetExtremeCandlesAsync(string assetPairId, CandlePriceType priceType, double limitLow, double limitHigh, double epsilon) { var(dateFrom, dateTo) = await GetDateTimeRangeAsync(assetPairId, priceType); // May be, we have got fake DateTime range. If so, this means there are no candles for the specified asset // pair at all and we should skip its filtration in the caller code. Return null. if (dateFrom == DateTime.MinValue || dateTo == DateTime.MinValue) { return(new List <ICandle>()); } var currentMonthBeginingDateTime = dateTo; // We will use it several times below for data query limiting. // The list of extreme candles for all stored time periods (there will be not so disastrous amount of them // to run out of memory). var extremeCandles = new List <ICandle>(); List <ICandle> lastCandles = null; // Now we will go through the candle storage deeps from the biggest candle time interval to the smallest one. // We can take in mind that if there was an extreme quote (or trade price), it will lead to generation of the // faulty (extreme) candles from Second to Month. But we have much less month candles than those for seconds. // So, the fastest way to find all the extreme second candles is to find all the extreme month candles first. // Then, having the list, we need to iterate it to find an extreme week candles, corresponding to each month, // and then a list of day candles, and so on. At the finish, we will obtain all the second candles with wrong // prices, and thus, we will be ready to delete 'em and go back through the stored time period list, from the // smallest to the biggest, producing the updated (corrected) candles for each of them. for (var i = Constants.DbStoredIntervals.Length - 1; i >= 0; i--) { List <ICandle> currentCandles; var interval = Constants.DbStoredIntervals[i]; if (i == Constants.DbStoredIntervals.Length - 1) { var candles = await _candlesHistoryRepository.GetCandlesAsync(assetPairId, interval, priceType, dateFrom, dateTo); currentCandles = candles .Where(c => IsExtremeCandle(c, limitLow, limitHigh, epsilon)) .ToList(); // There are no incorrect candles at all - returning. if (!currentCandles.Any()) { return(extremeCandles); // Empty collection here. } } else { currentCandles = new List <ICandle>(); // ReSharper disable once PossibleNullReferenceException foreach (var candle in lastCandles) { dateFrom = candle.Timestamp.TruncateTo(interval); // Truncating is important when searching weeks by months: the first week of month may start earlier than the month. In other cases, TruncateTo is redundant. dateTo = candle.Timestamp.AddIntervalTicks(1, GetBiggerInterval(interval)); if (dateTo > currentMonthBeginingDateTime) { dateTo = currentMonthBeginingDateTime; } var candles = await _candlesHistoryRepository.GetCandlesAsync(assetPairId, interval, priceType, dateFrom, dateTo); currentCandles.AddRange(candles .Where(c => IsExtremeCandle(c, limitLow, limitHigh, epsilon))); } } lastCandles = currentCandles; extremeCandles.AddRange(currentCandles); } return(extremeCandles); }