I'm writing software that trades on the market, keeping order books in sync. I keep wondering about the code readability, as I have written it myself, I am biased. Could anyone please review the code and show where I can improve on code readability?
#include "Market.hpp"
Market::Market(uint32_t mId, bool ime, CsvManager &cm)
: marketId(mId), isMatchingEnabled(ime), lowestAsk(ENDPRICE),
csvManager(cm), highestAsk(0), lowestBid(ENDPRICE), highestBid(0) {
insertGenesisOrder();
}
void Market::insertGenesisOrder() {
Order emptyOrder(0, ENDINDEX, "", true, OrderType::NEW, OrderSide::SELL, 0,
0);
emptyOrder.next = ENDINDEX;
emptyOrder.prev = ENDINDEX;
orders.push_back(emptyOrder);
}
void Market::handleOrder(Order &order) {
if (order.type == OrderType::NEW) {
if (isMatchingEnabled) {
sendAcknowledgement(order);
}
newOrder(order);
if (!isMatchingEnabled && order.accepted) {
sendAcknowledgement(order);
}
} else if (order.type == OrderType::CANCEL) {
if (order.userOrderId <= orders.size() &&
orders[order.userOrderId].userOrderId <= orders.size()) {
order = orders[order.userOrderId];
removeOrder(order.userOrderId);
order.accepted = true;
sendAcknowledgement(order);
} else {
sendReject(order);
}
} else if (order.type == OrderType::FLUSH) {
flushOrders();
}
if (isTopUpdate(order) && order.accepted) {
sendTopUpdate(order);
}
}
bool Market::isTopUpdate(Order &order) {
if (order.type == OrderType::NEW || order.type == OrderType::CANCEL) {
if (order.side == OrderSide::BUY && order.price >= highestBid) {
return true;
} else if (order.side == OrderSide::SELL && order.price <= lowestAsk) {
return true;
}
}
return false;
}
void Market::sendTopUpdate(Order &order) {
OutputMessage om;
om.type = OutputMessageType::TOPOFBOOK;
if (order.quan == 0) {
om.side =
(order.side == OrderSide::BUY) ? OrderSide::SELL : OrderSide::BUY;
} else {
om.side = order.side;
}
if (om.side == OrderSide::BUY) {
om.price = highestBid;
om.quan = getBidQuantityForPrice(highestBid);
} else {
om.price = lowestAsk;
om.quan = getAskQuantityForPrice(lowestAsk);
}
csvManager.writeCsvFile(om);
}
void Market::sendAcknowledgement(Order &order) {
OutputMessage om;
om.type = OutputMessageType::ACKNOWLEDGEMENT;
om.side = order.side;
if (order.side == OrderSide::BUY) {
om.userIdBuy = order.userId;
om.userOrderIdBuy = order.userOrderId;
} else {
om.userIdSell = order.userId;
om.userOrderIdSell = order.userOrderId;
}
csvManager.writeCsvFile(om);
}
void Market::sendReject(Order &order) {
OutputMessage om;
om.type = OutputMessageType::REJECTION;
om.side = order.side;
if (order.side == OrderSide::BUY) {
om.userIdBuy = order.userId;
om.userOrderIdBuy = order.userOrderId;
} else {
om.userIdSell = order.userId;
om.userOrderIdSell = order.userOrderId;
}
csvManager.writeCsvFile(om);
}
void Market::sendTrade(Order &order1, Order &order2) {
OutputMessage om;
om.type = OutputMessageType::TRADE;
if (order1.side == OrderSide::BUY) {
om.userIdBuy = order1.userId;
om.userOrderIdBuy = order1.userOrderId;
om.userIdSell = order2.userId;
om.userOrderIdSell = order2.userOrderId;
} else {
om.userIdBuy = order2.userId;
om.userOrderIdBuy = order2.userOrderId;
om.userIdSell = order1.userId;
om.userOrderIdSell = order1.userOrderId;
}
om.quan = order1.quan;
om.price = order1.price;
csvManager.writeCsvFile(om);
}
void Market::newOrder(Order &order) {
if (order.side == OrderSide::BUY) {
insertBid(order);
} else {
insertAsk(order);
}
if (isMatchingEnabled) {
match(order);
order.accepted = true;
} else {
handleCrossBook(order);
if (!order.accepted) {
cancelOrder(order);
}
}
}
void Market::cancelOrder(Order &order) { removeOrder(order.userOrderId); }
void Market::flushOrders() {
orders.clear();
asks.clear();
bids.clear();
setLowestAsk(ENDPRICE);
setHighestAsk(0);
setLowestBid(ENDPRICE);
setHighestBid(0);
insertGenesisOrder();
}
void Market::insertAsk(Order &order) {
Price *curPrice = &asks[order.price];
Price *nextPrice = findAsksNextHigherPrice(order.price);
Price *prevPrice = findAsksNextLowerPrice(order.price);
setAskExtremes(order.price);
insertOrder(order, curPrice, nextPrice, prevPrice);
}
void Market::insertBid(Order &order) {
Price *curPrice = &bids[order.price];
Price *nextPrice = findBidsNextLowerPrice(order.price);
Price *prevPrice = findBidsNextHigherPrice(order.price);
setBidExtremes(order.price);
insertOrder(order, curPrice, nextPrice, prevPrice);
}
Price *Market::findAsksNextHigherPrice(const uint32_t price) {
auto it = asks.find(price);
if (it == asks.end() || std::next(it) == asks.end()) {
return nullptr;
}
return &(++it)->second;
}
Price *Market::findAsksNextLowerPrice(const uint32_t price) {
auto it = asks.find(price);
if (it == asks.begin() || std::prev(it) == asks.end()) {
return nullptr;
}
return &(--it)->second;
}
Price *Market::findBidsNextHigherPrice(const uint32_t price) {
auto it = bids.find(price);
if (it == bids.end() || std::next(it) == bids.end()) {
return nullptr;
}
return &(++it)->second;
}
Price *Market::findBidsNextLowerPrice(const uint32_t price) {
auto it = bids.find(price);
if (it == bids.begin() || std::prev(it) == bids.end()) {
return nullptr;
}
return &(--it)->second;
}
void Market::setAskExtremes(const uint32_t price) {
if (price > highestAsk) {
setHighestAsk(price);
}
if (price < lowestAsk || lowestAsk == ENDPRICE) {
setLowestAsk(price);
}
}
void Market::setBidExtremes(const uint32_t price) {
if (price > highestBid) {
setHighestBid(price);
}
if (price < lowestBid || lowestBid == ENDPRICE) {
setLowestBid(price);
}
}
void Market::setLowestAsk(uint32_t price) { lowestAsk = price; }
void Market::setHighestAsk(uint32_t price) { highestAsk = price; }
void Market::setLowestBid(uint32_t price) { lowestBid = price; }
void Market::setHighestBid(uint32_t price) { highestBid = price; }
void Market::match(Order &order) {
Price *curPrice =
(order.side == OrderSide::BUY) ? &asks[lowestAsk] : &bids[highestBid];
uint32_t sum = 0;
Order *curOrder = &orders[curPrice->orders.front()];
while (curOrder->userOrderId != ENDINDEX &&
priceCanMatch(curOrder, order.price) && sum < order.quan) {
if (sum + curOrder->quan >= order.quan) {
sendTrade(order, *curOrder);
curOrder->quan -= order.quan - sum;
if (curOrder->quan == 0) {
removeOrder(curOrder->userOrderId);
}
order.quan = 0;
removeOrder(order.userOrderId);
return;
}
sum += curOrder->quan;
Order *nextOrder = &orders[curOrder->next];
removeOrder(curOrder->userOrderId);
curOrder = nextOrder;
}
order.quan -= sum;
if (order.quan == 0)
removeOrder(order.userOrderId);
}
void Market::handleCrossBook(Order &order) {
if (order.side == OrderSide::BUY && order.price >= lowestAsk) {
order.accepted = false;
sendReject(order);
} else if (order.side == OrderSide::SELL && order.price <= highestBid) {
order.accepted = false;
sendReject(order);
} else {
order.accepted = true;
}
}
bool Market::priceCanMatch(const Order *curOrder, const uint32_t orderPrice) {
if (curOrder->side == OrderSide::BUY) {
return curOrder->price >= orderPrice;
} else {
return curOrder->price <= orderPrice;
}
}
void Market::removeOrder(const uint64_t id) {
Order *curOrder = &orders[id];
Order *prevOrder = &orders[curOrder->prev];
Order *nextOrder = &orders[curOrder->next];
curOrder->quan = 0;
if (prevOrder->userOrderId != ENDINDEX) {
prevOrder->next = curOrder->next;
}
if (nextOrder->userOrderId != ENDINDEX) {
nextOrder->prev = curOrder->prev;
}
if (curOrder->side == OrderSide::BUY) {
bids[curOrder->price].orders.remove(curOrder->userOrderId);
if (bids[curOrder->price].orders.size() == 0) {
if (curOrder->price == lowestBid) {
lowestBid = (prevOrder->userOrderId == ENDINDEX)
? ENDPRICE
: prevOrder->price;
}
if (curOrder->price == highestBid) {
highestBid =
(nextOrder->userOrderId == ENDINDEX) ? 0 : nextOrder->price;
}
bids.erase(curOrder->price);
}
} else {
asks[curOrder->price].orders.remove(curOrder->userOrderId);
if (asks[curOrder->price].orders.size() == 0) {
if (curOrder->price == lowestAsk) {
setLowestAsk((nextOrder->userOrderId == ENDINDEX)
? ENDPRICE
: nextOrder->price);
}
if (curOrder->price == highestAsk) {
setHighestAsk((prevOrder->userOrderId == ENDINDEX)
? 0
: prevOrder->price);
}
asks.erase(curOrder->price);
}
}
}
void Market::insertOrder(Order &order, Price *curPrice, Price *nextPrice,
Price *prevPrice) {
if (curPrice->orders.size() == 0) {
if (nextPrice == nullptr) {
order.next = ENDINDEX;
} else {
order.next = nextPrice->orders.front();
}
if (prevPrice == nullptr) {
order.prev = ENDINDEX;
} else {
order.prev = prevPrice->orders.back();
}
} else {
order.next = orders[curPrice->orders.back()].next;
order.prev = curPrice->orders.back();
}
pushBackOrReplace(order);
curPrice->orders.push_back(order.userOrderId);
if (order.next != ENDINDEX) {
orders[order.next].prev = order.userOrderId;
}
if (order.prev != ENDINDEX) {
orders[order.prev].next = order.userOrderId;
}
}
void Market::pushBackOrReplace(Order &order) {
if (order.userOrderId > orders.size()) {
orders.resize(order.userOrderId);
}
if (order.userOrderId == orders.size()) {
orders.push_back(order);
} else {
orders[order.userOrderId] = order;
}
}
uint32_t Market::getAskQuantityForPrice(const uint32_t price) {
Order *curOrder = &orders[asks[price].orders.front()];
uint32_t totQuan = 0;
while (curOrder->userOrderId != ENDINDEX && curOrder->price == price) {
totQuan += curOrder->quan;
curOrder = &orders[curOrder->next];
}
return totQuan;
}
uint32_t Market::getBidQuantityForPrice(const uint32_t price) {
Order *curOrder = &orders[bids[price].orders.front()];
uint32_t totQuan = 0;
while (curOrder->userOrderId != ENDINDEX && curOrder->price == price) {
totQuan += curOrder->quan;
curOrder = &orders[curOrder->next];
}
return totQuan;
}
```