Elektron SDK - Java

API Family: Elektron

EMA Consumer - Requesting, parsing and decoding Level 2 data

Download tutorial source code

Click here to download

Last update May 2018
Environment Windows, Linux
Compilers JDK 1.7 or greater
Prerequisite Parsing and Decoding MarketPrice data

Introduction

Extending from previous tutorial, this tutorial will support additional RDM (Reuters Data Models) types such as the SymbolList as well as the level 2 content - MBP (Market By Price) and MBO (Market By Order) models. For our test, the MBP RDM is modelled which is well suited to convey OrderBook information for an instrument.

Description

When requesting for data, the MarketPrice model is selected by default. To support the ability to request for additional data models, we must explicitely specify this within our request.

Requesting for alternative data models

Extending the functionality from the previous tutorial, the following code snippet has been updated to request for an alternative data model:

// run
// Connect to our provider, request for data and run the application for a short time to capture the realtime data.
private void run()
{
    try
    {
        ...
			
        consumer.registerClient(
                     EmaFactory.createReqMsg()
                               .domainType(EmaRdm.MMT_MARKET_BY_PRICE)
                               .serviceName("ELEKTRON_AD")
                               .name("BB.TO"), 
                     eventHandler
        );
		
        ...
    }
}

A new specification has been added to our request to explicitely specify the domain model MBP (.domainType(EmaRdm.MMT_MARKET_BY_PRICE). The level 2 data models (MBP, MBO) as well as a few others result in a payload that captures the collection of data within a Map container. For testing, you can optionally specify different models, such as MBO, so long as the service and item is supported.

Processing the response

The above request will result in a MBP response that will contain a Map as the core of its message container. Each element within the Map will contain a MapEntry which encompasses a FieldList collection which we already know how to process from the previous tutorial. The Map will also typically contain a header or Summary Data section containing some relevant details for that message. As with each element of the Map, the Summary Data is a nested FieldList container.

To recognize the new container type, we extend the functionality within the decodePayload method as seen below:

private void decodePayload(Payload payload)
{
    // Decode the payload.
    // When decoding each message, we overload the method: decodeAndPrint based on the data type.
    switch ( payload.dataType() )
    {
        // A level 1 message (MARKET_PRICE)is packaged as a field list
        case DataType.DataTypes.FIELD_LIST:
            decodeAndPrint( payload.fieldList() );
            break;

        // A level 2 message (MBP, MBO) or SymbolList is packaged as a map
        case DataType.DataTypes.MAP:
            decodeAndPrint( payload.map() );
            break;
    }
	...	
	
}

We have overloaded the decodeAndPrint method to manage the different containers. The processing involved in decoding the Map container involves processing the Summary Data section followed by the collection of elements within the Map:

private void decodeAndPrint(Map map)
{
    // The Map that is used to package level 2 data typically contains a SUMMARY section which outlines 
    // general header information about the collection.  The SUMMARY uses the FieldList container.		
    if (DataTypes.FIELD_LIST == map.summaryData().dataType())
    {
        ...
			
        // Simply use the existing FieldList decoding method
        decodeAndPrint(map.summaryData().fieldList());

        ...
    }

    // The main body of our collection is a map of nodes containing an action and the data.
    for (MapEntry mapEntry : map)
    {
        // The action associated with the code  (ADD, UPDATE, DELETE)
        System.out.println("  Action: " + mapEntry.mapActionAsString());

        // The data value of the node
        if (DataTypes.FIELD_LIST == mapEntry.loadType())
        {
            System.out.println("  Entry data:");
				
            // Simply use the existing FieldList decoding method
            decodeAndPrint(mapEntry.fieldList());
				
            ...
        }
    }
}

After identifying we have a Summary Data section, we can reuse the decodeAndPrint functionality for the nested fieldList to display the contents. Following this section contains the main body of the map, which in itself is typically a collection of fieldList elements which we can once again reuse the same decodeAndPrint method to display the contents.

One important aspect of these containers is the action that is associated with each node within the Map. Due to the nature of the container, the contents will grow (ADD), change (UPDATE) and shrink (DELETE) dynamically throughout the day. As such, each map element presented will contain an action signifying how that node has been applied to the current container. This is especially important if we have chosen to stream our initial request. Each market data update, i.e. onUpdateMsg will present the container with the appropriate actions for each map node presented.

Multi-Part messages

When dealing with large containers such as the level 2 data (MBP, MBO), the payload content will be split across multiple parts. As outlined within the Transport API documentation, the multi-part messages will carry a complete() indicator that will allow the developer to determine the final part of the multi-part message. Multi-part messages are only prevalent within RefreshMsgs:

public void onRefreshMsg(RefreshMsg refreshMsg, OmmConsumerEvent event)
{
    ...
		
    // When dealing with level 2 or SymbolList messages, they are commonly sent as multi-part messages
    // due to their size.  As a result, we may receive multiple refreshes before completion.
    System.out.println("Refresh complete: " + (refreshMsg.complete() ? "YES" : "NO"));
}

Build and run

Refer to the Build and run section within the Tutorial 1 - Creating a barebones EMA consumer application for instructions to successfully execute this tutorial.  

Before building and executing this tutorial, ensure you have properly configured the connection details as well as the item request values for your environment.  Contact your market data administrator to acquire these details.

Eg (Windows):

> buildConsumer 4

Building tutorial 4...

Done.

> runConsumer 4

Running the tutorial will report our initial Refresh message. In our case, you will notice we have received multiple Refresh messages, as indicated by the completion state displayed:

Refresh complete: NO 

...

Refresh complete: YES

Note: You will notice the initial image contains an action of ADD for each map node which basically indicates that each entry needs to be added to your book. Based on the market, different types of actions may occur for each update (UpdateMsg) received, whether ADD, DELETE or UPDATE actions to the book. Due to the nature of our model (MBP), we will typically see an UPDATE for each UpdateMsg received because we are typically updating the number of orders for an entry. However, if we chose the model MBO, we would typically see ADD and DELETE UpdateMsgs because we are constantly adding and removing orders from the book.

Note: This tutorial will automatically exit after ~30 seconds.  Alternatively, you can (Ctrl+C) to exit at any time.

RefreshMsg
        Service Name: ELEKTRON_AD
        Item: BB.TO
        State: Open / Ok / None / 'All is well'
  Map Summary data:
    Name: PROD_PERM (Fid: 1) DataType: UInt, Value: 3044
    Name: DSPLY_NAME (Fid: 3) DataType: Rmtes, Value:
    Name: CURRENCY (Fid: 15) DataType: Enum, Value: 124
    Name: ACTIV_DATE (Fid: 17) DataType: Date, Value: 25/07/2016
    Name: PRC_QL2 (Fid: 131) DataType: Enum, Value:  blank
    Name: LOT_SIZE_A (Fid: 198) DataType: Real, Value: 100.0
    Name: RECORDTYPE (Fid: 259) DataType: UInt, Value: 113
    Name: PREF_DISP (Fid: 1080) DataType: UInt, Value:  blank
    Name: RDN_EXCHD2 (Fid: 1709) DataType: Enum, Value: 10
    Name: LIST_MKT (Fid: 3183) DataType: Rmtes, Value:
    Name: PROV_SYMB (Fid: 3422) DataType: Rmtes, Value:
    Name: PR_RNK_RUL (Fid: 3423) DataType: Enum, Value: 1
    Name: OR_RNK_RUL (Fid: 3425) DataType: Enum, Value: 2
    Name: MNEMONIC (Fid: 3694) DataType: Rmtes, Value:
    Name: MKT_STATUS (Fid: 3915) DataType: Rmtes, Value:
    Name: TIMACT_MS (Fid: 4148) DataType: UInt, Value: 54808250
    Name: CONTEXT_ID (Fid: 5357) DataType: Real, Value: 2171.0
    Name: DDS_DSO_ID (Fid: 6401) DataType: UInt, Value: 8244
    Name: SPS_SP_RIC (Fid: 6480) DataType: Ascii, Value: .[SPSTL2TRL2
    Name: BOOK_STATE (Fid: 6516) DataType: Enum, Value: 1
    Name: HALT_REASN (Fid: 6517) DataType: Rmtes, Value:  blank
    Name: ORD_ENT_ST (Fid: 6518) DataType: Enum, Value: 1
    Name: MKT_OR_RUL (Fid: 6519) DataType: Enum, Value: 0
    Name: TRD_STATUS (Fid: 6614) DataType: Enum, Value: 1
    Name: HALT_RSN (Fid: 6615) DataType: Enum, Value:  blank

  Action: Add
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 13.55
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 2
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 2
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 400.0
    Name: LV_TIM_MS (Fid: 6527) DataType: UInt, Value: 39617910
    Name: LV_TIM_MSP (Fid: 6528) DataType: UInt, Value: 194
    Name: LV_DATE (Fid: 6529) DataType: Date, Value: 29/06/2016

  Action: Add
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 15.1
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 2
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 1
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 100.0
    Name: LV_TIM_MS (Fid: 6527) DataType: UInt, Value: 42632232
    Name: LV_TIM_MSP (Fid: 6528) DataType: UInt, Value: 414
    Name: LV_DATE (Fid: 6529) DataType: Date, Value: 27/06/2016

  ...  

  Action: Add
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 13.05
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 2
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 1
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 200.0
    Name: LV_TIM_MS (Fid: 6527) DataType: UInt, Value: 64052383
    Name: LV_TIM_MSP (Fid: 6528) DataType: UInt, Value: 850
    Name: LV_DATE (Fid: 6529) DataType: Date, Value: 10/05/2016


Refresh complete: NO
RefreshMsg
        Service Name: ELEKTRON_AD
        Item: BB.TO
        State: Open / Ok / None / 'All is well'
  Action: Add
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 8.36
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 1
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 1
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 100.0
    Name: LV_TIM_MS (Fid: 6527) DataType: UInt, Value: 59332401
    Name: LV_TIM_MSP (Fid: 6528) DataType: UInt, Value: 651
    Name: LV_DATE (Fid: 6529) DataType: Date, Value: 14/07/2016

  Action: Add
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 5.0
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 1
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 1
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 1000.0
    Name: LV_TIM_MS (Fid: 6527) DataType: UInt, Value: 42650255
    Name: LV_TIM_MSP (Fid: 6528) DataType: UInt, Value: 931
    Name: LV_DATE (Fid: 6529) DataType: Date, Value: 27/06/2016
 
  ...

  Action: Add
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 9.79
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 2
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 1
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 200.0
    Name: LV_TIM_MS (Fid: 6527) DataType: UInt, Value: 65905964
    Name: LV_TIM_MSP (Fid: 6528) DataType: UInt, Value: 547
    Name: LV_DATE (Fid: 6529) DataType: Date, Value: 28/06/2016


Refresh complete: YES
UpdateMsg
  Map Summary data:
    Name: TIMACT_MS (Fid: 4148) DataType: UInt, Value: 54818170

  Action: Update
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 9.29
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 2
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 2700.0
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 2


UpdateMsg
  Map Summary data:
    Name: TIMACT_MS (Fid: 4148) DataType: UInt, Value: 54818170

  Action: Update
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 9.29
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 2
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 2600.0
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 2


UpdateMsg
  Map Summary data:
    Name: TIMACT_MS (Fid: 4148) DataType: UInt, Value: 54818172

  Action: Update
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 9.29
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 2
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 2400.0
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 2


UpdateMsg
  Map Summary data:
    Name: TIMACT_MS (Fid: 4148) DataType: UInt, Value: 54818252

  Action: Update
  Entry data:
    Name: ORDER_PRC (Fid: 3427) DataType: Real, Value: 8.21
    Name: ORDER_SIDE (Fid: 3428) DataType: Enum, Value: 1
    Name: ACC_SIZE (Fid: 4356) DataType: Real, Value: 25800.0
    Name: NO_ORD (Fid: 3430) DataType: UInt, Value: 15
    Name: LV_TIM_MS (Fid: 6527) DataType: UInt, Value: 54818252
    Name: LV_TIM_MSP (Fid: 6528) DataType: UInt, Value: 182
    Name: LV_DATE (Fid: 6529) DataType: Date, Value: 25/07/2016

Reference

To learn more about EMA please refer to the

Tutorial Group: 
EMA Consumer