EMA Consumer - Requesting MarketPrice data

Download tutorial source code

Click here to download

Last update Aug 2024
Compilers Tutorial demonstration: Visual Studio 2022
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 the system output stream.

Steps

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

Create OMMConsumer

The main function in Step2.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 the application should catch (omitted here for simplicity). This consumer initiates a TCP connection to a market data server, such as a deployed LSEG Real-Time Distribution System. 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 an OmmConsumerConfig object. OmmConsumerConfig reads entries from EmaConfig.xml if available, but can be selectively overridden in code as well.

Here we connect to a 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 30 seconds

  sleep(30000);

  

  return 0;

}

Subscribe to an 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 in-house 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 the 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. Refer to the Enterprise Message API Consumer Architecture section within the C++ Developer Guides for further details. 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 Enterprise Message API Consumer Architecture section within the C++ Developer Guides for further details. 

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 of 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 30 seconds

  sleep(30000);

  

  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:

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