- Home
- Article Catalog
- Functions to find Option RICs traded on different exchanges

Overview
The current article introduces functions to construct option RICs on equities and indices. Section 1 defines supplementary functions further called by the main RIC construction functions. In section 2, I define separate functions per supported stock exchange. Section 3 defines a universal function that takes ISIN, maturity, strike, and option type as an input finds all exchanges where the options on the given asset are traded, constructs RICs for them, validates, and returns the constructed RICs along with the prices.
Additionally, I have conducted the class implementation of the solution, which offers more scaleable usability of the functions. Please check it in the associated GitHub folder.
The current version covers the following exchanges:
- US OPRA - refer to RULES7, RULES2, RULES3, RULES4 in Workspace, and Guideline for strikes above 10000 in MyRefinitiv.
- EUREX - refer to RULES2, RULES3, RULES4 in Workspace, and general option RIC structure in MyRefinitiv.
- Osaka Exchange - refer to RULES2, RULES3, RULES4 in Workspace, and RIC structure for Osaka exchange in MyRefinitiv.
- Stock Exchange of Hong Kong - refer to RULES2, RULES3, RULES4 in Workspace, and RIC structure for HK exchange in MyRefinitiv.
- Hong Kong Future Exchange - refer to RULES2, RULES3, RULES4 in Workspace, and RIC structure for HK exchange in MyRefinitiv.
- Intercontinental Exchange (ICE) - refer to RULES2, RULES3, RULES4 in Workspace, and general option RIC structure in MyRefinitiv.
The syntax for the expired options is universal across exchanges and can be found here.
Table of Content
Overview
Install and import packages
Section 1: Define supplementary functions
1.1 Function to get exchange codes where the option is traded
1.2 Function to check if found RIC is valid (if price data exists)
1.3 Function to get option Expiration month code
Section 2: Define functions to get option RICs for each exchange
2.1 Function for OPRA
2.2 Function for the Stock Exchange of Hong Kong
2.3 Function for the Osaka Stock Exchange
2.4 Function for the EUREX
2.5 Function for the Intercontinental Exchange
Section 3: Universal function for all above exchanges
!pip install refinitiv.dataplatform
import refinitiv.dataplatform as rdp
import pandas as pd
from datetime import timedelta
from datetime import datetime
app_key = open("app_key.txt","r").read()
rdp.open_desktop_session(app_key)
1.1 Function to get exchange codes where the option is traded
This function allows getting the list of exchange codes where an option on the given asset is traded. The function takes asset RIC as an input and returns the list of exchanges. Then, the function in Section 3 constructs RICs for all supported exchanges in that list. The core of the function is the RDP Search function.
def get_exchange_code(asset):
# build search query to find exchange codes where the option on the given underlying is traded
response = rdp.Search.search(
query = asset,
filter = "SearchAllCategory eq 'Options' and Periodicity eq 'Monthly' ",
select = ' RIC, DocumentTitle, UnderlyingQuoteRIC,Periodicity, ExchangeCode',
navigators = "ExchangeCode",
top = 10000
)
result = response.data.raw["Navigators"]["ExchangeCode"]
# store a=exchange codes in a list
exchange_codes = []
for i in range(len(result['Buckets'])):
code = result['Buckets'][i]['Label']
exchange_codes.append(code)
return exchange_codes
get_exchange_code('.FTSE')
['IEU', 'EUX']
1.2 Function to check if found RIC is valid (if price data exists)
This function allows validation of the constructed option RICs by requesting price summaries. If prices are returned, we can confirm that the RIC(s) is (are) valid, otherwise, we can't confirm the validation. However, the RICs with no prices can be still valid as there might not be prices because of low liquidity for specific assets with specific strike prices.
Thus, the functions print all constructed possible RICs. This function takes the option RIC, maturity, and dictionary of identifiers as input and returns the RIC along with the prices.
def check_ric(ric, maturity, ident):
exp_date = pd.Timestamp(maturity)
# get start and end date for get_historical_price_summaries query (take current date minis 90 days period)
sdate = (datetime.now() - timedelta(90)).strftime('%Y-%m-%d')
edate = datetime.now().strftime('%Y-%m-%d')
# check if option is matured. If yes, add expiration syntax
# and recalculate start and end date of the query (take expiration day minus 90 days period)
if pd.Timestamp(maturity) < datetime.now():
ric = ric + '^' + ident[str(exp_date.month)]['exp'] + str(exp_date.year)[-2:]
sdate = (exp_date - timedelta(90)).strftime('%Y-%m-%d')
edate = exp_date.strftime('%Y-%m-%d')
# request option prices. Please note, there is no settle price for OPRA traded options
if ric.split('.')[1][0] == 'U':
prices = rdp.get_historical_price_summaries(ric, start = sdate, end = edate, interval = rdp.Intervals.DAILY,
fields = ['BID','ASK','TRDPRC_1'])
else:
prices = rdp.get_historical_price_summaries(ric, start = sdate, end = edate, interval = rdp.Intervals.DAILY,
fields = ['BID','ASK','TRDPRC_1', 'SETTLE'])
return ric, prices
def get_exp_month(exp_date, opt_type):
# define option expiration identifiers
ident = {'1': {'exp': 'A','C': 'A', 'P': 'M'},
'2': {'exp': 'B', 'C': 'B', 'P': 'N'},
'3': {'exp': 'C', 'C': 'C', 'P': 'O'},
'4': {'exp': 'D', 'C': 'D', 'P': 'P'},
'5': {'exp': 'E', 'C': 'E', 'P': 'Q'},
'6': {'exp': 'F', 'C': 'F', 'P': 'R'},
'7': {'exp': 'G', 'C': 'G', 'P': 'S'},
'8': {'exp': 'H', 'C': 'H', 'P': 'T'},
'9': {'exp': 'I', 'C': 'I', 'P': 'U'},
'10': {'exp': 'J', 'C': 'J', 'P': 'V'},
'11': {'exp': 'K', 'C': 'K', 'P': 'W'},
'12': {'exp': 'L', 'C': 'L', 'P': 'X'}}
# get expiration month code for a month
if opt_type.upper() == 'C':
exp_month = ident[str(exp_date.month)]['C']
elif opt_type.upper() == 'P':
exp_month = ident[str(exp_date.month)]['P']
return ident, exp_month
Section 2: Define functions to get option RICs for each exchange
In this section, I define functions for option RIC construction for different exchanges. Those functions take asset RIC, maturity, strike, and option type as input and return validated rics and the prices. If no price is found for constructed RICs, the functions print out possible RICs.
def get_ric_opra(asset, maturity, strike, opt_type):
exp_date = pd.Timestamp(maturity)
# trim underlying asset's RIC to get the required part for option RIC
if asset[0] == '.': # check if the asset is an index or an equity
asset_name = asset[1:] # get the asset name - we remove "." symbol for index options
else:
asset_name = asset.split('.')[0] # we need only the first part of the RICs for equities
ident = {'1': {'exp': 'A', 'C_bigStrike': 'a','C_smallStrike': 'A', 'P_bigStrike': 'm', 'P_smallStrike': 'M'},
'2': {'exp': 'B', 'C_bigStrike': 'b','C_smallStrike': 'B', 'P_bigStrike': 'n', 'P_smallStrike': 'N'},
'3': {'exp': 'C', 'C_bigStrike': 'c','C_smallStrike': 'C', 'P_bigStrike': 'o', 'P_smallStrike': 'O'},
'4': {'exp': 'D', 'C_bigStrike': 'd','C_smallStrike': 'D', 'P_bigStrike': 'p', 'P_smallStrike': 'P'},
'5': {'exp': 'E', 'C_bigStrike': 'e','C_smallStrike': 'E', 'P_bigStrike': 'q', 'P_smallStrike': 'Q'},
'6': {'exp': 'F', 'C_bigStrike': 'f','C_smallStrike': 'F', 'P_bigStrike': 'r', 'P_smallStrike': 'R'},
'7': {'exp': 'G', 'C_bigStrike': 'g','C_smallStrike': 'G', 'P_bigStrike': 's', 'P_smallStrike': 'S'},
'8': {'exp': 'H', 'C_bigStrike': 'h','C_smallStrike': 'H', 'P_bigStrike': 't', 'P_smallStrike': 'T'},
'9': {'exp': 'I', 'C_bigStrike': 'i','C_smallStrike': 'I', 'P_bigStrike': 'u', 'P_smallStrike': 'U'},
'10': {'exp': 'J', 'C_bigStrike': 'j','C_smallStrike': 'J', 'P_bigStrike': 'v', 'P_smallStrike': 'V'},
'11': {'exp': 'K', 'C_bigStrike': 'k','C_smallStrike': 'K', 'P_bigStrike': 'w', 'P_smallStrike': 'W'},
'12': {'exp': 'L', 'C_bigStrike': 'l','C_smallStrike': 'L', 'P_bigStrike': 'x', 'P_smallStrike': 'X'}}
# get expiration month code for a month
if opt_type.upper() == 'C':
if strike > 999.999:
exp_month = ident[str(exp_date.month)]['C_bigStrike']
else:
exp_month = ident[str(exp_date.month)]['C_smallStrike']
# calculate the strike price and get expiration month code for a month for put options
elif opt_type.upper() == 'P':
if strike > 999.999:
exp_month = ident[str(exp_date.month)]['P_bigStrike']
else:
exp_month = ident[str(exp_date.month)]['P_smallStrike']
# get strike prrice
if type(strike) == float:
int_part = int(strike)
dec_part = str(str(strike).split('.')[1])
else:
int_part = int(strike)
dec_part = '00'
if len(dec_part) == 1:
dec_part = dec_part + '0'
if int(strike) < 10:
strike_ric = '00' + str(int_part) + dec_part
elif int_part >= 10 and int_part < 100:
strike_ric = '0' + str(int_part) + dec_part
if int_part >= 100 and int_part < 1000:
strike_ric = str(int_part) + dec_part
elif int_part >= 1000 and int_part < 10000:
strike_ric = str(int_part) + '0'
elif int_part >= 10000 and int_part < 20000:
strike_ric = 'A' + str(int_part)[-4:]
elif int_part >= 20000 and int_part < 30000:
strike_ric = 'B' + str(int_part)[-4:]
elif int_part >= 30000 and int_part < 40000:
strike_ric = 'C' + str(int_part)[-4:]
elif int_part >= 40000 and int_part < 50000:
strike_ric = 'D' + str(int_part)[-4:]
# build initial ric
ric = asset_name + exp_month + str(exp_date.day) + str(exp_date.year)[-2:] + strike_ric + '.U'
# check ric validity
ric, prices = check_ric(ric, maturity, ident)
# return valid rics or append to the possible_ric list if no price is found
possible_rics = []
if prices is not None:
return ric, prices
else:
possible_rics.append(ric)
print(f'Here is a list of possible RICs {possible_rics}, however we could not find any prices for those!')
return ric, prices
ric, prices = get_ric_opra('AAPL.O', '2022-01-21', 180, 'C')
ric
'AAPLA212218000.U^A22'
prices.head()
TRDPRC_1 | BID | ASK | |
10/22/2021 | 0.54 | 0.51 | 0.54 |
10/25/2021 | 0.5 | 0.49 | 0.52 |
10/26/2021 | 0.55 | 0.53 | 0.55 |
10/27/2021 | 0.6 | 0.59 | 0.62 |
10/28/2021 | 0.82 | 0.75 | 0.84 |
def get_ric_hk(asset, maturity, strike, opt_type):
exp_date = pd.Timestamp(maturity)
# get asset name and strike price for the asset
if asset[0] == '.':
asset_name = asset[1:]
strike_ric = str(int(strike))
else:
asset_name = asset.split('.')[0]
strike_ric = str(int(strike * 100))
# get expiration month codes
ident, exp_month = get_exp_month(exp_date, opt_type)
possible_rics = []
# get rics for options on indexes. Return if valid add to the possible_rics list if no price is found
if asset[0] == '.':
ric = asset_name + strike_ric + exp_month + str(exp_date.year)[-1:] + '.HF'
ric, prices = check_ric(ric, maturity, ident)
if prices is not None:
return ric, prices
else:
possible_rics.append(ric)
else:
# get rics for options on equities. Return if valid add to the possible_rics list if no price is found
# there could be several generations of options depending on the number of price adjustments due to a corporate event
# here we use 4 adjustment opportunities.
for i in range(4):
ric = asset_name + strike_ric + str(i)+ exp_month + str(exp_date.year)[-1:] + '.HK'
ric, prices = check_ric(ric, maturity, ident)
if prices is not None:
return ric, prices # we return ric and prices for the first found ric (we don't check for other adjusted rics)
else:
possible_rics.append(ric)
print(f'Here is a list of possible RICs {possible_rics}, however we could not find any prices for those!')
return ric, prices
ric, prices = get_ric_hk('.HSI', '2022-03-30', 18400, 'C')
ric
'HSI18400C2.HF^C22'
prices.head()
TRDPRC_1 | BID | ASK | SETTLE | |
12/29/2021 | <NA> | <NA> | <NA> | 4651 |
12/30/2021 | <NA> | <NA> | <NA> | 4732 |
12/31/2021 | <NA> | <NA> | <NA> | 5016 |
1/3/2022 | <NA> | <NA> | <NA> | 4826 |
1/4/2022 | <NA> | <NA> | <NA> | 4862 |
def get_ric_ose(asset, maturity, strike, opt_type):
exp_date = pd.Timestamp(maturity)
if asset[0] == '.':
asset_name = asset[1:]
else:
asset_name = asset.split('.')[0]
strike_ric = str(strike)[:3]
ident, exp_month = get_exp_month(exp_date, opt_type)
possible_rics = []
if asset[0] == '.':
# Option Root codes for indexes are different from the RIC, so we rename where necessery
if asset_name == 'N225':
asset_name = 'JNI'
elif asset_name == 'TOPX':
asset_name = 'JTI'
# we consider also J-NET (Off-Auction(with "L")) and High frequency (with 'R') option structures
for jnet in ['', 'L', 'R']:
ric = asset_name + jnet + strike_ric + exp_month + str(exp_date.year)[-1:] + '.OS'
ric, prices = check_ric(ric, maturity, ident)
if prices is not None:
return ric, prices
else:
possible_rics.append(ric)
else:
generations = ['Y', 'Z', 'A', 'B', 'C'] # these are generation codes similar to one from HK
for jnet in ['', 'L', 'R']:
for gen in generations:
ric = asset_name + jnet + gen + strike_ric + exp_month + str(exp_date.year)[-1:] + '.OS'
ric, prices = check_ric(ric, maturity, ident)
if prices is not None:
return ric, prices
else:
possible_rics.append(ric)
print(f'Here is a list of possible RICs {possible_rics}, however we could not find any prices for those!')
return ric, prices
ric, prices = get_ric_ose('7974.T', '2022-03-30', 50000, 'P')
ric
'7974Y500O2.OS^C22'
prices.head()
TRDPRC_1 | BID | ASK | SETTLE | |
12/29/2021 | None | None | None | 1609 |
12/30/2021 | None | None | None | 1777 |
1/4/2022 | None | None | None | 1516 |
1/5/2022 | None | None | None | 1647 |
1/6/2022 | None | None | None | 1848 |
def get_ric_eurex(asset, maturity, strike, opt_type):
exp_date = pd.Timestamp(maturity)
if asset[0] == '.':
asset_name = asset[1:]
if asset_name == 'FTSE':
asset_name = 'OTUK'
elif asset_name == 'SSMI':
asset_name = 'OSMI'
elif asset_name == 'GDAXI':
asset_name = 'GDAX'
elif asset_name == 'ATX':
asset_name = 'FATXA'
elif asset_name == 'STOXX50E':
asset_name = 'STXE'
else:
asset_name = asset.split('.')[0]
ident, exp_month = get_exp_month(exp_date, opt_type)
if type(strike) == float:
int_part = int(strike)
dec_part = str(str(strike).split('.')[1])[0]
else:
int_part = int(strike)
dec_part = '0'
if len(str(int(strike))) == 1:
strike_ric = '0' + str(int_part) + dec_part
else:
strike_ric = str(int_part) + dec_part
possible_rics = []
generations = ['', 'a', 'b', 'c', 'd']
for gen in generations:
ric = asset_name + strike_ric + gen + exp_month + str(exp_date.year)[-1:] + '.EX'
ric, prices = check_ric(ric, maturity, ident)
if prices is not None:
return ric, prices
else:
possible_rics.append(ric)
print(f'Here is a list of possible RICs {possible_rics}, however we could not find any prices for those!')
return ric, prices
ric, prices = get_ric_eurex('.STOXX50E', '2022-03-30', 4200, 'P')
ric
'STXE42000O2.EX^C22'
prices.head()
TRDPRC_1 | BID | ASK | SETTLE | |
12/29/2021 | 112.5 | 110.8 | 114.4 | 112.9 |
12/30/2021 | 100.7 | 101.5 | 104.1 | 102.5 |
1/3/2022 | 91.1 | 87.3 | 88.8 | 88 |
1/4/2022 | 72.8 | 79.7 | 82.8 | 81.2 |
1/5/2022 | 69.4 | 68.4 | 71.5 | 70.3 |
def get_ric_ieu(asset, maturity, strike, opt_type):
exp_date = pd.Timestamp(maturity)
if asset[0] == '.':
asset_name = asset[1:]
if asset_name == 'FTSE':
asset_name = 'LFE'
else:
asset_name = asset.split('.')[0]
ident, exp_month = get_exp_month(exp_date, opt_type)
if len(str(int(strike))) == 2:
strike_ric = '0' + str(int(strike))
else:
strike_ric = str(int(strike))
if type(strike) == float and len(str(int(strike))) == 1:
int_part = int(strike)
dec_part = str(str(strike).split('.')[1])[0]
strike_ric = '0' + str(int_part) + dec_part
possible_rics = []
generations = ['', 'a', 'b', 'c', 'd']
for gen in generations:
ric = asset_name + strike_ric + gen + exp_month + str(exp_date.year)[-1:] + '.L'
ric, prices = check_ric(ric, maturity, ident)
if prices is not None:
return ric, prices
else:
possible_rics.append(ric)
print(f'Here is a list of possible RICs {possible_rics}, however we could not find any prices for those!')
return ric, prices
ric, prices = get_ric_ieu('.FTSE', '2022-06-30', 7000, 'C')
ric
'LFE7000F2.L'
prices.head()
TRDPRC_1 | BID | ASK | SETTLE | |
1/19/2022 | <NA> | 629.5 | 654 | 630.5 |
1/20/2022 | <NA> | 611 | 637.5 | 619 |
1/21/2022 | <NA> | 543 | 577 | 564.5 |
1/24/2022 | <NA> | 410 | 470.5 | 472 |
1/25/2022 | <NA> | 492.5 | 530 | 515 |
Section 3: Universal function for all above exchanges
In this section, I built a universal function that takes ISIN, maturity, strike, and option type as an input finds all exchanges where the options on the given asset are traded, constructs RICs for them, validates and returns the constructed RICs along with the prices. Here again, If no price is found for constructed RICs, the functions print out possible RICs.
def get_optionRic(isin, maturity, strike, opt_type):
# define covered exchanges along with functions to get RICs from
exchanges = {'OPQ': get_ric_opra,
'IEU': get_ric_ieu,
'EUX': get_ric_eurex,
'HKG': get_ric_hk,
'HFE': get_ric_hk,
'OSA': get_ric_ose}
# convert ISIN to RIC
df = rdp.convert_symbols( isin, from_symbol_type = "ISIN" , to_symbol_types = "RIC")
ricUnderlying = df['RIC'][0]
# get exchanges codes where the option on the given asset is traded
exchnage_codes = get_exchange_code(ricUnderlying)
# get the list of (from all available and covered exchanges) valid rics and their prices
option_rics = []
priceslist = []
for exch in exchnage_codes:
if exch in exchanges.keys():
ric, prices = exchanges[exch](ricUnderlying, maturity, strike, opt_type)
if prices is not None:
option_rics.append(ric)
priceslist.append(prices)
print(f'Option RIC for {exch} exchange is successfully constructed')
else:
print(f'The {exch} exchange is not supported yet')
return option_rics, priceslist
Below, I test the fuinction for several exchanges and assets:
# option_rics, priceslist = get_optionRic('CH0012221716', '2022-03-30', 34, 'C')
# option_rics, priceslist = get_optionRic('DE0008404005', '2022-03-18', 220, 'C')
# option_rics, priceslist = get_optionRic('ES0113211835', '2022-03-18', 4.7, 'C')
# option_rics, priceslist = get_optionRic('FR0000120073', '2022-03-18', 150, 'C')
# option_rics, priceslist = get_optionRic('GB0031348658', '2022-03-18', 210, 'P')
option_rics, priceslist = get_optionRic('GB0009895292', '2022-03-18', 9000, 'P')
# option_rics, priceslist = get_optionRic('GB00BH4HKS39', '2022-03-18', 100, 'P')
# option_rics, priceslist = get_optionRic('FR0010220475', '2022-06-18', 36, 'P')
# option_rics, priceslist = get_optionRic('FR0000131104', '2022-03-18', 70, 'P')
# option_rics, priceslist = get_optionRic('IT0003132476', '2022-06-16', 13, 'C')
# option_rics, priceslist = get_optionRic('NL0010273215', '2022-02-18', 640, 'P')
# option_rics, priceslist = get_optionRic('HK0000004322', '2022-03-30', 18400, 'C')
# option_rics, priceslist = get_optionRic('HK1093012172', '2022-03-30', 10, 'C')
# option_rics, priceslist = get_optionRic('KYG875721634', '2022-04-28', 480, 'C')
# option_rics, priceslist = get_optionRic('JP9010100007', '2022-06-10', 1900, 'C')
# option_rics, priceslist = get_optionRic('JP3788600009', '2022-06-10', 6500, 'C')
# option_rics, priceslist = get_optionRic('GB0001383545', '2022-03-18', 7650, 'C')
# option_rics, priceslist = get_optionRic('EU0009658145', '2022-03-18', 4200, 'C')
# option_rics, priceslist = get_optionRic('JP9010C00002', '2022-01-17', 25875, 'C')
# option_rics, priceslist = get_optionRic('US90184L1026', '2022-01-21', 40, 'C')
# option_rics, priceslist = get_optionRic('US78378X1072', '2022-02-18', 5000, 'C')
Option RIC for IEU exchange is successfully constructed
Option RIC for EUX exchange is successfully constructed
option_rics
['AZN9000O2.L^C22', 'AZN90000O2.EX^C22']
priceslist[0].head()
TRDPRC_1 | BID | ASK | SETTLE | |
12/17/2021 | 741 | 705.5 | 816 | 784 |
12/20/2021 | <NA> | 776 | 796 | 802.5 |
12/21/2021 | <NA> | 697.5 | 717 | 706 |
12/22/2021 | <NA> | 683.5 | 703.5 | 692 |
12/23/2021 | <NA> | 669 | 687 | 694 |
Conclusion
The current article presented functions to find valid RICs for options on stock and indices traded in several exchanges. Additionally, I presented a universal function that finds the exchanges where an option on a given asset is traded, constructs RICs for them, validates and returns the constructed RICs and the price.
Furthermore, I have conducted the class implementation of the solution, which offers more scaleable usability of the functions. Please check it in the associated GitHub folder.
The current version of this article is limited to certain exchanges, including OPRA, EUREX, ICE, Hong Kong, and Osaka, and options on certain asset types, including indices and stocks. Please let me know which other exchanges and/or options on other asset categories you want me to build functions for. You can contact me directly via h.aramyan@refinitiv.com or raise your questions/suggestion via the Q&A portal of the Developer community.
RELATED ARTICLES