EMA Consumer - Requesting and processing MarketByOrder data

Download tutorial source code

Click here to download

Last update Aug 2024
Compilers Tutorial demonstration: Visual Studio 2022
Prerequisites Tutorial 3 - Decoding MarketPrice data

 

Introduction

The goal of this tutorial is to programmatically decode the response received from API.

Description

In the previous tutorial, we subscribed and decoded MarketPrice data for "IBM.N". Following on similar approach, we will subscribe and decode a MarketByOrder (OrderBook) data for "IBM". MarketByOrder RDM is modeled using the OMM Map data structure and is well suited to convey OrderBook information for an instrument. Various OMM container classes are described in OMM White Paper.

Steps

  • Subscribe to Orderbook
  • Decode market data
  • Build and Run

Subscribe to Orderbook

The main method in Step4.cpp is modified and now instead of subscribing to MMT_MARKET_PRICE (default), we specify the requested domain as MMT_MARKET_BY_ORDER. The service you are using should carry the level II data for that instrument. All remaining semantics of requests is the same as in previous steps.

    	
            

int main( int argc, char* argv[] )

{

  .

  .

  .

  // subscribe to Level2 market data

  consumer.registerClient( 

    ReqMsg()

      .domainType( MMT_MARKET_BY_ORDER )

      .serviceName( "ELEKTRON_AD" )

      .name( "TD.TO" ),

    client );

 

return 0;

}

Decode market data

Just like Market Price, Market By Order message also consist of an initial Image which contains all the fields followed by Updates which contain only the fields which have changed since last image or update. It also contains status message which indicates status of our request and upstream delivery system.

In callback method for Refresh (Initial Image), we first dump the status of our request to console, and then check if the data payload is an OMM Map. If it is, we pass that payload to overloaded decode method which takes Map as an argument.

    	
            

void AppClient::onRefreshMsg( const RefreshMsg& refreshMsg, const OmmConsumerEvent& event) 

{

  .

  .

  .

  //  display the status of current request

  cout << endl << "Item State: " << refreshMsg.getState().toString() << endl;

  

  // Level2 data payload is encoded as an OMM Map or NoData if no payload data is available

  if( DataType::MapEnum == refreshMsg.getPayload().getDataType() )

    decode( refreshMsg.getPayload().getMap(), true );

}

OMM Map

MarketByOrder RDM data is modelled using an OMM data structure called a Map. A Map contains Summary data and Map entries. Summary data common set of information that is applicable to all Map entries and is encoded as OMM FieldList. We will use previously defined decode method for it. Map entries are composed of Key, Action and Data. A Key uniquely identifies a particular map entry. Action is either Add, Delete or Update the Map entry; and Data is a FieldList which describes that entry.

Map (used for MarketByOrder) vs FieldList (used in MarketPrice):

  MAP FIELDLIST
Summary Yes No
Key Complex data buffer Integer
Data FieldList Basic OMM data types like Int, Real etc

Figure 1: OMM Map

To decode a Map, we will first check is it has summary data and use previously defined FieldList decode method to display the summary values on console. Then, we loop over all the Map entries, displaying the key code and action on console. If the Map action is Add or Update, it also carries a valid data, which we display on console using FieldList decode method. In real world scenerio, the application maintains a shadow copy of OrderBook in memory. This shadow book is best implemented using some sort of Map (e.g. std::map), where Add and Update actions update the book and delete action deletes an entry from shadow book. In the example, we just display everything on console.

    	
            

void AppClient::decode( const Map& map, bool echo )

{

  // if map has summary data, it is of type OMM Fieldlist

  if( map.getSummaryData() == DataType::FieldListEnum )

  {

    cout << "Map Summary:" << endl;

    decode( map.getSummaryData().getFieldList() );

  }

  

  // loop over map entries

  while ( map.forth() ) {

    const MapEntry& me = map.getEntry();

     .

     .      

      // data for Add and Update actions is OMM Fieldlist

      switch ( me.getAction() ) {

      

        case MapEntry::AddEnum:

          cout<< "ADD Entry, Key: [" << keyBuf << "]" <<  endl;

          if (me.getLoadType() == DataType::FieldListEnum )

            decode( me.getFieldList() );

          break;

       .

       .

       .    

      }

    }

  }

}

Build and Run

Assuming you have properly setup the Visual Studio project, you can now compile and run the tutorial. If you encounter any compile errors, ensure your environment variables are properly defined. When you run the tutorial, you should see no errors and application will connect, send subscription request and display decoded market by order at the command line.