question

Upvotes
Accepted
36 1 3 5

Disconnect from DataServices.Instance

Hello,

I just recently taught myself to code, so please bear with me. I created a plug-in to a 3rd party app that pulls time-series data from the Eikon API. It works successfully when I first attempt to retrieve data. On a subsequent attempt, it seems to get hung up on the request. The request is an ITimeSeriesDataRequest.

My theory is that the application stays "connected" or "initiated" to the DataServices.Instance and DataServices.Instance.TimeSeries, and for some reason when I try to initiate a second request, something goes wrong.

I believe this can be solved if I can somehow disconnect/reset from the IDataServices and ITimeSeriesDataService objects. That way, when I run the second request, the entire process starts fresh with a new initialization. Is there a way to do this?

Thank you,

Steven

eikoneikon-com-apidisconnection
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

@StevenH unless you receive a StatusChange event from DataServices.Instance that says that the service went down, everything should be good.

Could you share more details on what you are trying to achieve? E.g.

  • project type;
  • name of the third-party software;
  • a sample of the request.

the .NET API is coupled with a COM event loop, so I suspect there might be an issue there.

Thank you Zhenya- more details (and some code) are in the reply below. I believe the real issue is that the subsequent data request is not receiving any data, so the DataReceivedCallback method is never entered. This prevents the DispatcherFrame's "Continue" being set to false, as the StopMessagePump() method which does that is never reached. I checked the States of the IDataServices and ITimeSeriesDataService objects, and they are both connected/up and running. For some reason though, the SetupDataRequest is not receiving any data on a second run though..

Steve, would you please drop me an email about this, as I do not have your contact details. We can schedule a support session, and I will try to figure out what might be the reason for this.

my address is evgenij.kovalev(at)tr.com

Upvotes
Accepted
45.2k 103 43 60

I have modified the code to use in the console application. From my test, the application can run properly. Please the attached code and output file.

output.txt, programcs.txt


output.txt (5.9 KiB)
programcs.txt (4.6 KiB)
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Thank you again, and it works for me as well. My code works as well in the 3rd party app- the issue is the second time I click the button in the 3rd party app's GUI that calls the RetreiveData() method. That's when it hangs up at this code:

        public void Launch(string RIC, DateTime startDate)
        {
            request = timeSeries.SetupDataRequest(RIC)
            .WithView("BID")
            .WithAllFields()
            .WithInterval(CommonInterval.Daily)
            .From(startDate)
            .OnDataReceived(DataReceivedCallback)
            .CreateAndSend();
        }
Upvotes
36 1 3 5

The part where it gets hung up is on a subsequent request (as below). The software is called RightEdge (rightedgesystems.com). Let me know if there's something else I can provide, and thank you in advance!

        public void Launch(string symbol)
        {
            request = timeSeries.SetupDataRequest(symbol)
            .WithView("BID")
            .WithAllFields()
            .WithInterval(CommonInterval.Daily)
            .WithNumberOfPoints(10)
            .OnDataReceived(DataReceivedCallback)
            .CreateAndSend();
        }
        public void DataReceivedCallback(DataChunk chunk)
        {
            foreach (IBarData bar in chunk.Records.ToBarRecords())
            {
                if (bar.Open.HasValue && bar.High.HasValue && bar.Low.HasValue && bar.Close.HasValue && bar.Timestamp.HasValue)
                {
                    Common.BarData reBar = new Common.BarData();
                    reBar.BarStartTime = bar.Timestamp.Value;
                    reBar.Open = bar.Open.Value;
                    reBar.High = bar.High.Value;
                    reBar.Low = bar.Low.Value;
                    reBar.Close = bar.Close.Value;
                    if (bar.Volume.HasValue)
                    {
                        reBar.Volume = Convert.ToUInt64(bar.Volume.Value);
                    }
                    ReutersRetrieval.bars.Add(reBar);
                }
            }
            if (!chunk.IsLast) return;
            request = null;
            ReutersRetrieval.StopMessagePump();
        }
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

You should call OnStatusUpdated() to register the status callback. If there is a problem, it may be notified via the status callback.

Moreover, please provide the code in StartMessagePump() and StopMessagePump().

Thank you, I included all of the relevant code in the post below (including the DispatcherFrame related stuff). I just added this as well, but it doesn't seem to ever be called:

        public static IRequestStatus requestStatus;

        public void StatusUpdatedCallback(IRequestStatus iRequestStatus)
        {
            requestStatus = iRequestStatus;
            MessageBox.Show(iRequestStatus.State.ToString());
        }
Upvotes
36 1 3 5

To completely clarify- here is the entire code that is relevant.

When I first click the button in the app to retrieve data, this is called:

                InitReuters.InitializeDataServices("RightEdge");

Here is the entire InitReuters class:

    public class InitReuters
    {
        public static IDataServices Services { get; set; }

        public static void InitializeDataServices(string appName)
        {
            Services = DataServices.Instance;
            Services.StateChanged += ServicesOnStateChanged;

            Services.Initialize(appName);
            InitializeTimeSeries();
        }

        private static void ServicesOnStateChanged(object sender, DataServicesStateChangedEventArgs dataServicesStateChangedEventArgs)
        {
            //
        }

        public static ITimeSeriesDataService timeSeries;

        private static void InitializeTimeSeries()
        {
            timeSeries = DataServices.Instance.TimeSeries;
            timeSeries.ServiceInformationChanged += timeSeries_ServiceInformationChanged;
        }

        private static void timeSeries_ServiceInformationChanged(object sender, ServiceInformationChangedEventArgs e)
        {
            Debug.Print("{0}: {1}", e.Information.State, e.Information.Message);
        }
    }

Then the code will run through the actual retrieval portion, which is the RetrieveData method below:

        public static DispatcherFrame Frame;

        public static void StopMessagePump()
        {
            Frame.Continue = false;
        }

        public static List<Common.BarData> bars;

        public List<Common.BarData> RetrieveData(Symbol symbol, int frequency, DateTime startDate, DateTime endDate, BarConstructionType barConstruction)
        {
            if (frequency != (int)BarFrequency.Daily)
            {
                return new List<Common.BarData>();
            }

            if (startDate == DateTime.MinValue)
            {
                startDate = new DateTime(1900, 1, 2);
            }

            if (endDate == DateTime.MaxValue)
            {
                endDate = DateTime.Now;
            }

            string RIC = symbol.SymbolInformation.CustomHistoricalData;

            bars = new List<Common.BarData>();

            Frame = new DispatcherFrame();
            (new TSRequest(InitReuters.timeSeries)).Launch(RIC, startDate);
            Dispatcher.PushFrame(Frame);
            Frame = null;
            return bars;
        }

.. and here is the TSRequest class that contains the actual code for requesting the data:

    public class TSRequest
    {
        public ITimeSeriesDataService timeSeries;
        public static ITimeSeriesDataRequest request;

        public TSRequest(ITimeSeriesDataService timeSeries)
        {
            this.timeSeries = timeSeries;
        }

        public void Launch(string RIC, DateTime startDate)
        {
            request = timeSeries.SetupDataRequest(RIC)
            .WithView("BID")
            .WithAllFields()
            .WithInterval(CommonInterval.Daily)
            .From(startDate)
            .OnDataReceived(DataReceivedCallback)
            .CreateAndSend();
        }

        public void DataReceivedCallback(DataChunk chunk)
        {
            foreach (IBarData bar in chunk.Records.ToBarRecords())
            {
                if (bar.Open.HasValue && bar.High.HasValue && bar.Low.HasValue && bar.Close.HasValue && bar.Timestamp.HasValue)
                {
                    Common.BarData reBar = new Common.BarData();
                    reBar.BarStartTime = bar.Timestamp.Value;
                    reBar.Open = bar.Open.Value;
                    reBar.High = bar.High.Value;
                    reBar.Low = bar.Low.Value;
                    reBar.Close = bar.Close.Value;
                    if (bar.Volume.HasValue)
                    {
                        reBar.Volume = Convert.ToUInt64(bar.Volume.Value);
                    }
                    ReutersRetrieval.bars.Add(reBar);
                }
            }
            if (!chunk.IsLast) return;

            request = null;
            ReutersRetrieval.StopMessagePump();
        }
    }
icon clock
10 |1500

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

i have noticed two things:

1. i was under the impression that you are using a console application, hence the message pump routine is required. If you are building a wpf or a informs application, you should be good;

2. The API is async, so it looks like the following call becomes out of scope:

(new TSRequest(InitReuters.timeSeries)).Launch(RIC, startDate);

you can do two things: either keep it in scope by having a class level object or a list that contains your request objects, or convert the ```Launch``` routine into a function that returns a Task.

Thank you again- I'm a little confused by your suggestion. Do you mean the RIC and startDate are out of scope? They are all included in the RetrieveData() method (which is where the Launch is called as well).

Keep in mind that everything here works on the first click of the 3rd party app's button that calls the RetrieveData(), but not on a subsequent click. The Reuter's services remain connected in b/w runs though. So the issue I'm thinking has something to do w/ my use of the DispatcherFrame or the connection somehow going stale but still having a state that is "connected"?