public bool CanAddGap(GapInfo gap) { if (Gaps.Count == 0) return true; if (Gaps.Count >= maxGapCount) return true; var newLength = totalLengthDays + (gap.end - gap.start).TotalDays; return newLength <= maxTotalLengthDays; }
public bool CanAddGap(GapInfo gap) { if (Gaps.Count == 0) { return(true); } if (Gaps.Count >= maxGapCount) { return(true); } var newLength = totalLengthDays + (gap.end - gap.start).TotalDays; return(newLength <= maxTotalLengthDays); }
public void AddGap(GapInfo gap) { Gaps.Add(gap); totalLengthDays += (gap.end - gap.start).TotalDays; }
/// <summary> /// получение карты потенциальных гэпов; /// она составляются по отсутвующим данным в котировке ticker-а, /// но учитывает карту гэпов сервера, составленную по предыдущим запросам /// </summary> /// <param name="ticker"></param> /// <param name="timeStart"></param> /// <param name="quoteCacheFolder"></param> /// <param name="worker"></param> /// <param name="nowTime"></param> /// <returns></returns> public static List <GapInfo> VerifyTickerHistory(string ticker, DateTime timeStart, string quoteCacheFolder, BackgroundWorker worker, DateTime nowTime = default(DateTime)) { if (worker != null && worker.CancellationPending) { return(new List <GapInfo>()); } if (nowTime == default(DateTime)) { nowTime = DateTime.Now; } var histStart = GapMap.Instance.GetServerTickerHistoryStart(ticker); if (timeStart < histStart) { timeStart = histStart; } // получить список гэпов, предположительно, имеющихся на сервере var serverGaps = GapMap.Instance.GetServerGaps(ticker); // получить имеющуюся историю var candles = AtomCandleStorage.Instance.GetAllMinuteCandles(ticker); if (candles == null || candles.Count == 0) { var loadedHist = AtomCandleStorage.Instance.LoadFromFile(quoteCacheFolder, ticker); if (loadedHist.HasValue) { candles = AtomCandleStorage.Instance.GetAllMinuteCandles(ticker); } } candles = candles ?? new List <CandleData>(); if (worker != null && worker.CancellationPending) { return(new List <GapInfo>()); } // определить гэпы var gaps = candles.Count > 0 ? QuoteCacheManager.GetGaps(candles, timeStart, nowTime) : new List <DateSpan> { new DateSpan(timeStart, nowTime) }; // исключить фрагменты, отсутствующие на сервере if (serverGaps != null && serverGaps.IsActual) { GapMap.ExcludeGapsThatLackedOnServer(ref gaps, serverGaps.serverGaps); } else { // получить время первой записи в БД и удалить / порезать все гэпы, начинающиеся // позже, чем первая запись базы var gapsTrimmed = new List <DateSpan>(); foreach (var gap in gaps) { if (gap.end <= histStart) { continue; } if (gap.start < histStart) { gapsTrimmed.Add(new DateSpan(histStart, gap.end)); } else { gapsTrimmed.Add(gap); } } gaps = gapsTrimmed; } var gapInfos = gaps.Select(g => new GapInfo { start = g.start, end = g.end }).ToList(); // склеиваем рядом стоящие гэпы GapInfo.StickSmallGaps(ref gapInfos, 30); if (worker != null && worker.CancellationPending) { return(new List <GapInfo>()); } return(gapInfos); }
/// <summary> /// устранение гэпов /// </summary> /// <param name="ticker"></param> /// <param name="startTime"></param> /// <param name="gaps"></param> /// <param name="quoteCacheFolder"></param> /// <param name="worker"></param> /// <param name="gapsUpdatedAction"></param> public static void FillGapsByTicker(string ticker, DateTime startTime, List <GapInfo> gaps, string quoteCacheFolder, BackgroundWorker worker, Action <string, List <GapInfo> > gapsUpdatedAction) { // закачать с сервера // параллельно обновляя контрол var candlesOld = AtomCandleStorage.Instance.GetAllMinuteCandles(ticker) ?? new List <CandleData>(); var candlesNew = new List <CandleData>(); var oldIndex = 0; if (worker != null && worker.CancellationPending) { return; } for (var i = 0; i < gaps.Count; i++) { var gap = gaps[i]; // добавить имеющиеся свечи for (; oldIndex < candlesOld.Count; oldIndex++) { if (candlesOld[oldIndex].timeOpen > gap.start) { break; } candlesNew.Add(candlesOld[oldIndex]); } // подкачать свечи с сервера var indexToInsert = i; var wasInserted = false; var status = LoadQuotesFromServer(ticker, gap.start, gap.end.AddMinutes(1), candlesNew, (time, gapStatus) => { // добавить или обновить временный гэп var passedGap = new GapInfo { start = gap.start, end = time, status = gapStatus }; if (!wasInserted) { gaps.Insert(indexToInsert, passedGap); wasInserted = true; } else { gaps[indexToInsert] = passedGap; } gaps[indexToInsert + 1] = new GapInfo { start = time.AddMinutes(1), end = gaps[indexToInsert + 1].end, status = gaps[indexToInsert + 1].status }; // перерисовать контрол gapsUpdatedAction(ticker, gaps); }, worker); if (wasInserted) { gaps.RemoveAt(indexToInsert); } if (status == GapInfo.GapStatus.FailedToFill) { // в старом списке могли быть какие-то котировки на интервале гэпа - добавить их for (; oldIndex < candlesOld.Count; oldIndex++) { if (candlesOld[oldIndex].timeOpen > gap.end) { break; } candlesNew.Add(candlesOld[oldIndex]); } } // перекрасить гэп другим цветом gaps[i] = new GapInfo { start = gap.start, end = gap.end, status = status }; if (worker != null && worker.CancellationPending) { return; } if (currentTickerCancelled) { currentTickerCancelled = false; return; } gapsUpdatedAction(ticker, gaps); // сместиться вперед в списке старых свеч for (; oldIndex < candlesOld.Count; oldIndex++) { if (candlesOld[oldIndex].timeOpen > gap.end) { break; } } } if (worker != null && worker.CancellationPending) { return; } if (candlesNew.Count == 0) { return; } // добавить "хвостик" - недостающие свечки var lastTime = candlesNew[candlesNew.Count - 1].timeOpen; for (; oldIndex < candlesOld.Count; oldIndex++) { if (candlesOld[oldIndex].timeOpen <= lastTime) { continue; } candlesNew.Add(candlesOld[oldIndex]); } if (candlesNew.Count <= candlesOld.Count) { return; } // убрать дублирующиеся свечки for (var i = 1; i < candlesNew.Count; i++) { if (candlesNew[i].timeOpen <= candlesNew[i - 1].timeOpen) { candlesNew.RemoveAt(i); i--; } } if (worker != null && worker.CancellationPending) { return; } // дырки, оставшиеся в истории, и есть серверные гэпы if (candlesNew.Count > 0) { var updatedGapsInfo = QuoteCacheManager.GetGaps(candlesNew, startTime, DateTime.Now); GapMap.Instance.UpdateGaps(ticker, updatedGapsInfo); GapMap.Instance.SaveToFile(); } if (worker != null && worker.CancellationPending) { return; } // сохранить свечи в хранилище и в файл AtomCandleStorage.Instance.RewriteCandles(ticker, candlesNew); AtomCandleStorage.Instance.FlushInFile(quoteCacheFolder, ticker); }
/// <summary> /// устранение гэпов /// </summary> /// <param name="ticker"></param> /// <param name="startTime"></param> /// <param name="gaps"></param> /// <param name="quoteCacheFolder"></param> /// <param name="worker"></param> /// <param name="gapsUpdatedAction"></param> public static void FillGapsByTicker(string ticker, DateTime startTime, List<GapInfo> gaps, string quoteCacheFolder, BackgroundWorker worker, Action<string, List<GapInfo>> gapsUpdatedAction) { // закачать с сервера // параллельно обновляя контрол var candlesOld = AtomCandleStorage.Instance.GetAllMinuteCandles(ticker) ?? new List<CandleData>(); var candlesNew = new List<CandleData>(); var oldIndex = 0; if (worker != null && worker.CancellationPending) return; for (var i = 0; i < gaps.Count; i++) { var gap = gaps[i]; // добавить имеющиеся свечи for (; oldIndex < candlesOld.Count; oldIndex++) { if (candlesOld[oldIndex].timeOpen > gap.start) break; candlesNew.Add(candlesOld[oldIndex]); } // подкачать свечи с сервера var indexToInsert = i; var wasInserted = false; var status = LoadQuotesFromServer(ticker, gap.start, gap.end.AddMinutes(1), candlesNew, (time, gapStatus) => { // добавить или обновить временный гэп var passedGap = new GapInfo { start = gap.start, end = time, status = gapStatus }; if (!wasInserted) { gaps.Insert(indexToInsert, passedGap); wasInserted = true; } else gaps[indexToInsert] = passedGap; gaps[indexToInsert + 1] = new GapInfo { start = time.AddMinutes(1), end = gaps[indexToInsert + 1].end, status = gaps[indexToInsert + 1].status }; // перерисовать контрол gapsUpdatedAction(ticker, gaps); }, worker); if (wasInserted) gaps.RemoveAt(indexToInsert); if (status == GapInfo.GapStatus.FailedToFill) { // в старом списке могли быть какие-то котировки на интервале гэпа - добавить их for (; oldIndex < candlesOld.Count; oldIndex++) { if (candlesOld[oldIndex].timeOpen > gap.end) break; candlesNew.Add(candlesOld[oldIndex]); } } // перекрасить гэп другим цветом gaps[i] = new GapInfo { start = gap.start, end = gap.end, status = status }; if (worker != null && worker.CancellationPending) return; if (currentTickerCancelled) { currentTickerCancelled = false; return; } gapsUpdatedAction(ticker, gaps); // сместиться вперед в списке старых свеч for (; oldIndex < candlesOld.Count; oldIndex++) { if (candlesOld[oldIndex].timeOpen > gap.end) break; } } if (worker != null && worker.CancellationPending) return; if (candlesNew.Count == 0) return; // добавить "хвостик" - недостающие свечки var lastTime = candlesNew[candlesNew.Count - 1].timeOpen; for (; oldIndex < candlesOld.Count; oldIndex++) { if (candlesOld[oldIndex].timeOpen <= lastTime) continue; candlesNew.Add(candlesOld[oldIndex]); } if (candlesNew.Count <= candlesOld.Count) return; // убрать дублирующиеся свечки for (var i = 1; i < candlesNew.Count; i++) { if (candlesNew[i].timeOpen <= candlesNew[i - 1].timeOpen) { candlesNew.RemoveAt(i); i--; } } if (worker != null && worker.CancellationPending) return; // дырки, оставшиеся в истории, и есть серверные гэпы if (candlesNew.Count > 0) { var updatedGapsInfo = QuoteCacheManager.GetGaps(candlesNew, startTime, DateTime.Now); GapMap.Instance.UpdateGaps(ticker, updatedGapsInfo); GapMap.Instance.SaveToFile(); } if (worker != null && worker.CancellationPending) return; // сохранить свечи в хранилище и в файл AtomCandleStorage.Instance.RewriteCandles(ticker, candlesNew); AtomCandleStorage.Instance.FlushInFile(quoteCacheFolder, ticker); }