TT CORE SDK

Position Reserve (PR) Orders

Position Reserve (PR) Orders

When an order is placed via TT Core SDK, it is routed to the TT risk system. If it passes the necessary risk checks, it is then routed to a TT component called the Order Connector which then routes it to the exchange. If it does not pass the necessary risk checks, it is rejected. Use of Position Reserve (PR) orders allows position risk to be reserved ahead of time so that the TT risk system can be skipped when orders are placed. This can result in a significant latency reduction in terms of routing new/change/cancel order messages.

To reserve position risk, you must specify:

  • Instrument
  • Account
  • Side
  • Total Quantity
  • Maximum Clip Size

It is intended for Position Reserve orders to be submitted when your application initializes or at least before any latency sensitive aspect of your application executes. Once successfully submitted, any subsequent orders for the same instrument and account will undergo a quick local risk check to confirm that they do not exceed the limits specified in the Position Reserve order. The behavior of this risk check varies depending upon whether you submit only a buy PR order, only a sell PR order, or both buy and sell PR orders for a given instrument / account.

Specifically:

  • Buy side only -> for buy orders, SDK sums worst-case-position of all buys (fills + working quantity) and checks against this limit. Sell orders are risk checked by the standard TT risk system.
  • Sell side only -> for sell orders, SDK sums worst-case-position of all sells (fills + working quantity) and checks against this limit. Buy orders are risk checked by the standard TT risk system.
  • Both -> SDK sums worst-case-position of all buys and sells (fills + working quantity) and checks all buy/sell orders against this limit.

Position Reserve orders are persistent in the TT system. As such, it is important that PR orders be deleted (released) as part of stopping your application.

The following code snippet demonstrates one way of using and managing Position Reserve orders when NOT running as an Application Server. If you are running as an Application Server, see the Initializing a Server Application section for further details.



std::condition_variable releaseReady;
std::condition_variable reserveReady;

class PositionReserveManager {

    public:

    PositionReserveManager()
    {
    }

    virtual ~PositionReserveManager()
    {
        ReleaseAllRisk();
    }

    void ReleaseAllRisk()
    {  
        for (auto itr = positionReserves_.cbegin(); itr != positionReserves_.cend();)
        {
            if (!ttsdk::ReleaseRisk(std::get<0>(*iter), std::get<1>(*iter), std::get<2>(*iter))
                std::cout << " Failed to release risk for instrumentId : " << std::get<0>(*iter).GetInstrumentId() << " accountId : "  << std::get<1>(*iter) << " side :  " << ttsdk::ToString(std::get<2>(*iter)) << std::endl;

            // wait for the risk released event
            std::unique_lock release_lock(releaseMutex);
            {
                if (releaseReady.wait_for(release_lock, std::chrono::seconds(300)) == std::cv_status::timeout)
                    std::cout << "Timeout waiting for the risk released event!" << std::endl;
                else
                    positionReserves_.erase(itr++);
            }
        }
    }

    bool ReserveRisk(ttsdk::InstrumentPtr instrument, const uint64_t accountId, ttsdk::RiskSide side, const double quantity, const double maxClipSize)
    {
        if (!ttsdk::ReserveRisk(instrument, accountId, side, quantity, maxClipSize))
        {
            std::cout << " Failed to reserve risk for instrumentId : " << instrument->GetAlias() << " accountId : " << accountId << " side :  " << ttsdk::ToString(side) << std::endl;
            return false;
        }

        // wait for the risk reserved event
        std::unique_lock reserve_lock(reserveMutex);
        {
            if (reserveReady.wait_for(reserve_lock, std::chrono::seconds(300)) == std::cv_status::timeout)
            {
                std::cout << "Timeout waiting for the risk reserved event!" << std::endl;
                return false;
            }

            positionReserves_.insert(std::make_tuple(instrument, accountId, side));
        }

        return true;
    }

    bool ReleaseRisk(ttsdk::InstrumentPtr instrument, const uint64_t accountId, ttsdk::RiskSide side)
    {
        if (!ttsdk::ReleaseRisk(instrument, accountId, side))

        {
            std::cout << " Failed to release risk for instrumentId : " << instrument << " accountId : " << accountId << " side :  " << ttsdk::ToString(side) << std::endl;
            return false;
        }

        // wait for the risk released event
        std::unique_lock release_lock(releaseMutex);
        {
            if (releaseReady.wait_for(release_lock, std::chrono::seconds(300)) == std::cv_status::timeout)
            {
                std::cout << "Timeout waiting for the risk released event!" << std::endl;
                return false;
            }

            positionReserves_.erase(std::make_tuple(instrument, accountId, side));
        }

        return true;
    }

    mutable std::mutex reserveMutex;
    mutable std::mutex releaseMutex;

    std::set> positionReserves_;
};


class MyOrderBookHandler : public ttsdk::IOrderBookEventHandler
{
    //
    //  ...
    //

    // Fired in response to a Position Reserve order being created

    virtual void OnRiskReserved(const uint64_t instrumentId, const uint64_t accountId, const ttsdk::RiskSide side, const bool successful)
    {
        if (!successful)
        {
            std::cout << " Failed to reserve risk for instrumentId : " << instrumentId << " accountId : " << accountId << " side :  " << ttsdk::ToString(side) << std::endl;
        }
        else
        {
            std::cout << " Reserved risk for instrumentId : " << instrumentId << " accountId : " << accountId << " side :  " << ttsdk::ToString(side) << std::endl;
            reserveReady.notify_one();
        }
    };

    // Fired in response to a Position Reserve order being released

    virtual void OnRiskReleased(const uint64_t instrumentId, const uint64_t accountId, const ttsdk::RiskSide side, const bool successful)
    {
        if (!successful)
        {
            std::cout << " Failed to release risk for instrumentId : " << instrumentId << " accountId : " << accountId << " side :  " << ttsdk::ToString(side) << std::endl;
        }
        else
        {
            std::cout << " Released risk for instrumentId : " << instrumentId << " accountId : " << accountId << " side :  " << ttsdk::ToString(side) << std::endl;
            releaseReady.notify_one();
        }
    };

    // Fired when an order submission fails

    virtual void OnSendFailed(ttsdk::OrderPtr order, const ttsdk::OrderProfile& profile, const ttsdk::IOrderEventHandler::SendCode code) override
    {
        if (code == ttsdk::IOrderBookEventHandler::SendCode::EXCEEDED_PREALLOCATED_RISK || code == ttsdk::IOrderBookEventHandler::SendCode::EXCEEDED_PREALLOCATED_RISK_CLIP_SIZE)
        {
            //Risk Rejection processing should be done here. 
            std::cout << "Order send failed due to risk rejection, RequestId=" << profile.request_id << " TTOrderId=" << order->GetOrderId() << std::endl;
        }
        else
        {
            std::cout << "Order send failed. RequestId=" << profile.request_id << " TTOrderId=" << order->GetOrderId() << " SendCode=" << (int)code << std::endl;
        }
    }

    //
    //  ...
    //
};


PositionReserveManager posResMgr;

void foo()
{
    ttsdk::Instrument::ResponseCode respCode;
    ttsdk::MarketId market = ttsdk::MarketId::CME;
    std::string product = “GE”;
    ttsdk::ProductType productType = ttsdk::ProductType::Future;
    std::string alias = "GE Sep28";

    ttsdk::InstrumentPtr instrument = ttsdk::GetInstrument(market, product.c_str(),
        productType, alias.c_str(), respCode);
    if (!instrument)
    {
    std::cout << "Unable to find instrument with alias = “ << alias << std::endl;
    }
    
    if(!posMgr.ReserveRisk(instrument, 12345, ttsdk::RiskSide::Buy, 100.0, 5.0))
    {
    std::cout << "Reserving risk failed!" << std::endl;
    }
}



The SDK also stores a collection of handles to PR orders. Access to specific PR orders can be obtained via the GetRiskBucket() function.


        
// Returns the current Position Reserve bucket for the given instrument and account
PositionReserveBucket GetRiskBucket(InstrumentPtr instrument, const uint64_t accountId) noexcept;