kraken: engine: add trading on cross behaviour

It is limited, and mostly untested, I would need more explicit semantics
for the border cases to make it more robust.
This commit is contained in:
Bruno BELANYI 2022-03-12 13:48:54 +01:00
parent 68a7e55238
commit ce9457fabd
2 changed files with 63 additions and 7 deletions

View file

@ -87,8 +87,9 @@ private:
TopInfo top_info_{}; TopInfo top_info_{};
}; };
Engine::Engine(std::shared_ptr<EngineListener> listener) Engine::Engine(std::shared_ptr<EngineListener> listener,
: listener_(listener) {} CrossBehaviour cross_behaviour)
: listener_(listener), cross_behaviour_(cross_behaviour) {}
void Engine::process_orders(std::vector<Order> const& orders) { void Engine::process_orders(std::vector<Order> const& orders) {
for (auto const& order : orders) { for (auto const& order : orders) {
@ -109,8 +110,31 @@ void Engine::operator()(TradeOrder const& trade_order) {
auto& [_, bid_map] = *bid_map_it; auto& [_, bid_map] = *bid_map_it;
if (bid_map.size() > 0 if (bid_map.size() > 0
&& bid_map.begin()->first >= trade_order.price) { && bid_map.begin()->first >= trade_order.price) {
// FIXME: handle matching if enabled if (cross_behaviour_ == CrossBehaviour::REJECT) {
listener_->on_rejection(trade_order.user, trade_order.id); listener_->on_rejection(trade_order.user, trade_order.id);
} else {
// FIXME: assumes a single trade for the order
// FIXME: assumes no remaining orders on both sides
auto matching = bid_map.begin();
auto const& bid_order = matching->second;
auto const matching_quantity
= std::min(bid_order.quantity, trade_order.quantity);
// NOTE: Pick the asking price for matching
auto const matching_price = trade_order.price;
listener_->on_acknowledgement(trade_order.user,
trade_order.id);
listener_->on_match(bid_order.user, bid_order.id,
trade_order.user, trade_order.id,
matching_price, matching_quantity);
assert(matching_quantity == bid_order.quantity
&& "multiple matches not implemented");
assert(matching_quantity == trade_order.quantity
&& "multiple matches not implemented");
bid_map.erase(matching);
}
return; return;
} }
} }
@ -124,8 +148,30 @@ void Engine::operator()(TradeOrder const& trade_order) {
auto& [_, ask_map] = *ask_map_it; auto& [_, ask_map] = *ask_map_it;
if (ask_map.size() > 0 if (ask_map.size() > 0
&& ask_map.begin()->first <= trade_order.price) { && ask_map.begin()->first <= trade_order.price) {
// FIXME: handle matching if enabled if (cross_behaviour_ == CrossBehaviour::REJECT) {
listener_->on_rejection(trade_order.user, trade_order.id); listener_->on_rejection(trade_order.user, trade_order.id);
} else {
// FIXME: assumes a single trade for the order
// FIXME: assumes no remaining orders on both sides
auto matching = ask_map.begin();
// NOTE: Pick the asking price for matching
auto const& [matching_price, ask_order] = *matching;
auto const matching_quantity
= std::min(ask_order.quantity, trade_order.quantity);
listener_->on_acknowledgement(trade_order.user,
trade_order.id);
listener_->on_match(trade_order.user, trade_order.id,
ask_order.user, ask_order.id,
matching_price, matching_quantity);
assert(matching_quantity == ask_order.quantity
&& "multiple matches not implemented");
assert(matching_quantity == trade_order.quantity
&& "multiple matches not implemented");
ask_map.erase(matching);
}
return; return;
} }
} }

View file

@ -9,12 +9,21 @@
namespace kraken::engine { namespace kraken::engine {
/// Which behaviour on cross orders.
enum class CrossBehaviour {
/// Reject the crossing order.
REJECT,
/// Make the trade with the matching order(s).
MATCH,
};
struct CallbackOnTopOfBookChange; struct CallbackOnTopOfBookChange;
struct EngineListener; struct EngineListener;
/// Matching engine which processes orders and keeps the book up-to-date. /// Matching engine which processes orders and keeps the book up-to-date.
struct Engine { struct Engine {
Engine(std::shared_ptr<EngineListener> listener); Engine(std::shared_ptr<EngineListener> listener,
CrossBehaviour cross_behaviour = CrossBehaviour::REJECT);
/// Process orders, triggerring the listener on each event. /// Process orders, triggerring the listener on each event.
void process_orders(std::vector<Order> const& orders); void process_orders(std::vector<Order> const& orders);
@ -25,6 +34,7 @@ private:
void operator()(FlushOrder const& flush_order); void operator()(FlushOrder const& flush_order);
std::shared_ptr<EngineListener> listener_; std::shared_ptr<EngineListener> listener_;
CrossBehaviour cross_behaviour_;
// Symbol, price, side are implicit given the way the book is represented // Symbol, price, side are implicit given the way the book is represented
struct OrderMetaData { struct OrderMetaData {