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