Skip to content
Get Started

Remote Access API

Nanoconda provides a Remote Access API that allows you to securely connect to a running trading session from a remote machine.

The API supports bidirectional communication with colocated programs through custom commands and user-defined payloads, making it possible to develop fully custom or white-labeled trading GUIs, dashboards, automation tools, and integrations while the trading infrastructure remains colocated

The API is designed for remote monitoring, operational control, and program communication. It is not intended for latency-sensitive order execution.

Key Features

  • Connect to a running Nanoconda DMA session from a remote machine.
  • Monitor real-time account statistics, including P&L, net exposure, positions, and system status.
  • Download the session trade log.
  • Automate risk controls, including enabling/disabling trading (kill switch) and adjusting risk limits programmatically.
  • Cancel all live orders.
  • Flatten the account.
  • Trigger custom commands on colocated programs from a remote machine.
  • Send arbitrary user-defined payloads to programs, enabling fully custom communication between remote applications and trading strategies.
  • Build custom dashboards, control panels, and operational tools that communicate directly with colocated programs.
  • Schedule automated actions such as parameter updates, strategy controls, or operational workflows without requiring direct access to the colocated server.
  • Build custom or white-labeled trading GUIs and dashboards that communicate directly with colocated programs.

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();

   const char* getAccountName();

   long long sessionPnl();
   long long maxDrawdown();
   long long capitalUse();
   long long accountBalance();
   reasoncode sessionStatus();

   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 getLastBook(unsigned long long symbolId, nanoconda::book* b);
   reasoncode getLastBook(const char* symbol, nanoconda::book* b);
   reasoncode getTradeLog(nanoconda::order* tradelog,unsigned int countLimit = 0, unsigned int startFrom = 0);

   reasoncode setRiskLimits(const char* underlyingSymbol, int maxpositions, int clipsize, int maxdailylots = 0, int capitalreq = 0);
   reasoncode disableTrading();
   reasoncode enableTrading();
   reasoncode blockProgram();
   reasoncode allowProgram();
   reasoncode cancelAllOrders();
   reasoncode flatten();
   reasoncode registerListener(remotelistener* rl);

   reasoncode subscribeInstrument(unsigned long long symbolId, bool L1only = true);
   reasoncode subscribeInstrument(const char* symbol, bool L1only = true);

   reasoncode unsubscribeInstrument(unsigned long long symbolId);
   reasoncode unsubscribeInstrument(const char* symbol);

   reasoncode sendcontrolaction(datainput* input, int buttonId, int viewId);
   reasoncode sendrecordaction(datarecord* record, int buttonId, int viewId);

   reasoncode sendcustomrequest(const char* data, unsigned short len);

   unsigned short apiVersion();

   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) { };

   virtual void onschemaupdate(interfaceschema* schema) { };
   virtual void ondatareport(nanoconda::datareport* datareport) { };

   virtual void oncustomreport(char* data, unsigned short len) { };
   virtual void oncustomresponse(char* data, unsigned short len) { };
};

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;
}

Remote Algorithm Communication

The Remote Access API allows a remote C++ application to exchange data and commands with an program running inside a colocated Nanoconda DMA session.

This enables:

  • Custom or white-labeled trading GUIs
  • Office dashboards
  • Remote strategy control panels
  • Scheduled command execution
  • Monitoring and reporting integrations

Communication supports both standard Nanoconda Algo API structures and arbitrary customer-defined binary payloads.

Communication Model

The communication consists of three components:

  • remotesession — Runs in the remote application.
  • dmasession — Runs inside the colocated program.
  • Program listener — Receives custom requests from the remote application.

Communication Patterns

The Remote Access API supports two complementary communication models:

Persistent Reports

The program can continuously publish structured or custom reports that are automatically distributed to all connected Remote API clients via setcustomreport(...)

Persistent reports are ideal for information that should always be available, such as:

  • Strategy status
  • P&L and statistics
  • Current parameters
  • Market metrics
  • Dashboard data
  • Health and monitoring information

The latest report is retained by the DMA session and transmitted to connected Remote API clients approximately once per second and delivered via oncustomreport(...)


Request / Response

For interactive communication, the Remote API also supports a request/response model.

A remote application can send an arbitrary binary request to the colocated program using:

sendcustomrequest(...)

The program receives the request through:

oncustomrequest(...)

The listener may optionally populate a binary response, which is automatically returned to the originating Remote API client through:

oncustomresponse(...)

This mechanism is useful for operations such as:

  • Querying program state on demand
  • Changing parameters
  • Triggering custom actions
  • Sending commands from a custom GUI
  • Returning validation results or status information
  • Implementing custom application protocols

Unlike persistent reports, request/response communication is initiated by the remote application and is intended for interactive, command-oriented workflows.

Receiving Data

Interface Schema

virtual void onschemaupdate(interfaceschema* schema);

Called whenever the program interface schema is received or updated.

The schema uses the standard Nanoconda Algo API format and describes all available views, controls, tables, and inputs exposed by the program. This allows remote applications to dynamically construct custom or white-labeled user interfaces.


Structured Data Report

virtual void ondatareport(nanoconda::datareport* report);

Receives a structured datareport generated by the colocated program using the standard Nanoconda Algo API format.


Custom Report

virtual void oncustomreport(char* data, unsigned short len);

Receives an arbitrary customer-defined binary report.

  • Maximum payload size: 16,376 bytes
  • Payload format is completely user-defined.

Custom Response

virtual void oncustomresponse(char* data, unsigned short len);

Receives a binary response to a previously issued custom request.

  • Maximum payload size: 16376 bytes
  • Payload format is completely user-defined.

Sending Commands

Control Action

reasoncode sendcontrolaction( datainput* input, int buttonId, int viewId );

Triggers a standard Nanoconda Algo API control action.

Use this to remotely activate buttons or controls exposed by the program.


Record Action

reasoncode sendrecordaction( datarecord* record, int buttonId, int viewId );

Triggers an action associated with a specific table record exposed by the program.


Custom Request

reasoncode sendcustomrequest( const char* data, unsigned short len );

Sends an arbitrary binary payload to the colocated program.

  • Maximum payload size: 504 bytes
  • Payload format is completely customer-defined.

The request is delivered to the program through the oncustomrequest() listener callback.


Publishing Data From the Program

Structured Data Report

reasoncode setdatareport(datareport* report) const;

Publishes a structured datareport.

The remote application receives it through:

void ondatareport(nanoconda::datareport* report);

Custom Report

reasoncode setcustomreport( void* src, unsigned short len = 16376 ) const;

Publishes an arbitrary binary report.

  • Maximum payload size: 16,376 bytes
  • Payload format is completely customer-defined.
  • The latest report is retained by the DMA session and transmitted to all connected Remote API clients approximately once per second.

The remote application receives it through:

oncustomreport(...)

Receiving Custom Requests

The program listener receives custom requests through:

unsigned short oncustomrequest(const char* data, unsigned short size, char* responsebuffer, unsigned short responsemaxsize) { return 0; };

The callback receives the binary request payload and may optionally populate a binary response.

  • Maximum request size: 504 bytes
  • Maximum response size: 16376 bytes

Any response generated by the listener is automatically delivered to the remote application through:

oncustomresponse(...)

Typical Use Cases

  • Build a completely custom or white-labeled trading GUI.
  • Build office dashboards displaying strategy state and statistics.
  • Remotely modify algorithm parameters.
  • Start or stop trading strategies.
  • Schedule automated commands.
  • Exchange arbitrary binary messages between remote applications and colocated algorithms.