Elektron SDK - C/C++

API Family: Elektron

EMA Consumer - Requesting and processing MarketByOrder data

Download tutorial source code

Click here to download

Last update September 2015
Compilers Tutorial demonstration: Visual Studio 2013

Refer to the EMA Compiler Guides for a complete list
Prerequisites Tutorial 3 - Decoding MarketPrice data

Introduction

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

 

Description

In 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 modelled using 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

Main method in Consumer.cpp is modified and now instead of subscribing to MMT_MARKET_PRICE (default) we specify the request domain as MMT_MARKET_BY_ORDER. The service you are using should carry the level II data for that instrument. All remaining symantics of request are 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() );
}

 

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 )	
{
  // 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.

Connecting to market data server
Subscribing to Level 2 market data

----------------------------------
Refresh message, item Handle: 108454304 Closure: 0000000000000000

Item Name: TD.TO
Service Name: ELEKTRON_AD
Item State: Open / Ok / None / 'All is well'
Map Summary:
Fid: 1 Name: PROD_PERM DataType: UInt Value: 6777
Fid: 3 Name: DSPLY_NAME DataType: Rmtes Value: 
Fid: 15 Name: CURRENCY DataType: Enum Value: 124
.
.

ADD Entry, Key: [3135 3035 3134 3030 3030 3030 3639 3330    1505140000006930
3032 42                                    02B
]
Fid: 1021 Name: SEQNUM DataType: Real Value: 44610
Fid: 3427 Name: ORDER_PRC DataType: Real Value: 52
Fid: 3428 Name: ORDER_SIDE DataType: Enum Value: 1
Fid: 3429 Name: ORDER_SIZE DataType: Real Value: 200
.
.

Item Name: TD.TO
Service Name: ELEKTRON_AD
Map Summary:
Fid: 4148 Name: TIMACT_MS DataType: UInt Value: 48788112

DELETE Entry, Key: [3135 3036 3233 3030 3030 3031 3635 3930    1506230000016590
3739 41                                    79A
]