Skip to content

Remote Access API

Nanoconda provides a Remote Access API that allows you to connect to a trading session programmatically.

Key Features

  • Connect to a running Nanoconda DMA session from a remote machine.
  • Monitor session statistics like P&L and net exposure.
  • Download the session trade log.
  • Integrate custom tooling for automated risk and performance monitoring.
  • Automate risk controls, including disabling trading (kill switch) or adjusting risk limits programmatically.
  • Flatten the account and/or cancel all live orders

Usage Guide

  1. Create a nanoconda::remotesession* object using the static init() function:

       nanoconda::remotesession* session = nanoconda::remotesession::init(rcode);
    

  2. Call the start() method to establish the connection:

       session->start();
    

  3. Poll Session Data:

       while(true) //Keep your application running and query session metrics as needed
       {
          usleep(2000000);
          printf("Session P&L %.2f / Max Drawdown %.2f\n", pnlToDouble(session->sessionPnl()), pnlToDouble(session->maxDrawdown()));
       }
    

  4. Link against nanocondaremote library when compiling:

    g++ yourapp.cpp -lnanocondaremote  ...
    

Remote API Overview

The nanoconda::remotesession struct exposes the key methods needed to connect to and interact with a running Nanoconda trading session from an external process.

nanoconda::remotesession
   struct remotesession
   {
      static remotesession* init(reasoncode& reason);
      reasoncode start(const char* username, const char* password, const char* host, unsigned short port, short cpu = -1);
      reasoncode stop();

      long long sessionPnl();
      long long maxDrawdown();

      unsigned int getSecurityList(security* usersecuritystorage);
      reasoncode getSecurity(unsigned long long symbolId, security* usersecurity);
      const char* getSymbolName(unsigned long long symbolId);

      reasoncode getRiskLimits(risk* riskreport);
      unsigned int getSecurityStats(nanoconda::securitystats* securitystatstorage);

      unsigned int tradesMade();
      reasoncode getTradeLog(nanoconda::order* tradelog,unsigned int countLimit = 0, unsigned int startFrom = 0);

      reasoncode setRiskLimits(const char* underlyingSymbol, unsigned short maxpositions, unsigned short clipsize);
      reasoncode disableTrading();
      reasoncode enableTrading();
      reasoncode cancelAllOrders();
      reasoncode flatten();

      reasoncode registerListener(remotelistener* rl);

      private:
      remotesession();
      void* implementation;
   };

Remote Listener

remotelistener object can be passed to the remote session via registerListener() method to receive helpful callbacks.

struct remotelistener
{
   virtual void onconnect() { };
   virtual void ondisconnect(const char* reason) { };
   virtual void onconnectionerror(int code, const char* reason) { };

   virtual void onlogin() { };
   virtual void onlogout() { } ;

   virtual void onnewtrades(unsigned int oldTradeCount, unsigned int newTradeCount) { };
};

Sample Remote Client Application

compilation
g++ remoteclient.cpp -lnanocondaremote -I nanocondaroot/include -L nanocondaroot/lib
remoteclient.cpp
#include "nanoconda.h"
#include <iostream>
#include <unistd.h>
#include <getopt.h>
#include <cstring>

using namespace nanoconda;

#define NANOCONDA_EXPONENT 100000
#define NANOCONDA_EXPONENT_HP 1000000000

void print_usage(const char* progname) {
    std::cout << "Usage: " << progname << " -H host -P port -u username -p password\n";
    std::cout << "Example: " << progname << " -h 127.0.0.1 -p 38080 -u hftclient -p password\n";
}

inline double pnlToDouble(long long pnl)
{
   return (double) pnl / NANOCONDA_EXPONENT;
}
inline double priceToDouble(long long price, bool highprecisionprice=false)
{
    return highprecisionprice ? (double) price / NANOCONDA_EXPONENT_HP : (double) price / NANOCONDA_EXPONENT;
}

struct myRemoteListener : nanoconda::remotelistener
{
      void onlogin() final override
      {
         printf("myRemoteListener::onlogin()\n");
      }
      void onnewtrades(unsigned int oldTradeCount, unsigned int newTradeCount) final override
      {
         printf("myRemoteListener::onnewtrades(%u:%u)\n", oldTradeCount, newTradeCount);
      }
      void onlogout() final override
      {
         printf("myRemoteListener::onlogout()\n");
      }
      void ondisconnect(const char* reason) final override
      {
         printf("myRemoteListener::ondisconnect() reason %s\n", reason);
      }
      void onconnectionerror(int code, const char* reason) final override
      {
         printf("myRemoteListener::onconnectionerror() code %d reason %s\n", code, reason);
      }
      void onconnect() final override
      {
         printf("myRemoteListener::onconnect()\n");
      }
};

int main(int argc, char *argv[])
{
   char host[32] = {};
   char username[32]={};
   char password[64]={};
   int port = 0;

   static struct option long_options[] = {
      {"host", required_argument, 0, 'H'},
      {"username", required_argument, 0, 'u'},
      {"password", required_argument, 0, 'p'},
      {"port", required_argument, 0, 'P'},
      {0, 0, 0, 0}
   };

   int opt;
   int option_index = 0;

   while ((opt = getopt_long(argc, argv, "H:P:p:u:", long_options, &option_index)) != -1) {
      switch (opt) {
         case 'H': strncpy(host, optarg, 32); break;
         case 'u': strncpy(username, optarg, 32); break;
         case 'p': strncpy(password, optarg, 32); break;
         case 'P': port = std::stoi(optarg); break;
         default: print_usage(argv[0]); return 1;
      }
   }

   if (strlen(host) == 0 || strlen(username) == 0 || strlen(password) == 0 || port == 0) {
      print_usage(argv[0]);
      return 1;
   }

   nanoconda::reasoncode rcode;
   nanoconda::remotesession* session = nanoconda::remotesession::init(rcode);

   myRemoteListener _l;
   session->registerListener(&_l);

   session->start(username,password,host,port);

   /* sample allocations for storing application data */
   nanoconda::security* securities              = (nanoconda::security*) malloc(128*sizeof(nanoconda::security));
   nanoconda::securitystats* securitiesstats    = (nanoconda::securitystats*) malloc(128*sizeof(nanoconda::securitystats));
   nanoconda::risk* riskreport                  = (nanoconda::risk*) malloc(1024);
   nanoconda::order* tradelog                   = (nanoconda::order*) malloc(100000*sizeof(nanoconda::order));

   bool riskLimitsChanged = false;
   while(true) //Keep your application running and query session metrics as needed
   {
      usleep(2000000);

      unsigned int securitiesCount = session->getSecurityList(securities);
      printf("Session P&L %.2f / Max Drawdown %.2f\n", pnlToDouble(session->sessionPnl()), pnlToDouble(session->maxDrawdown()));
      printf("\n======Securities List======\n");
      printf("SYMBOL,SYMBOLID,MULTUPLIER,TICKSIZE\n");
      for(int s=0;s<securitiesCount;s++) {
         printf("%s,%llu,%d,%lld\n",securities[s].symbol,securities[s].symbolId,securities[s].multiplier,securities[s].tickSize);
      }

      unsigned int securitiesstatsCount = session->getSecurityStats(securitiesstats);
      printf("\n======Securities Stats======\n");
      printf("SYMBOL,PNL\n");
      for(int s=0;s<securitiesstatsCount;s++) {
         printf("%s,%.2f\n",session->getSymbolName(securitiesstats[s].symbolId),pnlToDouble(securitiesstats[s].realizedPnl));
      }
      session->getRiskLimits(riskreport);

      printf("\n======RISK REPORT======\n");
      printf("SYMBOL,MAXNET,CLIP,FILLSSHORT,FILLSLONG,NETOPEN,LIVELOTS\n");
      for(int i=0;i<riskreport->symbolcount;i++) {
         nanoconda::securityrisk* undrisk = &(riskreport->risklimits[i]);
         printf("%s,%d,%d,%d,%d,%d,%d\n",undrisk->symbol,undrisk->maxpositions, undrisk->clipsize, undrisk->fillsshort,undrisk->fillslong,undrisk->netopenpositions, undrisk->livelots);
      }

      printf("\n======TRADE LOG======\n");
      printf("SYMBOL,SIDE,PRICE,SIZE\n");
      unsigned int tradesMade = session->tradesMade();
      session->getTradeLog(tradelog);
      for(int i=0;i<tradesMade;i++) {
         nanoconda::order* fill = &(tradelog[i]);
         nanoconda::security localsecurity;
         session->getSecurity(fill->symbolId, &localsecurity);
         if(localsecurity.highPrecisionPrice) {
            printf("%s,%c,%d,%.9f\n",localsecurity.symbol,fill->side,fill->quantity,priceToDouble(fill->priceLast,localsecurity.highPrecisionPrice));
         } else {
            printf("%s,%c,%d,%.5f\n",localsecurity.symbol,fill->side,fill->quantity,priceToDouble(fill->priceLast,localsecurity.highPrecisionPrice));
         }
      }

      fflush(stdout);

      if(tradesMade>10 && !riskLimitsChanged) {
         riskLimitsChanged=true;
         //session->setRiskLimits("ES",55,15);
         //session->cancelAllOrders();
         //session->flatten();
      }

   }

   return 0;
}