In financial markets, tradable instruments and securities have unique identifiers. The identifiers are very useful, because you can make sure that you and your counterparty are talking about the same instrument while trading. The difficulty is that there isn't really a standard for all the various sorts of instruments or markets. Anyone working in the industry will recognize this issue, especially people working at larger institutions who deal with a variety of instruments. Products like equities, bonds (fixed income), indices, derivatives, currencies and structured products all have their own conventions. Just to name a few identifiers, you may come across:

Fortunately, the problem is recognized and there are steps being made to tackle this. Bloomberg has initiated OpenFigi and Refinitiv (formerly Thomson Reuters) PermID. Basically, they are open sourcing their proprietary identifiers. This makes it easier to map instruments to other identifiers which you may use.

Please take a look at the following websites, before continuing this tutorial:

In this tutorial, we access OpenFIGI and PermID through the APIs and find for five companies traded at the Frankfurt Stock Exchange the full company name, FIGI, PermID, Legal Entity Identifier (LEI), initial public offering date, physical address, website and the company's phone number.

We will get the identifiers for a handful of companies listed in the DAX (Deutscher Aktienindex) in Germany. It is a blue chip stock market index consisting of the 30 major German companies trading on the Frankfurt Stock Exchange. We randomly chose 5 tickers, feel free to change the list or add any you may like.

The Market Identifier Code (MIC) for Xetra in Frankfurt Germany is XETR. If we specify this in our mapping requests, we have a better chance of getting the right identifiers back. Because some tickers may refer to other companies somewhere else in the world. For clarity, we write every mapping job out fully. For bigger lists, it is probably better to use a loop.

Now we have defined the jobs, we need to set some of the configurations and define the function we can use for the jobs. You don't necessarily need an API key for FIGI, but with one you will have higher rate limits.

As you can see, the result of the mapping job is a list of dictionaries. For every ticker, the 'key' is called "data". Let's change the structure a little bit, so we can easily convert it to a Pandas DataFrame. We don't need the keys named 'data', just the list of their values.

In [8]:

just_dictionaries=[d['data'][0]fordinjob_results]

With this new list of dictionaries, we can directly convert it:

In [9]:

df_figi=pd.DataFrame.from_dict(just_dictionaries)df_figi

Out[9]:

compositeFIGI

exchCode

figi

marketSector

name

securityDescription

securityType

securityType2

shareClassFIGI

ticker

uniqueID

uniqueIDFutOpt

0

BBG000FR1Q22

GY

BBG000FR1RP5

Equity

ADIDAS AG

ADS

Common Stock

Common Stock

BBG001S8J8Q3

ADS

EQ0018000100001000

None

1

BBG000BBVT77

GY

BBG000BBVVK7

Equity

BASF SE

BAS

Common Stock

Common Stock

BBG001S5SYB8

BAS

EQ0011569400001000

None

2

BBG000HJTKL0

GY

BBG000HJTMS9

Equity

DEUTSCHE TELEKOM AG-REG

DTE

Common Stock

Common Stock

BBG001S5T4S5

DTE

EQ0018055600001000

None

3

BBG000BG7DY8

GY

BBG000BG7GX2

Equity

SAP SE

SAP

Common Stock

Common Stock

BBG001S6RK27

SAP

EQ0011841200001000

None

4

BBG000BCCRV3

GY

BBG000BCCT76

Equity

SIEMENS AG-REG

SIE

Common Stock

Common Stock

BBG001S69GV4

SIE

EQ0011574600001000

None

The DataFrame actually contains a little bit more information than we need for this tutorial. We can filter the interesting columns and set the tickers to be the index.

NB: At the time of writing, it is not possible to use ISINs as input nor to get RICs as output. Hopefully, this will be added to the API's functionality in the future.

Please fill in your own access token before continuing:

In [22]:

# Your own access tokenaccess_token=''

Plus we define the configuration:

In [13]:

# API endpointrequest_url="https://api.thomsonreuters.com/permid/match"headers={'Content-Type':'text/plain','Accept':'application/json','x-ag-access-token':access_token,'x-openmatch-numberOfMatchesPerRecord':'1',# only return 1 match per ticker'x-openmatch-dataType':'Organization',# only match to "organizations", not "persons" or other tags}

Now it gets a little bit more tricky. As you can read in the documentation, the API excepts a CSV file or "specially formatted text" as input. We are working with a list of tickers in this tutorial, so we need to construct the "specially formatted text" ourselves.

In [14]:

# The first line in the text field is 'Standard Identifier'. We use 'Ticker' as identifier in this tutorialtext_field='Standard Identifier\n'# For every ticker, we will add a new line and specify the Market Identifier Code (MIC) / Exchangeexchange='XETR'fortickerintickers:identifier='TICKER:'+ticker+'&&MIC:'+exchange+'\n'text_field+=identifier# Print the 'text_field' to screen for inspectionprint(text_field)

Did you check out any of the links? PermID offers some additional data besides the identifier. Let's define a function which will help us to retrieve the additional data.

In [18]:

defpermid_data(permid_url):permid_headers={'Accept':'text/turtle',}permid_params={'format':'json-ld','access-token':access_token}# The actual requestpermid_response=requests.get(permid_url,headers=headers,params=permid_params)# Convert the response to JSONpermid_data=json.loads(permid_response.content)returnpermid_data

Now we will create a dictionary of dictionaries, one for every ticker we are interested in. We do this so we can then later convert it easily to a Pandas DataFrame. So, we use a loop to go through each company in the list of the tickers to:

retrieve the data about the respective company

extract the fields we are interested in.

In [19]:

# Create an empty dictionarypermid_dict={}# Loop through all tickers and put the data in the dictionaryforticker,iinzip(tickers,r['outputContentResponse']):# The PermID url for the ticker from the response earlierpermid_url=i['Match OpenPermID']# Use the function defined above to download the datadata=permid_data(permid_url)# Put the desired data in a dictionary for the tickerpermid_dict[ticker]={'company':data['vcard:organization-name'],'IPO':data['hasIPODate'],'address':data['mdaas:HeadquartersAddress'],'website':data['hasURL'],'phone':data['tr-org:hasHeadquartersPhoneNumber'],'LEI':data['tr-org:hasLEI'],'permid':data['tr-common:hasPermId'],'permid_url':permid_url}

All the data is now in a dictionary of dictionaries. Again, it is also very easy to convert this to a Pandas DataFrame.

In [20]:

df_permid=pd.DataFrame.from_dict(permid_dict,orient='index')# Orient='index' for data in rows instead of columnsdf_permid

Out[20]:

company

IPO

address

website

phone

LEI

permid

permid_url

ADS

Adidas AG

1997-11-28T05:00:00Z

Adi-Dassler-Strasse 1\nHERZOGENAURACH\nBAYERN\...

https://www.adidas-group.com/de/

499132840

549300JSX0Z4CW0V5023

4295868725

https://permid.org/1-4295868725

BAS

BASF SE

1952-01-30T05:00:00Z

Carl-Bosch-Str. 38\nLUDWIGSHAFEN AM RHEIN\nRHE...

https://www.basf.com/

49621600

529900PM64WH8AF1E917

4295869198

https://permid.org/1-4295869198

DTE

Deutsche Telekom AG

2000-01-24T05:00:00Z

Friedrich-Ebert-Allee 140\nBONN\nNORDRHEIN-WES...

https://www.telekom.com/

492281810

549300V9QSIG4WX4GJ96

4295870332

https://permid.org/1-4295870332

SAP

SAP SE

1988-11-04T05:00:00Z

Dietmar-Hopp-Allee 16\nWALLDORF\nBADEN-WUERTTE...

https://www.sap.com/

496227747474

529900D6BF99LW9R2E68

5043321284

https://permid.org/1-5043321284

SIE

Siemens AG

2008-02-25T05:00:00Z

Wittelsbacherplatz 2\nMUENCHEN\nBAYERN\n80333\...

https://www.siemens.com/global/de/

498963600

W38RGI023J3WT1HWRP32

4295869238

https://permid.org/1-4295869238

As a final touch, let's join both DataFrames:

In [21]:

df_final=df_figi.join(df_permid)df_final

Out[21]:

name

marketSector

figi

uniqueID

company

IPO

address

website

phone

LEI

permid

permid_url

ticker

ADS

ADIDAS AG

Equity

BBG000FR1RP5

EQ0018000100001000

Adidas AG

1997-11-28T05:00:00Z

Adi-Dassler-Strasse 1\nHERZOGENAURACH\nBAYERN\...

https://www.adidas-group.com/de/

499132840

549300JSX0Z4CW0V5023

4295868725

https://permid.org/1-4295868725

BAS

BASF SE

Equity

BBG000BBVVK7

EQ0011569400001000

BASF SE

1952-01-30T05:00:00Z

Carl-Bosch-Str. 38\nLUDWIGSHAFEN AM RHEIN\nRHE...

https://www.basf.com/

49621600

529900PM64WH8AF1E917

4295869198

https://permid.org/1-4295869198

DTE

DEUTSCHE TELEKOM AG-REG

Equity

BBG000HJTMS9

EQ0018055600001000

Deutsche Telekom AG

2000-01-24T05:00:00Z

Friedrich-Ebert-Allee 140\nBONN\nNORDRHEIN-WES...

https://www.telekom.com/

492281810

549300V9QSIG4WX4GJ96

4295870332

https://permid.org/1-4295870332

SAP

SAP SE

Equity

BBG000BG7GX2

EQ0011841200001000

SAP SE

1988-11-04T05:00:00Z

Dietmar-Hopp-Allee 16\nWALLDORF\nBADEN-WUERTTE...

https://www.sap.com/

496227747474

529900D6BF99LW9R2E68

5043321284

https://permid.org/1-5043321284

SIE

SIEMENS AG-REG

Equity

BBG000BCCT76

EQ0011574600001000

Siemens AG

2008-02-25T05:00:00Z

Wittelsbacherplatz 2\nMUENCHEN\nBAYERN\n80333\...

https://www.siemens.com/global/de/

498963600

W38RGI023J3WT1HWRP32

4295869238

https://permid.org/1-4295869238

We started with only the tickers for a handful of companies. Finally, we have for every ticker the full company name, FIGI, PermID, Legal Entity Identifier (LEI), initial public offering date, physical address, website and phone number.