public void Process(TimeBarReport report, out bool shouldRemoveHandler) { shouldRemoveHandler = true; // Проверяем статус отчета var status = (TimeBarReport.StatusCode)report.status_code; switch (status) { case TimeBarReport.StatusCode.SUCCESS: break; case TimeBarReport.StatusCode.DISCONNECTED: TrySetCanceled(); return; case TimeBarReport.StatusCode.OUTSIDE_ALLOWED_RANGE: // Мы зашли слишком глубоко в прошлое CQGCAdapter.Log.Debug().Print( "Historical data depth limit has been reached", LogFields.Instrument(data.Instrument), LogFields.Span(data.Span)); TrySetException(new NoHistoryDataException(nameof(TimeBarReport.StatusCode.OUTSIDE_ALLOWED_RANGE))); return; default: TrySetException(new Exception($"Request ended with {status:G} status code. {report.text_message}")); return; } // Складываем точки данных в пакет var dataPoints = provider.PrepareDataPoints(message.time_bar_parameters.contract_id, report) .Where(p => p.High != 0 && p.Low != 0 && p.Open != 0 && p.Close != 0); // иногда нули приходят foreach (var point in dataPoints) { HistoryDataPoint p; if (!points.TryGetValue(point.Point, out p)) { points.Add(point.Point, point); continue; } if (p != point) { points[point.Point] = point; } } // Если отчет не полон, то ожидаем прихода следующей пачки данных if (!report.is_report_complete) { CQGCAdapter.Log.Debug().Print( $"Got a {nameof(TimeBarReport)} but it's incomplete", LogFields.Instrument(data.Instrument), LogFields.Span(data.Span)); shouldRemoveHandler = false; consumer.Warning("This operation might take some time..."); return; } // Если все данные пришли, то собираем ответ и выставляем его потребителю var minDate = DateTime.MaxValue; var maxDate = DateTime.MinValue; data.Points.Clear(); foreach (var p in points.OrderBy(_ => _.Key)) { data.Points.Add(p.Value); if (p.Key > maxDate) { maxDate = p.Key; } if (p.Key < minDate) { minDate = p.Key; } } data.Begin = minDate; data.End = maxDate; TrySetResult(data); }
public void Process(TimeBarReport report, out bool shouldRemoveHandler) { shouldRemoveHandler = false; // Проверяем статус отчета var status = (TimeBarReport.StatusCode)report.status_code; switch (status) { case TimeBarReport.StatusCode.SUCCESS: case TimeBarReport.StatusCode.SUBSCRIBED: case TimeBarReport.StatusCode.UPDATE: break; case TimeBarReport.StatusCode.DISCONNECTED: case TimeBarReport.StatusCode.DROPPED: shouldRemoveHandler = true; return; default: shouldRemoveHandler = true; consumer.Error(report.text_message); return; } // Складываем точки в словарь var dataPoints = provider.PrepareDataPoints(contractId, report) .Where(p => p.High != 0 && p.Low != 0 && p.Open != 0 && p.Close != 0); // иногда нули приходят foreach (var point in dataPoints) { HistoryDataPoint p; if (!points.TryGetValue(point.Point, out p)) { points.Add(point.Point, point); newPoints++; continue; } if (p != point) { // TODO это неоптимально, в data.Points уже есть точка для этой даты, надо ее обновить points[point.Point] = point; updatedPoints++; } } // Если хотя бы одна точка изменилась - перестраиваем набор данных if (newPoints >= 0 || updatedPoints > 0) { var minDate = DateTime.MaxValue; var maxDate = DateTime.MinValue; data.Points.Clear(); foreach (var p in points.OrderBy(_ => _.Key)) { data.Points.Add(p.Value); if (p.Key > maxDate) { maxDate = p.Key; } if (p.Key < minDate) { minDate = p.Key; } } data.Begin = minDate; data.End = maxDate; } // Если еще не все данные пришли - выходим if (!report.is_report_complete) { CQGCAdapter.Log.Debug().Print( $"Got a {nameof(TimeBarReport)} but it's incomplete", LogFields.Instrument(data.Instrument), LogFields.Span(data.Span)); return; } if (newPoints > 0 || updatedPoints > 0) { if (newPoints == 1 && updatedPoints == 0) { // Пришла одна новая свечка consumer.Update(data, HistoryDataUpdateType.OnePointAdded); } else if (newPoints == 0 && updatedPoints == 1) { // Одна свечка обновилась consumer.Update(data, HistoryDataUpdateType.OnePointUpdated); } else { // Свалилась пачка новых данных consumer.Update(data, HistoryDataUpdateType.Batch); } newPoints = 0; updatedPoints = 0; } }