These chapters describe the creation of a simple MICEX application step-by step with samples.
Follow these instructions to get it to work:
- Initialize FIX engine
- Create micex_mfix_application
- Subscribe to symbol
- Process incoming market data
- Unsubscribe from symbol
- Destroy micex_mfix_application
- Destroy engine (release resources)
Engine initialization
Execute the following instruction to initialize FIX engine.
// Initializes engine. Engine::FixEngine::init();
The engine.properties file is required to read the engine configuration parameters. It must, by default, be present in the current directory. If the file is located elsewhere or has a different name specify the properties file name and path explicitly.
// Initializes engine. Engine::FixEngine::init ("engine.properties");
If an error occurs during initialization (the properties file is not found, a required property is missing etc.) the exception will be thrown.
// Initializes engine. try { Engine::FixEngine::init("engine.properties"); } catch( const Utils::Exception& ex ) { cout << "ERROR: " << ex.what() << endl; }
micex_mfix_application creation
You can create an micex_mfix_application in three steps:
- Create a listener
- Configure micex_mfix_application parameters
- Create a micex_mfix_application object
// Class application_listener_impl implements a micex_mfix_application_listener interface class application_listener_impl : public micex_mfix::micex_mfix_application_listener { public: application_listener_impl() : app_(NULL) { micex_mfix::micex_mfix_application_params app_params; app_params.templates_fn_ = "./FIX50SP2.xml"; app_params.config_xml_ = "./config.xml"; app = Engine::FixEngine::singleton()->createMICEXApplication(app_params, this); } virtual void on_error(const std::string &error) { //add your processing code here } virtual void on_process(const Engine::FIXMessage &msg, const std::string &channel_id) { //add your processing code here } virtual void on_feed_reset(const std::string &channel_id, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_heartbeat(const std::string &channel_id, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } private: micex_mfix::micex_mfix_application *app_; };
- micex_mfix::micex_mfix_application_params::templates_fn_ - Path to the MICEX FAST templates file. It can be specified as an URL address to the MICEX FTP server.
- micex_mfix::micex_mfix_application_params::config_xml_ - Path to the MICEX configuration file. It can be specified as an URL address to the MICEX FTP server.
Prior to calling createMICEXApplication, create a listener, a class that implements micex_mfix::micex_mfix_application_listener interface. Usually this interface is implemented by classes that aggregate a micex_mfix::micex_mfix_application.
Subscribing and unsubscribing
MICEX uses four feeds to distribute the market data. Use
micex_mfix::micex_feed &order_book_feed = app->get_orderbook_feed();
or
micex_mfix::micex_feed &orders_feed = app->get_orders_feed();
or
micex_mfix::micex_feed &trades_feed = app->get_trades_feed();
or
micex_mfix::micex_feed &statistics_feed = app->get_statistics_feed();
to get a reference to a object that represents corresponding feed. Next, create an instument listener:
// Class instrument_listener_impl implements a micex_mfix::instrument_listener interface class instrument_listener_impl : public micex_mfix::instrument_listener { public: virtual bool on_security_definition(const micex_mfix::security_description &sec_desc, const micex_mfix::security_id &sec_id, const micex_mfix::symbol &symb, const std::string &board, const Engine::FIXMessage &d_msg, const std::string &channel_id) { //add your processing code here, return your result true or false return false; } virtual void on_subscribed(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_unsubscribed(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_increment(const micex_mfix::symbol &symb, const std::string &board, const micex_mfix::increments &msgs, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_security_status(const micex_mfix::symbol &symb, const std::string &board, const Engine::FIXMessage &msg, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual bool on_natural_refresh(const micex_mfix::symbol &symb, const std::string &board, const micex_mfix::increments &nr_msgs, micex_mfix::mfix_feed_type feed_type) { //add your processing code here, return your result true or false return true; } virtual void on_snapshot(const micex_mfix::symbol &symb, const std::string &board, const micex_mfix::snapshots &msgs, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_recovery_started(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_recovery_stopped(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_recovery_reason reason, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_error(const micex_mfix::symbol &symb, const std::string &board, const std::string &error, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } };
Once created use
micex_mfix::micex_feed::subscribe_by_symbol(const symbol &symb, const std::string &board, instrument_listener &listener, const std::string &channel_id, mfix_recovery_mode recovery = RM_USE_MARKET_RECOVERY);
method to subscribe to an any necessary symbol:
instrument_listener_impl ins_listener; some_feed.subscribe_by_symbol("AFLT", "EQBR", ins_listener, "FOND", micex_mfix::RM_USE_MARKET_RECOVERY);
The listener will be notified about the subscription by calling the instrument_listener_impl::on_subscribed callback:
void instrument_listener_impl::on_subscribed(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_feed_type feed_type) { std::cout << "Subscribed at '" << symb << "' symbol on '" << board << "' board." << std::endl; }
Use
void instrument_listener_impl::unsubscribe_by_symbol(const symbol &symb, const std::string &board, const std::string &channel_id);
method to unsubscribe from the symbol:
some_feed.unsubscribe_by_symbol("AFLT", "EQBR", "FOND");
After you call the method, the engine notify listener by calling the instrument_listener_impl::on_unsubscribed callback:
void instrument_listener_impl::on_unsubscribed(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_feed_type feed_type)
Use micex_mfix::micex_feed::subscribe_all and micex_mfix::micex_feed::unsubscribe_all to subscribe/unsubscribe for all MICEX symbols:
void micex_mfix::micex_feed::subscribe_all(instrument_listener &listener, const std::string &channel_id, mfix_recovery_mode recovery = RM_USE_MARKET_RECOVERY) void micex_mfix::micex_feed::unsubscribe_all(instrument_listener &listener, const std::string &channel_id, mfix_recovery_mode recovery = RM_USE_MARKET_RECOVERY)
Processing incoming marketdata
When a some fix message was received, the engine notifies a corresponding listener by calling one of the following callbacks:
// Faired when a Market Data Incremental Refresh (35=X) FIX message was received void instrument_listener_impl::on_increment(const symbol &symb, const std::string &board, const increments &msgs, mfix_feed_type feed_type);
// Faired when a Security Status (35=f) FIX message was received void instrument_listener_impl::on_security_status(const symbol &symb, const std::string &board, const Engine::FIXMessage &msg, mfix_feed_type feed_type);
// Faired in case when a recovery was started and all Market Data Snapshot Full Refresh (35=W) FIX messages were received void instrument_listener_impl::on_snapshot(const symbol &symb, const std::string &board, const snapshots &msgs, mfix_feed_type feed_type);
// Faired when a Security Definition (35=d) FIX message was received bool instrument_listener_impl::on_security_definition(const security_description &sec_desc, const security_id &sec_id, const symbol &symb, const std::string &board, const Engine::FIXMessage &d_msg, const std::string &channel_id);
Add your own code into the corresponding method to process the received data.
Releasing resources
Use the micex_mfix::micex_mfix_application::release() method to release the resources consumed by micex_mfix::micex_mfix_application. The listeners have the same method and must be released too once micex_mfix::micex_mfix_application is released. Calling micex_mfix::micex_feed::unsubscribe is optional.
Full sample
The sample below illustrates all abovementioned instructions combined in one application.
#pragma once #include <iostream> #include <B2BITS_FixEngine.h> #include <B2BITS_micex_mfix_listeners.h> #include <B2BITS_micex_mfix_application.h> class instrument_listener_impl : public micex_mfix::instrument_listener { public: virtual bool on_security_definition(const micex_mfix::security_description &sec_desc, const micex_mfix::security_id &sec_id, const micex_mfix::symbol &symb, const std::string &board, const Engine::FIXMessage &d_msg, const std::string &channel_id) { //add your processing code here, return your result true or false return false; } virtual void on_subscribed(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_unsubscribed(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_increment(const micex_mfix::symbol &symb, const std::string &board, const micex_mfix::increments &msgs, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_security_status(const micex_mfix::symbol &symb, const std::string &board, const Engine::FIXMessage &msg, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual bool on_natural_refresh(const micex_mfix::symbol &symb, const std::string &board, const micex_mfix::increments &nr_msgs, micex_mfix::mfix_feed_type feed_type) { //add your processing code here, return your result true or false return true; } virtual void on_snapshot(const micex_mfix::symbol &symb, const std::string &board, const micex_mfix::snapshots &msgs, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_recovery_started(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_recovery_stopped(const micex_mfix::symbol &symb, const std::string &board, micex_mfix::mfix_recovery_reason reason, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_error(const micex_mfix::symbol &symb, const std::string &board, const std::string &error, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } }; class application_listener_impl : public micex_mfix::micex_mfix_application_listener { public: virtual void on_error(const std::string &error) { //add your processing code here } virtual void on_process(const Engine::FIXMessage &msg, const std::string &channel_id) { //add your processing code here } virtual void on_feed_reset(const std::string &channel_id, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } virtual void on_heartbeat(const std::string &channel_id, micex_mfix::mfix_feed_type feed_type) { //add your processing code here } }; void subscribe_and_wait(micex_mfix::micex_mfix_application *app, instrument_listener_impl *&ins_listener) { //get channels id micex_mfix::channel_ids channels(app->get_channel_ids()); //get orderbook feed micex_mfix::micex_feed &order_book_feed = app->get_statistics_feed(); ins_listener = new instrument_listener_impl(); //subscribe to known instrument in channel[1], with market recovery as recovery type order_book_feed.subscribe_by_symbol("AFLT", "EQBR", *ins_listener, channels[1], micex_mfix::RM_USE_MARKET_RECOVERY); while (true) { std::cout << "Type 'q' for exit\n\n"; char c(0); std::cin >> c; if ('q' == c || 'Q' == c) { break; } } order_book_feed.unsubscribe_by_symbol("AFLT", "EQBR", channels[1]); } int main(int argc, char *agrv[]) { micex_mfix::micex_mfix_application *app = NULL; application_listener_impl *app_listener = NULL; instrument_listener_impl *ins_listener = NULL; try { Engine::FixEngine::init("./engine.properties"); //configure parameters micex_mfix::micex_mfix_application_params app_params; app_params.templates_fn_ = "./FIX50SP2.xml"; app_params.config_xml_ = "./config.xml"; app_listener = new application_listener_impl(); app = Engine::FixEngine::singleton()->createMICEXApplication(app_params, app_listener); subscribe_and_wait(app, ins_listener); } catch (const Utils::Exception &ex) { std::cerr << "Exception: " << ex.what() << "\n"; if (NULL != app_listener) { app_listener->release(); } if (NULL != ins_listener) { ins_listener->release(); } if (NULL != app) { app->release(); } return 100; } // release the listeners app_listener->release(); ins_listener->release(); // release micex_mfix_application app->release(); return 0; }