Introduction

This article provides an example of how Eikon .NET SDK can be used in Matlab to retrieve timeseries of price history and to subscribe to streaming market data. This example requires Matlab R2016b or higher only because Matlab R2016b permits one to have functions at the bottom of the script file, which was convenient for the code structure. With the exception of keeping functions in the script file, the techniques used in this example will work in any earlier version of Matlab. In this example we do not use any dependency on the Datafeed Toolbox™, which may present a cost saving opportunity, since Datafeed Toolbox is a chargeable module.

Prerequisites

  • Thomson Reuters Eikon 4.0.27 or later;
  • Matlab R2016b or later;
  • Visual Studio or Nuget (optional);

Installation

Before we begin we need to download Eikon 4 Desktop Data APIs package from NuGet. Depending on the bitness of your Matlab, get 32-bit or 64-bit version of the API. Follow the instructions in the paragraph titled Installing Data API in this tutorial. Note that the bitness of the package must match the bitness of your Matlab. I.e. if you use 64-bit Matlab you need to download from NuGet Eikon 4 Desktop Data APIs (x64) package.

Create a folder for Eikon .NET SDK and copy the following libraries from downloaded package into this folder:

  • Common.Logging.dll
  • EikonPipeDll.dll
  • i18nresource.dll
  • Newtonsoft.Json.dll
  • protobuf-net.dll
  • ThomsonReuters.Desktop.SDK.DataAccess.dll
  • ThomsonReuters.Udap.BusTools.dll
  • ThomsonReuters.Udap.Ipc.Managed.Common.dll
  • ThomsonReuters.Udap.ManagedPS.dll

Where multiple versions of the same library exist in the package pick the version targeted for .NET 4.0 framework. This version is located in lib\net40 folder. If you don't already have version 12 Microsoft C runtime libraries in the PATH you may also need to copy msvcp120.dll and msvcr120.dll into the same folder with all the other libraries. In this example the folder used to store the libraries is C:\Temp\EikonNetSDK\

Create a class to load Eikon .NET SDK assemblies

classdef treikonnet < handle
    properties
        Assembly
        Services
    end
end

Inside this class add a method to load Eikon .NET SDK assemblies and create an instance of Eikon DataServices

methods (Access = 'public')
    function t = treikonnet(eikonsdkpath)
        if exist([eikonsdkpath 'ThomsonReuters.Desktop.SDK.DataAccess.dll'],'file') ~= 2
            error(['Thomson Reuters Eikon .NET SDK not found in the specified folder: ' eikonsdkpath]); 
        end
        t.Assembly{1} = NET.addAssembly([eikonsdkpath 'ThomsonReuters.Desktop.SDK.DataAccess.dll']);
        t.Assembly{2} = NET.addAssembly([eikonsdkpath 'ThomsonReuters.Udap.BusTools.dll']);
        t.Assembly{3} = NET.addAssembly([eikonsdkpath 'ThomsonReuters.Udap.Ipc.Managed.Common.dll']);
        t.Assembly{4} = NET.addAssembly([eikonsdkpath 'ThomsonReuters.Udap.ManagedPS.dll']);
        t.Assembly{5} = NET.addAssembly([eikonsdkpath 'protobuf-net.dll']);
        t.Assembly{6} = NET.addAssembly([eikonsdkpath 'Newtonsoft.Json.dll']);
        t.Services = ThomsonReuters.Desktop.SDK.DataAccess.DataServices.Instance;      
    end
end

Retrieving timeseries

Declare a global variable and assign to it an instance of treikonnet class defined above. The parameter passed to treikonnet method defines the location of Eikon .NET SDK libraries.

global t
t=treikonnet('C:\Temp\EikonNetSDK\');

Then initialize Eikon .NET SDK data retrieval services. The Initialize method below requires application ID string. The value can be any string. If data retrieval services are already initialized SendTimeSeriesRequest function is called immediately. Otherwise the script listens for ServiceInformationChanged event to be raised before calling SendTimeSeriesRequest function.

t.Services.Initialize('MyMatlabEikonTestApp');
timeSeries = t.Services.TimeSeries;
if strcmp(t.Services.State,'Up')
    SendTimeSeriesRequest(timeSeries);
else
    addlistener(timeSeries,'ServiceInformationChanged',@OnTimeSeriesServiceInformationChanged);
end
    
function r = OnTimeSeriesServiceInformationChanged(timeSeries,eventArgs)
disp('TimeSeries ServiceInformationChanged event called');
disp(System.String.Concat('Timeseries service state is ',eventArgs.Information.State));
r = char(eventArgs.Information.State);
if strcmp(r,'Up')
    SendTimeSeriesRequest(timeSeries);
end
end

Finally SendTimeSeriesRequest function below requests 10 most recent data points from default Daily interval for the RIC EUR=, and DataReceivedCallback function processes the data retrieved.

function SendTimeSeriesRequest(timeSeries)
disp('Sending timeseries request');
timeSeriesRequestSetup = timeSeries.SetupDataRequest('EUR=');
timeSeriesRequestSetup.WithView('BID');
timeSeriesRequestSetup.WithInterval(ThomsonReuters.Desktop.SDK.DataAccess.TimeSeries.CommonInterval.Intraday60Minutes);
timeSeriesRequestSetup.WithNumberOfPoints(10);
timeSeriesRequestSetup.OnDataReceived(@DataReceivedCallback);
timeSeriesRequestSetup.CreateAndSend();
end
    
function r = DataReceivedCallback(chunk)
% The data is returned in chunks. IsLast property of the chunk
% object indicates if data retrieval is complete or if more data is
% expected to be retrieved.
disp(System.String.Concat('RIC: ',chunk.Ric));
disp(System.String.Concat('Is this the last chunk: ',chunk.IsLast));
records = chunk.Records.GetEnumerator();
timeSeriesDataOutput = {};
k=1;
while records.MoveNext()
    bar = records.Current.ToBarRecord();
    ts = char(records.Current.Timestamp.ToString());
    timeSeriesDataOutput(k,1:5) = {ts,bar.Open.Value,...
        bar.High.Value,bar.Low.Value,bar.Close.Value};
    k=k+1;
end
disp(timeSeriesDataOutput);
end

Subscribing to streaming market data

As in the timeseries retrieval example, start by declaring a global variable and assigning to it an instance of treikonnet class.

global t
t=treikonnet('C:\Temp\EikonNetSDK\');

Then initialize Eikon .NET SDK data retrieval services. The Initialize method below requires application ID string. The value can be any string. If data retrieval services are already initialized StartRealTimeSubscriptions function is called immediately. Otherwise the script listens for ServiceInformationChanged event to be raised before calling StartRealTimeSubscriptions function.

t.Services.Initialize('MyMatlabEikonTestApp');
realTimeService = t.Services.Realtime;
if strcmp(t.Services.State,'Up')
    StartRealTimeSubscriptions(realTimeService);
else
    addlistener(realTimeService,'ServiceInformationChanged',@OnRealTimeServiceInformationChanged);
end
    
function r = OnRealTimeServiceInformationChanged(realTimeService,eventArgs)
disp('RealTime ServiceInformationChanged event called');
disp(System.String.Concat('RealTime service state is ',eventArgs.Information.State));
r = char(eventArgs.Information.State);
if strcmp(r,'Up')
    StartRealTimeSubscriptions(realTimeService);
end
end

StartRealTimeSubscriptions function below creates real-time data subscription for a couple of RICs. Note that realTimeSub variable holding the subscription is declared as persistent. This is to ensure the lifetime of the subscription goes beyond the run time of StartRealTimeSubscriptions function and subscription object remains in memory. Otherwise Matlab will drop the reference to the subscription as soon as StartRealTimeSubscriptions function exits, although in a quick test you may not notice it because you will continue to receive real-time data updates until the .NET garbage collector picks up the subscription object. It is quite likely that, if realTimeSub variable is not declared as persistent, upon running the module in this example you will see real-time data update events raised for a few minutes and then stop.

function StartRealTimeSubscriptions(realTimeService)
disp('Starting real-time subscriptions');
ricList = NET.createGeneric('System.Collections.Generic.List',{'System.String'});
ricList.Add('EUR=');
ricList.Add('GBP=');
realTimeSubSetup = realTimeService.SetupDataSubscription(ricList);
fieldList = NET.createGeneric('System.Collections.Generic.List',{'System.String'});
fieldList.Add('BID');
fieldList.Add('ASK');
realTimeSubSetup.WithFields(fieldList);
realTimeSubSetup.OnDataUpdated(@RealTimeDataUpdatedCallback);
persistent realTimeSub
realTimeSub = realTimeSubSetup.CreateAndStart();
end

The event handler for OnDataUpdated event is called whenever an update message is received from the real-time data stream for any of the RICs in the subscription. The data delivered to the event handler as a parameter is a .NET dictionary where keys are RICs and values are of type ThomsonReuters.Desktop.SDK.DataAccess.Realtime.IInstrumentUpdates that contains the updated fields. The event handler function below iterates through records (or RICs) in the real-time data update dictionary passed to the function. Then for each record it iterates through the field updates received in the update message, extracts the field name, value, numeric field ID (also known as FID) and field type, and outputs it to the console together with the RIC.

function r = RealTimeDataUpdatedCallback(realtimeUpdateDictionary)
disp('Data Updated event called');
records = realtimeUpdateDictionary.GetEnumerator();
while records.MoveNext()
    currentRecord = records.Current;
    val = currentRecord.Value;
    ric = val.Ric;
    fieldUpdate =val.FieldUpdates.GetEnumerator();
    while fieldUpdate.MoveNext()
        currentField = fieldUpdate.Current;
        fld = currentField.Field;
        rval = currentField.Value.RawValue;
        fieldID = currentField.Descriptor.Id;
        fieldType =  currentField.Descriptor.Type;
        disp({char(ric),char(fld),rval,fieldID,fieldType});
    end
end
end