Skip to content

C++ programming interfaces

Apifiny Algo offers rich programming interfaces to users. Conceptually, we can categorize the APIs into 2 groups:

  • High level: Quants/traders could use c++ to implement algo components such as samplers, pricing models, variables and strategies.
  • Low level: TradingLib provides interfaces to allow traders/developers to use c++ to directly access various aspects of the libraries, such as market data callbacks, order placing api, historical data player, etc.

Component framework

Algo's C++ code uses a component framework to manage and extend functionalities. All components are managed using similar component manager and lifecycle mechanisms.

Component lifecycle

All components in Algo follow the same life-cycle management process: creation, initialization, handling event callbacks, handling onNotify() callback.

  • Creation: All components are created when an Algo application starts
  • Initialization: All components get initialized then. Function init() gets called at this time. It takes a json object as the only parameter, which contains the properties in the corresponding component node within the configuration file. init() uses information in the json object to initialize the component, and setup links to the other components specified in the json object.
  • Handling event callbacks: book updates, trade updates, timer updates and sampler callbacks are handled when they happen. The states of different components might not be in sync, some represent state before the event and others after the event. So you should only process data that has no dependencies to other components at this time.
  • Handling onNotify() callbacks: All components are in updated states triggered by the last event. They are in sync and you can implement your main logic in this function.

Register a component

After adding a component class, you need to register it into the corresponding component manager so it can be used in the configuration file.

Components are registered by adding a line into the corresponding getter function in XlibComponentFactory.

class MyComponentFactory : public XlibComponentFactory
{
public:
    Variable *getVariable(const string &type, const string &name, const json &attr) override
    {
        if (type == "TrendVar") 
            return new TrendVar(name, attr);            
        return nullptr;
    }   

    Strategy *getStrategy(const string &type, const string &name, const json &attr) override
    {
        if (type == "SignalTakeStrategy") 
            return new SignalTakeStrategy(name, attr);            
        return nullptr;
    }   
};

There are two ways to package your algo components: as a shared library or inside the main application code. The first option allows you to release the library to your organization or the public; the seconds option gives you a more compact way to organize your code.

  • To release it as a shared library, you create a class named MyComponentFactory that inherits from XlibComponentFactory, and add the following lines to create and expose object xCompFactory.

        extern "C" BOOST_SYMBOL_EXPORT MyComponentFactory xCompFactory;
        MyComponentFactory xCompFactory;
    

  • To include algo components in your main application, you create a class named MyComponentFactory that inherits from XlibComponentFactory, and add the following lines in the main function to integrate your factory into the system.

        XlibComponentFactoryPtr xmgr(new MyComponentFactory);
        SamplerManager::instance()->addXlibComponentFactory(xmgr);
        PricingModelManager::instance()->addXlibComponentFactory(xmgr);
        VariableManager::instance()->addXlibComponentFactory(xmgr);
        ModelManager::instance()->addXlibComponentFactory(xmgr);
        StrategyManager::instance()->addXlibComponentFactory(xmgr);
    

Get and use a component

All components are managed by their corresponding component managers, e.g. variables are managed by VariableManager. Component managers are singletons. You use instance() to get its pointer, and then call getter function with a name string to get the component object. Below is an example on how to get a variable named 'trend_ema' in json configuration file.

    VariableManager *varMgr = VariableManager::instance();
    string trend_ema = _cfg.at("trend_ema");
    _trend_ema = varMgr->getVariable(trend_ema);

Note

For performance reason, you should get components at initialization time and cache them in your classes. Avoid getting components from component managers at callbacks.

Component managers

Component Component Manager
Symbol SymbolManager
Account AccountManager
RiskFormula RiskFormulaManager
Player PlayerManager
Sampler SamplerManager
Variable VariableManager
PricingModel PricingModelManager
Model ModelManager
Strategy StrategyManager

High level API

Quant Researchers and traders use APIs in this level to implement trading algorithm components. The main components are samplers, pricing_models, variables, models, and strategies. To implement a component, you create a class that inherits from one of the following base classes and override the init(), onNotify() and several other functions. You then register it into your XlibComponentFactory to make it usable in json configuration.

Sampler
PricingModel
Variable
Model
Strategy

Create a sampler

A sampler inherits base class Sampler, implements init() function to load configurations, and call fireOnSample() function when an event happens. Function fireOnSample() will trigger callbacks to all objects that listen to this sampler.

Below is the implementation of a simple time based sampler. It inherits from TimerListener, creates a TimerHandler, and add itself as a listener at init(). When the specified duration passes, the TimerHandler will call onTimer() of its listeners. We implement fireOnSampler() in this call back to generate a sampler event.

  • Header file: TimeSampler.h

    #pragma once
    #include "base/Sampler.h"
    #include "components/TimerManager.h"
    
    class TimeSampler: public Sampler, public TimerListener {
    public:
        using Sampler::Sampler;
        void init();
        void onTimer(TimerHandler* th, long msecs);
    
    private:
        long _msecs;
    };
    

  • Source file: TimeSampler.cpp

    #include "TimeSampler.h"
    
    void TimeSampler::init() {
        auto timerMgr = TimerManager::instance();
    
        double halflife = _cfg.at("halflife"));
        setHalflife(halflife);
    
        _msecs = _cfg.at("msecs");
        TimerHandler* th = timerMgr->getTimerHandler(msecs);
        th->addListener(this);
    }
    
    void TimeSampler::onTimer(TimerHandler* th, long msecs) {
        if(msecs == _msecs) {
            fireOnSample(1, _decay);
        }
    }
    

  • Register the component

    class MyComponentFactory : public XlibComponentFactory
    {
    public:
        Sampler *getSampler(const string &type, const string &name, const json &attr)
        {
            if (type == "TimeSampler")
                return  new TimeSampler(name, attr);
            return nullptr;
        }
    };
    

Create a pricing model

A pricing model calculates the fair value of an asset and store it in its member variable _price. It also has a boolean variable _ready to store the readyness of this fair value. It uses public methods price() and is_ready() to expose these variables to the public.

It inherits from base class PricingModel. PricingModel is a sub class of SymbolListener. We first implement init() function to load configurations. In most cases, we override onQuote()/onTrade() to handle market data events, and implement onNotify() if the data we need to use is dirty at market data callback time.

Below is an example that calculates mid price for a symbol. It inherits from PricingModel and listens to market data callbacks of the specified symbol. It calculates mid price at onQuote() callback, and set _price and _ready.

Note

We need to call setUpdated() to trigger the onNotify() callback for objects that use this pricing model.

  • Header file: MidPx.h

    #pragma once
    #include "base/PricingModel.h"
    using namespace std;
    
    class MidPx: public PricingModel {
    public:
        using PricingModel::PricingModel;
        void init();
        void onQuote(long cid, const SymbolInfo& si);
    
    protected:
        SymbolInfo* _si;
    };
    

  • Source file: MidPx.cpp

    #include "MidPx.h"
    #include "components/SymbolManager.h"
    
    void MidPx::init() {
        auto symMgr = SymbolManager::instance();
    
        string ticker = _cfg.at("port").at(0);
        string exch = _cfg.at("port").at(1);
        auto sh = symMgr->getSymbolHandler(ticker, exch);
        sh->addListener(this);
        _si = &sh->symbolInfo();
    }
    
    void MidPx::onQuote(long cid, const SymbolInfo& si) {
        _price = 0.5 * (si.bid_px + si.ask_px);
        _ready = si.is_ready();
        setUpdated();
    }
    

  • Register the component

    class MyComponentFactory : public XlibComponentFactory
    {
    public:
        PricingModel *getPricingModel(const string &type, const string &name, const json &attr)
        {
            if(type == "MidPx")
                return new MidPx(name, attr);
            return nullptr;
        }
    };
    

Create a variable

An Algo variable holds a value and its readyness, and updates them when events happen. The corresponding C++ member variables are _value and _ready, and public methods are value() and is_ready().

It inherits from base class Variable. To create an Algo variable, We first implement init() function to load configurations. We then do calculation inside callback functions and/or onNotify(). Calculation that might use dirty variables (whose values do not match the current state due to the calculation tree populating process) should only happen within onNotify().

An Algo variable can be used as a feature (some people call it alpha) to predict market movement, or just as a support one to help further calculations. The value of an Algo variable can represent any thing. We recommend you to use it to represent asset returns if it is designed as a feature.

We use a relative complicated Algo variable as an example here. It calculates the return between weighted price from multiple levels of market order books and a reference price, such as midpx. You can learn how to get a pricing model and use it in an Algo component, and how to iterate through market orderbooks.

Note

We need to call setUpdated() to trigger the onNotify() callback for objects that use this variable.

  • Header file: BookReturn.h

    #pragma once
    #include "base/Variable.h"
    #include "base/SymbolHandler.h"
    
    class BookReturn: public Variable, public L2ChangeListener {
    public:
        using Variable::Variable;
        void init();
        void onQuote(long cid, const SymbolInfo& si);
        void onL2Change(long cid, const SymbolInfo& si);
        void onNotify();
    
    protected:
        double getBookSize(TradeDirs side);
        double getSizeWeightedPx(TradeDirs side, double sizeTaken);
    
    protected:
        SymbolInfo* _si;
        int _levelCap = 5;
        double _sizeCap = 1000000000;
        bool _bookChanged = true;
        double _weightedPx = 0.0;
        PricingModel* _refPm;
    };
    

  • Source file: BookReturn.cpp

    #include "BookReturn.h"
    #include "components/PricingModelManager.h"
    #include "components/SymbolManager.h"
    
    void BookReturn::init() {
        auto symMgr = SymbolManager::instance();
        auto pmMgr = PricingModelManager::instance();
    
        string ticker = _cfg.at("port").at(0);
        string exch = _cfg.at("port").at(1);
        _sh = symMgr->getSymbolHandler(ticker, exch);
        _sh->addListener(this);
        _sh->addL2ChangeListener(this);
        _si = &_sh->symbolInfo();
    
        _levelCap = getJsonValue(_cfg, "level_cap", 5);
        _sizeCap = getJsonValue(_cfg, "size_cap", 1000000000);
    
        string ref_pm = _cfg.at("ref_pm");
        _refPm = pmMgr->getPricingModel(ref_pm);
        addNotifiableChild(_refPm);
    }
    
    void BookReturn::onL2Change(long cid, const SymbolInfo& si) {
        _bookChanged = true;
    }
    
    void BookReturn::onQuote(long cid, const SymbolInfo& si) {
        _bookChanged = true;
        setUpdated();
    }
    
    void BookReturn::onNotify() {
        if(_bookChanged) {
            double bidSizeSum = getBookSize(BUY);
            double askSizeSum = getBookSize(SELL);
            double sizeTaken = min(min(bidSizeSum, askSizeSum), _sizeCap);
    
            double weightedBidPx = getSizeWeightedPx(BUY, sizeTaken);
            double weightedAskPx = getSizeWeightedPx(SELL, sizeTaken);
            _weightedPx = 0.5 * (weightedBidPx + weightedAskPx);
            _bookChanged = false;
        }
    
        double refpx = _refPm->price();
        _value = (refpx > EPS) ? _weightedPx / refpx - 1.0 : 0.0;
        _ready = _si->is_ready() && _refPm->is_ready();
    }
    
    double BookReturn::getBookSize(TradeDirs side) {
        LevelAccessor& la = _si->getBookLevelAccessor(side);
        Level* level = la.begin();
        int i = 0;
        double csz = 0;
        while(level) {
            if(i >= _levelCap)
                break;
            csz += level->qty;
            level = la.next();
            ++i;
        }
        return csz;
    }
    
    double BookReturn::getSizeWeightedPx(TradeDirs side, double sizeTaken) {
        LevelAccessor& la = _si->getBookLevelAccessor(side);
        Level* level = la.begin();
        int i = 0;
        double szpx = 0;
        double csz = 0;
        while(level) {
            if(i >= _levelCap)
                break;
            double sz = level->qty;
            csz += sz;
            if(csz >= sizeTaken) {
                sz -= (csz - sizeTaken);
                csz = sizeTaken;
                szpx += sz * level->price;
                break;
            }
            szpx += sz * level->price;
            level = la.next();
            ++i;
        }
        return szpx / csz;
    }
    

  • Register the component

    class MyComponentFactory : public XlibComponentFactory
    {
    public:
        Variable *getVariable(const string &type, const string &name, const json &attr)
        {
            if (type=="BookReturn") 
                return new BookReturn(name, attr);
            return nullptr;
        }
    };
    

Create a model

We use model to feed signal into trading strategies. They can be the simple pass-through of a variable, or contain advanced logics such as switching to different variable at different condition.

  • Header file: SimpleModel.h

    #pragma once
    #include "base/Model.h"
    #include "base/Variable.h"
    using namespace std;
    
    class SimpleModel: public Model{
    public:
        using Model::Model;
        void init();
        void onNotify();
    
    private:
        Variable* _var;
    };
    

  • Source file: SimpleModel.cpp

    #include "SimpleModel.h"
    #include "components/VariableManager.h"
    
    void SimpleModel::init()
    {
        auto varMgr = VariableManager::instance();
        _var = varMgr->getVariable(_cfg.at("variable"));
        addNotifiableChild(_var);
    }
    
    void SimpleModel::onNotify() {
        _signal = _var->value();
        _ready = _var->is_ready();
    }
    

  • Register the component

    class MyComponentFactory : public XlibComponentFactory
    {
    public:
        Model *getModel(const string &type, const string &name, const json &attr){
            if (type == "SimpleModel")
                return new SimpleModel(name, attr);
            return nullptr;
        }
    };
    

Create a strategy

An Algo strategy is designed to implement order execution logics. It gets signal inputs from models and variables, then places or cancels orders accordingly. It handles order update callbacks and manage positions/risks. It is the center piece of code in trading strategy implementation.

An Algo strategy inherits from base class Strategy. We also include a refenrence implementation to address the common tasks when creating a strategy. We will give an example that directly inherits from Strategy and another one that inherits from CCModelStrategy.

Inherit from Strategy
  • Header file: SignalTakeStrategy.h

    #pragma once
    #include "base/Strategy.h"
    #include "components/TimerManager.h"
    #include "base/Order.h"
    #include "base/SymbolInfo.h"
    #include "base/Variable.h"
    
    class SignalTakeStrategy: public Strategy, public OrderSender {
    public:
        using Strategy::Strategy;
    
        //implements Strategy
        void init() override;
        void onNotify() override;
        SymbolInfo *getSymbolInfo() override { return _si; }
        void onCommand(json& cmd) override {}
        bool isUseMargin() override { return _useMargin; }
        string& marginSource() override { return _marginSource; }
    
        //imlements SymbolListener
        void onQuote(long cid, const SymbolInfo& si) override;
        void onTick(long cid, const SymbolInfo& si) override;
        void onQuoteStale(long cid, const SymbolInfo& si) override {}
    
        //implements TimerListener
        void onTimer(TimerHandler* th, long msecs) override;
    
        //implements OrderSender
        void onOrderCreated(LOrder* order) override {};
        void onOrderAcked(LOrder* order) override {};
        void onOrderRejected(LOrder* order) override {};
        void onOrderCancelCreated(LOrder* order) override {};
        void onOrderCancelAcked(LOrder* order) override {};
        void onOrderCancelRejected(LOrder* order) override {};
        void onOrderExec(TradeDirs side, double px, double qty, Liquidity liq, LOrder* order) override {};
        void onOrderCanceled(LOrder* order) override {};
        void onOrderClosed(LOrder* order) override {};
    
    protected:
        void sendIocOrder(TradeDirs side, double px, double qty);
    
    protected:
        TimerManager *_timerMgr;
        SymbolInfo* _si;
        bool _useMargin = false;
        string _marginSource = "spot";
        bool _hasTimeEvt = false;
    
        Variable* _signalVar;
        double _order_size;
    };
    

  • Source file: SignalTakeStrategy.cpp

    #include "SignalTakeStrategy.h"
    #include "components/VariableManager.h"
    #include "components/TradeApiManager.h"
    #include "components/SymbolManager.h"
    
    void SignalTakeStrategy::init() {
        auto symMgr = SymbolManager::instance();
        auto varMgr = VariableManager::instance();
    
        string symbol = _cfg.at("symbol");
        string exch = _cfg.at("trade_market");
        auto sh = symMgr->getSymbolHandler(symbol, exch);
        sh->addListener(this);
        _si = &sh->symbolInfo();
    
        _timerMgr = TimerManager::instance();
        TimerHandler* th = _timerMgr->getTimerHandler(60000);
        th->addListener(this);
    
        _order_size = _cfg.at("order_size");
    
        string signal = _cfg.at("signal");
        _signalVar = varMgr->getVariable(signal);
        addNotifiableChild(_signalVar); 
    }
    
    void SignalTakeStrategy::onNotify() {
        if(!_si->is_ready()) 
            return;
    
        if(!_signalVar->is_ready())
            return;
    
        if(_hasTimeEvt) {
            _hasTimeEvt = false;
    
            double midpx = _si->mid_px();
            double signal = _signalVar->value();
    
            if(signal > 0.01) {
                sendIocOrder(SELL, _si->bid_px, _order_size);
            } else if(signal < -0.01) {
                sendIocOrder(BUY, _si->ask_px, _order_size);
            }
        }
    }
    
    void SignalTakeStrategy::sendIocOrder(TradeDirs side, double px, double qty) {
        std::cout << "send IOC order: " << side << " " << px << " " << qty << std::endl;
    
        LOrder* ord = new LOrder();
        ord->sender = this;
        ord->account = 101;
        ord->use_margin = false;
        ord->margin_source = "spot";
        ord->side = side;
        ord->si = _si;
        ord->px = px;
        ord->qty = qty;
        ord->remainingQty = ord->qty;
        ord->signal = 0.0;
        ord->spread = _si->spread();
        ord->tif = Tif::TIF_IOC;
        ord->intention = OrderIntention::OI_AGGRESSIVE;
    
        TradeApi* tradeApi = TradeApiManager::instance()->tradeApi();
        tradeApi->sendOrder(ord);
    }
    
    void SignalTakeStrategy::onQuote(long cid, const SymbolInfo& si) {
    
    }
    
    void SignalTakeStrategy::onTick(long cid, const SymbolInfo& si) {
    
    }
    
    void SignalTakeStrategy::onTimer(TimerHandler* th, long msecs) {
        _hasTimeEvt = true;
    }
    

  • Register the component

    class MyComponentFactory : public XlibComponentFactory
    {
    public:
        Strategy *getStrategy(const string &type, const string &name, const json &attr) override
        {
            if (type == "SignalTakeStrategy") 
                return new SignalTakeStrategy(name, attr);            
            return nullptr;
        } 
    };
    

Inherit from CCModelStrategy

Algo SDK includes a few strategy classes that inherit from Strategy. The relations among these classes are:

classDiagram
    Strategy <|-- BaseStrategy
    BaseStrategy <|-- CCBaseStrategy
    CCBaseStrategy <|-- CCModelStrategy

We will inherit from CCModelStrategy in the example below:

  • Header file: CCTakerStrategy.h

    #pragma once
    #include "strategies/CCModelStrategy.h"
    
    class CCTakerStrategy: public CCModelStrategy {
    public:
        using CCModelStrategy::CCModelStrategy;
        void init() override;
    
    protected:
        void tradeOnSignal(double signal) override;
    
    protected:
        double _max_spread;
    };
    

  • Source file: CCTakerStrategy.cpp

    #include "CCTakerStrategy.h"
    
    void CCTakerStrategy::init() {
        CCModelStrategy::init();
    
        _max_spread = getJsonValue(_cfg, "max_spread_bps", 10000.0) * 0.0001;
    
        std::cout << "created CCTakerStrategy model:" << _model->name() << std::endl;
    }
    
    void CCTakerStrategy::tradeOnSignal(double signal){
        const nanoseconds& eventTime = _timerMgr->currentTime();
    
        double depPx = _depPm->price();
        double pos = _account->position(_si->cid);
        double bbo_from_mid = 0.5 * _si->spread() / _si->mid_px();
    
        double ret_from_mid = returnFromMid(signal, _depPm);
    
        TradeDirs side = (ret_from_mid > 0) ? BUY : SELL;
        bool expPos = willExpandPosition(side, pos);
        double thresh = expPos ? _take_r_thold : _low_take_r_thold;
    
        if(fabs(ret_from_mid) < thresh + bbo_from_mid)
            return;
    
        if(_si->spread() > _max_spread * _si->mid_px())
            return;
    
        TradeDirs oppoSide = oppositeSide(side);
        double notional = _account->notional(_si->cid);
        double oppoPx = _si->getOppositeBestPrice(side);
        double tgt_px = _si->mid_px() * (1.0 + ret_from_mid + ((side==BUY) ? -thresh : thresh));
    
        double sweep_px = oppoPx * (1.0 + ((side==BUY) ? _max_sweep : -_max_sweep));
        double desired_px = (side==BUY) ? min(sweep_px, tgt_px) : max(sweep_px, tgt_px);
    
        double px = roundPrice(desired_px, side);
        double ioc_size = _si->isUsdFutures() ? int(_ioc_notional / _si->contract_multiplier) : _ioc_notional / _si->contract_multiplier / px;
        double qty = expPos ? ioc_size : min(ioc_size, fabs(pos));
    
        LOrder* ord = sendIocOrder(side, px, qty, signal);
        if(ord) {
            if(_isLive)
                cout << toStr(TimerManager::instance()->currentTime())
                    << " cid:" << _si->cid
                    << " side:" << side << " px:" << px << " qty:" << qty
                    << " bid:" << _si->bid_px << " ask:" << _si->ask_px
                    << " tgt_px:" << tgt_px
                    << " signal: " << signal << " ret_from_mid: " << ret_from_mid << endl;
        }
    }
    

  • Register the component

    class MyComponentFactory : public XlibComponentFactory
    {
    public:
        Strategy *getStrategy(const string &type, const string &name, const json &attr) override
        {
            if (type == "CCTakerStrategy") 
                return new CCTakerStrategy(name, attr);            
            return nullptr;
        } 
    };
    

Low level API

You can use the low level API to access many functionalities in the system.

SymbolInfo and SymbolHandler

SymbolInfo contains symbol's static characteristics such as tick size, lot size, minimum order size, price precision, quantity precision, multiple for contracts and etc. It also provides symbol's latest information, such as mid price, bid/ask price, quantity and etc. SymbolHandler first initializes symbol's static information and keeps update symbol's real time information when onQuote/onTick/onTrade is triggered.

Below is the information you can access from SymbolInfo:

#pragma once
#include "common/common.h"
#include "base/Consts.h"
#include "base/IOrderBookManager.h"

class SymbolInfo {
public:
    bool is_ready() const { return _ready; }
    bool is_stale() const { return _stale; }
    double mid_px() const { return _mid_px; }
    double spread() const { return _spread; }
    double risk_px() const { return _risk_px; }
    //double open_vwap() const { return _open_vwap; }
    double open_mid_avg() const { return _open_mid_avg; }

    double mid_xbbo() const { return 0.5 * (bid_xbbo + ask_xbbo); }

    double ticks2Price(int ticks) const { return ticks * tick_size; }
    int getTicks(double px) const { return int((px + EPS) / tick_size); }
    double getXbboPrice(TradeDirs side) const { return (side == BUY) ? bid_xbbo : ask_xbbo; }
    double getTbboPrice(TradeDirs side) const { return (side == BUY) ? bid_tbbo : ask_tbbo; }
    double getBBOPrice(TradeDirs side) const { return (side == BUY) ? bid_px : ask_px; }
    double getBBOQty(TradeDirs side) const { return (side == BUY) ? bid_qty : ask_qty; }
    double getBestPrice(TradeDirs side) const { return (side == BUY) ? bid_px : ask_px; }
    double getOppositeBestPrice(TradeDirs side) const { return (side == SELL) ? bid_px : ask_px; }
    double improvedTicks(TradeDirs side, double tpx, double px) const {
        double ticks = (tpx - px) / tick_size;
        return (side==BUY) ? ticks : -ticks;
    }
    double getImprovedPrice(double improvedTicks, TradeDirs side) const {
        double improvedPx = improvedTicks * tick_size;
        return (side==BUY) ? bid_px + improvedPx: ask_px - improvedPx;
    }

    void setPrevClosePrice(double px) { _prevClosePx = px; }
    double prevClosePrice() { return _prevClosePx; }

    void setCalendarDaysSincePrevTradingDay(int days) { _calendarDaysSincePrevTradingDay = days; }
    int calendarDaysSincePrevTradingDay() { return _calendarDaysSincePrevTradingDay; }

    void setOrderBookManager(IOrderBookManager* orderBookMgr) { _orderBookMgr = orderBookMgr; }
    IOrderBookManager* getOrderBookManager() { return _orderBookMgr; }
    LevelAccessor& getBookLevelAccessor(TradeDirs side) { return _orderBookMgr->getLevelAccessor(side); }

    double calcBookQty(TradeDirs side, double deepestPrice, bool inclusive=true);

    double getLevelPrice(TradeDirs side, int level, bool isPrevBook=false) const;
    double getLevelQty(TradeDirs side, int level, bool isPrevBook=false) const;
    int getLevelOrds(TradeDirs side, int level, bool isPrevBook=false) const;
    double getQtyOnLevels(TradeDirs side, double deepestPrice, bool inclusive=true, bool isPrevBook=false) const;
    double getPrevQtyOnLevels(TradeDirs side, double deepestPrice, bool inclusive=true) const;

    string getProductName() const { return SymbolUtils::getProductName(ticker, exchange); }
    string getLocalSymbolName() const { return SymbolUtils::getLocalSymbolName(ticker, exchange); }
    const string& getExchangeFullName() const { return SymbolUtils::getExchangeFullName(exchange); }
    string converToTradeVenue() const {return SymbolUtils::converToTradeVenue(exchange); }
    string converToCVenue() const{ return SymbolUtils::converToCVenue(exchange);}
    string  converToTradeSymbol() const{ return SymbolUtils::converToTradeSymbol(ticker);}
    // string converToCVenue const {return SymbolUtils::converToCVenue(exchange);}


    void setConfig(json& cfg) { _cfg = cfg; }
    json& getConfig() { return _cfg; }

    bool isUsdFutures() const { return asset_class == AssetClass::CC_USD_FUTURES; }
    bool isUsdtFutures() const { return asset_class == AssetClass::FUTURES; }
    bool isCryptoSpot() const { return asset_class == AssetClass::CC; }
    double calcNotional(double qty) const { return qty * contract_multiplier * (isUsdFutures() ? 1.0 : _risk_px); }
    double calcNotional(double qty, double px) const  { return qty * contract_multiplier * (isUsdFutures() ? 1.0 : px); }
    double qtyFromNotional(double notional) const { return notional / contract_multiplier / (isUsdFutures() ? 1.0 : _risk_px); }
    double qtyFromNotional(double notional, double px) const  { return notional / contract_multiplier / (isUsdFutures() ? 1.0 : px); }

    bool validate_trade(double price, double qty) const;

    double getCoinBalance(AccounType type);
    double getBaseCoinBalance(AccounType type);
    double getLongContractPosition();
    double getShortContractPosition();
    double getNetContractPosition();


public:
    json _cfg;
    uint64_t cid = -1;
    string ticker;
    string exchange;
    string local_name;

    //options
    string underlying;
    string expiry;
    double strike;
    bool is_call;

    bool active = true;
    bool trade = false;
    double tick_size = 0.01;
    double lot_size = 1;
    double min_order_size = 1.0;
    double contract_multiplier = 1;
    int qty_precision = 0;
    int price_precision = 2;
    int lever = 1;
    AssetClass asset_class;

    double _prevClosePx = std::numeric_limits<double>::quiet_NaN();
    int _calendarDaysSincePrevTradingDay = 1;

    double trade_px = 0;
    double trade_qty = 0;
    int trade_type = 0;
    double volume = 0;
    double bid_px = 0;
    double ask_px = 0;
    double bid_qty = 0;
    double ask_qty = 0;
    int64_t bid_ords = 0;
    int64_t ask_ords = 0;
    nanoseconds quote_time = nanoseconds(0);
    nanoseconds trade_time = nanoseconds(0);

    double bid_tbbo = 0;
    double ask_tbbo = 0;

    double bid_xbbo = 0;
    double ask_xbbo = 0;
    double bid_xbbo_qty = 0;
    double ask_xbbo_qty = 0;

    //double _open_vwap = 0.0;
    double _open_mid_avg = 0.0;
    double _mid_px = 0.0;
    double _spread = 0.0;
    double _risk_px = 0.0;
    bool _hasRiskPrice = false;
    bool _stale = false;
    bool _ready = false;

    bool _useIBdata = false; //ib qty is in lot !!!

    IOrderBookManager* _orderBookMgr = nullptr;
};

Handle market data callbacks

Market data callbacks have three main categories, onTick, onQuote and onL2Change. onTick will be triggered when a trade occurs in the market. onQuote will be triggered once BBO level changes. onL2Change will be triggered as long as market depth changes.

You can handler these events using the below callbacks:

//imlements SymbolListener
void onQuote(long cid, const SymbolInfo& si) override;
void onTick(long cid, const SymbolInfo& si) override;
void onL2Change(long cid, const SymbolInfo& si) override;
void onQuoteStale(long cid, const SymbolInfo& si) override {}

Place and cancel orders

You can use tradeAPI to place or cancel order, below is the example function to send order:

LOrder* BaseStrategy::sendOrderImpl(TradeDirs side, double px, double qty, double signal, Tif tif, OrderIntention intention, bool checkRisk) {
    double addedRisk = _riskMultiple * _si->calcNotional(qty) * ((side==BUY) ? 1.0 : -1.0);
    double futureRisk = _risk + addedRisk;
    double absRisk = fabs(_risk);
    double absFutureRisk = fabs(futureRisk);
    if(checkRisk && (absFutureRisk  > _max_risk) && (absFutureRisk > absRisk)) {
        //SLOG << " orderBlocked(exceeding_risk) risk=" << _risk << " futureRisk=" << futureRisk << endl;
        return nullptr;
    }

    double pos = _account->position(_si->cid);
    double notional = _account->notional(_si->cid);
    bool expanding_pos = willExpandPosition(side);
    if(expanding_pos) {
        if(fabs(notional) > _max_notional) {
            //SLOG << " orderBlocked(exceeding_max_notional) pos=" << pos << " notional=" << notional << endl;
            return nullptr;
        }
        if((px < _min_px) || (px > _max_px)) {
            //SLOG << " orderBlocked(price out of range) px=" << px << endl;
            return nullptr;
        }
    }

    if(miscle(_si->spread(), 0)) {
        //SLOG << " orderBlocked(invalid spread) spread=" << _si->spread() << endl;
        return nullptr;
    }

    const nanoseconds& now = _timerMgr->currentTime();

    LOrder* ord = new LOrder();
    ord->sender = this;
    ord->account = _account->accountId();
    ord->use_margin = _use_margin;
    ord->margin_source = _margin_source;
    ord->side = side;
    ord->si = _si;
    ord->px = px;
    ord->qty = qty;
    ord->remainingQty = qty;
    ord->signal = signal;
    ord->spread = _si->spread();
    ord->tif = tif;
    ord->intention = intention;
    ord->noticeId = _notMgr->getNoticeId();
    ord->is_post_only = true;

    double bbopx = _si->getBBOPrice(side);
    if(priceBetterThan(px, bbopx, side))
        ord->estQtyAhead = 0;
    else if(misceq(px, bbopx))
        ord->estQtyAhead = _si->getBBOQty(side);
    else
        ord->estQtyAhead = 1e6;

    LOrder *order = _tradeApi->sendOrder(ord);
    if(side == BUY) _last_buy_order = now;
    else if(side == SELL) _last_sell_order = now;
    return order;
}

Process order update callbacks

onOrder* will be triggered once order state changes from exchange where * represent the corresponding state.

You can use the following order callbacks to manage your order lifecycle.

class MyStrategy : public OrderSender
{
public:
    using OrderSender::OrderSender;

    // implements OrderSender
    void onOrderCreated(LOrder *order) override
    {
        cout << "order created. local id = " << order->orderId << endl;
    };
    void onOrderAcked(LOrder *order) override
    {
        cout << "order ack. local id = " << order->orderId << ", id = " << order->remoteOrderId << endl;
    };
    void onOrderRejected(LOrder *order) override
    {
        cout << "order rejected. local id = " << order->orderId << endl;
    };
    void onOrderCancelCreated(LOrder *order) override
    {
        cout << "order cancel created. id = " << order->remoteOrderId << endl;
    };
    void onOrderCancelAcked(LOrder *order) override
    {
        cout << "order cancel ack. id = " << order->remoteOrderId << endl;
    };
    void onOrderCancelRejected(LOrder *order) override
    {
        cout << "order cancel rejected. id = " << order->remoteOrderId << endl;
    };
    void onOrderExec(TradeDirs side, double px, double qty, Liquidity liq, LOrder *order) override
    {
        cout << "order exec. id = " << order->remoteOrderId << (side == BUY ? " buy" : "sell") 
            << "order px: " << px << " size: " << qty << endl;
    };
    void onOrderCanceled(LOrder *order) override
    {
        cout << "order canceled. id = " << order->remoteOrderId << endl;
    };
    void onOrderClosed(LOrder *order) override
    {
        cout << "order closed. id = " << order->remoteOrderId << endl;
    };
};

Get Balance

To get the balance of a given trading pair, there are two methods.

Using BalanceManager

We first define the following:

BalanceManager* _balanceMgr;
BalanceItem* _coinBalanceItem = NULL;
BalanceItem* _baseBalanceItem = NULL;

We then fetch the coins in the trading pair from SymbolInfo, and generate the two BalanceItems, which have the balance property.

string coin = _si->coin;
string baseCoin = _si->base_coin;
string exchName = _si->exchange;
string accttype = "spot"; // Allowed values: "spot". "isolated", "cross"
string coinItemName = coin + "-" + exchName + "-" + accttype;
string baseItemName = baseCoin + "-" + exchName + "-" + accttype;
_balanceMgr = BalanceManager::instance();
_coinBalanceItem = _balanceMgr->getBalanceItem(coinItemName);
_baseBalanceItem = _balanceMgr->getBalanceItem(baseItemName);
Using SymbolInfo

SymbolInfo also has a function that you can call to fetch your balances of its associated trading pair.

double getCoinBalance(AccounType type);
double getBaseCoinBalance(AccounType type);

AccounType is an enum that can take on the values ACCOUNT_TYPE_SPOT, ACCOUNT_TYPE_CROSS, and ACCOUNT_TYPE_ISOLATED.

Get Contract Position

SymbolInfo has methods to get your contract position in its trading pair:

double getLongContractPosition();
double getShortContractPosition();
double getNetContractPosition();