Read me

The objective of this project is to show that it is better to express regulatory requirements using executable expressions which all interested parties can share and run and test, rather than to express regulatory requirements as text documents which everyone has to interpret for themselves.

This page is a Jupyter notebook. It is a combination of a document and some live software which you can execute if you are running your own jupyter-notebook server. If you are not running a Jupyter server you can still read the document and see the code examples - you just can't run them.

If you see something wrong on this page or in the code, please create an issue in the GitHub project.

MiFID II classification of trades using the RTS 2 Annex 3 taxonomy.

Governments would prefer to avoid another financial crisis like the one in 2008 and believe that making the big players operate in a more open and transparent way will help avoid another crash.

Markets in Financial Instruments Directive II (MiFID II) is an EU law which has market transparency as its key objective. The predecessor law, MiFID I, only looked at a part of what banking firms do. MiFID II aims to cover most mainstream activity.

Governments rely on regulators to make sure that their laws are being followed. For MiFID II the primary regulator is ESMA. ESMA have produced a number of Regulatory Technical Standard (RTS) documents which aim to explain what banking firms must do to comply with the MiFID II law.

One of the RTS documents, RTS 2, explains how different kinds of trading activity can be identified. Having a clear way to say what has been traded is an important part of making the markets more transparent.

Some kinds of trading activity are already pretty transparent, for example buying and selling shares in a public company. Trades of this kind are mostly done using a public exchange, such as the New York or London stock exchanges. The 'price' for a given stock is simply the amount of money paid in the most recent trade and this price is made public by the exchange so everyone can see what the latest price is. It is pretty easy to identify what has been traded because each stock has a identifier, e.g. 'AAPL' identifies Apple Inc. shares.

Not all trades happen on public exchanges. Many trades happen directly between two parties and these are known as over the counter (OTC) trades. Each OTC trade can be fine-tuned, for example setting payment dates and interest rates. The fine tuning of OTC trades makes it hard to give an identity to what has been traded, but this is where RTS 2 comes in.

The easiest way to understand what RTS 2 is all about is to use it to classify some trades, and you can do just that below.

A Python Implementation of RTS 2 Annex 3

It would be nice if ESMA published a working software implememtation of the RTS rules along with some test data so people can see exactly how the rules are supposed to work, and how reports are supposed to look. But ESMA don't do that. Each participant must somehow get an implementation of the RTS rules, either by writing it themselves or buying an implementation.

One market participant implemented the RTS rules themselves and have now released part of that implementation under an open source license, the BSD license, so anyone can see the implementaion and use it. This document forms a part of that release.

Hopefully this software will encourage ESMA to produce reference implementaions of their rules in future. They could even take this software as a starting point.

The software here is written in the Python programming language. Python was chosen because the language is ubiquitous, that is it can be used easily and immediately on most modern computers; everything from a Raspberry Pi to the largest of big data clusters.

Running a really simple initial classification

The box below contains python code which runs the classification software. If you are just viewing this page then you won't be able to run the code, but if you start the page using your own local Jupyter notebook server then the code will really run if you select the box below and press control+enter. If you can run the code you might like to try changing the values of the attributes below (e.g. to_date) to see what happens.


In [1]:
# Import the RTS 2 module and the Python date & time tools module
import rts2_annex3
import datetime

# Create a simple Python object to represent a trade.
class SampleTrade(object):
    pass
sample_trade = SampleTrade()
sample_trade.asset_class_name = 'Foreign Exchange Derivatives'
sample_trade.sub_asset_class_name= 'Deliverable FX options (DO)'
sample_trade.underlying_currency_pair = ('GBP~USD')
sample_trade.from_date = datetime.date(2017, 9, 13)
sample_trade.to_date = datetime.date(2017, 10, 12)

# Now classify the trade
sample_classification = rts2_annex3.class_root.classification_for(sample_trade)

# Lastly, display the classificaton
sample_classification.classification_dict()


Out[1]:
OrderedDict([('RTS2 version', 'EU 2017/583 of 14 July 2016'),
             ('Asset class', 'Foreign Exchange Derivatives'),
             ('Sub-asset class', 'Deliverable FX options (DO)'),
             ('Segmentation criterion 1 description',
              'underlying currency pair defined as combination of the two currencies underlying the derivative contract'),
             ('Segmentation criterion 1', 'GBP~USD'),
             ('Segmentation criterion 2 description',
              'time to maturity bucket of the swap defined as follows:'),
             ('Segmentation criterion 2',
              'Maturity bucket 2: 1 week to 3 months')])

Understanding a classification

The classification is shown here as a Python dictionary, but one could imagine presenting this classification in many ways ... and this is a problem. What is the official accepted literal form of an RTS 2 classification? Nobody seems to know. So let's go with this dictionary for now.

Another point about the above representation is that it is very big, and the example is not one of the biggest! The reason for the size is that the text which appears is exactly as it appears in RTS 2. There is no obvious way to shorten the classification without inventing something, and that would open the door to arguments about what is right. This way, the classification links back to the RTS document in an extremely obvious, if verbose, way. No arguments.

To a large degree, the classification is simply repeating the information we gave our sample_trade object in the code above, but information has been checked and other information added.

This classification first confirms the identity of the RTS document the classification is based upon. The RTS rules may change over time, so it is important to know which version of the RTS a particular classification is based upon.

Next we see the Asset class and Sub-asset class, which is repeating just what we said above. When classifying a trade there are some things you just have to know. There will be some help on how to choose Asset classes and Sub-asset classes below.

Then we see something we didn't include in our trade object. The RTS 2 Annex 3 document defines a number of criteria for each kind of Sub-asset class. The Sub-asset class in this case has two criteria, and the classification included the description, the exact text, from the RTS document to explain what the criteria mean.

The values for the criteria do come from the values on our object, but some involve calculation. The currency pair criterion, criterion 1, is simply the name of underlying_currency_pair value we provided. Criterion 2 gets its value from date calculations which use the from and to dates we gave; the resulting value is a date bucket, bucket 2 in this case.

Would Json be a better format for classifications?

Because the classification is just a Python object we can change its implementation to render the classification in any way we please, or we can take the dictionary it currently produces and convert it to something else. Here, the classification above is shown as json:


In [2]:
print(sample_classification.as_json(indent=4))


{
    "RTS2 version": "EU 2017/583 of 14 July 2016",
    "Asset class": "Foreign Exchange Derivatives",
    "Sub-asset class": "Deliverable FX options (DO)",
    "Segmentation criterion 1 description": "underlying currency pair defined as combination of the two currencies underlying the derivative contract",
    "Segmentation criterion 1": "GBP~USD",
    "Segmentation criterion 2 description": "time to maturity bucket of the swap defined as follows:",
    "Segmentation criterion 2": "Maturity bucket 2: 1 week to 3 months"
}

RTS 2 Annex 3 defines a taxonomy. A Tree.

To understand how the classification process works we need to look at what the RTS says.

The RTS 2 Annex 3 taxonomy is made up of Asset classes which get broken down into Sub-asset classes which are further broken down by combinations of criteria values.

Here is some code to list the names of elements of the taxonomy:


In [3]:
# The root of the taxonomy is rts2_annex3.class_root.  Here we ask the
# root for the asset classes, and then ask each asset class for its name.
# The names are exactly the names of the Asset classes you'll see in the RTS document.
[asset_class.name for asset_class in rts2_annex3.class_root.asset_classes]


Out[3]:
['Bonds (all bond types except ETCs and ETNs)',
 'Bonds (ETC and ETN bond types)',
 'Structured Finance Products (SFPs)',
 'Securitised Derivatives',
 'Interest Rate Derivatives',
 'Equity Derivatives',
 'Commodity Derivatives',
 'Foreign Exchange Derivatives',
 'Credit Derivatives',
 'C10 Derivatives',
 'Financial contracts for differences (CFDs)',
 'Emission Allowances',
 'Emission Allowance Derivatives']

In [4]:
# Each asset class is broken down into Sub-asset classes. 
# So now we take the FX Derivatives asset class and display the names of 
# its children, the sub-asset classes.
fx_asset_class = rts2_annex3.class_root.asset_class_by_name('Foreign Exchange Derivatives')
[sub_asset_class.name for sub_asset_class in fx_asset_class.children]


Out[4]:
['Non-deliverable forward (NDF)',
 'Deliverable forward (DF)',
 'Non-Deliverable FX options (NDO)',
 'Deliverable FX options (DO)',
 'Non-Deliverable FX swaps (NDS)',
 'Deliverable FX swaps (DS)',
 'FX futures',
 'Other Foreign Exchange Derivatives']

In [5]:
# Each sub-asset class has a number of criteria.
# Here we ask the Deliverable FX Options sub-asset class to list its
# criteria:
fx_do_sub_asset_class = fx_asset_class.sub_asset_class_by_name('Deliverable FX options (DO)')
[criterion.description for criterion in fx_do_sub_asset_class.criteria]


Out[5]:
['underlying currency pair defined as combination of the two currencies underlying the derivative contract',
 'time to maturity bucket of the swap defined as follows:']

Viewing the RTS 2 taxonomy using ipywidgets

If you are running this notebook on a live Jupyter server then you can run the code below to display widgets which let you navigate the RTS 2 taxonomy.

You can select an asset class in a drop-down widget. This then populates the sub-asset classes drop-down widget for the selected asset class. Selecting a sub-asset class causes the criteria for that sub-asset class to be displayed.

Here is a screen shot of how the widgets look in action. In this example I have selected Energy Commodity Swaps which has seven criteria:


In [6]:
import rts2_annex3
import collections
import ipywidgets as widgets
from IPython.display import display

asset_classes = rts2_annex3.class_root.asset_classes
asset_class_dict = collections.OrderedDict([
        (an_asset_class.name, an_asset_class) 
        for an_asset_class 
        in asset_classes])

asset_class_widget = widgets.Dropdown(
    options=asset_class_dict,
    description='Asset Classes:',
    disabled=False,
)

def sub_asset_class_dict(asset_class):
    return collections.OrderedDict([
        (sub_asset_class.name, sub_asset_class) 
        for sub_asset_class 
        in asset_class.sub_asset_classes])

sub_asset_class_widget = widgets.Dropdown(
    options=sub_asset_class_dict(asset_class_widget.value),
    description='Sub-asset Classes:',
    disabled=False,
)

criteria_vbox = widgets.VBox([])

def criteria_widgets(sub_asset_class):
    # OK, in here I need to look up the criteria for the
    # sub-asset class and build the widgets in rows of HBox es
    return [widgets.Label(criterion.display(prefix=""))
            for criterion
            in sub_asset_class.criteria]
    
def asset_class_changed(change):
    if change['type'] == 'change' and change['name'] == 'value':
        selected_asset_class = change['new']
        sub_asset_class_widget.options = sub_asset_class_dict(selected_asset_class)
        
def sub_asset_class_changed(change):
    if change['type'] == 'change' and change['name'] == 'value':
        selected_sub_asset_class = change['new']
        criteria_vbox.children = criteria_widgets(selected_sub_asset_class)

asset_class_widget.observe(asset_class_changed)
sub_asset_class_widget.observe(sub_asset_class_changed)
display(asset_class_widget)
display(sub_asset_class_widget)
criteria_vbox.children = criteria_widgets(sub_asset_class_widget.value)
display(criteria_vbox)

Viewing the RTS 2 Annex 3 taxonomy as a tree

The following code walks the RTS 2 Annex 3 taxonomy building up a string which presents the taxonomy as a tree, in the same kind of way that nested file folders on a computer could be shown as a tree.

The names are all trimmed to 50 characters just to force each item onto a single line.


In [7]:
import rts2_annex3
from IPython.display import display

max_name_length = 50
target_string = ''
root = rts2_annex3.class_root
target_string += 'Root\n'
for asset_class in root.asset_classes:
    target_string += '  Asset class: "' + asset_class.name + '"\n'
    for sub_asset_class in asset_class.children:
        target_string += '    Sub-asset class: "' \
            + sub_asset_class.name[:max_name_length] \
            + '"\n'
        for criterion in sub_asset_class.criteria:
            target_string += '      Critrion: ' \
                + str(criterion.criterion_number) \
                + ' "' \
                + criterion.description[:max_name_length] \
                + '"\n'

print("\nDon't forget, all strings have been trimmed to {limit} characters! ... \n".format(
        limit=max_name_length))
print(target_string)


Don't forget, all strings have been trimmed to 50 characters! ... 

Root
  Asset class: "Bonds (all bond types except ETCs and ETNs)"
    Sub-asset class: "Sovereign Bond"
    Sub-asset class: "Other Public Bond"
    Sub-asset class: "Convertible Bond"
    Sub-asset class: "Covered Bond"
    Sub-asset class: "Corporate Bond"
    Sub-asset class: "Other Bond"
  Asset class: "Bonds (ETC and ETN bond types)"
    Sub-asset class: "Exchange Traded Commodities (ETCs)"
    Sub-asset class: "Exchange Traded Notes (ETNs)"
  Asset class: "Structured Finance Products (SFPs)"
  Asset class: "Securitised Derivatives"
  Asset class: "Interest Rate Derivatives"
    Sub-asset class: "Bond futures/forwards"
      Critrion: 1 "issuer of the underlying"
      Critrion: 2 "term of the underlying deliverable bond defined as"
      Critrion: 3 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Bond options"
      Critrion: 1 "underlying bond or underlying bond future/forward"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "IR futures and FRA"
      Critrion: 1 "underlying interest rate"
      Critrion: 2 "term of the underlying interest rate"
      Critrion: 3 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "IR options"
      Critrion: 1 "underlying interest rate or underlying interest ra"
      Critrion: 2 "term of the underlying interest rate"
      Critrion: 3 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Swaptions"
      Critrion: 1 "underlying swap type defined as follows: fixed-to-"
      Critrion: 2 "notional currency defined as the currency in which"
      Critrion: 3 "inflation index if the underlying swap type is eit"
      Critrion: 4 "time to maturity bucket of the swap defined as fol"
      Critrion: 5 "time to maturity bucket of the option defined as f"
    Sub-asset class: "Fixed-to-Float 'multi-currency swaps' or 'cross-cu"
      Critrion: 1 "notional currency pair defined as combination of t"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Float-to-Float 'multi-currency swaps' or 'cross-cu"
      Critrion: 1 "notional currency pair defined as combination of t"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Fixed-to-Fixed 'multi-currency swaps' or 'cross-cu"
      Critrion: 1 "notional currency pair defined as combination of t"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Overnight Index Swap (OIS) 'multi-currency swaps' "
      Critrion: 1 "notional currency pair defined as combination of t"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Inflation 'multi-currency swaps' or 'cross-currenc"
      Critrion: 1 "notional currency pair defined as combination of t"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Fixed-to-Float 'single currency swaps' and futures"
      Critrion: 1 "notional currency in which the two legs of the swa"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Float-to-Float 'single currency swaps' and futures"
      Critrion: 1 "notional currency in which the two legs of the swa"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Fixed-to-Fixed 'single currency swaps' and futures"
      Critrion: 1 "notional currency in which the two legs of the swa"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Overnight Index Swap (OIS) 'single currency swaps'"
      Critrion: 1 "notional currency in which the two legs of the swa"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Inflation 'single currency swaps' and futures/forw"
      Critrion: 1 "notional currency in which the two legs of the swa"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Other Interest Rate Derivatives"
  Asset class: "Equity Derivatives"
    Sub-asset class: "Stock index options"
      Critrion: 1 "underlying stock index"
    Sub-asset class: "Stock index futures/ forwards"
      Critrion: 1 "underlying stock index"
    Sub-asset class: "Stock options"
      Critrion: 1 "underlying share"
    Sub-asset class: "Stock futures/ forwards"
      Critrion: 1 "underlying share"
    Sub-asset class: "Stock dividend options"
      Critrion: 1 "underlying share entitling to dividends"
    Sub-asset class: "Stock dividend futures/ forwards"
      Critrion: 1 "underlying share entitling to dividends"
    Sub-asset class: "Dividend index options"
      Critrion: 1 "underlying dvidend index"
    Sub-asset class: "Dividend index futures/ forwards"
      Critrion: 1 "underlying dividend index"
    Sub-asset class: "Volatility index options"
      Critrion: 1 "underlying volatility index"
    Sub-asset class: "Volatility index futures/ forwards"
      Critrion: 1 "underlying volatility index"
    Sub-asset class: "ETF options"
      Critrion: 1 "underlying ETF"
    Sub-asset class: "ETF futures/ forwards"
      Critrion: 1 "underlying ETF"
    Sub-asset class: "Swaps"
      Critrion: 1 "underlying type: single name, index, basket"
      Critrion: 2 "underlying single name, index, basket"
      Critrion: 3 "parameter: price return basic performance paramete"
      Critrion: 4 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Portfolio Swaps"
      Critrion: 1 "underlying type: single name, index, basket"
      Critrion: 2 "underlying single name, index, basket"
      Critrion: 3 "parameter: price return basic performance paramete"
      Critrion: 4 "Price return basic performance parameter"
    Sub-asset class: "Other equity derivatives"
  Asset class: "Commodity Derivatives"
    Sub-asset class: "Metal commodity futures/forwards"
      Critrion: 1 "metal type: precious metal, non-precious metal"
      Critrion: 2 "underlying metal"
      Critrion: 3 "notional currency defined as the currency in which"
      Critrion: 4 "time to maturity bucket of the future/forward defi"
    Sub-asset class: "Metal commodity options"
      Critrion: 1 "metal type: precious metal, non-precious metal"
      Critrion: 2 "underlying metal"
      Critrion: 3 "notional currency defined as the currency in which"
      Critrion: 4 "time to maturity bucket of the option defined as f"
    Sub-asset class: "Metal commodity swaps"
      Critrion: 1 "metal type: precious metal, non-precious metal"
      Critrion: 2 "underlying metal"
      Critrion: 3 "notional currency defined as the currency in which"
      Critrion: 4 "settlement type defined as cash, physical or other"
      Critrion: 5 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Energy commodity futures/forwards"
      Critrion: 1 "energy type: oil, oil distillates, coal, oil light"
      Critrion: 2 "underlying energy"
      Critrion: 3 "notional currency defined as the currency in which"
      Critrion: 4 "load type defined as baseload, peakload, off-peak "
      Critrion: 5 "delivery/ cash settlement location applicable to e"
      Critrion: 6 "time to maturity bucket of the future/forward defi"
    Sub-asset class: "Energy commodity options"
      Critrion: 1 "energy type: oil, oil distillates, coal, oil light"
      Critrion: 2 "underlying energy"
      Critrion: 3 "notional currency defined as the currency in which"
      Critrion: 4 "load type defined as baseload, peakload, off-peak "
      Critrion: 5 "delivery/ cash settlement location applicable to e"
      Critrion: 6 "time to maturity bucket of the option defined as f"
    Sub-asset class: "Energy commodity swaps"
      Critrion: 1 "energy type: oil, oil distillates, coal, oil light"
      Critrion: 2 "underlying energy"
      Critrion: 3 "notional currency defined as the currency in which"
      Critrion: 4 "settlement type defined as cash, physical or other"
      Critrion: 5 "load type defined as baseload, peakload, off-peak "
      Critrion: 6 "delivery/ cash settlement location applicable to e"
      Critrion: 7 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Agricultural commodity futures/forwards"
      Critrion: 1 "underlying agricultural commodity"
      Critrion: 2 "notional currency defined as the currency in which"
      Critrion: 3 "time to maturity bucket of the future/forward defi"
    Sub-asset class: "Agricultural commodity options"
      Critrion: 1 "underlying agricultural commodity"
      Critrion: 2 "notional currency defined as the currency in which"
      Critrion: 3 "time to maturity bucket of the option defined as f"
    Sub-asset class: "Agricultural commodity swaps"
      Critrion: 1 "underlying agricultural commodity"
      Critrion: 2 "notional currency defined as the currency in which"
      Critrion: 3 "settlement type defined as cash, physical or other"
      Critrion: 4 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Other commodity derivatives"
  Asset class: "Foreign Exchange Derivatives"
    Sub-asset class: "Non-deliverable forward (NDF)"
      Critrion: 1 "underlying currency pair defined as combination of"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Deliverable forward (DF)"
      Critrion: 1 "underlying currency pair defined as combination of"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Non-Deliverable FX options (NDO)"
      Critrion: 1 "underlying currency pair defined as combination of"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Deliverable FX options (DO)"
      Critrion: 1 "underlying currency pair defined as combination of"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Non-Deliverable FX swaps (NDS)"
      Critrion: 1 "underlying currency pair defined as combination of"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Deliverable FX swaps (DS)"
      Critrion: 1 "underlying currency pair defined as combination of"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "FX futures"
      Critrion: 1 "underlying currency pair defined as combination of"
      Critrion: 2 "time to maturity bucket of the swap defined as fol"
    Sub-asset class: "Other Foreign Exchange Derivatives"
  Asset class: "Credit Derivatives"
    Sub-asset class: "Index credit default swap (CDS)"
      Critrion: 1 "underlying index"
      Critrion: 2 "notional currency defined as the currency in which"
      Critrion: 3 "time maturity bucket of the CDS defined as follows"
    Sub-asset class: "Single name credit default swap (CDS)"
      Critrion: 1 "underlying reference entity"
      Critrion: 2 "underlying reference entity type defined as follow"
      Critrion: 3 "notional currency defined as the currency in which"
      Critrion: 4 "time maturity bucket of the CDS defined as follows"
    Sub-asset class: "Bespoke basket credit default swap (CDS)"
    Sub-asset class: "CDS index options"
      Critrion: 1 "CDS index sub-class as specified for the sub-asset"
      Critrion: 2 "time maturity bucket of the option defined as foll"
    Sub-asset class: "Single name CDS options"
      Critrion: 1 "single name CDS sub-class as specified for the sub"
      Critrion: 2 "time maturity bucket of the option defined as foll"
    Sub-asset class: "Other credit derivatives"
  Asset class: "C10 Derivatives"
    Sub-asset class: "Freight derivatives"
      Critrion: 1 "contract type: Forward Freight Agreements (FFAs) o"
      Critrion: 2 "freight type: wet freight, dry freight"
      Critrion: 3 "freight sub-type: dry bulk carriers, tanker, conta"
      Critrion: 4 "specification of the size related to the freight s"
      Critrion: 5 "specific route or time charter average"
      Critrion: 6 "time maturity bucket of the derivative defined as "
    Sub-asset class: "Other C10 derivatives"
  Asset class: "Financial contracts for differences (CFDs)"
    Sub-asset class: "Currency CFDs"
      Critrion: 1 "a currency CFD sub-class is defined by the underly"
    Sub-asset class: "Commodity CFDs"
      Critrion: 1 "a commodity CFD sub-class is defined by the underl"
    Sub-asset class: "Equity CFDs"
      Critrion: 1 "an equity CFD sub-class is defined by the underlyi"
    Sub-asset class: "Bond CFDs"
      Critrion: 1 "a bond CFD sub-class is defined by the underlying "
    Sub-asset class: "CFDs on an equity future/forward"
      Critrion: 1 "a CFD on an equity future/forward sub-class is def"
    Sub-asset class: "CFDs on an equity option"
      Critrion: 1 "a CFD on an equity option sub-class is defined by "
    Sub-asset class: "Other CFDs"
  Asset class: "Emission Allowances"
    Sub-asset class: "European Union Allowances (EUA)"
    Sub-asset class: "European Union Aviation Allowances (EUAA)"
    Sub-asset class: "Certified Emission Reductions (CER)"
    Sub-asset class: "Emission Reduction Units (ERU)"
  Asset class: "Emission Allowance Derivatives"
    Sub-asset class: "Emission allowance derivatives whose underlying is"
    Sub-asset class: "Emission allowance derivatives whose underlying is"
    Sub-asset class: "Emission allowance derivatives whose underlying is"
    Sub-asset class: "Emission allowance derivatives whose underlying is"