示例#1
0
        public async Task <(int deletedCandlesCount, int replacedCandlesCount)> FixExtremeCandlesAsync(IReadOnlyList <ICandle> extremeCandles, CandlePriceType priceType)
        {
            // Okay, the incorrect candles are listed. Now we need to group it by time intervals and iterate from the
            // smallest interval to the biggest, back. But now we will delete the smallest candles at all, and then
            // recalculate (and replace in storage) the bigger candles.

            int deletedCountSummary = 0, replacedCountSummary = 0;

            var candlesByInterval = extremeCandles
                                    .GroupBy(c => (int)c.TimeInterval)
                                    .ToSortedDictionary(g => g.Key);

            if (candlesByInterval.Count != Constants.DbStoredIntervals.Length)
            {
                throw new ArgumentException($"Something is wrong: the amount of (unique) time intervals in extreme candles list is not equal to stored intervals array length. " +
                                            $"Filtration for {priceType} is impossible.");
            }

            foreach (var candleBatch in candlesByInterval)
            {
                var interval = (CandleTimeInterval)candleBatch.Key;

                // The Second time interval is the smallest, so, we simply delete such a candles from storage and go next.
                if (interval == CandleTimeInterval.Sec)
                {
                    var deletedCountQuant =
                        await _candlesHistoryRepository.DeleteCandlesAsync(candleBatch.Value.ToList());

                    deletedCountSummary += deletedCountQuant;
                    continue;
                }

                var smallerInterval = GetSmallerInterval(interval);

                // My dear friend, who will read or refactor this code in future, please, excuse me for such a terrible
                // loop cascade. Currently, I just can't imagine how to make it shorter and more comfortable for reading.
                // And from the other side, there is no such a necessity to invent an ideal bicycle here.
                // ReSharper disable once PossibleNullReferenceException
                var currentCandlesToReplace = new List <ICandle>();
                var currentCandlesToDelete  = new List <ICandle>();
                foreach (var candle in candleBatch.Value.AsEnumerable())
                {
                    var dateFrom = candle.Timestamp;
                    var dateTo   = candle.Timestamp.AddIntervalTicks(1, interval);

                    var smallerCandles = await _candlesHistoryRepository.GetCandlesAsync(candle.AssetPairId,
                                                                                         smallerInterval, priceType, dateFrom, dateTo);

                    // Trying to reconstruct the candle from the corresponfing smaller interval candles, if any.
                    ICandle updatedCandle = null;
                    foreach (var smallerCandle in smallerCandles)
                    {
                        if (updatedCandle == null)
                        {
                            updatedCandle = smallerCandle
                                            .RebaseToInterval(interval);
                        }
                        else
                        {
                            updatedCandle = updatedCandle
                                            .ExtendBy(smallerCandle
                                                      .RebaseToInterval(interval));
                        }
                    }

                    // If the candle is not empty (e.g., there are some smaller interval candles for its construction),
                    // we should update it in storage. Otherwise, it is to be deleted from there.
                    if (updatedCandle != null)
                    {
                        currentCandlesToReplace.Add(updatedCandle);
                    }
                    else
                    {
                        currentCandlesToDelete.Add(candle);
                    }
                }

                if (currentCandlesToDelete.Count > 0)
                {
                    var deletedCountQuant = await _candlesHistoryRepository.DeleteCandlesAsync(currentCandlesToDelete);

                    deletedCountSummary += deletedCountQuant;
                }

                if (currentCandlesToReplace.Count > 0)
                {
                    var replacedCountQuant = await _candlesHistoryRepository.ReplaceCandlesAsync(currentCandlesToReplace);

                    replacedCountSummary += replacedCountQuant;
                }
            }

            return(deletedCandlesCount : deletedCountSummary, replacedCandlesCount : replacedCountSummary);
        }
示例#2
0
        /// <summary>
        /// Extends a candle by a trade, if trade's DateTime corresponds to candle's TimeStamp (i.e., the trade belongs to the same time period).
        /// </summary>
        public static ICandle ExtendBy(this ICandle self, TradeHistoryItem trade, decimal volumeMultiplier = 1.0M)
        {
            var tradeCandle = trade.CreateCandle(self.AssetPairId, self.PriceType, self.TimeInterval, volumeMultiplier);

            return(self.ExtendBy(tradeCandle));
        }