Article

Migrating COM API calls to Python

Authors:

Jason Ramchandani
Lead Developer Advocate Lead Developer Advocate
Jonathan Legrand
Developer Advocate Developer Advocate

Note: Please keep in mind that this is a living document. Keep an eye on it as we update it with latest info and your feedback.

 

What are the COM APIs

 

The COM APIs are older APIs that were initially delivered with 3000 Xtra Terminals and then Eikon. They provided access to a broad set of content and capabilities in Eikon.

The COM API covers a large range of functionalities, as shown in this article. Below we will show you how to migrate the following COM Components and API calls/functions:

 

----The APIs below do not currently have replacements in Workspace---------------

  • Adxfo.dll
    •      AdfinX Analytics 2.0 Module
  • Adxfoo.dll
    •      AdfinX Analytics 3.0 Module

 

Reasons you might need or want to migrate away from COM APIs:

Need to operate in 64-bit environment

The COM APIs were designed to be used in 32-bit environments. Many teams are stil migrating to 64-bit environments where these will not work correctly and are not supported environments.

You want access to new datasets and improved capabilties offered on Refinitiv Data Platform

The COM APIs are feature-complete and no new development work is being done on them. This means that new datasets and capabilities will not be available to users of these APIs.

You want to upgrade from Eikon to Workspace

The COM APIs will not be available in Workspace - so to take advantage of the best desktop experience you would need to migrate to our more modern web-based APIs - which are much better and work with modern scripting environments such as Python - one of the most popular language ecosystems used in finance.

All the Python code below works in Codebook too! You can try it out as outlined in this Tutorial Video. We will use the Refinitiv Data Library (RD Library). To learn more about the Refinitiv Data Library for Python please join the Refinitiv Developer Community. By registering and logging into the Refinitiv Developer Community portal you will have free access to a number of learning materials like:

including the ability to ask questions on our Q&A forums and much more.

Prerequisites

COM Prerequisites - see annex at end of article for code

Documentation on using the COM API in the Microsoft Office suite is available here: COM APIs for Microsoft Office. Users were also able to use the COM APIs outside of Microsoft Office suite for example in a standalone app: COM APIs for use in custom applications. A list of the prerequisites in question can be found in the index of this article.

If you are new to Python, don't hesitate to install it on your machine and try it out yourself as outlined in this 3rd party tutorial. Otherwise, you can simply use Codebook as outlined in this Tutorial Video.

Python works with libraries that one can import to use functionalities that are not natively supported by the base coding package. Some popular distributuions of python include many of the popular packages that one could use for various tasks - Anaconda is the most popular such distribution.

The RD Library allows for code portability across the desktop and enterprise platforms - with only small changes in authentication credentials. These credentials are stored in a config file - but if you are just using the desktop you need not concern yourself with this as a desktop session is the default credential setup.

    	
            

import refinitiv.data as rd # pip install httpx==0.21.3 # !pip install refinitiv.data --upgrade
from refinitiv.data.discovery import Chain
from refinitiv.data.content import search
import pandas as pd
pd.set_option('display.max_columns', None)
import numpy as np
import os
import time
import datetime # `datetime` allows us to manipulate time as we would data-points.
from IPython.display import display, clear_output # `IPython` here will allow us to plot grahs and the likes.

rd.open_session("desktop.workspace")

<refinitiv.data.session.Definition object at 0x7fa34230ac18 {name='workspace'}>

AdfinXRtLib (rtx.dll)

AdfinX RealTime AdxRtSourceList

What does 'AdfinX RealTime AdxRtSourceList' do?

This functionality was used to get the real-time field list for the selected Source Name, such as an instrument (e.g.: VOD.L) (using AdxRtSourceList Class of AdfinXRtLib, the AdfinX Real Time 6.0 Library, rtx.dll). It was best demonstrated in the Tutorial 1 - Real-time Source List, Fields - AdxRtSourceList's Excel Workbook:

VBA

The VBA for AdxRtSourceList is very simple, and consists simply in creating an instance of an AdxRtSourceList object using the PLVbaApis function:

Set myAdxRtSrcLst = CreateAdxRtSourceList()

New Method

This functionality is replaced with a user interface called the Data Item Browswer (DIB) that you can find on workspace, and for which there is a video tutorial. This will give you a list of all real-time and non-real-time fields available for a particular instrument. For real-time fields the RD library can also provide this programatically - see below:

Real-Time Fields Available With The COM API

There are a limited number of fields available on the COM API in 'AdxRtSourceList', you can lookup fields available in the Quote app for any instrument in question:

More are available on the DIB and via the code available below in the 'Real-Time Fields Available In Python' section.

Note that available fields for each instrument type difffers on the type.

Note that the CF_ fields are also available to streaming Desktop sessions (not to platform sessions due to differences in data licenses)

Real-Time Fields Available In Python

You can get a collection of all the Real-Time fields available via:

    	
            RTCurrDf = rd.get_data(universe=['GBP='])
print(list(RTCurrDf.columns))

['Instrument', 'PROD_PERM', 'RDNDISPLAY', ..., 'MIDLO1_MS', 'BID_HR_MS']

Note that available fields for each instrument type difffers on the type, e.g.:

    	
            ATMIVDf = rd.get_data(universe=['AAPLATMIV.U'])
print(list(ATMIVDf.columns))

['Instrument', 'PROD_PERM', 'RDNDISPLAY', ..., 'CF_CURR', 'SPS_SP_RIC']

AdfinX RealTime AdxRtList

What does AdxRtList do?

Returns real-time data for multiple (or single) instrument and fields. Data is returned initially as ONIMAGE - which is a snapshot of data for the requested fields, followed by a series of ONUPDATE messages - which are received whenever a data item changes or gets updated. You can also request ONTIME returns which would give an ONIMAGE snapshot at periodic intervals (say every hour for example). All the following functions rely on AdxRtList API calls - RtGet(), RData() and TR() for real-time data. Typically we would need to write callback handlers to deal with the returns from the API.

RtGet Real-Time

When using the old COM API to get RtGet Real Time data, one may be greeted with an Excel sheet that looks like the below, as per Tutorial 2 - Real-time Data Retrieval - AdxRtList's Excel workbook:

The functionalities shown here are easily recreated using the RD Library:

  1. Real Time FX rates snapshot - 'Real-Time ONIMAGE'
  2. 'Real Time Update', which updates real time, as soon as an update for the instrument and field is received
  3. A periodic ONTIME snapshot

Real-Time ONIMAGE

When collecting data ONIMAGE, we are collecting a current snapshot of the data we're after. This could not be simpler in RD in Python!

VBA

In VBA, you'd create an instance of an AdxRtList object using the PLVbaApis function CreateAdxRtList.

Set myRtGet = CreateAdxRtList() ' The code will replicate RtGet(), one instrument, one field.'

Set myAdxRtList = CreateAdxRtList() ' The code will replicate RData(), multiple items & fields.'

Then create your function cmdGetRealTimeONIMAGE_Click:

Private Sub cmdGetRealTimeONIMAGE_Click()
Dim strRICs As String ' Can have one or more items
Dim varFIDs As Variant ' Field can be numeric as well as a string, e.g. BID is field 22

ActiveCell.Select

If Not myRtGet Is Nothing Then Set myRtGet = Nothing
Set myRtGet = CreateAdxRtList()

With myRtGet
.ErrorMode = DialogBox
.Source = [Source].Value
strRICs = [RIC].Value
varFIDs = [FID].Value

.RegisterItems strRICs, varFIDs
' 'Different methods shown below.
' strRICs = "EUR="
' varFIDs = "BID"
' .RegisterItems strRICs, varFIDs
' .RegisterItems "EUR=,GBP=,JPY=", "BID,ASK"

.StartUpdates RT_MODE_IMAGE ' 4
'.StartUpdates RT_MODE_ONUPDATE ' 3
'.StartUpdates RT_MODE_NOT_SET ' 5
'.StartUpdates RT_MODE_ONTIME ' 2
'.StartUpdates RT_MODE_ONTIME_IF_UPDATED ' 1
End With ' For the With myRtGet
End Sub

This would allow, in this example, for the 'Get Real Time ONIMAGE' buttons to work. For updates, the below could be used:

' Returns the initial image for the instrument. NOTE - .StartUpdates RT_MODE_IMAGE
Private Sub myRtGet_OnImage(ByVal DataStatus As AdfinXRtLib.RT_DataStatus)
Dim arrRICs As Variant, arrFields As Variant
Dim lngRICFidVal As Single
Dim a As Integer

If DataStatus = RT_DS_FULL Then
With myRtGet
' Array of the list of instruments - only one in this case.
arrRICs = .ListItems(RT_IRV_ALL, RT_ICV_USERTAG)
' Array of the list of Fields for the ath item in the arrRics (base 0)
a = 0
arrFields = .ListFields(arrRICs(a, 0), RT_FRV_ALL, RT_FCV_VALUE)
End With

' And a specific value for a specific instrument, specific field.
'lngRICFidVal = myRtGet.Value("EUR=", "BID")
lngRICFidVal = myRtGet.Value([RIC].Value, [FID].Value)
[F7].Value = lngRICFidVal
End If
End Sub

Python

In python, things could not be easier as most of the equivalent code about is abstracted to the library and you just use a one-line function! You can go ahead and try it all out in Codebook:

    	
            

rd.get_data(

    universe=['GBP=', 'EUR=', 'JPY='],

    fields=['BID', 'ASK'])

  Instrument BID ASK
0 GBP= 1.2003 1.2006
1 EUR= 1.0663 1.0667
2 JPY= 135.96 135.97

You can easily assign this info to an object too.

    	
            

realTimeImage = rd.get_data(

    universe=['GBP=', 'EUR=', 'JPY='],

    fields=['BID', 'ASK'])

realTimeImage

  Instrument BID ASK
0 GBP= 1.2002 1.2006
1 EUR= 1.0664 1.0667
2 JPY= 135.93 135.96

Real-Time ONUPDATE

VBA

The 'Real Time ONUPDATE' buttons in the example pictured above was coded with VBA code for cmdGetRealTimeONUPDATE_Click:

Private Sub cmdGetRealTimeONUPDATE_Click()
Dim strRICs As Variant, varFIDs As Variant


ActiveCell.Select
Set myRtGet2 = CreateAdxRtList
With myRtGet2 .ErrorMode = DialogBox .Source = [Source].Value strRICs = [RIC].Value varFIDs = [FID].Value
.RegisterItems strRICs, varFIDs .StartUpdates RT_MODE_ONUPDATE End With ' For the With myRtGet2 End Sub

' Returns the data for updates - NOTE .StartUpdates RT_MODE_ONUPDATE. Private Sub myRtGet2_OnUpdate(ByVal a_itemName As String, ByVal a_userTag As Variant, ByVal a_itemStatus As AdfinXRtLib.RT_ItemStatus) Dim arrFields As Variant Dim lngRICFidVal As Long
If a_itemStatus = RT_ITEM_OK Then arrFields = myRtGet2.ListFields(a_itemName, RT_FRV_ALL, RT_FCV_VALUE)
' And a specific value for a specific instrument, specific field. 'If a_itemName = "EUR=" Then lngRICFidVal = myRtGet2.Value("EUR=", "BID"): [F12].Value = arrFields(0, 1) If a_itemName = [RIC].Value Then lngRICFidVal = myRtGet2.Value([RIC].Value, [FID].Value): [F12].Value = arrFields(0, 1) End If End Sub

Then, on VBA, you'd have to have a buttons to stop the stream with cmdSwitchRealTimeOFF_Click, which, in python, is stream.close():

Python

For us to start using pricing streams with events, we need to define a callback to receive data events:

    	
            

def display_data(data, instrument, stream):

    clear_output(wait=True)

    current_time = datetime.datetime.now().time()

    print(current_time, "- Data received for", instrument)

    display(data)

Open the stream and register the callback

    	
            

stream = rd.open_pricing_stream(

    universe=['GBP=', 'EUR=', 'JPY='],

    fields=['BID', 'ASK'],

    on_data=display_data

)

stream.open()

11:38:32.995630 - Data received for EUR=

Close the stream

    	
            stream.close()
        
        
    
  BID ASK
EUR= 1.0663 1.0667

We can use a Python loop with sleep to recreate that simply:

The cell below gets an update for instruments 'GBP=', 'EUR=' and 'JPY=' and fields 'BID' and 'ASK' every 5 seconds:

    	
            

# This cell's code is usually commented out so that the kernel doesn't get stuck in the while loop.

now = time.perf_counter()

while time.perf_counter() < now + 30:

    time.sleep(5)

    clear_output(wait=True)

    df = stream.get_snapshot(

        universe=['GBP=', 'EUR=', 'JPY='],

        fields=['BID', 'ASK'])

    display(df)

  Instrument  BID ASK
0 GBP= 1.2003 1.2006
1 EUR= 1.0663 1.0667
2 JPY= 135.96 135.97

NEW FUNCTIONALITY: Record ticks

With the RD library we now have the ability to record a pricing stream. Here's how:

Create and open a Pricing stream

    	
            

stream = rd.open_pricing_stream(

    universe=['GBP=', 'EUR=', 'JPY='],

    fields=['BID']

)

Start recording

    	
            stream.recorder.record(frequency='tick')
        
        
    

... Wait for a little while (5 seconds) ...

    	
            time.sleep(5)
        
        
    

Stop recording and display the recorded history

    	
            

stream.recorder.stop()

tick_history = stream.recorder.get_history()

display(tick_history)

  GBP= JPY= EUR=
  BID BID BID
Timestamp      
40:43.2 <NA> 135.97 <NA>
40:43.3 <NA> <NA> 1.0661
40:43.5 <NA> 135.96 <NA>
40:43.5 1.1995 <NA> <NA>
40:50.2 <NA> 135.95 <NA>
40:50.8 1.1994 <NA> <NA>
40:50.8 <NA> 135.95 <NA>

Resample the tick history to 5 seconds bars

    	
            tick_history.ohlc("5s")
        
        
    

 

 

 

GBP= JPY= EUR=
  BID BID BID
  open high low close open high low close open high low close
Timestamp                        
07/03/2023 11:40 1.1995 1.1995 1.1995 1.1995 135.97 135.97 135.95 135.95 1.0661 1.0661 1.0661 1.0661
07/03/2023 11:40 1.1995 1.1995 1.1994 1.1994 135.95 135.97 135.95 135.95 1.0661 1.0661 1.0661 1.0661
07/03/2023 11:40 1.1994 1.1994 1.1994 1.1994 135.95 135.95 135.95 135.95 1.0661 1.0661 1.0661 1.0661

Close the stream

    	
            stream.close()
        
        
    

<OpenState.Closed: 'Closed'>

AdfinX RealTime - AdxRtChain

What does AdxRtChain do?

As per Tutorial 3 - Real-time Chain Retrieval - AdxRtChain's Excel Workbook, Adfin X RealTime Chain (AdxRtChain) returns a list of the constituent instrument codes for any chain such as 0#.FTSE (the FTSE 100 instruments). Data is returned as OnUpdate event, the only other event is OnStatusChange:

VBA

In VBA, we went through with the creation of cmdGetChain_Click:

Private Sub cmdGetChain_Click()
ActiveCell.Select

If myAdxRtChain Is Nothing Then Set myAdxRtChain = CreateAdxRtChain()

With myAdxRtChain
.Source = "IDN"
.ItemName = Range("G6").Value
.RequestChain
End With
End Sub

then myAdxRtChain_OnUpdate:

Private Sub myAdxRtChain_OnUpdate(ByVal DataStatus As AdfinXRtLib.RT_DataStatus)
Dim i As Integer

If DataStatus = RT_DS_FULL Then
For i = 1 To UBound(myAdxRtChain.Data)
Range("G8").Offset(i - 1, 0).Value = myAdxRtChain.Data(i)
Next i
End If
End Sub

then we ought to make sure we can close the connection with cmdClearChain_Click, which is done simply in Python with rd.close_session().

We can replicate this easily in Python with the Pricing snapshots and Fundamental & Reference data function get_data() - moreover we can decode the chain and request fields in one operation:

Python

    	
            

FTSEConstituentDf1 = rd.get_data(

    universe=['0#.FTSE'],

    fields=['TR.TURNOVER.timestamp', 'TR.TURNOVER', 'TR.EVToSales'])

FTSEConstituentDf1

 

 

 

Instrument Timestamp Turnover Enterprise Value To Sales (Daily Time Series Ratio)
0 STAN.L 2023-03-06T00:00:00Z 5254690524 3.641311
1 CRDA.L 2023-03-06T00:00:00Z 1274351304 4.528984
... ... ... ... ...
98 TSCO.L 2023-03-06T00:00:00Z 3041956489 0.468989
99 LGEN.L 2023-03-06T00:00:00Z 2561324328 <NA>

Not all chains resolve directly - for example a commodity chain - in such cases we can use the Chain Object to decode as follows:

    	
            

LCOConstituentDf = rd.get_data(

    universe=Chain('0#LCO:'),

    fields=["CF_NAME", "CF_CLOSE", "OPINT_1"])

 

LCOConstituentDf

 

 

 

Instrument CF_NAME CF_CLOSE OPINT_1
0 LCOTOT BRENT CRUDE VOLS <NA> 2459512
1 LCOK3 BRENT CRUDE MAY3 86.18 467381
... ... ... ... ...
82 LCOG0 BRENT CRUDE FEB0 65.02 <NA>
83 LCOH0 BRENT CRUDE MAR0 65 <NA>

AdfinX RealTime - AdxRtHistory - Interday Time Series History

What does AdxRtHistory do?

Adfin RealTime History (AdxRtHistory) is used to retrieve interday (not intraday) time series (historic) data for an instrument or instruments. This was best exemplified in Tutorial 5 - Time Series History - AdxRtHistory's Excel Workbook:

VBA

In VBA, we used AdfinXRtLib:

' Note the use of CreateReutersObject - function in the PLVbaApis module.
If myAdxRtHist Is Nothing Then Set myAdxRtHist = CreateReutersObject("AdfinXRtLib.AdxRtHistory")

On Error GoTo errHndlr
With myAdxRtHist
.FlushData
.ErrorMode = EXCEPTION ' EXCEPTION, DialogBox, NO_EXCEPTION
.Source = "IDN"
.ItemName = [C7].Value
.Mode = [H8].Value
.RequestHistory ("DATE,CLOSE,VOLUME") 'NOTE USE OF OLD FIELD NAMES, NOT ("TRDPRC_1.TIMESTAMP,TRDPRC_1.CLOSE,TRDPRC_1.VOLUME")

'arrFlds = Array("DATE","CLOSE","VOLUME")
'.RequestHistory ()arrFlds
'.RequestHistory ("*") ' "*" requests all fields.
End With

before the Private Sub 'myAdxRtHist_OnUpdate(ByVal DataStatus As AdfinXRtLib.RT_DataStatus)'.

Things are simpler in Python:

Python

As aforementioned, AdxRtHistory is used to retrieve time series (historic) data for an instrument or instruments except for intraday data. This is exactly what the instruments get_history is for!

    	
            

FTSEConstituents = list(FTSEConstituentDf1['Instrument'])

print(FTSEConstituents)

['STAN.L', 'CRDA.L', 'ANTO.L', ..., 'TSCO.L', 'LGEN.L']

    	
            

TimeSeriesDf = rd.get_history(

    universe=FTSEConstituents[1:6],

    fields=['TR.PriceClose', 'TR.Volume'],  # 'TR' fields are usually historic ones.

    interval="1D",

    start="2022-01-25",

    end="2022-02-01")

 

TimeSeriesDf

 

 

 

 

 

 

 

 

 

CRDA.L ANTO.L BNZL.L SGE.L SVT.L
  Price Close Volume Price Close Volume Price Close Volume Price Close Volume Price Close Volume
Date                    
25/01/2022 7666 371438 1379 1429044 2721 678948 762.4 3467017 2858 642275
26/01/2022 7830 755599 1411.5 889172 2754 628530 713 4323758 2871 318280
27/01/2022 7880 754142 1391.5 1460311 2776 671478 701 4752740 2914 522647
28/01/2022 7774 510683 1337.5 2839242 2786 1203491 711.2 3683775 2893 1017099
31/01/2022 7972 442252 1332.5 1333271 2767 545449 720.8 2966860 2873 751851
01/02/2022 8008 690445 1361.5 1605104 2775 433783 718.6 4462156 2903 439666

AdxRtHistory - Intraday Time Series History

VBA

Adfin RealTime History (AdxRtHistory) Intraday is similar

Which had few VBA lines needed:

Private Sub cmdGetInterday_Click()
ActiveCell.Select

MsgBox "AdxRtHistory cannot retrieve INTRA day data, use the RHistoryAPI instead"
End Sub

Python

Intraday data is just as easy to get:

    	
            

IntradayTimeSeriesDf = rd.get_history(

    universe=FTSEConstituents,

    fields=['TRDPRC_1'],

    interval="1min",  # The consolidation interval. Supported intervals are: tick, tas, taq, minute, 1min, 5min, 10min, 30min, 60min, hourly, 1h, daily, 1d, 1D, 7D, 7d, weekly, 1W, monthly, 1M, quarterly, 3M, 6M, yearly, 1Y.

    start="2022-06-01T13:00:00",

    end="2022-06-01T15:30:00")

 

IntradayTimeSeriesDf

 

TRDPRC_1

 

STAN.L CRDA.L ANTO.L BNZL.L SGE.L SVT.L BLND.L ICAG.L REL.L SMIN.L AZN.L HSBA.L CTEC.L WPP.L FRES.L AAF.L SGRO.L SJP.L TW.L AHT.L HLMA.L III.L CNA.L MNG.L BKGH.L SMDS.L NG.L RKT.L SKG.L WEIR.L MRON.L HSX.L CPG.L AUTOA.L AV.L ENT.L DGE.L INF.L UU.L PSHP.L HLN.L WTB.L PRU.L IMB.L EXPN.L BRBY.L RS1R.L ABDN.L GSK.L LAND.L BEZG.L BP.L JD.L ABF.L AAL.L ADML.L RTO.L RMV.L SBRY.L PHNX.L FLTRF.L IHG.L BT.L MNDI.L BATS.L PSON.L CRH.L SPX.L PSN.L RIO.L JMAT.L CCH.L RR.L SN.L BMEB.L SSE.L SMT.L FRAS.L HRGV.L KGF.L LLOY.L NWG.L SDR.L NXT.L ITRK.L BDEV.L SHEL.L GLEN.L VOD.L BARC.L FCIT.L UTG.L BAES.L DCC.L ULVR.L EDV.L OCDO.L LSEG.L TSCO.L LGEN.L
Timestamp                                                                                                                                                                                                        
01/06/2022 13:00 636.8 <NA> <NA> 2785 652.2 2855 526.506 129.2256 <NA> 1570 10492 535.4 <NA> 937.2 <NA> <NA> 1096 1256.5 130.95 4115 2198 <NA> 80.0871 <NA> 4253 306.7 1127.47 <NA> 3221 1620.5 134.6 924.8 1811.5 587.6 429.8 <NA> 3662.36 545 <NA> <NA> <NA> 2721 1022.467 1811 2602 1734.5 969.5 <NA> 1745.186 <NA> 488 433.308 123.9 1730 3869 <NA> 500.4 588.2 <NA> <NA> 9450 <NA> 189.9 1546.5 3568.5 759.4 <NA> 10520 <NA> 5781 2139 1729.5 89.1448 <NA> 376.1799 1786 812.8979 699.5 846.6 264.5 45.625 <NA> <NA> 6504 4612 <NA> 2370 515.3862 127.26 171.36 <NA> 1135 777.16 5606 3759.7 1794 <NA> 7252.004 260.87 258.3
01/06/2022 13:01 636.8 6884 <NA> 2784 <NA> 2854 526.6 128.74 2242 <NA> 10492 535.5 217.8 937.4 <NA> <NA> <NA> <NA> 130.9 4114 <NA> 1251.573 80.14 <NA> 4256 306.768 1127.35 <NA> 3223 1619.5 134.55 <NA> 1811.5 587.8 430.1 <NA> 3663.5 545.2 1049.61 <NA> <NA> <NA> 1022 1810.5 2605.347 1733.5 <NA> <NA> 1746.398 770.4 <NA> 433.5681 123.9 <NA> 3868 <NA> 501 589.2 230 <NA> 9442 <NA> 189.716 1547 3566 <NA> 3272.5 10525 <NA> 5781 2140 <NA> 89.18 <NA> 376.3712 1786.5 <NA> 700.5 846.6 <NA> 45.6034 231.9109 <NA> <NA> 4613 <NA> 2371 515.0922 <NA> 171.42 <NA> 1136 777.5818 5608 3760.406 1793 920 7253.768 260.8942 258.4
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
01/06/2022 15:28 632.4 6780 1499 2788 652.8 2836 521.2 126.64 2207 1558.5 10428 528.7 213.8 923.8 <NA> 154.2 1084.5 1242.5 129.65 4029 2190 1241 79.92 216.3931 4238 302.8 1119 6168 3184 1612 132.95 912.8 1770 586.4 426.95 1459 3628 534.2 1044.75 2560 <NA> 2642 1015.5 1794.5 2580 1705.5 <NA> 193.55 1722.763 766.6 478.8 431.5 122.45 1706 3850.5 2152.507 495.2 588.2 227.9 632.1798 9260.797 4827 188.71 1533.5 3541.5 749.2 3231 10455 2178 5754 2109 1706 88.53 1271 365.4757 1764.8 793.6 700.5 837 262 44.953 227.5902 491.64 6448 4557.56 500.2 2360.5 514.2102 126.383 167.64 832 1114 778 5606 3700.5 1804 909.4 7146 259 255
01/06/2022 15:29 632.4 6782 1500 2793 652.4 2836 520.6 126.54 2206 1558.5 10424 528.4 214 923.8 768.4 154 1084 1242 129.65 4027 2188 1241 80.02 216.2 4238 302.3 1118 6172 3186 1611.5 132.8 912.8 1772 586.4 426.7 1459.5 3625 533.8 1044 2560 <NA> 2639 1015 1794.5 2577 1703 961 193.4 1722.763 766.8 478.8 431.6 122.45 1704.5 3846 2152.507 495 587.6 228.1 632 9254 4825 188.7 1533.5 3540.5 748.4 3234.5 10465 2175 5756 2111 1707.5 88.51 1271.5 367.4828 1764 796.2 701 835.4 262 44.9 227.5902 491.98 6456 4553 499.8 2361.5 513.9162 126.28 167.52 832 1116 777.6 5600 3695.5 1805 910.4 7138 259 254.6

As you can see, we get the data sought after. If you are after several fields for any one instrument (e.g.: an FX Pair), it couldn't be any simpler.

DEX2.dll

The DEX2.dll COM API component provides access to a broad range of fundamental and reference data (including all the TR.xxx fields). The RData Excel function provided both Fundamental and Reference as well as streaming realtime prices and news using this component under the hood along with RTX.dll.

 

Rdata List Realtime

When using the old COM API to get Rdata List data, one may be greeted with an Excel sheet that looks like this:

VBA

In VBA, this was done with a function akin to .StartUpdates RT_MODE_ONUPDATE & myRTList = CreateAdxRtList(), e.g.:

With myRTList
.ErrorMode = EXCEPTION
' N.B.! Source name may need to be changed if not named as below!
.Source = "IDN" '_SELECTFEED"
' Register the items and fields
.RegisterItems ItemArray, FieldArray

' Set the user tag on each item. This helps indexing the results
' table for displaying the data in the callback
For m = LBound(ItemArray) To UBound(ItemArray)
.UserTag(ItemArray(m), "*") = m
For n = LBound(FieldArray) To UBound(FieldArray)
.UserTag(ItemArray(m), FieldArray(n)) = n
Next n
Next m

.Mode = "TIMEOUT:5"
' If timed basis desired, then FRQ setting and RT_MODE_ONTIME or RT_MODE_ONTIME_IF_UPDATED required,
' which will trigger the OnUpdate event, shown below.
'.Mode = "FRQ:2S"
' And, finally, request the data!
Select Case Range("dcUpdateType").Value
Case "RT_MODE_IMAGE"
.StartUpdates RT_MODE_IMAGE
Case "RT_MODE_ONUPDATE"
.StartUpdates RT_MODE_ONUPDATE
End Select

'.StartUpdates RT_MODE_ONUPDATE
'.StartUpdates RT_MODE_IMAGE
'Other modes shown below; different events will be fired.
'.StartUpdates RT_MODE_ONTIME, RT_MODE_ONTIME_IF_UPDATED, RT_MODE_ONTIME,
' RT_MODE_ONUPDATE, RT_MODE_IMAGE , RT_MODE_NOT_SET
End With

To stop this update, you would have to create some VBA code to (e.g.: Sub cmdStop_Click()), but that is simpler in Python with stream.close():

However - many developers also used the RData worksheet function object directly in VBA.

Python

Here we have a data-frame of instruments and fields updating live every x seconds, let's say (for the sake of the use-case example) every 3 seconds. This is simple to recreate in Python:

    	
            

#define stream

stream = rd.open_pricing_stream(

    universe=['GBP=', 'EUR=', 'JPY=', '.GDAXI', '.FTSE', '.NDX', 'TRI.TO', 'EURGBP=R'],

    fields=['CF_TIME', 'CF_LAST', 'BID', 'ASK', 'TRDTIM_1'])

 

#open stream

stream.open()

<OpenState.Opened: 'Opened'>

    	
            

#add temporal update functionality using stream.get_snapshot 

now = time.perf_counter()

while time.perf_counter() < now + 30:

    time.sleep(3)

    clear_output(wait=True)

    df = stream.get_snapshot(

        universe=['GBP=', 'EUR=', 'JPY=', '.GDAXI', '.FTSE', '.NDX', 'TRI.TO', 'EURGBP=R'], 

        fields=['CF_TIME', 'CF_LAST', 'BID', 'ASK', 'TRDTIM_1'])

    display(df)

 

 

 

 

 

 

 

 

 

 

Instrument CF_TIME CF_LAST BID ASK TRDTIM_1
0 GBP= 11:44:36 1.1983 1.1983 1.1987 <NA>
1 EUR= 11:44:36 1.0657 1.0657 1.0661 <NA>
2 JPY= 11:44:37 136.02 136.02 136.03 <NA>
3 .GDAXI 11:44:00 15677.13 <NA> <NA> 11:44:00
4 .FTSE 11:44:00 7948.93 <NA> <NA> 11:44:00
5 .NDX 22:15:59 12302.48 <NA> <NA> <NA>
6 TRI.TO 21:00:00 165.81 162.61 167 <NA>
7 EURGBP=R 11:44:37 0.889 0.889 0.8897 <NA>

Close the stream

    	
            stream.close()
        
        
    

<OpenState.Closed: 'Closed'>

Create a Streaming Price and register event callbacks using RDP

You can build upon the example above, using the RD Library Example notebook present in Codebook that demonstrates how to use a StreamingPrice with events to update a Pandas DataFrame with real-time streaming data. Using a StreamingPrices object that way allows your application to have at its own in memory representation (a Pandas DataFrame in this example) that is kept updated with the latest streaming values received from Eikon or Refinitiv Workspace. Here we're putting ourselves in the shoes of a Foreign eXchange (FX) trader looking at Emerging Market (EM) currency exchange rates; e.g: the Nigerian Nairas (NGN) and Indonesian Rupiah (IDR).

You can find the code for this on GitHub here.

 

RData Function

What does RData do?

RData is a flexible excel worksheet function allowing access to realtime and fundamental & reference data content. It can also be used programatcally in VBA and the results then dumped to an excel range for example.

VBA

For VBA related to Fundamental data, please see the 'DEX2 Fundamental and Reference' section below.

Python

We have separated getting current fundamental snapshots - using a rd.get_data function and getting historical fundamental timeseries using either the rd.get_data function or the rd.get_history() function.

Snapshot requests

For snapshot current fundamental requests - things are pretty straight forward - select your universe of instruments and then the list of fields you want. A full list of fields is available using the Data Item Browser App (type DIB into Eikon or Workspace search bar).

    	
            

df1 = rd.get_data(

    universe=['BARC.L', 'TRI.N', 'TSLA.O'],

    fields=['TR.RevenueMean.date', 'TR.RevenueMean', 'TR.TRBCEconomicSector',

            'TR.TRBCEconSectorCode', 'TR.TRBCBusinessSector',

            'TR.TRBCBusinessSectorCode', 'TR.TRBCIndustryGroup',

            'TR.TRBCIndustryGroupCode', 'TR.TRBCIndustry', 'TR.TRBCIndustryCode'])

df1

 

 

 

 

 

 

 

 

 

Instrument Date Revenue - Mean TRBC Economic Sector Name TRBC Economic Sector Code TRBC Business Sector Name TRBC Business Sector Code TRBC Industry Group Name TRBC Industry Group Code TRBC Industry Name TRBC Industry Code
0 BARC.L 06/03/2023 26185926370 Financials 55 Banking & Investment Services 5510 Banking Services 551010 Banks 55101010
1 TRI.N 22/02/2023 6937020650 Industrials 52 Industrial & Commercial Services 5220 Professional & Commercial Services 522030 Professional Information Services 52203070
2 TSLA.O 05/03/2023 1.03134E+11 Consumer Cyclicals 53 Automobiles & Auto Parts 5310 Automobiles & Auto Parts 531010 Auto & Truck Manufacturers 53101010

 

 

 

 

 

 

 

 

If we want to add some fundamental history to this request - we can add a parameters section to the get_data request - as below which will give us the last 4 fiscal years ('FRQ': 'FY') of history for each RIC. Note for static reference fields such sector codes - these will not be published as a timeseries history - however, we can forward fill as shown below.

    	
            

df1 = rd.get_data(

    universe=['BARC.L', 'TRI.N', 'TSLA.O', Peers('HD'), Customers],

    fields=[

        'TR.RevenueMean.date', 'TR.RevenueMean',

        'TR.TRBCEconomicSector', 'TR.TRBCEconSectorCode', 'TR.TRBCBusinessSector',

        'TR.TRBCBusinessSectorCode', 'TR.TRBCIndustryGroup', 'TR.TRBCIndustryGroupCode',

        'TR.TRBCIndustry', 'TR.TRBCIndustryCode'],

    parameters={'SDate': 0, 'EDate': -3, 'FRQ': 'FY'}

)

df1

 

 

 

 

 

 

 

 

 

Instrument Date Revenue - Mean TRBC Economic Sector Name TRBC Economic Sector Code TRBC Business Sector Name TRBC Business Sector Code TRBC Industry Group Name TRBC Industry Group Code TRBC Industry Name TRBC Industry Code
0 BARC.L 06/03/2023 26185926370 Financials 55 Banking & Investment Services 5510 Banking Services 551010 Banks 55101010
1 BARC.L 13/02/2023 25107439220                
2 BARC.L 11/02/2022 21896182240                
3 BARC.L 28/01/2021 21603248110                
4 TRI.N 22/02/2023 6937020650 Industrials 52 Industrial & Commercial Services 5220 Professional & Commercial Services 522030 Professional Information Services 52203070
5 TRI.N 01/02/2023 6626869820                
6 TRI.N 07/02/2022 6311529500                
7 TRI.N 22/02/2021 5980789530                
8 TSLA.O 05/03/2023 1.03134E+11 Consumer Cyclicals 53 Automobiles & Auto Parts 5310 Automobiles & Auto Parts 531010 Auto & Truck Manufacturers 53101010
9 TSLA.O 25/01/2023 81715341140                
10 TSLA.O 25/01/2022 52595085190                
11 TSLA.O 27/01/2021 31012329500                
    	
            

# The below in this cell is needed to forward fill our dataframe correctly:

df1.replace({'': np.nan}, inplace=True)

df1.where(pd.notnull(df1), np.nan, inplace=True)

 

for i in df1.groupby(by=["Instrument"]):

    if i[0] == df1["Instrument"][0]: _df1 = i[1].ffill()

    else: _df1 = _df1.append(i[1].ffill())

_df1

 

 

 

 

 

 

 

 

 

Instrument Date Revenue - Mean TRBC Economic Sector Name TRBC Economic Sector Code TRBC Business Sector Name TRBC Business Sector Code TRBC Industry Group Name TRBC Industry Group Code TRBC Industry Name TRBC Industry Code
0 BARC.L 06/03/2023 26185926370 Financials 55 Banking & Investment Services 5510 Banking Services 551010 Banks 55101010
1 BARC.L 13/02/2023 25107439220 Financials 55 Banking & Investment Services 5510 Banking Services 551010 Banks 55101010
2 BARC.L 11/02/2022 21896182240 Financials 55 Banking & Investment Services 5510 Banking Services 551010 Banks 55101010
3 BARC.L 28/01/2021 21603248110 Financials 55 Banking & Investment Services 5510 Banking Services 551010 Banks 55101010
4 TRI.N 22/02/2023 6937020650 Industrials 52 Industrial & Commercial Services 5220 Professional & Commercial Services 522030 Professional Information Services 52203070
5 TRI.N 01/02/2023 6626869820 Industrials 52 Industrial & Commercial Services 5220 Professional & Commercial Services 522030 Professional Information Services 52203070
6 TRI.N 07/02/2022 6311529500 Industrials 52 Industrial & Commercial Services 5220 Professional & Commercial Services 522030 Professional Information Services 52203070
7 TRI.N 22/02/2021 5980789530 Industrials 52 Industrial & Commercial Services 5220 Professional & Commercial Services 522030 Professional Information Services 52203070
8 TSLA.O 05/03/2023 1.03134E+11 Consumer Cyclicals 53 Automobiles & Auto Parts 5310 Automobiles & Auto Parts 531010 Auto & Truck Manufacturers 53101010
9 TSLA.O 25/01/2023 81715341140 Consumer Cyclicals 53 Automobiles & Auto Parts 5310 Automobiles & Auto Parts 531010 Auto & Truck Manufacturers 53101010
10 TSLA.O 25/01/2022 52595085190 Consumer Cyclicals 53 Automobiles & Auto Parts 5310 Automobiles & Auto Parts 531010 Auto & Truck Manufacturers 53101010
11 TSLA.O 27/01/2021 31012329500 Consumer Cyclicals 53 Automobiles & Auto Parts 5310 Automobiles & Auto Parts 531010 Auto & Truck Manufacturers 53101010
Snapshot Requests Tip 1

Some fundamental fields will give multiple rows for a given day - for example if we request ratings sources - there could be more than one per date eg if there are 5 ratings agencies providing a rating - this is not usual for a time series history - or perhaps it is very different say than non-expandable single point timeseries. In this example as we have multiple RICS whose ratings dates may not overlap ie be on the same row <NA> artifacts are added to deliver the dataframe

    	
            

df2 = rd.get_history(

    universe=['BARC.L', 'TRI.N','TSLA.O'],

    fields=['TR.IR.RatingSourceDescription', 'TR.IR.RatingSourceType',

            'TR.IR.Rating','TR.IR.Rating.date'],

    interval="1Y",

    start="2015-01-25",

    end="2022-02-01")

 

df2

 

 

 

BARC.L TSLA.O
  Rating Source Description Rating Source Type Issuer Rating Date Rating Source Description Rating Source Type Issuer Rating Date
Date                
16/07/2015 <NA> <NA> <NA> NaT <NA> <NA> <NA> NaT
19/11/2015 Fitch Senior Unsecured FSU A 19/11/2015 <NA> <NA> <NA> NaT
19/11/2015 Fitch Short-term Debt Rating FDT F1 19/11/2015 <NA> <NA> <NA> NaT
16/08/2016 <NA> <NA> <NA> NaT <NA> <NA> <NA> NaT
12/12/2016 Moody's Long-term Issuer Rating MIS Baa2 12/12/2016 <NA> <NA> <NA> NaT
12/12/2016 Moody's Long-term Senior Unsecured MTN Rating MMU (P)Baa2 12/12/2016 <NA> <NA> <NA> NaT
22/10/2021 <NA> <NA> <NA> NaT S&P Senior Unsecured SSU BB+ 22/10/2021
26/11/2021 R&I Long-term Issuer Rating RII A 26/11/2021 <NA> <NA> <NA> NaT
Snapshot Requests Tip 2

Again this same multi-row exanding timeseries history - here in the case of broker recommendations - is another example - with lots of <NA> artifacts added.

    	
            

df2 = rd.get_history(

    universe=['BARC.L', 'TRI.N', 'TSLA.O'],

    fields=['TR.RecEstValue', 'TR.TPEstValue', 'TR.EPSEstValue'],

    interval="1M",

    start="2020-01-25",

    end="2022-02-01")

df2

  BARC.L TRI.N TSLA.O
  Standard Rec (1-5) - Broker Estimate Target Price - Broker Estimate Earnings Per Share - Broker Estimate Standard Rec (1-5) - Broker Estimate Target Price - Broker Estimate Earnings Per Share - Broker Estimate Standard Rec (1-5) - Broker Estimate Target Price - Broker Estimate Earnings Per Share - Broker Estimate
Date                  
02/10/2013 00:00 2 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
02/10/2013 00:00 2 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
... ... ... ... ... ... ... ... ... ...
31/01/2022 21:05 <NA> <NA> <NA> <NA> <NA> <NA> <NA> 326.66633 4.28333
31/01/2022 23:00 <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA> 4.84999

DEX2

What does this do?

The DEX2 interface provided a broad range of content and functionality such Fundamental and Reference as well as timeseries histories of such fields. The DEX2 interface also provided interday timeseries histories for both realtime and non-realtime data. In addition you could use it for symbology conversion.

DEX2 ID to RIC (Symbology Conversion)

As shown in Tutorial 6 - Data Engine - Dex2's Excel Workbook, we can convert symbols using the COM API.

VBA

After setting MyDex2Mgr = CreateReutersObject("Dex2.Dex2Mgr"), for ISINs, we can then go ahead with

' Must call Initialise() at once
m_cookie = MyDex2Mgr.Initialize()
' We can then create an RData object
Set myRData1 = MyDex2Mgr.CreateRData(m_cookie)


With MyDex2Mgr .SetErrorHandling m_cookie, DE_EH_STRING ' Could also use DE_EH_ERRORCODES End With
' Set the properties & methods for the DEX2Lib.RData object With myRData1 .InstrumentIDList = Range("B7").Value ' Could use "TRI.N", "TRI.N; GOOG.O; MSFT.O" or array, e.g. arrInstrList. .FieldList = Range("D7").Value & "; " & Range("D8").Value '"RI.ID.RIC; RI.ID.ISIN" ' Could use "RI.ID.RIC", "RI.ID.RIC; RI.ID.WERT" or array, e.g. arrFldList. .DisplayParam = "Transpose:Y" 'N.B. Could use .SetParameter "TRI.N; MSFT.O","RF.G.COMPNAME; RF.G.NUMEMPLOY; RF.G.CNTEMAIL", "", "RH:In CH:Fd Transpose:Y" 'Hence .SetParameter [InstrumentIDList].Value, [FieldList].Value, [RequestParam].Value, [DisplayParam].Value
'Ignore cache; get data directly from the Snapshot Server '.Subscribe False 'Or use cache by default .Subscribe End With Exit Sub

For SEDOL, we can use:

' Must call Initialise() at once
m_cookie = MyDex2Mgr.Initialize()
' We can then create an RData object
Set myRData2 = MyDex2Mgr.CreateRData(m_cookie)


With MyDex2Mgr .SetErrorHandling m_cookie, DE_EH_STRING ' Could also use DE_EH_ERRORCODES End With
' Set the properties & methods for the DEX2Lib.RData object With myRData2 .InstrumentIDList = [B10].Value ' Could use "TRI.N", "TRI.N; GOOG.O; MSFT.O" or array, e.g. arrInstrList. .FieldList = Range("D10").Value & "; " & Range("D11").Value '"RI.ID.RIC; RI.ID.SEDOL" ' Could use "RI.ID.RIC", "RI.ID.RIC; RI.ID.WERT" or array, e.g. arrFldList. .DisplayParam = "Transpose:Y" 'N.B. Could use .SetParameter "TRI.N; MSFT.O","RF.G.COMPNAME; RF.G.NUMEMPLOY; RF.G.CNTEMAIL", "", "RH:In CH:Fd Transpose:Y" 'Hence .SetParameter [InstrumentIDList].Value, [FieldList].Value, [RequestParam].Value, [DisplayParam].Value
'Ignore cache; get data directly from the Snapshot Server '.Subscribe False 'Or use cache by default .Subscribe End With Exit Sub

Python

Symbology conversions in python are a lot more powerful than in Excel using the COM API. The extent of the use-cases for symbology conversions are best explained in our GitHub Repository, but for the sake of completeness, you can see an example use in the 2 cells directly below:

    	
            

# # Get generic table of many symbols for 4 companies of choice:

from refinitiv.data.content import symbol_conversion

response = symbol_conversion.Definition(symbols=["MSFT.O", "AAPL.O", "GOOG.O", "IBM.N"]).get_data()

response.data.df

  DocumentTitle RIC IssueISIN CUSIP SEDOL TickerSymbol IssuerOAPermID
MSFT.O Microsoft Corp, Ordinary Share, NASDAQ Global ... MSFT.O US5949181045 594918104 <NA> MSFT 4295907168
AAPL.O Apple Inc, Ordinary Share, NASDAQ Global Selec... AAPL.O US0378331005 37833100 <NA> AAPL 4295905573
GOOG.O Alphabet Inc, Ordinary Share, Class C, NASDAQ ... GOOG.O US02079K1079 02079K107 <NA> GOOG 5030853586
IBM.N International Business Machines Corp, Ordinary... IBM.N US4592001014 459200101 2005973 IBM 4295904307
    	
            

# # Convert specific symbols:

response = symbol_conversion.Definition(

    symbols=["US5949181045", "US02079K1079"],

    from_symbol_type= symbol_conversion.SymbolTypes.ISIN,  # Symbol types: RIC => RIC; ISIN => IssueISIN; CUSIP => CUSIP; SEDOL => SEDOL; TICKER_SYMBOL => TickerSymbol; OA_PERM_ID => IssuerOAPermID; LIPPER_ID => FundClassLipperID

    to_symbol_types=[symbol_conversion.SymbolTypes.RIC,

                     symbol_conversion.SymbolTypes.OA_PERM_ID],

).get_data()

 

response.data.df

DocumentTitle RIC IssuerOAPermID  
US5949181045 Microsoft Corp, Ordinary Share, NASDAQ Global ... MSFT.O 4295907168
US02079K1079 Alphabet Inc, Ordinary Share, Class C, NASDAQ ... GOOG.O 5030853586

DEX2 RData Equity Data

As best exemplified in Tutorial 6 - Data Engine - Dex2's Excel Workbook, the DEX2 RData Equity Data allows us to access historical Market Capital:

VBA

DEX2 replicates RData() and TR() functions for real time data retrieval in Eikon for Excel / Eikon - Microsoft Office. The DEX2 methods differ slightly in the initialisation and use of the Dex2Mgr object depending upon whether RData() or the TR() function is being replicated. The examples below explain this. The TR() function can be used to retrieve data from ADC (the Analytics Data Cloud) and this is contained in Tutorial 11 - Dex2 TR function Analytics Data Cloud ADC data here.

NOTE - Eikon for Excel or Eikon - Microsoft Office should be logged in otherwise the sample VBA code will generate an error "ERROR #360c - AdxRtx : No connection to the platform".

  1. Create an instance of an DEX2Mgr object using the PLVbaApis function CreateDex2Mgr().

    Set myDEX2Mgr = CreateDex2Mgr()

  2. To replicate RData(), create the Dex2Mgr object (myDex2Mgr) and initialise it. Use the return value from the initialisation to create an instance of the Dex2Lib.RData Class (myDex2RData) using the CreateRData method.

  3. Now go ahead with cmdMktCapHist_Click creation:

Private Sub cmdMktCapHist_Click() On Error GoTo errHandler
ActiveCell.Select
Range("F20:G100").ClearContents If MyDex2Mgr Is Nothing Then Set MyDex2Mgr = CreateReutersObject("Dex2.Dex2Mgr")
' Must call Initialise() at once m_cookie = MyDex2Mgr.Initialize() ' We can then create an RData object Set myRData2 = MyDex2Mgr.CreateRData(m_cookie)
With MyDex2Mgr .SetErrorHandling m_cookie, DE_EH_STRING ' Could also use DE_EH_ERROR_CODES End With
' Set the properties & methods for the DEX2Lib.RData object. With myRData2 .InstrumentIDList = [C15].Value .FieldList = [C16].Value '"RII.A.INDEX_MKT_CAP_RTRS" '"RII.A.INDEX_MKT_CAP_RTRS; RII.A.INDEX_MKT_CAP_USDRTRS" ' Could use single "RI.ID.RIC", multiple "RI.ID.RIC; RI.ID.WERT" or array, e.g. arrFldList. .RequestParam = [C17].Value .DisplayParam = "RH:D CH:Fd SORT:DESC" 'N.B. Could use .SetParameter "TRI.N; MSFT.O","RF.G.COMPNAME; RF.G.NUMEMPLOY; RF.G.CNTEMAIL", "", "RH:In CH:Fd Transpose:Y" 'Hence .SetParameter [InstrumentIDList].Value, [FieldList].Value, [RequestParam].Value, [DisplayParam].Value
'Ignore cache; get data directly from the Snapshot Server '.Subscribe False 'Or use cache by default .Subscribe End With Exit Sub
errHandler: MsgBox MyDex2Mgr.GetErrorString(Err.Number) End Sub
' OnUpdate event callback for myRData1 Private Sub myRData2_OnUpdate(ByVal DataStatus As Dex2Lib.DEX2_DataStatus, ByVal Error As Variant) Dim C As Integer, r As Integer Dim res2 As Variant
If Error <> 0 Then [F21].Value = Error: Exit Sub
res2 = myRData2.Data
If IsEmpty(res2) Then [F21].Value = "No data": Exit Sub
' r for the rows For r = LBound(res2, 1) To UBound(res2, 1) ' c for the columns For C = LBound(res2, 2) To UBound(res2, 2) [F21].Offset(r, C).Value = res2(r, C) Next C Next r End Sub

Python

Couldn't be easier in Python:

    	
            

MarketCapDf = rd.get_history(

    universe=['VOD.L','BARC.L'],

    fields=['TR.CompanyMarketCapitalization'],

    interval="1D", # The consolidation interval. Supported intervals are: tick, tas, taq, minute, 1min, 5min, 10min, 30min, 60min, hourly, 1h, daily, 1d, 1D, 7D, 7d, weekly, 1W, monthly, 1M, quarterly, 3M, 6M, yearly, 1Y.

    start="2022-08-10",

    end="2022-09-13")

MarketCapDf

 

Company Market Capitalization

 

VOD.L BARC.L
Date    
10/08/2022 33802223010 27530345491
11/08/2022 33794859479 27383302388
12/09/2022 30687668213 27864039079
13/09/2022 30275827985 27526300175

VBA

You'd have to Initialize Dex2 session under the sub cmdInitialize_Click():

' Initialize Dex2 session when the data request is first started. Private Sub cmdInitialize_Click() On Error GoTo ErrorHandle
ActiveCell.Select
' Clear the output of logger lbLog.Clear
ClearAllOutput
' Clear the Cookie and old query If Not MyDex2Cookie = 0 Then MyDex2Mgr.Finalize (MyDex2Cookie) MyDex2Cookie = 0 Set MyDex2Mgr = Nothing Set MyDex2RData = Nothing End If
' Instantiate the Dex2 manager Set MyDex2Mgr = CreateDex2Mgr() Set MyDex2MgrADC = MyDex2Mgr ' Instantiate the RSearch logger Set MyDex2Logger = New CLogger
' Initialize Dex2 session MyDex2Cookie = MyDex2MgrADC.Initialize(DE_MC_ADC_POWERLINK, MyDex2Logger)
' We can choose to display error code MyDex2Mgr.SetErrorHandling MyDex2Cookie, DE_EH_ERROR_CODES ' Or display error description ' MyDex2Mgr.SetErrorHandling MyDex2Cookie, DE_EH_STRING
' Create a Dex2 query using the session cookie Set MyDex2RData = MyDex2Mgr.CreateRData(MyDex2Cookie)
' Create a Dex2 query manager using the session cookie Set MyDex2RDataMgr = MyDex2Mgr.CreateRDataMgr(MyDex2Cookie)
Exit Sub

Python

In Python, things are a little simpler:

    	
            

DEX2Df = rd.get_history(

    universe=['VOD.L', 'BARC.L', 'TRI.N'],

    fields=['TR.TotalReturn', 'TR.PRICECLOSE'],

    interval="1D",

    start="2021-10-01",

    end="2021-10-11")

 

DEX2Df

 

 

 

 

 

 

 

 

 

VOD.L BARC.L TRI.N
  Total Return Price Close Total Return Price Close Total Return Price Close
Date            
01/10/2021 -0.970874 112.2 -0.907173 187.88 -0.289645 110.16
04/10/2021 1.4082 113.78 -0.319353 187.28 -0.67175 109.42
05/10/2021 0.773422 114.66 3.908586 194.6 0.923049 110.43
06/10/2021 -2.651317 111.62 -1.387461 191.9 1.213438 111.77
07/10/2021 0.734635 112.44 0.958833 193.74 1.673079 113.64
08/10/2021 -0.302383 112.1 0.732941 195.16 0.228793 113.9
11/10/2021 -0.303301 111.76 1.291248 197.68 0.412643 114.37

VBA

Private Sub cmdClearAll_Click()
ActiveCell.Select

Range("G10").Value = ""
Range("G21:J100").Value = ""

If Not myRData1 Is Nothing Then Set myRData1 = Nothing
If Not myRData2 Is Nothing Then Set myRData2 = Nothing
If Not MyDex2Mgr Is Nothing Then Set MyDex2Mgr = Nothing
End Sub


Private Sub cmdGetRating_Click() On Error GoTo errHandler
ActiveCell.Select
[G7].Value = "" ' Note the use of CreateReutersObject - function in the PLVbaApis module. If MyDex2Mgr Is Nothing Then Set MyDex2Mgr = CreateReutersObject("Dex2.Dex2Mgr")
' Must call Initialise() at once m_cookie = MyDex2Mgr.Initialize() ' We can then create an RData object Set myRData1 = MyDex2Mgr.CreateRData(m_cookie)
With MyDex2Mgr .SetErrorHandling m_cookie, DE_EH_STRING ' Could also use DE_EH_ERRORCODES End With
' Set the properties & methods for the DEX2Lib.RData object With myRData1 .InstrumentIdList = [C6].Value ' Could use "TRI.N", "TRI.N; GOOG.O; MSFT.O" or array, e.g. arrInstrList. .FieldList = [C7].Value '"EJV.GR.Rating" ' Could use "RI.ID.RIC", "RI.ID.RIC; RI.ID.WERT" or array, e.g. arrFldList. .RequestParam = [C8].Value '"RTSRC:S&P" 'N.B. Could use .SetParameter "TRI.N; MSFT.O","RF.G.COMPNAME; RF.G.NUMEMPLOY; RF.G.CNTEMAIL", "", "RH:In CH:Fd Transpose:Y" 'Hence .SetParameter [InstrumentIDList].Value, [FieldList].Value, [RequestParam].Value, [DisplayParam].Value
'Ignore cache; get data directly from the Snapshot Server '.Subscribe False 'Or use cache by default .Subscribe End With Exit Sub
errHandler: MsgBox MyDex2Mgr.GetErrorString(Err.Number) End Sub
' OnUpdate event callback for myRData1 Private Sub myRData1_OnUpdate(ByVal DataStatus As Dex2Lib.DEX2_DataStatus, ByVal Error As Variant) Dim res As Variant
'Debug.Print DataStatus
If Error <> 0 Then [G10].Value = Error: Exit Sub
' get the data retrieved from the database res = myRData1.Data
' Display the result. [G10].Value = res End Sub
Private Sub cmdGetHistoryOfRating_Click() On Error GoTo errHandler
ActiveCell.Select
Range("G21:J100").ClearContents If MyDex2Mgr Is Nothing Then Set MyDex2Mgr = CreateReutersObject("Dex2.Dex2Mgr")
' Must call Initialise() at once m_cookie = MyDex2Mgr.Initialize() ' We can then create an RData object Set myRData2 = MyDex2Mgr.CreateRData(m_cookie)
With MyDex2Mgr .SetErrorHandling m_cookie, DE_EH_STRING ' Could also use DE_EH_ERRORCODES End With
' Set the properties & methods for the DEX2Lib.RData object With myRData2 .InstrumentIdList = [C15].Value .FieldList = [C16].Value .RequestParam = [C17].Value .DisplayParam = [C18].Value
'N.B. Could use .SetParameter "TRI.N; MSFT.O","RF.G.COMPNAME; RF.G.NUMEMPLOY; RF.G.CNTEMAIL", "", "RH:In CH:Fd Transpose:Y" 'Hence .SetParameter [InstrumentIDList].Value, [FieldList].Value, [RequestParam].Value, [DisplayParam].Value
'Ignore cache; get data directly from the Snapshot Server '.Subscribe False 'Or use cache by default .Subscribe End With Exit Sub
errHandler: MsgBox MyDex2Mgr.GetErrorString(Err.Number) End Sub

Python

Things are much simpler in Python:

    	
            

rating = rd.get_history(

    universe=['GB137283921='],

    fields=['TR.IR.RatingSourceDescription', 'TR.IR.RatingSourceType',

            'TR.IR.Rating'],  

    interval="1Y",

    start="2015-01-25",

    end="2023-02-01")

rating

 

 

 

 

GB137283921=

 

 

 

 

Rating Source Description Rating Source Type Issuer Rating
Date      
17/12/2015 Egan-Jones Commercial Paper EJC A1
17/12/2015 Egan-Jones Senior Unsecured EJU BBB+
06/07/2016 Egan-Jones Senior Unsecured EJU BBB
04/10/2018 Fitch Subordinated FBD BBB-
26/11/2019 Egan-Jones Senior Unsecured EJU BBB-
29/07/2021 Fitch Commercial Paper FCP F2
25/11/2022 Egan-Jones Commercial Paper EJC A1

DEX2 Fundamental and Reference

Time Series data as the name suggests changes with time. Reference data, on the other hand, does not primarily change with time; when it does, it usually accounts for a structural change in the instrument at play (e.g.: a company changes from banking to tech operation industries or is acquired and changes name etc). Fundamental data is released temporally say quarterly or half-yearly or annually and is usually looked at across time eg Revenue or Sales. DEX2 provides access to all of our TR fields - which allow you to specify begin dates and end dates amongst other parameters. Access to these is unchanged in our new APIs - only its a lot simpler.

VBA

In VBA, after creating 'Private MyDex2Mgr As Dex2Lib.Dex2Mgr':

Private MyDex2Mgr As Dex2Lib.Dex2Mgr
Private MyDex2MgrADC As Dex2Lib.IDex2Mgr2
Private MyDex2Cookie As Long
' Private variable that holds the Dex2 RData, able to obtain TR fields.
Private WithEvents MyDex2RData As Dex2Lib.RData

to complete the Tutorial 6 example, one could go through the following to collect DEX2 Fundamental and Reference data:

' Now create the Dex2 and IDex2 objects.
Set MyDex2Mgr = CreateDex2Mgr()
Set MyDex2MgrADC = MyDex2Mgr

' Initialise using the DE_MC_ADC_POWERLINK enumeration
MyDex2Cookie = MyDex2MgrADC.Initialize(DE_MC_ADC_POWERLINK)
' And create an RData object.
Set MyDex2RData = MyDex2Mgr.CreateRData(MyDex2Cookie)

With MyDex2RData
.InstrumentIDList = Range("G6").Value ' Or for multiple isntruments "TRI.N;MSFT.O;GOOG.O"
.FieldList = strInstrList ' Or single field "TR.CLOSE"
.RequestParam = "" ' Or of the form "edate:-20d sdate:-9d"
.DisplayParam = "CH:Fd" ' Or of the form "RH:In CH:Fd"

'' OR can use .SetParameter
'.SetParameter Range("G6").Value, strInstrList, "", "CH:Fd"

' Send the query without using cache
.Subscribe False ' Or use cache by default - myDex2RData.Subscribe

' When the data is returned, the myDex2RData_OnUpdate event and Sub are 'fired'.

Python

Fundamental data was covered above under 'RData Fundamentals'; such data can be found in Python with RD (and rd.get_data, rd.get_history or rd.content.fundamental_and_reference.Definition) or EDAPI.

Fundamental and Reference Timeseries

VBA

DEX2 Fundamental and Reference Timeseries data could be fetched similarly to simple time series data:

Start with

' Private Variable that holds the instance of the Dex2 manager singleton
Private MyDex2Mgr As Dex2Lib.Dex2Mgr
Private MyDex2MgrADC As Dex2Lib.IDex2Mgr2


' Private variable that holds the cookie that identifies the Dex2 session Private MyDex2Cookie As Long ' Private variable that holds the Dex2 RData Private WithEvents MyDex2RData As Dex2Lib.RData ' Private variable that holds the Dex2 RDataMgr Private MyDex2RDataMgr As Dex2Lib.RDataMgr
' Private variable that holds the Dex2 logger Private MyDex2Logger As CLogger

Then initialise clicks:

' Instantiate the Dex2 manager
Set MyDex2Mgr = CreateDex2Mgr()
Set MyDex2MgrADC = MyDex2Mgr
' Instantiate the RSearch logger
Set MyDex2Logger = New CLogger

' Initialize Dex2 session
MyDex2Cookie = MyDex2MgrADC.Initialize(DE_MC_ADC_POWERLINK, MyDex2Logger)

' We can choose to display error code
MyDex2Mgr.SetErrorHandling MyDex2Cookie, DE_EH_ERROR_CODES
' Or display error description
' MyDex2Mgr.SetErrorHandling MyDex2Cookie, DE_EH_STRING

' Create a Dex2 query using the session cookie
Set MyDex2RData = MyDex2Mgr.CreateRData(MyDex2Cookie)

' Create a Dex2 query manager using the session cookie
Set MyDex2RDataMgr = MyDex2Mgr.CreateRDataMgr(MyDex2Cookie)

Then, after some error & event handling:

' Set input values
MyDex2RData.SetParameter _
Range("Dex2Item").Value, _
Range("Dex2Fields").Value, _
Range("Dex2RequestParameters").Value, _
Range("Dex2DisplayParameters").Value
' Or using the following individual properties
' MyDex2RData.InstrumentIDList = Range("Dex2Item").Value
' MyDex2RData.FieldList = Range("Dex2Fields").Value
' MyDex2RData.requestParam = Range("Dex2RequestParameters").Value
' MyDex2RData.displayParam = Range("Dex2DisplayParameters").Value


' Send the query without using cache MyDex2RData.Subscribe (False) ' Or use cache by default ' MyDex2RData.Subscribe

Before creating 'OnUpdate' code.

This is all quite heavy in VBA, while it could hardly be simpler in Python:

Python

This was covered above, in the section 'RData Fundamentals' using RD's rd.get_history function. We can also do this with the rd.get_data function:

    	
            

DEX2TrDf = rd.get_data(

    ['VOD.L', 'MSFT.N', 'TRI.N'],

    fields=[

        'TR.RevenueMean.date', 'TR.RevenueMean', 'TR.TRBCEconomicSector', 'TR.TRBCEconSectorCode',

        'TR.TRBCBusinessSector', 'TR.TRBCBusinessSectorCode', 'TR.TRBCIndustryGroup',

        'TR.TRBCIndustryGroupCode', 'TR.TRBCIndustry', 'TR.TRBCIndustryCode'],

    parameters={'SDate': 0, 'EDate': -3, 'FRQ': 'FY'})

 

DEX2TrDf

 

 

 

Instrument Date Revenue - Mean TRBC Economic Sector Name TRBC Economic Sector Code TRBC Business Sector Name TRBC Business Sector Code TRBC Industry Group Name TRBC Industry Group Code TRBC Industry Name TRBC Industry Code
0 VOD.L 14/02/2023 45864975420 Technology 57 Telecommunications Services 5740 Telecommunications Services 574010 Wireless Telecommunications Services 57401020
8 TRI.N 22/02/2023 6937020650 Industrials 52 Industrial & Commercial Services 5220 Professional & Commercial Services 522030 Professional Information Services 52203070
9 TRI.N 01/02/2023 6626869820                
10 TRI.N 07/02/2022 6311529500                
11 TRI.N 22/02/2021 5980789530                

RHistory

What does this do?

As per the EIKON FOR DEVELOPERS documentation that you may find here,

The RHistory API enables developers to access time series data in VBA inside Excel in the same way as the RHistory function. The RHistory function retrieves a list of time series data for one instrument or a list of instruments at regular intervals (for example, on a daily, weekly, monthly, and yearly basis) for a given time period or for a given number of records. It also provides time series data at non-regular intervals, for example, TAS (Time and Sales), TAQ (Trade and Quote), and TICK (tick by tick).


This COM API is best exemplified in Tutorial 9 - Time Series History - RHistoryAPI's Excxel Workbook in which you will find the following VBA:

VBA

In VBA, we declared myRHistoryQuery via Private WithEvents myRHistoryQuery As RHistoryAPI.RHistoryQuery before:

' Set the query parameters accordingly to your needs
With myRHistoryQuery
.InstrumentIdList = Range("G6").Value
.FieldList = Range("G7").Value 'Or of the form "TRDPRC_1.TIMESTAMP;TRDPRC_1.VALUE;TRDPRC_1.VOLUME"

'.FieldList = "TRDPRC_1.TIMESTAMP;TRDPRC_1.HIGH;TRDPRC_1.CLOSE;TRDPRC_1.LOW;TRDPRC_1.OPEN;TRDPRC_1.VOLUME;TRDPRC_1.COUNT"
.RequestParams = Range("G8").Value
.RefreshParams = Range("G9").Value
.DisplayParams = Range("G10").Value

.Subscribe
End With

This allowed us to run sheets such as:

Python

For this, we can (yet again) use the get_history function:

    	
            

IntradayTimeSeriesDf2 = rd.get_history(

    universe=FTSEConstituents,

    fields=['TRDPRC_1'],

    interval="10min", # The consolidation interval. Supported intervals are: tick, tas, taq, minute, 1min, 5min, 10min, 30min, 60min, hourly, 1h, daily, 1d, 1D, 7D, 7d, weekly, 1W, monthly, 1M, quarterly, 3M, 6M, yearly, 1Y.

    start="2022-06-01T13:00:00",

    end="2022-06-01T16:00:00")

 

IntradayTimeSeriesDf2

 

TRDPRC_1

 

STAN.L CRDA.L TSCO.L LGEN.L
Timestamp        
01/06/2022 13:00 637.6 6918 260.64 258.4002
01/06/2022 13:10 636.6 6936 260.1 257.7
01/06/2022 15:40 <NA> <NA> <NA> <NA>
01/06/2022 15:50 <NA> <NA> <NA> <NA>

PLSynchronization Manager

This synchronisation manager was an old method whereby the COM API managed connections to Refinitiv Datasets. It is no longer required in python.

RSearch

RSearch is a COM API function for instrument level search - designed for building instrument lists conforming to various search criteria. See the example below:

RSearch is a powerful COM API function. It was best exemplified in Tutorial 7 - Instrument Search - RSearch's Excel Workbook.

VBA

Creating the sub cmdRSearch_Click:

' Instantiate the RSearch manager
Set myRSrchMgr = CreateRSearchMgr()

If Not myRSrchMgr Is Nothing Then
' Initialize RSearch session (we do not provide any logger here)
' NOTE - This will error if Eikon for Excel is not logged in.
myRSrchCookie = myRSrchMgr.Initialize(RS_CT_EIKON)
' Create a RSearch query using the session cookie
Set myRSrchQry = myRSrchMgr.CreateRSearchQuery(myRSrchCookie)

If Not myRSrchMgr Is Nothing Then
With myRSrchQry
'Initialize the RSearch query with the criteria to use for the search
.AssetClass = [AssetClass].Value
.SearchCriteria = [SearchCriteria].Value '"EPS:>5 RCSIssuerCountryLeaf:Canada"
.SearchParameters = [SearchParameters].Value '"NBROWS:50 SORT:EPS:A"

' Send the query
.Send
End With
End If
End If

Then you can check the status of the query with 'myRSrchQry_OnUpdate'.

Python

RSearch is a powerful COM API function, and we're happy to announce that the Python equivalent - Search API - is even more powerful. For the full works on it, please do read Nick Zicone's article 'Building Search into your Application Workflow'.

The code below is a simple example of how one may use the Search API in Python.  The last example requests M&A data using the filters specified above and orders the data by the announcement date in descending order. More on how you can use search, including guidance, examples, and tips to determine the possible approaches, from simple discovery through experimentation to more advanced techniques, are presented in this article. More is shown here.

    	
            

bondsSearch = rd.discovery.search(

    view = rd.discovery.Views.BOND_FUT_OPT_QUOTES,

    top = 10,

    filter = "IssueCouponRate ge 2",

    select = "CommonName, IssuerCommonName, IssueCouponRate, Currency, IssuerCountryName",

)

bondsSearch

 

 

 

CommonName IssuerCommonName IssueCouponRate Currency IssuerCountryName
0 TTN 2.375 11/16/24 '24 Titan Global Finance PLC 2.375 EUR United Kingdom
1 BNP 4.000 10/21/23 Banca Nazionale del Lavoro SpA 4 EUR Italy
    	
            

equitySerarch = rd.discovery.search(

    view = rd.discovery.Views.EQUITY_QUOTES,

    top = 100,

    filter = "MktCapCompanyUsd ge 1000000000000",

    select = 'CommonName, PriceCloseUsd, MktCapCompanyUsd',

)

equitySerarch

 

 

 

CommonName PriceCloseUsd MktCapCompanyUsd
0 APPLE ORD 151.03 2.38959E+12
1 MICROSOFT ORD 255.29 1.90033E+12
2 ALPHABET CL A ORD 93.65 1.20158E+12
3 SAUDI ARABIAN OIL ORD 8.526739 1.87588E+12
4 ALPHABET CL C ORD 94.02 1.20158E+12
    	
            

MnA = rd.discovery.search(

    view = rd.discovery.Views.DEALS_MERGERS_AND_ACQUISITIONS,

    # specify filtering properties

    filter="((AcquirerCompanyName ne 'Creditors' and AcquirerCompanyName ne 'Shareholder') and (TargetCountry eq 'US' or TargetCountry eq 'UK')"

    + "and TransactionValueIncludingNetDebtOfTarget ge 100 and TargetPublicStatus eq 'Public')"

    + "and (TransactionStatus eq 'Completed' or TransactionStatus eq 'Pending' or TransactionStatus eq 'Withdrawn')"

    + "and (FormOfTransactionName xeq 'Merger' or FormOfTransactionName xeq 'Acquisition') and (TransactionAnnouncementDate le 2021-11-15 and TransactionAnnouncementDate ge 2020-09-15)",

 

    # select only the required fields and order them based on announcement date

    # then specify number of items to be 10000, which is the max; default value is 100

    select='TransactionAnnouncementDate, TargetCompanyName, TargetRIC',

    top = 10000,

    order_by='TransactionAnnouncementDate desc'

)

 

#remove companies which doesn't have RIC

MnA = MnA.dropna(subset = ['TargetRIC']).reset_index(drop = True)

 

print(f'Number of M&A deals for the specified period is {len(MnA)}')

MnA

Number of M&A deals for the specified period is 326

 

 

 

TransactionAnnouncementDate TargetCompanyName TargetRIC
0 15/11/2021 CyrusOne Inc [CONE.O^C22]
1 15/11/2021 CoreSite Realty Corp [COR^L21]
2 15/11/2021 LAACO Ltd [LAACZ.PK^L21]
3 15/11/2021 Casper Sleep Inc [CSPR.K^A22]
4 08/11/2021 McAfee Corp [MCFE.O^C22]

A more complex method may be to create a function that incorporates that search function, outputing an excel file. This is a real-life use case replicating RSearch functionality's in looking for Government and Corporate Debt Instruments; the function is rather large, so we put it online for you to access.

The RD Library has also added a number of ease-of-use features as the Search API is very comprehensive - but with that comes some complexity. Search Templates is one such useful feature.

The "Mines" and "VesselsBoundFor" templates shown here are template examples that you can modify and adapt to your needs. They are defined in the "search-templates.config.json" configuration file. Below is a brief description of the parameters you can use for each template definition.

Search templates are defined using the following JSON structure

  • description (string): Description of the template.
  • parameters (object): Parameters of the template. These parameters can be used as placeholders in the request_body of the template and as named parameters of the search() method of the template. Each parameter has a name, a description, and an optional default value.
  • request_body (object): Body of the request sent to the Search REST API. This request body can include template parameters surrounded by '#{' and '}' (for example: “#{my_param}”). More details on the structure of the request body can be found in the Search API reference guide (access to this guide requires a Refinitiv Workspace account or RDP account to log in).
Template example

"MyTemplate": {
"description": "Search template example.",
"parameters": {
"name": {
"description": "Name of the person to search for.",
"default": "Edison"
}
},
"request_body": {
"Query": "#{name}",
"View":"People",
"Top":10
}
}

Example of usage

rd.discovery.search_templates["MyTemplate"].search(name="Pasteur")

    	
            

from physical_assets_map import PhysicalAssetsMap

 

#some imports to start with

from physical_assets_map import PhysicalAssetsMap

 

#load the search templates configuration file

rd.load_config("search-templates.config.json")

<ConfigurationSet: 0x7fe91a3c3908>

 

Mine Search Template example
    	
            mines = rd.discovery.search_templates["Mines"]
        
        
    

 

Get help about this template

 

    	
            help(mines)
        
        
    

Help on DiscoverySearchTemplate in module refinitiv.data.discovery._search_templates.search object:

class DiscoverySearchTemplate(refinitiv.data.discovery._search_templates.base.TargetTemplate)
| DiscoverySearchTemplate(name=None, *, placeholders_defaults: Union[Dict[str, Any], NoneType] = None, pass_through_defaults: Union[Dict[str, Any], NoneType] = None, optional_placeholders: Iterable[str] = None, ns: 'Namespace' = None, **search_defaults)
|
| Discovery search preset class
|
| Method resolution order:
| DiscoverySearchTemplate
| refinitiv.data.discovery._search_templates.base.TargetTemplate
| builtins.object
|
| Methods defined here:
|
| __repr__(self)
| Return repr(self).
|
| search(self, **kwargs) -> pandas.core.frame.DataFrame
| Please, use help() on a template object itself to get method documentation
|
| ----------------------------------------------------------------------
| Methods inherited from refinitiv.data.discovery._search_templates.base.TargetTemplate:
|
| __init__(self, name=None, *, placeholders_defaults: Union[Dict[str, Any], NoneType] = None, pass_through_defaults: Union[Dict[str, Any], NoneType] = None, optional_placeholders: Iterable[str] = None, ns: 'Namespace' = None, **search_defaults)
| Parameters
| ----------
| name : str, optional
| name of the template
| placeholders_defaults: dict, optional
| Dict of string template placeholders default values.
| pass_through_defaults: dict, optional
| default values for the Target parameters
| optional_placeholders: Iterable[str], optional
| names of placeholders that are optional without default values
| ns: Namespace
| Namespace in which template will operate. Used for subtemplates.
|
| ----------------------------------------------------------------------
| Data descriptors inherited from refinitiv.data.discovery._search_templates.base.TargetTemplate:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)

 

Use the predefined parameters of the template to search for gold mines in south Africa
    	
            

from ipyleaflet import Map

mines_coordinates = mines.search(commodity="Gold", region="South Africa")

 

PhysicalAssetsMap().plot(mines_coordinates).show()

display(mines_coordinates)

Map(center=[-26.416700363159, 27.666700363159], controls=(ZoomControl(options=['position', 'zoom_in_text', 'zo…

 

 

 

 

 

 

RIC RCSRegionLeaf RCSCommodityTypeLeaf DTSubjectName PhysicalAssetStatus Latitude Longitude
0 C}PX7309413492 South Africa Gold South Deep Normal Operation -26.4167 27.6667
1 C}PX7309413493 South Africa Gold Target Normal Operation -27.76 26.63
... ... ... ... ... ... ... ...
91 C}PX7310054031 South Africa Gold Far West Gold Recoveries (FWGR) Normal Operation -26.3895 27.36032
92 C}PX7310101973 South Africa Gold Mine Waste Solutions Normal Operation -26.8417 26.8667

 

News

Streaming News

The Office COM API allowed for streaming real time news. This was rather inconvenient because one would have to (i) record news flowing through on their own environment, (ii) be recording with an open streaming session when the news they're looking for is published, (iii) deal with the memory management involved with such streaming data. The Python code below recreated this, but takes a snapshot at the time the code is run:

(N.B: The Accessing News data with the RD or EDAPI Python libraries will only allow you access to news data up to three months ago. For news data predating that, look into this article.)

 

    	
            

#Define Callback for stream

def display_data(data, instrument, stream):

    clear_output(wait=True)

    current_time = datetime.datetime.now().time()

    print(current_time, "- Data received for", instrument)

    display(data)

 

 

# This will trigger the stream:

stream = rd.open_pricing_stream(

    universe=['NFCP_UBMS'],

    on_data=display_data)

11:21:11.353212 - Data received for NFCP_UBMS

 

 

 

 

 

 

NEWSCODE18 PNAC SEQ_NO TAKE_SEQNO NEWSCODE20 SYS_DUPID AREA_ID ATTRIBTN PRODCODE_N PROD_PERM NEWSCODE13 PROC_DATE NEWSCODE11 SRCOFDATA NEWS_PRIO STORY_TYPE CROSS_REF STORY_DATE NEWSCODE15 RECORDTYPE DSPLY_NAME SF_NAME HEADLINE1 NEWSCODE01 NEWSCODE02 NEWSCODE03 NEWSCODE04 NEWSCODE05 NEWSCODE06 NEWSCODE07 NEWSCODE08 NEWSCODE09 NEWSCODE10 NEWSCODE12 NEWSCODE14 NEWSCODE16 NEWSCODE17 NEWSCODE19 TOT_SEGS HEAD_DIR HEAD_LANG NEWSMGTSTG DSO_ID TAKETM_MS STORYTM_MS CF_NAME
NFCP_UBMS None nBER3DRDqJ 543729 1 None news_bma 3 BER BER 457 None ######## None 3 3 S None ######## None 232 30 bma CRUDE PALM OIL FUTURES CLOSING: MARCH 6 A:4 G:1 G:2EK G:8S G:CI G:K G:S M:1QD M:2CM M:... None None None None None None None None None None None None None None 1 L en 2 52 40871439 40871327 30
    	
            stream.close()
        
        
    

<OpenState.Closed: 'Closed'>

 

Selecting Only a Subset of Fields

Above we are dumping all the fields - you may only be interested in a subset of fields - if so you can manage as below:

 

    	
            

stream = rd.open_pricing_stream(

    universe=['NFCP_UBMS'],

    fields=['PNAC','HEADLINE1'],

    on_data=display_data)

11:21:21.862759 - Data received for NFCP_UBMS

 

 

 

 

 

 

PNAC HEADLINE1
NFCP_UBMS nNSEsrY7f APOLLOTYRE-Loss of Share Certificates
    	
            stream.close()
        
        
    

<OpenState.Closed: 'Closed'>

 

NEW FUNCTIONALITY: Get News headlines

We added this functionality to find the headlines of news which was not a functionality in the old COM API:

 

    	
            

newsResponse = rd.news.get_headlines(query='LSEG',start="20.03.2022",end="25.03.2022",count=3)

newsResponse

 

 

 

headline storyId sourceCode
versionCreated      
27:20.0 BRIEF-London Stock Exchange Secondary ABO Book... urn:newsml:newswire.refinitiv.com:20220324:nFW... NS:RTRS
09:06.0 BRIEF-London Stock Exchange Secondary ABO Book... urn:newsml:newswire.refinitiv.com:20220324:nFW... NS:RTRS
56:21.7 BLOCKTRADE: LONDON STOCK EXCHANGE SECONDARY A... urn:newsml:newswire.refinitiv.com:20220324:nFW... NS:RTRS

Get News Story

Thankfully, the ek library News API is much more powerful and simple to use. Again, most of it is better shown and explained on GitHub, but the below is a great starting point of how to collect News data (that is 15 months old or older):

    	
            

story_id = newsResponse.iat[1,1]

story_id

'urn:newsml:newswire.refinitiv.com:20220324:nFWN2VR17K:1'

    	
            

from IPython.display import HTML

story = rd.news.get_story(story_id)

HTML(story)

March 24 (Reuters) - London Stock Exchange Group Secondary ABO Bookrunner:

  • BLOCKTRADE: LONDON STOCK EXCHANGE SECONDARY ABO: DEAL EXPECTED TO PRICE AT £77.00 PER SHARE; BOOKS MULTIPLE TIMES COVERED AT THAT LEVEL - BOOKRUNNER

  • BLOCKTRADE: LONDON STOCK EXCHANGE SECONDARY ABO: BOOKS WILL CLOSE AT 18:15 UK / 19:15 CET - BOOKRUNNER

Further company coverage: LSEG.L

 

(( Reuters.Briefs@thomsonreuters.com ;))

 

(c) Copyright Thomson Reuters 2022. Click For Restrictions - https://agency.reuters.com/en/copyright.html

 

Contribution - AdxRtContribute.dll

 

What does AdxRtContribute.dll do?

VBA

AdxRtContribute is for data contribution either locally (SCOPE:LOCAL) within the instance of Excel (or application if EikonDesktopDataAPI has been used) or on to a server (SCOPE:SERVER) and potentially on to IDN (where the Source Alias of "TRC" should be specified).

AdxRtContribute replicates the RtContribute() function in Eikon for Excel or Eikon - Microsoft Office.

NOTE - Eikon for Excel or Eikon - Microsoft Office should be logged in otherwise the sample VBA code will generate an error "ERROR #360c - AdxRtx : No connection to the platform".

Prerequisites

1. Open a new single sheet Excel workbook.
Save As with an appropriate name (e.g. AdxRtContribute.xls or AdxRtContribute.xlsm in Office 2007 or higher).

2. Go to the VBE (Visual Basic Editor), ensure the Project Explorer is visible and select the project for the workbook above.
<ALT><F11> or Tools, Macro, Visual Basic Editor in Excel 2003 or Developer, Visual Basic in Excel 2007 and above, View, Project Explorer If the Developer header is not visible in Excel 2007 and above, go to the Excel Office Button, select Excel Options (lower right), Popular, and check the 'Show Developer tab in the Ribbon' box.
3. In the VBE, click on File, Import File and import PLVbaApis.bas.
The .bas location is C:\Program Files (x86)\Thomson Reuters\Eikon\Z\Bin (Z may be X or Y, depending on the last Eikon update). The .bas is loaded as a new VB project module, PLVbaApis.
4. In the PLVbaAPis module, comment out the sections which aren't required.
As this example is dealing with AdxRtContribute, part of the real time library AdfinXRtLib, the AdfinX Real Time section can remain uncommented.
5. In the VBE, go Tools, References and ensure that AdfinX Real Time Library is checked.
If it is not in the list the library is called rtx.dll and its location for Eikon 4 is >C:\Program Files (x86)\Thomson Reuters\Eikon\Z\Bin (Z may be X or Y, depending on the last Eikon update).
AdxRtContribute

6. Create an instance of an AdxRtContribute object using the PLVbaApis function CreateAdxRtContribute.

Set myAdxRtContrib = CreateAdxRtContribute

7. To replicate RtContribute(), when the object has been created set the source, item name and mode (if required) and then contribute the field(s) and value(s) desired.

Public myAdxRtContrib As AdfinXRtLib.AdxRtContribute

Dim fields (1 To 3) As Variant
Dim values (1 To 3) As Variant

Sub myContribution()
Set myAdxRtContrib = CreateAdxRtContribute
If myAdxRtContrib Is Nothing Then MsgBox "Failed to create RtContribute"
With myAdxRtContrib
.Source = "DAVID2"
.ItemName = "TEST_RIC2"
.Mode = "SCOPE:LOCAL UPDATE:CHANGED"

fields (1)="BID"
fields (2)="ASK"
fields (3)="ASKROW80_1"
values(1)=210
values(2)=220
values(3)="ABCDEF"

.Contribute fields, values
'.Contribute "ASK", 220 ' Alternative method of actual names and values'
'.Contribute Array("BID", "ASK"), Array(210, 220) ' Another alternative method'
End With
End Sub

8. RtGet() or RData() can be used in Eikon for Excel to check that the contribution has been successful. If the AdxRtList COM API for real time data retrieval is being used this can be set with the appropriate source and instrument parameters.

9. If no more contributions are required the AdxRtContribute object can be closed (set to Nothing).

 

Python

You can use the Refinitiv Data Library (RD Lib.) for Python's Content Layer's Pricing stream set of functions to send contributions. Using the Content Layer allows for a better ease of use than the Delivery Layer that nesesitates a better understanindg of APIs' inner workings; with the Content Layer, you have the option to set initialization parameters of the RD Lib. in the _refinitiv-data.config.json_ configuration file. You can find an example version of this configuration file here. This file must be located beside your notebook, in your user folder or in a folder defined by the _RD_LIB_CONFIG_PATH_ environment variable; the _RD_LIB_CONFIG_PATH_ environment variable is the option used by this series of examples; you can find more information about the configuration proccess here. The following code sets this environment variable.      

    	
            

import os

os.environ["RD_LIB_CONFIG_PATH"] = "../../../Configuration"

Next, we will need to import some libraries and modules/functions:

    	
            

import refinitiv.data as rd

from refinitiv.data.content import pricing

from refinitiv.data.delivery.omm_stream import ContribType

FYI, we advise using the RD Lib. for Python version 1.4.0 or higher:

    	
            rd.__version__
        
        
    

Next, let's open our session. The open_session() function creates and open sessions based on the information contained in the refinitiv-data.config.json configuration file. Please edit this file to set the session type and other parameters required for the session you want to open. Note also the format expected in the config file here:

{"logs": {"level": "debug","transports": {"console": {"enabled": false},"file": {"enabled": false,"name": "refinitiv-data-lib.log"}}}, "sessions": {"default": "desktop.workspace","platform": {"rtds": {"app-key": "qwerty1234qwerty1234qwerty1234qwerty1234","realtime-distribution-system": {"url": "00.000.0.000:00000","dacs": {"username": " ","application-id": 000,"position": ""}}}},"desktop": {"workspace": {"app-key": "qwerty1234qwerty1234qwerty1234qwerty1234"}}}}

In this config file, you will see that we specified details for the highlighed `platform` & `rtds`; you ought to have already been provided with your contribution RTDS URL and DACS details. We can poit to these details in-code, in Python, in our code:

    	
            rd.open_session("platform.rtds")
        
        
    

<refinitiv.data.session.Definition object at 0x111a0ac1100 {name='rtds'}>

Now let's see what we can do. Start with defining the service we aould like to use; here we'll be using `ATS_GLOBAL_1` that is here for example purposes only:

    	
            service = "ATS_GLOBAL_1" # Accept contribs on only a curated list of RICs
        
        
    

Now let's try some off-stream contributions:

    	
            

def display_contrib_response(response):

    if response.is_success:

        print(f">> Contribution successfully sent.")

    else:

        if response.nak_code:

            print(f'>> Contrib rejected because "{response.nak_message}".')

        if response.error:

            print(f'>> Contrib failed because "{response.error}\n\t{response.debug}"')

 

response = rd.content.pricing.contribute(

    name = "TESTRIC01",

    fields = {

        "BID": 5.555,

        "ASK": 4.444

    },

    service=service,

    contrib_type=ContribType.REFRESH

)

 

display_contrib_response(response)

>> Contribution successfully sent.

Now let's try some on-stream contributions by subscrigin to test RICs created for test purposes:

    	
            

stream = rd.content.pricing.Definition(

    universe=["TESTRIC01", "TESTRIC02", "TESTRIC03"],

    service=service

).get_stream()

 

stream.open()

<OpenState.Opened: 'Opened'>

Let's have a look at our contribution:

    	
            stream.get_snapshot()
        
        
    
  Instrument RDNDISPLAY DSPLY_NAME TIMACT TRADE_DATE TRDTIM_1 BID ASK BIDSIZE ASKSIZE RECORDTYPE ROW80_1 ROW80_2 ROW80_3 STOCK_RIC SPARE_TS1 QUOTE_DATE
0 TESTRIC01 123 BANK 1 57:20.5 05/12/2023 15:39:00 5.555 4.444 10 20 209 22-Mar-23 contrib ask and bid 3 25-Jul-21 16:30:00 01/05/2003
1 TESTRIC02 153 INVESTMENT BANK HKG 55:51.7 05/12/2023 15:39:00 2.1 2.11 30 2 209 22-Mar-23 25-Jul-22 25-Jul-23 25-Jul-21 11:12:13 27/07/2022
2 TESTRIC03 123 BANK 2 12:19.4 05/12/2023 10:12:00 6 3 50 60 209 25-Jul-21 25-Jul-22 25-Jul-23 25-Jul-21 11:12:13 18/10/2021

Let's not foret to close our stream and session:

    	
            

stream.close()

rd.close_session()

Conclusion

In conclusion, we can see that the Office COM API had many great uses, but limitations too. This was without mentioning its reliability on DLLs that can be heavy to run on a personal machine. But the Refinitiv Python Libraries (RDRDP and EDAPI) can not only replicate these COM functionalities but enhance them in many instances, the simplest example being the Historical News functionality shown above.

Several COM API functionalities relying on a technology called Adfin was not replicated in Python in this article, but we will investigate them in another article - so stay tuned!

Further Information

Annex: COM Prerequisites

  1. Open a new single sheet Excel workbook.

    Save As with an appropriate name (e.g. AdxRtSourceList.xls or AdxRtSourceList.xlsm in Office 2007 or higher).

  2. Go to the VBE (Visual Basic Editor), ensure the Project Explorer is visible and select the project for the workbook.

    <ALT><F11> or Tools, Macro, Visual Basic Editor in Excel 2003 or Developer, Visual Basic in Excel 2007 and above, View, Project Explorer If the Developer header is not visible in Excel 2007 and above, go to the Excel Office Button, select Excel Options (lower right), Popular, and check the 'Show Developer tab in the Ribbon' box.

  3. In the VBE, click on File, Import File and import PLVbaApis.bas.

    The .bas location is C:\Program Files (x86)\Thomson Reuters\Eikon\Z\Bin (Z may be X or Y, depending on the last Eikon update). The .bas is loaded as a new VB project module, PLVbaApis.

  4. In the PLVbaAPis module, comment out the sections which aren't required.

    E.G.: when dealing with AdxRtSourceList, part of the real time library AdfinXRtLib, the AdfinX Real Time section can remain uncommented.

  5. In the VBE, go Tools, References and ensure that AdfinX Real Time Library is checked.

    If it is not in the list the library is called rtx.dll and its location for Eikon 4 is ">C:\Program Files (x86)\Thomson Reuters\Eikon\Z\Bin (Z may be X or Y, depending on the last Eikon update).

Further Resources

COM APIs: Overview | Quickstart Guide | Documentation | Downloads | Tutorials | Q&A Forum

RD Library: Overview | Quickstart Guide | Documentation | Tutorials | Q&A Forum