Ejemplo n.º 1
0
        //This event is raised when real time data arrives
        //We convert them and pass them on downstream
        private void _client_RealTimeBar(object sender, RealTimeBarEventArgs e)
        {
            RealTimeDataEventArgs args = TWSUtils.RealTimeDataEventArgsConverter(e);
            var originalRequest        = _realTimeDataRequests[e.RequestId];

            args.InstrumentID = originalRequest.Instrument.ID.Value;
            args.RequestID    = _requestIDMap[e.RequestId];
            RaiseEvent(DataReceived, this, args);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// This event is raised when historical data arrives from TWS
        /// </summary>
        private void _client_HistoricalData(object sender, Krs.Ats.IBNet.HistoricalDataEventArgs e)
        {
            //convert the bar and add it to the Dictionary of arrived data
            var bar = TWSUtils.HistoricalDataEventArgsToOHLCBar(e);
            int id;

            lock (_subReqMapLock)
            {
                //if the data is arriving for a sub-request, we must get the id of the original request first
                //otherwise it's just the same id
                id = _subRequestIDMap.ContainsKey(e.RequestId)
                    ? _subRequestIDMap[e.RequestId]
                    : e.RequestId;
            }

            //stocks need to have their volumes multiplied by 100, I think all other instrument types do not
            if (_historicalDataRequests[id].Instrument.Type == InstrumentType.Stock)
            {
                bar.Volume *= 100;
            }

            _arrivedHistoricalData[id].Add(bar);

            if (e.RecordNumber >= e.RecordTotal - 1) //this was the last item to receive for this request, send it to the broker
            {
                bool requestComplete = true;

                lock (_subReqMapLock)
                {
                    if (_subRequestIDMap.ContainsKey(e.RequestId))
                    {
                        _subRequestIDMap.Remove(e.RequestId);
                        _subRequestCount[id]--;
                        if (_subRequestCount[id] > 0)
                        {
                            //What happens here: this is a subrequest.
                            //We check how many sub-requests in this group have been delivered.
                            //if this is the last one, we want to call HistoricalDataRequestComplete()
                            //otherwise there's more data to come, so we have to wait for it
                            requestComplete = false;
                        }
                        else
                        {
                            //if it is complete, we'll need to sort the data because subrequests may not come in in order
                            _arrivedHistoricalData[id] = _arrivedHistoricalData[id].OrderBy(x => x.DTOpen).ToList();
                        }
                    }
                }

                if (requestComplete)
                {
                    HistoricalDataRequestComplete(id);
                }
            }
        }
Ejemplo n.º 3
0
Archivo: IB.cs Proyecto: herbota/QDMS
        private void _client_HistoricalDataUpdate(object sender, QDMSIBClient.HistoricalDataEventArgs e)
        {
            if (e.Bar.Volume < 0)
            {
                return;
            }

            var originalRequest = _realTimeDataRequests[e.RequestId];
            var args            = TWSUtils.HistoricalDataEventArgsToRealTimeDataEventArgs(e, originalRequest.Instrument.ID.Value, _requestIDMap[e.RequestId]);

            RaiseEvent(DataReceived, this, args);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// This event is raised in the case of some error
        /// This includes pacing violations, in which case we re-enqueue the request.
        /// </summary>
        private void _client_Error(object sender, ErrorEventArgs e)
        {
            //if we asked for too much real time data at once, we need to re-queue the failed request
            if ((int)e.ErrorCode == 420) //a real time pacing violation
            {
                HandleRealTimePacingViolationError(e);
            }
            else if ((int)e.ErrorCode == 162) //a historical data pacing violation
            {
                HandleHistoricalDataPacingViolationError(e);
            }
            else if ((int)e.ErrorCode == 200) //No security definition has been found for the request.
            {
                HandleNoSecurityDefinitionError(e);
            }

            //different messages depending on the type of request
            var errorArgs = TWSUtils.ConvertErrorArguments(e);
            HistoricalDataRequest histReq;
            RealTimeDataRequest   rtReq;
            var isHistorical = _historicalDataRequests.TryGetValue(e.TickerId, out histReq);

            if (isHistorical)
            {
                int origId = _subRequestIDMap.ContainsKey(histReq.RequestID)
                    ? _subRequestIDMap[histReq.RequestID]
                    : histReq.RequestID;

                errorArgs.ErrorMessage += string.Format(" Historical Req: {0} @ {1} From {2} To {3} - TickerId: {4}  ReqID: {5}",
                                                        histReq.Instrument.Symbol,
                                                        histReq.Frequency,
                                                        histReq.StartingDate,
                                                        histReq.EndingDate,
                                                        e.TickerId,
                                                        histReq.RequestID);

                errorArgs.RequestID = origId;
            }
            else if (_realTimeDataRequests.TryGetValue(e.TickerId, out rtReq)) //it's a real time request
            {
                errorArgs.ErrorMessage += string.Format(" RT Req: {0} @ {1}",
                                                        rtReq.Instrument.Symbol,
                                                        rtReq.Frequency);

                errorArgs.RequestID = rtReq.RequestID;
            }

            RaiseEvent(Error, this, errorArgs);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// This event is raised when historical data arrives from TWS
        /// </summary>
        private void _client_HistoricalData(object sender, Krs.Ats.IBNet.HistoricalDataEventArgs e)
        {
            //convert the bar and add it to the Dictionary of arrived data
            var bar = TWSUtils.HistoricalDataEventArgsToOHLCBar(e);
            int id;

            lock (_subReqMapLock)
            {
                //if the data is arriving for a sub-request, we must get the id of the original request first
                //otherwise it's just the same id
                id = _subRequestIDMap.ContainsKey(e.RequestId)
                    ? _subRequestIDMap[e.RequestId]
                    : e.RequestId;
            }

            //stocks need to have their volumes multiplied by 100, I think all other instrument types do not
            if (_historicalDataRequests[id].Instrument.Type == InstrumentType.Stock)
            {
                bar.Volume *= 100;
            }

            _arrivedHistoricalData[id].Add(bar);

            if (e.RecordNumber >= e.RecordTotal - 1) //this was the last item to receive for this request, send it to the broker
            {
                bool requestComplete = true;

                lock (_subReqMapLock)
                {
                    if (_subRequestIDMap.ContainsKey(e.RequestId))
                    {
                        //If there are sub-requests, here we check if this is the last one
                        requestComplete = ControlSubRequest(e.RequestId);

                        if (requestComplete)
                        {
                            //If it was the last one, we need to order the data because sub-requests can arrive out of order
                            _arrivedHistoricalData[id] = _arrivedHistoricalData[id].OrderBy(x => x.DTOpen).ToList();
                        }
                    }
                }

                if (requestComplete)
                {
                    HistoricalDataRequestComplete(id);
                }
            }
        }
Ejemplo n.º 6
0
Archivo: IB.cs Proyecto: herbota/QDMS
        /// <summary>
        /// real time data request
        /// </summary>
        public void RequestRealTimeData(RealTimeDataRequest request)
        {
            var id = _requestCounter++;

            lock (_requestIDMapLock)
            {
                _realTimeDataRequests.Add(id, request);
                _requestIDMap.Add(id, request.AssignedID);
                if (_reverseRequestIDMap.ContainsKey(request.AssignedID))
                {
                    _reverseRequestIDMap[request.AssignedID] = id;
                }
                else
                {
                    _reverseRequestIDMap.Add(request.AssignedID, id);
                }
            }

            try
            {
                Contract contract = TWSUtils.InstrumentToContract(request.Instrument);

                if (_ibUseNewRealTimeDataSystem)
                {
                    //the new system uses the historical data update endpoint instead of realtime data
                    _client.RequestHistoricalData(id, contract, "",
                                                  "60 S", QDMSIBClient.BarSize.FiveSeconds, HistoricalDataType.Trades, request.RTHOnly, true);

                    //todo: write test
                }
                else
                {
                    _client.RequestRealTimeBars(
                        id,
                        contract,
                        "TRADES",
                        request.RTHOnly);
                }
            }
            catch (Exception ex)
            {
                Log(LogLevel.Error, "IB: Could not send real time data request: " + ex.Message);
                RaiseEvent(Error, this, new ErrorArgs(-1, "Could not send real time data request: " + ex.Message));
            }
        }
Ejemplo n.º 7
0
        public void HistoricalRequestsAreNotSplitIfNotNecessary()
        {
            int[] requestCount = { 0 };

            _ibClientMock.Setup(
                x => x.RequestHistoricalData(
                    It.IsAny <int>(),
                    It.IsAny <Contract>(),
                    It.IsAny <DateTime>(),
                    It.IsAny <string>(),
                    It.IsAny <BarSize>(),
                    It.IsAny <HistoricalDataType>(),
                    It.IsAny <int>(),
                    It.IsAny <List <TagValue> >()))
            .Callback(() => requestCount[0]++);

            var requests = new Dictionary <KeyValuePair <BarSize, int>, int> //left side is barsize/seconds, right side is expected splits
            {
                { new KeyValuePair <BarSize, int>(BarSize.OneDay, 300 * 24 * 3600), 1 },
                { new KeyValuePair <BarSize, int>(BarSize.OneHour, 25 * 24 * 3600), 1 },
                { new KeyValuePair <BarSize, int>(BarSize.ThirtyMinutes, 6 * 24 * 3600), 1 },
                { new KeyValuePair <BarSize, int>(BarSize.OneMinute, 1 * 24 * 3600), 1 },
                { new KeyValuePair <BarSize, int>(BarSize.ThirtySeconds, 21 * 3600), 1 },
                { new KeyValuePair <BarSize, int>(BarSize.FifteenSeconds, 13400), 1 },
                { new KeyValuePair <BarSize, int>(BarSize.FiveSeconds, 6900), 1 },
                { new KeyValuePair <BarSize, int>(BarSize.OneSecond, 1500), 1 }
            };

            var inst = new Instrument();

            foreach (var kvp in requests)
            {
                _ibDatasource.RequestHistoricalData(new HistoricalDataRequest(
                                                        inst,
                                                        TWSUtils.BarSizeConverter(kvp.Key.Key),
                                                        DateTime.Now.AddSeconds(-kvp.Key.Value),
                                                        DateTime.Now,
                                                        dataLocation: DataLocation.ExternalOnly));

                Assert.AreEqual(kvp.Value, requestCount[0], kvp.Key.Key.ToString());
                requestCount[0] = 0;
            }
        }
Ejemplo n.º 8
0
        public void HistoricalRequestsAreSplitToRespectRequestLimits()
        {
            int[] requestCount = { 0 };

            _ibClientMock.Setup(x => x.RequestHistoricalData(
                                    It.IsAny <int>(),
                                    It.IsAny <Contract>(),
                                    It.IsAny <string>(),
                                    It.IsAny <string>(),
                                    It.IsAny <QDMSIBClient.BarSize>(),
                                    It.IsAny <HistoricalDataType>(),
                                    It.IsAny <bool>(),
                                    It.IsAny <bool>(),
                                    It.IsAny <List <TagValue> >()))
            .Callback(() => requestCount[0]++);

            var requests = new Dictionary <KeyValuePair <BarSize, int>, int> //left side is barsize/seconds, right side is expected splits
            {
                { new KeyValuePair <BarSize, int>(BarSize.OneDay, 500 * 24 * 3600), 2 },
                { new KeyValuePair <BarSize, int>(BarSize.OneHour, 75 * 24 * 3600), 3 },
                { new KeyValuePair <BarSize, int>(BarSize.ThirtyMinutes, 22 * 24 * 3600), 4 },
                { new KeyValuePair <BarSize, int>(BarSize.OneMinute, 9 * 24 * 3600), 5 },
                { new KeyValuePair <BarSize, int>(BarSize.ThirtySeconds, 40 * 3600), 2 },
                { new KeyValuePair <BarSize, int>(BarSize.FifteenSeconds, 4 * 14400), 5 },
                { new KeyValuePair <BarSize, int>(BarSize.FiveSeconds, 2 * 7200), 3 },
                { new KeyValuePair <BarSize, int>(BarSize.OneSecond, 10 * 1800), 11 }
            };

            var inst = new Instrument();

            foreach (var kvp in requests)
            {
                _ibDatasource.RequestHistoricalData(new HistoricalDataRequest(
                                                        inst,
                                                        TWSUtils.BarSizeConverter(kvp.Key.Key),
                                                        DateTime.Now.AddSeconds(-kvp.Key.Value),
                                                        DateTime.Now,
                                                        dataLocation: DataLocation.ExternalOnly));

                Assert.AreEqual(kvp.Value, requestCount[0], kvp.Key.Key.ToString());
                requestCount[0] = 0;
            }
        }
Ejemplo n.º 9
0
        private void SendContractDetailsRequest(string symbol)
        {
            var contract = new Contract
            {
                Symbol         = symbol,
                SecurityType   = TWSUtils.SecurityTypeConverter(SelectedType),
                Exchange       = SelectedExchange == "All" ? "" : SelectedExchange,
                IncludeExpired = IncludeExpired,
                Currency       = Currency
            };

            if (ExpirationDate.HasValue)
            {
                contract.Expiry = ExpirationDate.Value.ToString("yyyyMM");
            }

            if (Strike.HasValue)
            {
                contract.Strike = Strike.Value;
            }

            SearchUnderway = true; //disables the search commands
            _client.RequestContractDetails(_nextRequestID, contract);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Splits a historical data request into multiple pieces so that they obey the request limits
        /// </summary>
        private List <HistoricalDataRequest> SplitRequest(HistoricalDataRequest request)
        {
            var requests = new List <HistoricalDataRequest>();

            //start at the end, and work backward in increments slightly lower than the max allowed time
            int      step        = (int)(TWSUtils.MaxRequestLength(request.Frequency) * .95);
            DateTime currentDate = request.EndingDate;

            while (currentDate > request.StartingDate)
            {
                var newReq = (HistoricalDataRequest)request.Clone();
                newReq.EndingDate   = currentDate;
                newReq.StartingDate = newReq.EndingDate.AddSeconds(-step);
                if (newReq.StartingDate < request.StartingDate)
                {
                    newReq.StartingDate = request.StartingDate;
                }

                currentDate = currentDate.AddSeconds(-step);
                requests.Add(newReq);
            }

            return(requests);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// historical data request
        /// </summary>
        public void RequestHistoricalData(HistoricalDataRequest request)
        {
            //Historical data limitations: https://www.interactivebrokers.com/en/software/api/apiguide/api/historical_data_limitations.htm
            //the issue here is that the request may not be fulfilled...so we need to keep track of the request
            //and if we get an error regarding its failure, send it again using a timer
            int originalReqID = ++_requestCounter;

            _historicalDataRequests.TryAdd(originalReqID, request);

            _arrivedHistoricalData.TryAdd(originalReqID, new List <OHLCBar>());

            //if necessary, chop up the request into multiple chunks so as to abide
            //the historical data limitations
            if (TWSUtils.RequestObeysLimits(request))
            {
                //send the request, no need for subrequests
                SendHistoricalRequest(originalReqID, request);
            }
            else
            {
                //create subrequests, add them to the ID map, and send them to TWS
                var subRequests = SplitRequest(request);
                _subRequestCount.Add(originalReqID, subRequests.Count);

                foreach (HistoricalDataRequest subReq in subRequests)
                {
                    lock (_subReqMapLock)
                    {
                        _requestCounter++;
                        _historicalDataRequests.TryAdd(_requestCounter, subReq);
                        _subRequestIDMap.Add(_requestCounter, originalReqID);
                        SendHistoricalRequest(_requestCounter, subReq);
                    }
                }
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// This event is raised in the case of some error
        /// This includes pacing violations, in which case we re-enqueue the request.
        /// </summary>
        private void _client_Error(object sender, ErrorEventArgs e)
        {
            //if we asked for too much real time data at once, we need to re-queue the failed request
            if ((int)e.ErrorCode == 420) //a real time pacing violation
            {
                lock (_queueLock)
                {
                    if (!_realTimeRequestQueue.Contains(e.TickerId))
                    {
                        //since the request did not succeed, what we do is re-queue it and it gets requested again by the timer
                        _realTimeRequestQueue.Enqueue(e.TickerId);
                    }
                }
            }
            else if ((int)e.ErrorCode == 162) //a historical data pacing violation
            {
                //turns out that more than one error uses the same error code! What were they thinking?
                if (e.ErrorMsg.StartsWith("Historical Market Data Service error message:HMDS query returned no data"))
                {
                    //no data returned = we return an empty data set
                    RaiseEvent(HistoricalDataArrived, this, new QDMS.HistoricalDataEventArgs(
                                   _historicalDataRequests[e.TickerId],
                                   new List <OHLCBar>()));
                }
                else if (e.ErrorMsg.StartsWith("Historical Market Data Service error message:No market data permissions"))
                {
                    //We don't have permission to view this data, return an empty data set
                    RaiseEvent(HistoricalDataArrived, this, new QDMS.HistoricalDataEventArgs(
                                   _historicalDataRequests[e.TickerId],
                                   new List <OHLCBar>()));
                }
                else
                {
                    //simply a data pacing violation
                    lock (_queueLock)
                    {
                        if (!_historicalRequestQueue.Contains(e.TickerId))
                        {
                            //same as above
                            _historicalRequestQueue.Enqueue(e.TickerId);
                        }
                    }
                }
            }
            else if ((int)e.ErrorCode == 200) //No security definition has been found for the request.
            {
                //Again multiple errors share the same code...
                if (e.ErrorMsg.Contains("No security definition has been found for the request"))
                {
                    //this will happen for example when asking for data on expired futures
                    //return an empty data list
                    if (_historicalDataRequests.ContainsKey(e.TickerId))
                    {
                        HistoricalDataRequestComplete(e.TickerId);
                    }
                }
                else //in this case we're handling a "Invalid destination exchange specified" error
                {
                    //not sure if there's anything else to do, if it's a real time request it just fails...
                    if (_historicalDataRequests.ContainsKey(e.TickerId))
                    {
                        HistoricalDataRequestComplete(e.TickerId);
                    }
                }
            }

            //different messages depending on the type of request
            var errorArgs = TWSUtils.ConvertErrorArguments(e);
            HistoricalDataRequest histReq;
            RealTimeDataRequest   rtReq;
            var isHistorical = _historicalDataRequests.TryGetValue(e.TickerId, out histReq);

            if (isHistorical)
            {
                errorArgs.ErrorMessage += string.Format(" Historical Req: {0} @ {1} From {2} To {3} - ID {4}",
                                                        histReq.Instrument.Symbol,
                                                        histReq.Frequency,
                                                        histReq.StartingDate,
                                                        histReq.EndingDate,
                                                        histReq.RequestID);
            }
            else if (_realTimeDataRequests.TryGetValue(e.TickerId, out rtReq)) //it's a real time request
            {
                errorArgs.ErrorMessage += string.Format(" RT Req: {0} @ {1}",
                                                        rtReq.Instrument.Symbol,
                                                        rtReq.Frequency);
            }

            RaiseEvent(Error, this, errorArgs);
        }