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
-
Create a
nanoconda::remotesession*object using the staticinit()function: -
Call the
start()method to establish the connection: -
Poll Session Data:
-
Link against
nanocondaremotelibrary when compiling:
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.
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
#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:
The program receives the request through:
The listener may optionally populate a binary response, which is automatically returned to the originating Remote API client through:
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
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
Receives a structured datareport generated by the colocated program using the standard Nanoconda Algo API format.
Custom Report
Receives an arbitrary customer-defined binary report.
- Maximum payload size: 16,376 bytes
- Payload format is completely user-defined.
Custom Response
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
Triggers a standard Nanoconda Algo API control action.
Use this to remotely activate buttons or controls exposed by the program.
Record Action
Triggers an action associated with a specific table record exposed by the program.
Custom Request
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
Publishes a structured datareport.
The remote application receives it through:
Custom Report
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:
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:
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.