Skip to content

Commit

Permalink
Separate match and account update messages
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenewald committed Oct 30, 2024
1 parent e8f16e2 commit ee48097
Show file tree
Hide file tree
Showing 33 changed files with 277 additions and 190 deletions.
42 changes: 15 additions & 27 deletions exchange/src/common/types/messages/messages_exchange_to_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,43 +7,33 @@
#include <glaze/core/common.hpp>
#include <glaze/core/meta.hpp>

#include <chrono>

namespace nutc::common {

struct start_time {
int64_t start_time_ns;
std::int64_t start_time_ns;

start_time() = default;

explicit start_time(int64_t stns) : start_time_ns(stns) {}
explicit start_time(std::chrono::high_resolution_clock::time_point stns) :
start_time_ns(stns.time_since_epoch().count())
{}
};

struct match {
common::position position;
std::string buyer_id;
std::string seller_id;
common::decimal_price buyer_capital;
common::decimal_price seller_capital;
std::string match_type{};

match() = default;

match(
const common::position& position, std::string bid, std::string sid,
common::decimal_price bcap, common::decimal_price scap
) :
position(position), buyer_id(std::move(bid)), seller_id(std::move(sid)),
buyer_capital(bcap), seller_capital(scap)
{}
struct account_update {
common::position trade;
common::decimal_price available_capital;
};

struct tick_update {
std::vector<common::position> ob_updates;
std::vector<match> matches;
std::vector<common::position> matches;

tick_update() = default;

explicit tick_update(
std::vector<common::position> ob_updates, std::vector<match> matches
std::vector<common::position> ob_updates, std::vector<common::position> matches
) : ob_updates(std::move(ob_updates)), matches(std::move(matches))
{}
};
Expand All @@ -67,12 +57,10 @@ struct glz::meta<nutc::common::tick_update> {
};

template <>
struct glz::meta<nutc::common::match> {
using t = nutc::common::match;
static constexpr auto value = object(
"match", &t::position, &t::buyer_id, &t::seller_id, &t::buyer_capital,
&t::seller_capital
);
struct glz::meta<nutc::common::account_update> {
using t = nutc::common::account_update;
static constexpr auto value =
object("account_update", &t::trade, &t::available_capital);
};

template <>
Expand Down
3 changes: 2 additions & 1 deletion exchange/src/exchange/algos/dev_mode/dev_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ DevModeAlgoInitializer::initialize_trader_container(
traders.add_trader<AlgoTrader>(algo, start_capital);
}

int64_t start_time = get_start_time(WAIT_SECS);
auto start_time = get_start_time(WAIT_SECS);
std::for_each(traders.begin(), traders.end(), [start_time](auto& trader) {
send_start_time(trader, start_time);
});
std::this_thread::sleep_until(start_time);
}

void
Expand Down
3 changes: 2 additions & 1 deletion exchange/src/exchange/algos/normal_mode/normal_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ NormalModeAlgoInitializer::initialize_trader_container(
}
}

int64_t start_time = get_start_time(WAIT_SECS);
auto start_time = get_start_time(WAIT_SECS);
std::for_each(traders.begin(), traders.end(), [start_time](auto& trader) {
send_start_time(trader, start_time);
});
std::this_thread::sleep_until(start_time);
}

glz::json_t::object_t
Expand Down
17 changes: 8 additions & 9 deletions exchange/src/exchange/matching/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
namespace nutc::exchange {

enum class MatchFailure { buyer_failure, seller_failure, done_matching };
using match = nutc::common::match;

template <common::Side AggressiveSide, typename OrderPairT>
glz::expected<match, bool>
glz::expected<tagged_match, bool>
match_orders_(
OrderPairT& orders, CompositeOrderBook& orderbook, common::decimal_price order_fee
)
Expand All @@ -38,7 +37,7 @@ match_orders_(
}

template <common::Side AggressiveSide, TaggedOrder OrderT>
glz::expected<match, bool>
glz::expected<tagged_match, bool>
match_incoming_order_(
OrderT& aggressive_order, LimitOrderBook::stored_limit_order passive_order,
CompositeOrderBook& orderbook, common::decimal_price order_fee
Expand Down Expand Up @@ -73,7 +72,7 @@ total_order_cost_(
}

template <common::Side AggressiveSide, typename OrderPairT>
glz::expected<match, MatchFailure>
glz::expected<tagged_match, MatchFailure>
attempt_match_(OrderPairT& orders, common::decimal_price order_fee)
{
auto price_opt = orders.potential_match_price();
Expand Down Expand Up @@ -106,7 +105,7 @@ attempt_match_(OrderPairT& orders, common::decimal_price order_fee)
}

template <TaggedOrder OrderT>
glz::expected<match, bool>
glz::expected<tagged_match, bool>
match_incoming_order_(
OrderT& aggressive_order, CompositeOrderBook& orderbook,
common::decimal_price order_fee
Expand All @@ -130,12 +129,12 @@ match_incoming_order_(
}

template <TaggedOrder OrderT>
std::vector<match>
std::vector<tagged_match>
match_order(
OrderT order, CompositeOrderBook& orderbook, common::decimal_price order_fee
)
{
std::vector<match> matches;
std::vector<tagged_match> matches;

while (order.quantity != 0.0) {
auto match_opt = match_incoming_order_(order, orderbook, order_fee);
Expand All @@ -154,9 +153,9 @@ match_order(
return matches;
}

template std::vector<match>
template std::vector<tagged_match>
match_order<>(tagged_limit_order, CompositeOrderBook&, common::decimal_price);

template std::vector<match>
template std::vector<tagged_match>
match_order<>(tagged_market_order, CompositeOrderBook&, common::decimal_price);
} // namespace nutc::exchange
3 changes: 1 addition & 2 deletions exchange/src/exchange/matching/engine.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma once

#include "common/types/messages/messages_exchange_to_wrapper.hpp"
#include "exchange/orders/orderbook/composite_orderbook.hpp"

#include <glaze/util/expected.hpp>
Expand All @@ -10,7 +9,7 @@
namespace nutc::exchange {

template <TaggedOrder OrderT>
std::vector<common::match> match_order(
std::vector<tagged_match> match_order(
OrderT order, CompositeOrderBook& orderbook, common::decimal_price order_fee = 0.0
);

Expand Down
29 changes: 9 additions & 20 deletions exchange/src/exchange/matching/order_pair.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,24 +101,13 @@ class OrderPair {
}

template <common::Side AggressiveSide>
common::match
tagged_match
create_match(common::decimal_quantity quantity, common::decimal_price price) const
{
auto& buyer = get_underlying_order<side::buy>();
auto& seller = get_underlying_order<side::sell>();
common::position position{buyer.ticker, AggressiveSide, quantity, price};
// TODO: match_type is pretty bad, we should have a better way of tracking this.
// It's only used for metrics
std::string match_type =
fmt::format("{}->{}", seller.trader->get_type(), buyer.trader->get_type());
// TODO: can just use TraderPortfolio instead of entire trader
common::match match{
position, buyer.trader->get_id(), seller.trader->get_id(),
buyer.trader->get_portfolio().get_capital(),
seller.trader->get_portfolio().get_capital()
};
match.match_type = match_type;
return match;
return {buyer.trader, seller.trader, position};
}

common::decimal_quantity
Expand All @@ -131,21 +120,21 @@ class OrderPair {

void
handle_match(
const common::match& match, common::decimal_price order_fee,
const tagged_match& match, common::decimal_price order_fee,
CompositeOrderBook& orderbook
)
{
get_underlying_order<side::buy>().trader->get_portfolio().notify_match(
{match.position.ticker, common::Side::buy, match.position.quantity,
match.position.price * (common::decimal_price{1.0} + order_fee)}
{match.ticker, common::Side::buy, match.quantity,
match.price * (common::decimal_price{1.0} + order_fee)}
);
get_underlying_order<side::sell>().trader->get_portfolio().notify_match(
{match.position.ticker, common::Side::sell, match.position.quantity,
match.position.price * (common::decimal_price{1.0} - order_fee)}
{match.ticker, common::Side::sell, match.quantity,
match.price * (common::decimal_price{1.0} - order_fee)}
);

change_order_quantity(seller, -match.position.quantity, orderbook);
change_order_quantity(buyer, -match.position.quantity, orderbook);
change_order_quantity(seller, -match.quantity, orderbook);
change_order_quantity(buyer, -match.quantity, orderbook);
}

private:
Expand Down
64 changes: 57 additions & 7 deletions exchange/src/exchange/matching_cycle/base/base_cycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@ BaseMatchingCycle::collect_orders(uint64_t) -> std::vector<OrderVariant>
return orders;
}

std::vector<common::match>
std::vector<tagged_match>
BaseMatchingCycle::match_orders_(std::vector<OrderVariant> orders)
{
std::vector<common::match> matches;
std::vector<tagged_match> matches;

auto match_incoming_order = [&]<typename OrderT>(OrderT& order) {
auto& ticker_data = tickers_[order.ticker];
Expand Down Expand Up @@ -83,20 +83,63 @@ BaseMatchingCycle::match_orders_(std::vector<OrderVariant> orders)
return matches;
}

void
BaseMatchingCycle::handle_matches_(std::vector<common::match> matches)
std::vector<common::position>
BaseMatchingCycle::get_orderbook_updates_()
{
std::vector<common::position> ob_updates{};
std::vector<common::position> ob_updates;

for (auto [symbol, info] : tickers_) {
auto tmp = info.get_orderbook().get_and_reset_updates();
std::ranges::copy(tmp, std::back_inserter(ob_updates));
}
return ob_updates;
}

std::vector<common::position>
BaseMatchingCycle::tagged_matches_to_positions(const std::vector<tagged_match>& matches)
{
std::vector<common::position> untagged_matches(matches.size());
std::transform(
matches.begin(), matches.end(), untagged_matches.begin(),
[](const tagged_match& match) { return match; }
);
return untagged_matches;
}

if (ob_updates.empty() && matches.empty())
void
BaseMatchingCycle::send_account_updates(const std::vector<tagged_match>& matches)
{
std::for_each(matches.begin(), matches.end(), [](const tagged_match& match) {
common::position trade{match.ticker, match.side, match.quantity, match.price};
common::account_update buyer_update{
trade, match.buyer->get_portfolio().get_capital()
};
common::account_update seller_update{
trade, match.seller->get_portfolio().get_capital()
};
auto buyer_update_str = glz::write_json(buyer_update);
if (!buyer_update_str.has_value()) [[unlikely]] {
throw std::runtime_error(glz::format_error(buyer_update_str.error()));
}
auto seller_update_str = glz::write_json(seller_update);
if (!seller_update_str.has_value()) [[unlikely]] {
throw std::runtime_error(glz::format_error(seller_update_str.error()));
}
match.buyer->send_message(buyer_update_str.value());
match.seller->send_message(seller_update_str.value());
});
}

void
BaseMatchingCycle::send_market_updates_(const std::vector<tagged_match>& matches)
{
std::vector<common::position> orderbook_updates = get_orderbook_updates_();
std::vector<common::position> trade_updates = tagged_matches_to_positions(matches);

if (orderbook_updates.empty() && trade_updates.empty()) [[unlikely]]
return;

common::tick_update updates{ob_updates, matches};
common::tick_update updates{orderbook_updates, trade_updates};
auto update = glz::write_json(updates);
if (!update.has_value()) [[unlikely]] {
throw std::runtime_error(glz::format_error(update.error()));
Expand All @@ -108,4 +151,11 @@ BaseMatchingCycle::handle_matches_(std::vector<common::match> matches)
);
}

void
BaseMatchingCycle::handle_matches_(std::vector<tagged_match> matches)
{
send_market_updates_(matches);
send_account_updates(matches);
}

} // namespace nutc::exchange
13 changes: 11 additions & 2 deletions exchange/src/exchange/matching_cycle/base/base_cycle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,22 @@ class BaseMatchingCycle : public MatchingCycleInterface {

std::vector<OrderVariant> collect_orders(uint64_t) override;

std::vector<common::match> match_orders_(std::vector<OrderVariant> orders) override;
std::vector<tagged_match> match_orders_(std::vector<OrderVariant> orders) override;

void handle_matches_(std::vector<common::match> matches) override;
void handle_matches_(std::vector<tagged_match> matches) override;

void
post_cycle_(uint64_t) override
{}

private:
std::vector<common::position> get_orderbook_updates_();

static std::vector<common::position>
tagged_matches_to_positions(const std::vector<tagged_match>& matches);

static void send_account_updates(const std::vector<tagged_match>& matches);
void send_market_updates_(const std::vector<tagged_match>& matches);
};

} // namespace nutc::exchange
4 changes: 2 additions & 2 deletions exchange/src/exchange/matching_cycle/cycle_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ class MatchingCycleInterface {

virtual std::vector<OrderVariant> collect_orders(uint64_t new_tick) = 0;

virtual std::vector<common::match> match_orders_(std::vector<OrderVariant> orders
virtual std::vector<tagged_match> match_orders_(std::vector<OrderVariant> orders
) = 0;

virtual void handle_matches_(std::vector<common::match> matches) = 0;
virtual void handle_matches_(std::vector<tagged_match> matches) = 0;

virtual void post_cycle_(uint64_t new_tick) = 0;

Expand Down
4 changes: 2 additions & 2 deletions exchange/src/exchange/matching_cycle/dev/dev_cycle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class DevMatchingCycle : public BaseMatchingCycle {
{}

protected:
std::vector<common::match>
std::vector<tagged_match>
match_orders_(std::vector<OrderVariant> orders) override
{
// TODO: add back
Expand All @@ -31,7 +31,7 @@ class DevMatchingCycle : public BaseMatchingCycle {
}

void
handle_matches_(std::vector<common::match> matches) override
handle_matches_(std::vector<tagged_match> matches) override
{
pusher.report_matches(matches);
BaseMatchingCycle::handle_matches_(std::move(matches));
Expand Down
Loading

0 comments on commit ee48097

Please sign in to comment.