0% found this document useful (0 votes)
9 views8 pages

Order Management System Algorithm Overview

The document describes the MarketMaker algorithm that sends orders to an Order Management System (OMS) and how it interacts with a TradeEngine to manage order updates and position calculations. It details the process of updating positions, calculating average prices (VWAP), and determining realized and unrealized profit/loss (PnL) for trades executed. An example illustrates the step-by-step calculations involved in managing trades and positions in a trading system.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views8 pages

Order Management System Algorithm Overview

The document describes the MarketMaker algorithm that sends orders to an Order Management System (OMS) and how it interacts with a TradeEngine to manage order updates and position calculations. It details the process of updating positions, calculating average prices (VWAP), and determining realized and unrealized profit/loss (PnL) for trades executed. An example illustrates the step-by-step calculations involved in managing trades and positions in a trading system.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

OMS

MarketMaker is an algo which is sending orders to OMS.

class MarketMaker {
public:
MarketMaker(Common::Logger *logger, TradeEngine *trade_engine, const
FeatureEngine *feature_engine,
OrderManager *order_manager,
const TradeEngineCfgHashMap &ticker_cfg);

auto onOrderBookUpdate(TickerId ticker_id, Price price, Side side, const M


arketOrderBook *book) noexcept -> void {
logger_->log("%:% %() % ticker:% price:% side:%\n", __FILE__, __LINE__, _
_FUNCTION__,
Common::getCurrentTimeStr(&time_str_), ticker_id, Common::price
ToString(price).c_str(),
Common::sideToString(side).c_str());

const auto bbo = book->getBBO();


const auto fair_price = feature_engine_->getMktPrice();

if (LIKELY(bbo->bid_price_ != Price_INVALID && bbo->ask_price_ != Price_I


NVALID && fair_price != Feature_INVALID)) {
logger_->log("%:% %() % % fair-price:%\n", __FILE__, __LINE__, __FUNC
TION__,
Common::getCurrentTimeStr(&time_str_),
bbo->toString().c_str(), fair_price);

const auto clip = ticker_cfg_.at(ticker_id).clip_;


const auto threshold = ticker_cfg_.at(ticker_id).threshold_;

OMS 1
const auto bid_price = bbo->bid_price_ - (fair_price - bbo->bid_price_ >=
threshold ? 0 : 1);
const auto ask_price = bbo->ask_price_ + (bbo->ask_price_ - fair_price >
= threshold ? 0 : 1);

order_manager_->moveOrders(ticker_id, bid_price, ask_price, clip); // ord


er sent to OMS
}
}

OMS sends the order to TradeEngine, when TradeEngine receives Fills it sends it
to the algorithm also to positon kepper

auto TradeEngine::onOrderUpdate(const Exchange::MEClientResponse *clie


nt_response) noexcept -> void {
logger_.log("%:% %() % %\n", __FILE__, __LINE__, __FUNCTION__, Commo
n::getCurrentTimeStr(&time_str_),
client_response->toString().c_str());

if (UNLIKELY(client_response->type_ == Exchange::ClientResponseType::FI
LLED))
position_keeper_.addFill(client_response);

algoOnOrderUpdate_(client_response);
}

Schema of clinet_response →

struct MEClientResponse {
ClientResponseType type_ = ClientResponseType::INVALID;

OMS 2
ClientId client_id_ = ClientId_INVALID;
TickerId ticker_id_ = TickerId_INVALID;
OrderId client_order_id_ = OrderId_INVALID;
OrderId market_order_id_ = OrderId_INVALID;
Side side_ = Side::INVALID;
Price price_ = Price_INVALID;
Qty exec_qty_ = Qty_INVALID;
Qty leaves_qty_ = Qty_INVALID;
};

addFill method in position keeper calulated pnl for every ticker id.

auto addFill(const Exchange::MEClientResponse *client_response, Logger *


logger) noexcept {
const auto old_position = position_;
const auto side_index = sideToIndex(client_response->side_);
const auto opp_side_index = sideToIndex(client_response->side_ == Side::
BUY ? Side::SELL : Side::BUY);
const auto side_value = sideToValue(client_response->side_);
position_ += client_response->exec_qty_ * side_value;
volume_ += client_response->exec_qty_;

if (old_position * sideToValue(client_response->side_) >= 0) { // opened / i


ncreased position.
open_vwap_[side_index] += (client_response->price_ * client_response->
exec_qty_);
} else { // decreased position.
const auto opp_side_vwap = open_vwap_[opp_side_index] / std::abs(old_
position);
open_vwap_[opp_side_index] = opp_side_vwap * std::abs(position_);
real_pnl_ += std::min(static_cast<int32_t>(client_response->exec_qty_), st
d::abs(old_position)) *

OMS 3
(opp_side_vwap - client_response->price_) * sideToValue(client_r
esponse->side_);
if (position_ * old_position < 0) { // flipped position to opposite sign.
open_vwap_[side_index] = (client_response->price_ * std::abs(position
_));
open_vwap_[opp_side_index] = 0;
}
}

if (!position_) { // flat
open_vwap_[sideToIndex(Side::BUY)] = open_vwap_[sideToIndex(Side::S
ELL)] = 0;
unreal_pnl_ = 0;
} else {
if (position_ > 0)
unreal_pnl_ =
(client_response->price_ - open_vwap_[sideToIndex(Side::BUY)] / st
d::abs(position_)) *
std::abs(position_);
else
unreal_pnl_ =
(open_vwap_[sideToIndex(Side::SELL)] / std::abs(position_) - client_re
sponse->price_) *
std::abs(position_);
}

total_pnl_ = unreal_pnl_ + real_pnl_;

std::string time_str;
logger->log("%:% %() % % %\n", __FILE__, __LINE__, __FUNCTION__, Com
mon::getCurrentTimeStr(&time_str),
toString(), client_response->toString().c_str());
}

OMS 4
The example for calculation is as follows -

🧠 Basic Idea
Every time your order executes (buy or sell), your system must:

1. Update your position (how many units you own — positive for buy, negative
for sell).

2. Update VWAP (average price at which your position was built).

3. Update PnL:

Realized PnL → profit/loss made on trades that are closed (you bought
and then sold, or vice versa).

Unrealized PnL → profit/loss on open positions (you haven’t closed them


yet).

📊 Step-by-Step Example
We’ll follow the same example the book uses.

1️⃣ You buy 10 units @ 100.0


Old position: 0 → New position: +10 (long)

You just opened a new long position.

Item Value

open_vwap (BUY) 10 × 100 = 1000

VWAP (BUY) 1000 / 10 = 100.0

Realized PnL 0 (nothing sold yet)

Unrealized PnL 0 (since no price change yet)

✅ You now own 10 units, bought at an average price of 100.

OMS 5
2️⃣ You buy 10 more @ 90.0
Old position: +10 → New position: +20

You added to your long position.

Item Value

open_vwap (BUY) 1000 + (10 × 90) = 1900

VWAP (BUY) 1900 / 20 = 95.0

Realized PnL 0 (nothing sold yet)

Unrealized PnL (90 - 95) × 20 = -100

📉 You now own 20 units with an average buy price of 95.


Since the last trade happened at 90 (below 95), you have an unrealized loss of
100.

3️⃣ You sell 10 @ 92.0


Old position: +20 → New position: +10

You partially closed your long position.

Item Value

Realized PnL (92 - 95) × 10 = -30

Unrealized PnL (92 - 95) × 10 = -30

open_vwap (BUY) stays 1900

VWAP (BUY) 1900 / 20 = 95.0

💡 You sold 10 units that you bought at 95, making a small realized loss of 30.
You still hold 10 units, worth slightly less (unrealized -30).

4️⃣ You sell 20 @ 97.0


Old position: +10 → New position: -10

You completely sold out your long and went short (you sold more than you
owned).

OMS 6
Item Value

Realized PnL (97 - 95) × 10 = +20 → previous (-30) + 20 = -10

open_vwap (SELL) 97 × 10 = 970

VWAP (SELL) 970 / 10 = 97.0

Unrealized PnL 0

📈 You closed your long (realizing -10 total PnL so far)


and opened a short position of 10 units at 97.

5️⃣ You sell 20 more @ 94.0


Old position: -10 → New position: -30

You increased your short position.

Item Value

open_vwap (SELL) 970 + (20 × 94) = 2850

VWAP (SELL) 2850 / 30 = 95.0

Realized PnL unchanged = -10

Unrealized PnL (95 - 94) × 30 = +30

📉 You’re now short 30 units at avg. 95.


Since price (94) < 95, your short is in profit (+30 unrealized).

6️⃣ You sell 10 more @ 90.0


Old position: -30 → New position: -40

You’re increasing your short again.

Item Value

open_vwap (SELL) 2850 + (10 × 90) = 3750

VWAP (SELL) 3750 / 40 = 93.75

Realized PnL still -10

Unrealized PnL (93.75 - 90) × 40 = +150

OMS 7
💡 You’re short 40 units at avg. 93.75.
Price is 90 → you could buy back lower → unrealized profit +150.

7️⃣ You buy 40 @ 88.0


Old position: -40 → New position: 0

You close your short completely.

Item Value

Realized PnL (93.75 - 88) × 40 = +230 → (-10 + 230) = +220 total

Unrealized PnL 0

open_vwap reset to 0

✅ You’re now flat (no position) with total realized profit = +220.
⚙️ In Code Terms ( PositionInfo::addFill() )
Here’s what the method is doing:

Step Code Logic Meaning

1 Save old_position Remember position before update

Compute side_index / Which side is this execution (BUY or


2
opp_side_index SELL)?

3 Update position_ Add or subtract executed quantity

4 Update open_vwap_ Add (price × qty) if position increased

If position decreased → update Compute realized profit/loss on


5
real_pnl_ closed quantity

If position flipped → reset Starting new position in opposite


6
open_vwap_ direction

Based on VWAP and latest execution


7 Compute unreal_pnl_
price

8 Compute total_pnl_ Sum of realized + unrealized

OMS 8

You might also like