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); }
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); }
// 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); } }
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); }
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); } }
public HistoryTaskCompletionSource(IBHistoricalDataRequest request, CancellationToken cancellationToken) { this.request = request; this.cancellationToken = cancellationToken; cancellationToken.RegisterSafe(() => TrySetCanceled()); }