Elektron SDK - Java

API Family: Elektron

EMA Consumer - Parsing and Decoding MarketPrice data

Download tutorial source code

Click here to download

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

Introduction

The goal of this tutorial is to demonstrate how to parse and decode MarketPrice (level 1) Data received in response of a request sent to a Refinitiv Market Data System. In the previous tutorial, the received message was simply printed to the terminal window. We will demonstrate how to extract some general information within the response as well as navigating through the list of entries to parse and convert each value into its native data type.

Description

In the last tutorial, we demonstrated the ability to capture market data events within our callbacks. In each callback, we utilized a convenient EMA method (toString()) to display the contents of the message to the terminal window. Our goal here is to extend this capability by identifying the type of payload, parsing and displaying specific details of the message.

Market data is encapsulated in various RDM (Reuters Domain Model) container classes, which are based on the Open Message Model specification described in the OMM White Paper. In this tutorial, we are working with level 1 market data which can contain details such as Bid, Ask, Trade Price etc, all encapsulated in an OMM FieldList container class. As we briefly described in the previous tutorial, this container class is a collection of entries describing the market data fields containing attributes such as the name, data type, value etc. Other types of market data models, such as level 2 models, are embedded within more complex container classes that we will cover in the next tutorial.

Message Processing - message attributes

As previously outlined, the onRefreshMsg callback is responsible for capturing the initial image. The initial image contains a complete list of field elements associated with the market data message. In addition, the refresh contains other useful message attributes that are available for the developer that we saw within the previous tutorial:

RefreshMsg
    streamId="5"
    domain="MarketPrice Domain"
    solicited
    RefreshComplete
    state="Open / Ok / None / 'All is well'"
    itemGroup="00 05"
    permissionData="03 01 64 62 c0"
    name="IBM.N"
    nameType="1"
    serviceId="356"
    serviceName="ELEKTRON_AD"

The above message attributes are typically only available within the RefreshMsg for the developer to extract. Within our message processing callback, the following code snippet demonstrates how we retrieve the name, ServiceName and state attributes:

// onRefreshMsg
// Capture the initial image after subscribing (registering interest) in a market data item.  This 
// callback parses and decodes the message and displays to the terminal.
public void onRefreshMsg(RefreshMsg refreshMsg, OmmConsumerEvent event)
{
    System.out.println("RefreshMsg");
		
    // Display the Service Name and Item Name
    // These two fields are typically sent in a RefreshMsg from the Provider.  However, this information
    // is usually not sent for subsequent updates (UpdateMsg), unless explicitely requested during
    // registration.  As a result, we first check of their existence as a safeguard.
		
    // Service Name 
    String serviceName = "Not Available";
    if (refreshMsg.hasServiceName())
    {
        serviceName = refreshMsg.serviceName();
    }
    System.out.println("\tService Name: " + serviceName);

    // Item Name
    String itemName = "Not Available";
    if (refreshMsg.hasName())
    {
        itemName = refreshMsg.name();
    }
    System.out.println("\tItem: " + itemName);
	
    // Retrieve and display the state of the item. In this example we directly print the item state. 
    // However, finer grained information can be retrieved via the OmmState methods.  
    System.out.println("\tState: " + refreshMsg.state());
	
    ...

}

Message Processing - message payload

Every data response from a Provider, whether a refresh or update, will contain a payload of data. The refresh will contain a payload with a complete list of entries specific to that item, whereas the update will typically only contain a small subset of entries. The update represents only those fields that are relevant to the update based on the changing market conditions. Within the onRefreshMsg and onUpdateMsg callbacks, we will be receiving the same payload of data:

// onRefreshMsg
// Capture the initial image after subscribing (registering interest) in a market data item.  This 
// callback parses and decodes the message and displays to the terminal.
public void onRefreshMsg(RefreshMsg refreshMsg, OmmConsumerEvent event)
{
    ...
		
    // Decode the Payload
    // The data for a refresh message is conveyed by the payload. The payload will contain a complex 
    // data structure that must be decoded and parsed to retrieve the individual fields of interest.
    // The refreshMsg or initial image will contain the complete set of fields related to the data.
    decodePayload( refreshMsg.payload() );
}

// onUpdateMsg
// After receiving the initial image, we capture any updates to the item based on market events.
// This callback parses and decodes the message and displays to the terminal.
public void onUpdateMsg(UpdateMsg updateMsg, OmmConsumerEvent event)
{
    ...
	
    // Decode the Payload
    // The data for an update message is conveyed by the payload. As with the refresh message, payload 
    // will contain a complex data structure that must be decoded and parsed to retrieve the individual 
    // fields of interest. However, the updatehMsg will contain only thoese fields that have changed 
    // based on the market conditions.
    decodePayload( updateMsg.payload() );
}

In order to decode a payload, we must identify the type of container used to organize the data. In addition, try to simplify the decoding to better reuse as much processing as possible. More complex containers will nest other containers so reusability is preferred. The following code outlines how to recognize the different types of containers:

// decodePayload
// Based on type of data we are interested in, i.e. level 1 or level 2 data, the Provider will send down
// the corresponding payload.  The payload provides convenient getter methods for the different data types.  
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;

        // Reserved for additional container types
    }
	
    ...
						
}

Presently, we are only working with the MarketPrice data model, so we would only expect to deal with a FieldList container. However, we have prepared the logic to capture additional container types. The decodeAndPrint is an overloaded method to manage multiple containers.

Message Processing - FieldList decode

The FieldList walks through the list of elements within a container, and based on the type of element, displays the appropriate data to the terminal.

// decodeAndPrint - FieldList
// The FieldList is a list of entries commonly used in level 1 (MarketPrice) data responses.
private void decodeAndPrint(FieldList fieldList)
{
    // A FieldList is a collection of FieldEntries. Each of these entries conveys information about a specific 
	// field of the requested MarketPrice data item. Our loop walks through the collection, determines the 
	// data type and displays the appropriate output to the terminal.
    for (FieldEntry fieldEntry : fieldList)
    {
        ...

        // Display the value based on the type of data
        //
        // Note: It's possible that a field may exist but there is no data, i.e. BLANK.  This is commonly used 
        //		 within market data systems to differentiate fields that have explicit values of zero, 
        //		 empty strings, etc.
        if (Data.DataCode.BLANK == fieldEntry.code())
            System.out.println(" blank");
        else
            switch (fieldEntry.loadType())
            {
                case DataTypes.REAL :
                    System.out.println(fieldEntry.real().asDouble());
                    break;
                case DataTypes.DATE :
                    System.out.println(String.format("%02d", fieldEntry.date().day()) + "/" + 
                                       String.format("%02d", fieldEntry.date().month()) + "/" + 
                                       fieldEntry.date().year());
                    break;
					
                    ...
        }
    }
}

It is quite common in data processing to use "zero values" such as 0.0 for real, 0 for int and "" (empty string) for ASCII to express that a data element doesn't contain any data. However, within market data systems, zero values are relevant and have meaning. As a result, the elements within a FieldList carry a blank state to represent the data for the element contains no value. Within the above code snippet, we explicitely capture and display this state when present.

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 3

Building tutorial 3...

Done.

> runConsumer 3

As with the previous tutorial, we initially report back the same general startup information. However, the fields related to the Refresh message followed by multiple Update messages are presented differently based on the processing logic within this tutorial:

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'
    Name: PROD_PERM (Fid: 1) DataType: UInt, Value: 84
    Name: RDNDISPLAY (Fid: 2) DataType: UInt, Value: 65
    Name: DSPLY_NAME (Fid: 3) DataType: Rmtes, Value:
    Name: RDN_EXCHID (Fid: 4) DataType: Enum, Value: 10
    Name: TRDPRC_1 (Fid: 6) DataType: Real, Value: 9.085
    Name: TRDPRC_2 (Fid: 7) DataType: Real, Value: 9.08
    Name: TRDPRC_3 (Fid: 8) DataType: Real, Value: 9.08
    Name: TRDPRC_4 (Fid: 9) DataType: Real, Value: 9.08
    Name: TRDPRC_5 (Fid: 10) DataType: Real, Value: 9.08
    Name: NETCHNG_1 (Fid: 11) DataType: Real, Value: 0.125
    Name: HIGH_1 (Fid: 12) DataType: Real, Value: 9.09
    Name: LOW_1 (Fid: 13) DataType: Real, Value: 8.93
    Name: PRCTCK_1 (Fid: 14) DataType: Enum, Value: 1
    Name: CURRENCY (Fid: 15) DataType: Enum, Value: 124
    Name: TRADE_DATE (Fid: 16) DataType: Date, Value: 22/07/2016
    Name: TRDTIM_1 (Fid: 18) DataType: Time, Value: 15:56:00:0
    Name: OPEN_PRC (Fid: 19) DataType: Real, Value: 8.93
    Name: HST_CLOSE (Fid: 21) DataType: Real, Value: 8.96
    Name: BID (Fid: 22) DataType: Real, Value: 9.08
    Name: BID_1 (Fid: 23) DataType: Real, Value: 9.08
    Name: BID_2 (Fid: 24) DataType: Real, Value: 9.08
    Name: ASK (Fid: 25) DataType: Real, Value: 9.09
    Name: ASK_1 (Fid: 26) DataType: Real, Value: 9.09
    Name: ASK_2 (Fid: 27) DataType: Real, Value: 9.09
    Name: NEWS (Fid: 28) DataType: Rmtes, Value:
    Name: NEWS_TIME (Fid: 29) DataType: Time, Value: 13:05:47:0
    Name: BIDSIZE (Fid: 30) DataType: Real, Value: 85.0
    Name: ASKSIZE (Fid: 31) DataType: Real, Value: 140.0
    Name: ACVOL_1 (Fid: 32) DataType: Real, Value: 317475.0
    Name: EARNINGS (Fid: 34) DataType: Real, Value: -2.80655
    Name: YIELD (Fid: 35) DataType: Real, Value:  blank
    ...
    Name: ACVOL_UNS (Fid: 32743) DataType: UInt, Value: 317475

UpdateMsg
    Name: BID (Fid: 22) DataType: Real, Value: 9.08
    Name: ASK (Fid: 25) DataType: Real, Value: 9.09
    Name: BIDSIZE (Fid: 30) DataType: Real, Value: 84.0
    Name: ASKSIZE (Fid: 31) DataType: Real, Value: 140.0
    Name: SEQNUM_QT (Fid: 3887) DataType: Real, Value: 232599.0
    Name: QUOTIM (Fid: 1025) DataType: Time, Value: 15:56:33:0

UpdateMsg
    Name: BID (Fid: 22) DataType: Real, Value: 9.08
    Name: ASK (Fid: 25) DataType: Real, Value: 9.09
    Name: BIDSIZE (Fid: 30) DataType: Real, Value: 97.0
    Name: ASKSIZE (Fid: 31) DataType: Real, Value: 140.0
    Name: SEQNUM_QT (Fid: 3887) DataType: Real, Value: 232600.0
    Name: QUOTIM (Fid: 1025) DataType: Time, Value: 15:56:33:0

Reference

To learn more about EMA please refer to the

Tutorial Group: 
EMA Consumer