Skip to content

Overview and Conventions

Using our market data API is straightforward. Simply include the nanoconda.h header file in your project and link your program with the -lnanoconda library.

Nanoconda threads

Nanoconda API allows for a very flexible and powerful threading model. Here is how it works:

Whenever you subscribe to a topic, such as market data for an instrument or exchange updates for your trading session, you have a choice of placing the callbacks of the new topic to an existing thread or to create a new thread for the topic.

This is controlled by the last argument to subscribe() / subscribeUnderlying or to dmasession::init()

Signatures
static dmasession* init(const char* accountName, reasoncode& reason, short cpu = -1);

   reasoncode subscribe(const char* symbol, const char* entitlement, short cpu = -1);
   reasoncode subscribeUnderlying(const char* symbol, const char* entitlement, short cpu = -1);
Examples
   nanoconda::subscribe("ESM5", "XCME", 3); // subscribe to ESM5 Futures on a new thread pinned to cpu #3
   nanoconda::subscribeUnderlying("NQ", "XCME", 3); // subscribe to ESM5 Futures on same thread on cpu #3

   nanoconda::reasoncode rcode;
   nanoconda::dmasession::init("useraccount1", rcode, 1); //subscribe to account updates on a new thread on cpu #1

Tip

a) Whenever a new cpu argument is provided the library creates a new thread pinned to the cpu ID.
b) If cpu number was provided in a previous subscription method then the new subscription will be placed onto the same thread.
c) If cpu argument is ommited then the new subscription will be placed onto a default thread and it will not be pinned.
d) If cpu is invalid then reasoncode::CPU_OUT_OF_BOUNDS will be returned.

User threads

You may create additional threads for any internal processing as needed. The environment provides full access to both C++ std::thread and POSIX pthread APIs.

Order submissions to nanoconda::dmaSession require no additional user-level synchronization. All order-management functions are internally implemented in a thread-safe manner.

API functions

Note

API Calls return nanoconda::reasoncode to notify the user if the call was successful or if there was an error. It is users responsibility to handle any errors returned. Please refer to Reason Codes for explanation of each code and to Sample Application for an example on how to handle the codes.

Register Application

To ensure user is entitled to a market data set and allocated trading session, credentials must be set and each application must be registered. Please supply your credentials and a pointer to your callback listenerobject

   reasoncode registerApplication(const char* username, const char* password, listener* l); 

   //Example: rcode = nanoconda::registerApplication("username1","password", mdApp); 

Start nanoconda Threads

When your application is ready to receive callbacks, call start() which will trigger listening to live updates and generage callbacks for both market data and dmasession.

nanoconda::start(); 

Stop nanoconda Threads

It is recommended to call stop() when terminating your application or when you intend to stop receiving callbacks.

nanoconda::stop(); 

Note

After invoking stop(), the internal state may take several seconds to fully clear and remove your application's logged-in status. Do not call start() earlier than five seconds after stop() has returned.

Memory Architecture

Your container will have access to a shared memory region.

All communications between your application and the exchange are handled via the API and are going through the memory region.

Nanoconda Managed Services are in charge of running the market data normalization processes and keeping trading sessions in operational state.

You can start and stop your application at any time.

Server Diagram

Architecture

Prices

All prices are stored and communicated as long long type. To display any price as a human readable double, use double nacoPx(long long px) (1) method.

  1. Please refer to Market Data API for more usage examples.
    Example Price Conversion
       void ontrade(const nanoconda::trade* t) { // callback for a new trade
    
              printf("Human Readable price is %f", nanoconda::nacoPx(t->lastPrice));
       };
    

Info

For most instruments prices are stored as 10^5 multiplier of the original price. Some instruments have 10^9 price precision, they are identified by security::highPrecisionPrice set to 1

Security ID

Securities are idendified by symbolid field only inside all data structures except struct security.

  1. To get symbol name as a string please call const char* getSymbolName(unsigned long long symbolId)

  2. Securities are idendified by symbolid field inside all data structures. To get full symbol object with product information you can call security* getSecurity(unsigned long long symbolId) at any time.

    From nanoconda.h
       enum securityStatus : unsigned short
       {
          HALT = 0,
          CLOSE = 200,
          POST_CLOSE = 220,
          PRE_OPEN = 120,
          OPEN = 100
       };
       //...
       struct security
       {
          char symbol[32];
          unsigned long long symbolId;
          unsigned long long exchangeSecurityId;
          unsigned long long tickSize;
          unsigned long long multiplier;
          unsigned long long underlyingId;
          long long lowLimitBand;
          long long highLimitBand;
          securityStatus status;
          char entCode[6];
          char highPrecisionPrice;
          unsigned char segmentId;
          char reserved[6];
          long long settlementPrice;
          int openInterest;
          int clearedVolume;
          long long reservedL2;
          static inline unsigned short size() 
          { 
             return 128;
          }
    
       };
    

Reason Codes

Most of API calls return or populate nanoconda::reasoncode to notify the program of any errors. It is user responsibility to log and handle errors returned by the system.

From nanoconda.h
   enum reasoncode : unsigned short
   {
      SUCCESS = 0,
      ERROR = 10,
      SYSTEM_ERROR = 12,
      API_VERSION_ERROR = 15,
      ENTITLEMENT_EMPTY = 1002,
      MARKET_NOT_FOUND = 1004,
      USER_NOT_ENTITLED = 1006,
      SYMBOL_EMPTY = 1010,
      SYMBOL_NOT_FOUND = 1012,
      ORDER_TYPE_NOT_SET = 1022,
      ORDER_SIDE_EMPTY = 1032,
      CPU_OUT_OF_BOUNDS = 1111,
      QUANTITY_EMPTY = 1020,
      PRICE_BAND_BREACHED = 1025,
      ORDER_IS_NULL=1015,
      ORDERID_EMPTY = 1030,
      ORDER_NOT_FOUND = 1035,
      ORDER_NOT_LIVE = 1036,
      ORDER_IN_FLIGHT = 1044,
      ACCOUNTNAME_EMPTY = 1052,
      DUPLICATE_REQUEST_SESSION = 1055,
      USERNAME_EMPTY = 1060,
      PASSWORD_EMPTY = 1070,
      LISTENER_NOT_PROVIDED = 1090,
      RISK_LIMIT_EXCEEDED = 1220,
      RISK_CLIP_SIZE_EXCEEDED = 1230,
      RISK_MAX_LOSS_EXCEEDED = 1250,
      PERMISSION_ERROR = 2070,
      SESSION_IN_USE = 2075,
      ALGO_BLOCKED = 2080,
      SESSION_DOWN = 2099,
      SESSION_UP = 4000,
      SECURITY_DELETED = 9012,
      RISK_NOT_SET = 9212,
      REQUEST_LIMIT = 9370,

   };