Elektron SDK - C/C++

API Family: Elektron

EMA Consumer - Requesting MarketPrice data

Download tutorial source code

Click here to download

Last update June 2018
Compilers Tutorial demonstration: Visual Studio 2013

Refer to the EMA Compiler Guides for a complete list
Prerequisites Tutorial 1 - Creating a barebones EMA consumer application

Description

Building upon the previous tutorial - barebones application shell; we will modify the Consumer class and add code to interface with API. This would entail creating a MarketPrice subscription request and receiving events and data callbacks. We begin by creating an instance of OMMConsumer, express our interest in getting market data for IBM, and dump the response on system output stream.

Steps

  • Create OMMConsumer
  • Subscribe to item of interest
  • Receive response from API
  • Build and Run

Create OMMConsumer

The main function in Consumer.cpp is modified and an instance of ema::access::OmmConsumer is created. The overloaded constructor of OMMConsumer has two variants. The way we are using it here, this class would raise an exception upon invalid usage, which application should catch (omitted here for simplicity). This consumer initiates a TCP connection to market data server, which can be TREP ADS or Elektron Connect etc. In addition to hostname and port, a consumer needs a valid DACS username. This username is the entity authorized to receive market data. All these configuration variables are passed in through OmmConsumerConfig object. OmmConsumerConfig reads entries from EmaConfig.xml if available, but can be selectively overriden in code as well.

Here we connect to server named "ADS" on port "14002", and use DACS username "user1".

int main( int argc, char* argv[] )	
{
  // instantiate callback client
  AppClient client;
  
  // create OMM consumer
  OmmConsumer consumer( 
    OmmConsumerConfig()
      .host( "ADS:14002" )
      .username( "user1" ) 
  );

  // block this thread for a minute
  sleep(60000);
  
  return 0;
}

 

Subscribe to item of interest

In the previous step, the OMMConsumer established a connection to our market data feed server. Now we will request an item from it. Market data servers support multiple data services. It could be a real time feed, delayed data feed or inhouse contribution etc, depending upon how it is configured. To request data, the application needs to know the market data service name and RIC code for the item of interest. RIC for common equity instrument is usually composed of street symbol and exchange code where it trades, separated by a period. For e.g, IBM trading at NYSE would be represented as IBM.N. We create a request message object - ReqMsg and pass it desired service name and RIC code. As soon as this ReqMsg is registered with OMMConsumer, EMA sends the request to the connected upstream market data server which begins responding by dispatching both data and status messages to our OmmConsumerClient callback.

Message Processing - dispatch

As outlined above, the OmmConsumer interface utilizes OmmConsumerConfig to capture configuration details such as your login credentials. In addition to that, the interface also allows the specification of an Operation Model. The Operation Model determines which thread should dispatch events to your client callback. Specifically, the model chooses whether to capture your callback events within a user thread, or within an Api thread.

Choosing your Operation Model

User    

The user model specification utilizes your application thread of execution and message dispatch. The application thread is commonly your main thread of execution.  When using this model, you must explicitly call the OmmConsumer.dispatch() method to capture messages within your client callback.

To use this model, specify: OmmConsumerConfig(OmmConsumerConfig::UserDispatchEnum) as configutaion option.

API

The Api model specification utilizes an internally EMA-managed thread that will automatically dispatch events during the life of the OmmConsumer instance. Once the instance destructs, the thread will automatically stop dispatching events. Note: Be aware when using this model, your application is multi-threaded. Ensure you take appropriate actions to protect your application resources against concurrent access. Refer to the EMA in Multi-Threaded Applications topic.

To use this model, specify: OmmConsumerConfig(OmmConsumerConfig::ApiDispatchEnum) as the configuration option. This is also the default option.

The tutorials utilize the default Operation Model API, which is why we need to temporarily sleep within the main thread to capture our messages. For an overview on the details around EMA dispatch and the Operation model, refer to the Product Architecture chapter within the EMA documentation. For a detailed outline of event management and dispatch, refer to the Transport API Reactor Concepts within the ETA documentation.

 

int main( int argc, char* argv[] )	
{
  // instantiate callback client
  AppClient client;
  
  // create OMM consumer
  OmmConsumer consumer( 
    OmmConsumerConfig()
      .host( "ADS:14002" )
      .username( "user1" ) 
  );

  
  // subscribe to Level1 market data                          
  consumer.registerClient(                                    
    ReqMsg()                                                  
      // default subscription domain is MMT_MARKET_PRICE      
      .serviceName( "ELEKTRON_AD" )                           
      .name( "IBM.N" ),                                       
    client );                                                 

  // block this thread for a minute
  sleep(60000);
  
  return 0;
}

 

Receive response from API

The API calls onRefreshMsg, onUpdateMsg of OmmConsumerClient instance passed in the registerClient method call. A simplest way to quickly test everything out would be to dump the response object RespMsg on output stream. The method prints out its payload on console output.

void AppClient::onRefreshMsg( const RefreshMsg& refreshMsg, const OmmConsumerEvent& event) {
{
  cout << "Response message: " << refreshMsg << endl;    
}

 

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 price at the command line.

Upon executing Consumer.exe, console output looks as follows:

Response message: RefreshMsg
    .
    .
    name="IBM.N"
    serviceName="ELEKTRON_AD"
    Payload dataType="FieldList"
        FieldList FieldListNum="79" DictionaryId="1"
            .
            .
            FieldEntry fid="11" name="NETCHNG_1" dataType="Real" value="0.4400"
            FieldEntry fid="12" name="HIGH_1" dataType="Real" value="167.3600"
            FieldEntry fid="13" name="LOW_1" dataType="Real" value="165.9300"
        FieldListEnd
    PayloadEnd
RefreshMsgEnd

Update message: UpdateMsg
    .
    .
    Payload dataType="FieldList"
        FieldList
            .
            .
            FieldEntry fid="22" name="BID" dataType="Real" value="166.6700"
            FieldEntry fid="25" name="ASK" dataType="Real" value="166.7200"
            FieldEntry fid="30" name="BIDSIZE" dataType="Real" value="2"
            FieldEntry fid="31" name="ASKSIZE" dataType="Real" value="1"
         FieldListEnd

    PayloadEnd
UpdateMsgEnd
.
.

This is string representation of Response message and multiple Update messages.

Tutorial Group: 
EMA Consumer