Пример #1
0
        internal async Task <IList <HistoryDataPoint> > FetchHistoryDataBlock(
            IHistoryDataConsumer consumer,
            Contract contract,
            DateTime begin,
            DateTime end,
            HistoryProviderSpan span,
            CancellationToken cancellationToken = new CancellationToken())
        {
            // Формируем параметры запроса
            ApplyHistoryDataLimits(span, ref begin, ref end);

            // Ждем, чтобы не превысить лимиты по частоте запросов
            var request = new IBHistoricalDataRequest(
                this,
                consumer,
                contract: contract,
                begin: begin,
                end: end,
                span: span,
                whatToShow: "TRADES",
                useRth: 1,
                formatDate: 1
                );

            // Отправляем запрос
            var points = await request.ExecuteAsync(cancellationToken).ConfigureAwait(false);

            return(points);
        }
Пример #2
0
 public bool Equals(IBHistoricalDataRequest other)
 {
     return(contract == other.contract &&
            begin == other.begin &&
            end == other.end &&
            span == other.span &&
            string.Equals(whatToShow, other.whatToShow) &&
            useRth == other.useRth &&
            formatDate == other.formatDate);
 }
Пример #3
0
        // Pacing Violations
        // =================
        //
        // All of the API technologies support historical data requests.
        // However, requesting the same historical data in a short period of time can cause extra load on the backend and subsequently cause pacing violations.
        // The error code and message that indicates a pacing violation is:
        //  * 162 - Historical Market Data Service error message: Historical data request pacing violation
        //
        // The following conditions can cause a pacing violation:
        //  * Making identical historical data requests within 15 seconds;
        //  * Making six or more historical data requests for the same Contract, Exchange and Tick Type within two seconds.
        //
        // Also, observe the following limitation when requesting historical data:
        //  * Do not make more than 60 historical data requests in any ten-minute period.
        //  * If the whatToShow parameter in reqHistoricalData() is set to BID_ASK, then this counts as two requests and we will call BID and ASK historical data separately.

        public async Task WaitForPaceLimitAsync(IBHistoricalDataRequest request,
                                                CancellationToken cancellationToken = default(CancellationToken))
        {
            var waitTime = ComputeEffectiveWaitTime(DateTime.UtcNow, request);

            if (waitTime > 0)
            {
                const int LongEnough = 5 * 1000; // 5 sec

                if (waitTime >= LongEnough)
                {
                    IBAdapter.Log.Warn().PrintFormat("Will wait for history data for {0}s due to pace limits",
                                                     waitTime / 1000);
                }
                else
                {
                    IBAdapter.Log.Debug().PrintFormat("Pace limit wait time: {0}ms", waitTime);
                }

                await Task.Delay(waitTime, cancellationToken);
            }
        }
Пример #4
0
        private double GetWaitTimeByContract(DateTime now, IBHistoricalDataRequest request)
        {
            // Не более 3 запросов за 2 секунды
            const double MinRequestRate = 2d / 3d;

            DateTime lastRequestTime;

            if (!lastRequestTimesByContract.TryGetValue(request.ContractId, out lastRequestTime))
            {
                return(0d);
            }

            var delta = (now - lastRequestTime).TotalSeconds;

            delta = MinRequestRate - delta;

            if (delta <= 0)
            {
                return(0d);
            }

            return(delta);
        }
Пример #5
0
        private int ComputeEffectiveWaitTime(DateTime now, IBHistoricalDataRequest request)
        {
            var key = request.Key;

            using (lastRequestTimesLock.Lock())
            {
                // Ограничение 1 - не более 2.5 запросов в секунду по одному и тому же инструменту
                var waitTimeByContract = GetWaitTimeByContract(now, request);

                // Ограничение 2 - идентичные запросы должны идти не чаще, чем 1 раз в 15 секунд
                var waitTimeByRequestParameters = GetWaitTimeByRequestParameters(now, key);

                // Ограничение 3 - не более 60 запросов за 10 минут
                var waitTimeByTotalRequestCount = GetWaitTimeByTotalRequestCount(now);

                // Берем наибольшее время ожидания
                var waitTime = Math.Max(waitTimeByContract, waitTimeByRequestParameters);
                waitTime = Math.Max(waitTime, waitTimeByTotalRequestCount);

                // Переводим в миллисекунды
                var waitTimeMs = (int)Math.Ceiling(waitTime * 1000d);
                if (waitTimeMs <= 0)
                {
                    waitTimeMs = 0;
                }

                // Сразу же запоминаем время данного запроса с учетом ожидания
                // Это поможет в случае параллельных запросов
                var future = now.AddMilliseconds(waitTimeMs);

                lastRequestTimesByContract[request.ContractId] = future;
                lastRequestTimesByRequestParameters[key]       = future;
                allRequestTimes.Push(future);

                return(waitTimeMs);
            }
        }
Пример #6
0
 public HistoryTaskCompletionSource(IBHistoricalDataRequest request, CancellationToken cancellationToken)
 {
     this.request           = request;
     this.cancellationToken = cancellationToken;
     cancellationToken.RegisterSafe(() => TrySetCanceled());
 }