public CandleSourceEnumerator(CandleSeries series, DateTimeOffset from, DateTimeOffset to, IEnumerable <TSource> sources, Func <TValue, DateTimeOffset> processing, Action stopped) { if (series == null) { throw new ArgumentNullException(nameof(series)); } if (from >= to) { throw new ArgumentOutOfRangeException(nameof(to), to, LocalizedStrings.Str635Params.Put(from)); } if (sources == null) { throw new ArgumentNullException(nameof(sources)); } if (processing == null) { throw new ArgumentNullException(nameof(processing)); } if (stopped == null) { throw new ArgumentNullException(nameof(stopped)); } var info = new List <SourceInfo>(); var requestRanges = new List <Range <DateTimeOffset> >(new[] { new Range <DateTimeOffset>(from, to) }); foreach (var group in sources.GroupBy(s => s.SpeedPriority).OrderBy(g => g.Key)) { foreach (var source in group) { foreach (var supportedRange in source.GetSupportedRanges(series)) { var index = 0; while (index < requestRanges.Count) { var requestRange = requestRanges[index]; var intersectedRange = requestRange.Intersect(supportedRange); if (intersectedRange != null) { info.Add(new SourceInfo(source, intersectedRange)); requestRanges.Remove(requestRange); var results = requestRange.Exclude(supportedRange).ToArray(); requestRanges.InsertRange(index, results); index += results.Length; } else { index++; } } } } } SourceInfo prevInfo = null; foreach (var i in info.OrderBy(i => i.Range.Min)) { if (prevInfo == null) { _sources.Enqueue(i); prevInfo = i; } else { if (prevInfo.Source == i.Source) { prevInfo.ExtendRange(i.Range); } else { _sources.Enqueue(i); prevInfo = i; } } } _series = series; _processing = processing; _stopped = stopped; }