Esempio n. 1
0
        /// <summary>
        ///     Подписаться на исторические данные
        /// </summary>
        /// <param name="consumer">
        ///     Потребитель исторических данных
        /// </param>
        /// <param name="instrument">
        ///     Инструмент
        /// </param>
        /// <param name="begin">
        ///     Начало диапазона
        /// </param>
        /// <param name="span">
        ///     Интервал свечей для исторических данных
        /// </param>
        /// <returns>
        ///     Подписка на исторические данные
        /// </returns>
        /// <remarks>
        ///     Провайдер вправе переопределить параметры исторических графиков - диапазон, интервал,
        ///     если он не в состоянии предоставить запрошенные данные.
        /// </remarks>
        public async Task <IHistoryDataSubscription> SubscribeToHistoryDataAsync(
            IHistoryDataConsumer consumer,
            Instrument instrument,
            DateTime begin,
            HistoryProviderSpan span)
        {
            var symbol = await adapter.ResolveSymbolAsync(instrument);

            if (symbol == null)
            {
                consumer.Error($"Unable to resolve symbol for {instrument}");
                return(new NullHistoryDataSubscription());
            }

            QLAdapter.Log.Debug().Print($"Candles subscription: {symbol}, span {span}, from {begin}");
            var subscriptionMessage = new QLHistoryDataSubscription(symbol, begin, span);
            var subscription        =
                new HistoryDataSubscription(subscriptionMessage.id, instrument, begin, span, adapter, consumer);

            using (requestsLock.Lock())
            {
                subscriptions[subscription.Id] = subscription;
            }

            adapter.SendMessage(subscriptionMessage);

            return(subscription);
        }
Esempio n. 2
0
        /// <summary>
        ///     Получить исторические данные
        /// </summary>
        /// <param name="consumer">
        ///     Потребитель исторических данных
        /// </param>
        /// <param name="instrument">
        ///     Инструмент
        /// </param>
        /// <param name="begin">
        ///     Начало диапазона
        /// </param>
        /// <param name="end">
        ///     Конец диапазона
        /// </param>
        /// <param name="span">
        ///     Интервал свечей для исторических данных
        /// </param>
        /// <param name="cancellationToken">
        ///     Токен отмены
        /// </param>
        /// <returns>
        ///     Исторические данные
        /// </returns>
        /// <remarks>
        ///     Провайдер вправе переопределить параметры исторических графиков - диапазон, интервал,
        ///     если он не в состоянии предоставить запрошенные данные.
        /// </remarks>
        /// <exception cref="NoHistoryDataException">
        ///     Бросается, если исторические данные за указанный период недоступны
        /// </exception>
        public async Task GetHistoryDataAsync(
            IHistoryDataConsumer consumer,
            Instrument instrument,
            DateTime begin,
            DateTime end,
            HistoryProviderSpan span,
            CancellationToken cancellationToken = new CancellationToken())
        {
            var symbol = await adapter.ResolveSymbolAsync(instrument);

            if (symbol == null)
            {
                consumer.Error($"Unable to resolve symbol for {instrument}");
                return;
            }

            QLAdapter.Log.Debug().Print($"Candles request: {symbol}, span {span}, from {begin} to {end}");
            var dataRequestMessage = new QLHistoryDataRequest(symbol, span);
            var request            = new HistoryDataRequest(dataRequestMessage.id, instrument, begin, end, span);

            using (requestsLock.Lock())
            {
                requests[request.Id] = request;
            }

            // Поддержка отмены запроса
            cancellationToken.RegisterSafe(() => request.TrySetCanceled());

            adapter.SendMessage(dataRequestMessage);

            var data = await request.Task;

            QLAdapter.Log.Debug().Print("Push candles to consumer. ", LogFields.RequestId(request.Id));
            consumer.Update(data, HistoryDataUpdateType.Batch);
        }
Esempio n. 3
0
        /// <summary>
        ///     Получить исторические данные
        /// </summary>
        /// <param name="consumer">
        ///     Потребитель исторических данных
        /// </param>
        /// <param name="instrument">
        ///     Инструмент
        /// </param>
        /// <param name="begin">
        ///     Начало диапазона
        /// </param>
        /// <param name="end">
        ///     Конец диапазона
        /// </param>
        /// <param name="span">
        ///     Интервал свечей для исторических данных
        /// </param>
        /// <param name="cancellationToken">
        ///     Токен отмены
        /// </param>
        /// <returns>
        ///     Исторические данные
        /// </returns>
        /// <remarks>
        ///     Провайдер вправе переопределить параметры исторических графиков - диапазон, интервал,
        ///     если он не в состоянии предоставить запрошенные данные.
        /// </remarks>
        /// <exception cref="NoHistoryDataException">
        ///     Бросается, если исторические данные за указанный период недоступны
        /// </exception>
        public async Task GetHistoryDataAsync(
            IHistoryDataConsumer consumer,
            Instrument instrument,
            DateTime begin,
            DateTime end,
            HistoryProviderSpan span,
            CancellationToken cancellationToken = new CancellationToken())
        {
            using (LogManager.Scope())
            {
                var instrumentData = await instrumentConverter.ResolveInstrumentAsync(this, instrument);

                if (instrumentData == null)
                {
                    consumer.Error($"Unable to resolve symbol for {instrument}");
                    return;
                }

                // Выгружаем список точек
                var points = await FetchHistoryDataAsync(instrumentData.Symbol, begin, end, span, cancellationToken);

                // Собираем результат
                var data = new HistoryData(instrument, begin, end, span);
                foreach (var p in points.OrderBy(_ => _.Point))
                {
                    data.Points.Add(p);
                }

                // Передаем результат потребителю
                consumer.Update(data, HistoryDataUpdateType.Batch);
            }
        }
Esempio n. 4
0
        /// <summary>
        ///     Подписаться на исторические данные
        /// </summary>
        /// <param name="consumer">
        ///     Потребитель исторических данных
        /// </param>
        /// <param name="instrument">
        ///     Инструмент
        /// </param>
        /// <param name="begin">
        ///     Начало диапазона
        /// </param>
        /// <param name="span">
        ///     Интервал свечей для исторических данных
        /// </param>
        /// <returns>
        ///     Подписка на исторические данные
        /// </returns>
        /// <remarks>
        ///     Провайдер вправе переопределить параметры исторических графиков - диапазон, интервал,
        ///     если он не в состоянии предоставить запрошенные данные.
        /// </remarks>
        public async Task <IHistoryDataSubscription> SubscribeToHistoryDataAsync(
            IHistoryDataConsumer consumer,
            Instrument instrument,
            DateTime begin,
            HistoryProviderSpan span)
        {
            var instrumentData = await instrumentConverter.ResolveInstrumentAsync(this, instrument);

            if (instrumentData == null)
            {
                consumer.Error($"Unable to resolve symbol for {instrument}");
                return(new NullHistoryDataSubscription());
            }

            // Создаем подписку
            var subscription = new HistorySubscription(this, consumer, instrument, instrumentData.Symbol, span);

            subscription.StartFetch(begin);
            return(subscription);
        }
Esempio n. 5
0
 private void HandleException(Exception exception, string message)
 {
     consumer.Error(message);
     _Log.Error().Print(exception, $"History data subscription failed: {message.Preformatted()}");
     Dispose();
 }
Esempio n. 6
0
        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;
            }
        }