Skip to content

Commit

Permalink
Log instead of throw for duplicate prices in MarketOrderBook and merg…
Browse files Browse the repository at this point in the history
…e lines
  • Loading branch information
sjanel committed Mar 23, 2024
1 parent 7c09065 commit 92b3b77
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
19 changes: 15 additions & 4 deletions src/objects/src/marketorderbook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,21 @@ MarketOrderBook::MarketOrderBook(TimePoint timeStamp, Market market, const Marke
}

std::ranges::sort(_orders, [](auto lhs, auto rhs) { return lhs.price < rhs.price; });
const auto adjacentFindIt =
std::ranges::adjacent_find(_orders, [](auto lhs, auto rhs) { return lhs.price == rhs.price; });
if (adjacentFindIt != _orders.end()) {
throw exception("Forbidden duplicate price {} in the order book for market {}", adjacentFindIt->price, market);

for (auto it = _orders.begin(); it != _orders.end();) {
it = std::adjacent_find(it, _orders.end(), [](auto lhs, auto rhs) { return lhs.price == rhs.price; });
if (it != _orders.end()) {
auto nextIt = std::next(it);
log::warn("Forbidden duplicate price {} at amounts {} & {} in the order book for market {}, summing them",
it->price, it->amount, nextIt->amount, market);
nextIt->amount += it->amount;
// Remove the first duplicated price line (we summed the amounts on the next line)
it = _orders.erase(it);
if (it->amount == 0) {
// If the sum has 0 amount, remove the next one as well
it = _orders.erase(it);
}
}
}

const auto highestBidPriceIt =
Expand Down
31 changes: 31 additions & 0 deletions src/objects/test/marketorderbook_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,37 @@ TEST_F(MarketOrderBookTestCase1, Convert) {
EXPECT_EQ(marketOrderBook.convert(MonetaryAmount("800", "EUR")), MonetaryAmount("0.61443932411674347", "ETH"));
}

class MarketOrderBookTestDuplicatedLines : public ::testing::Test {
protected:
MarketOrderBook marketOrderBook{
TimePoint{}, Market("ETH", "EUR"),
CreateMarketOrderBookLines(
{OrderBookLine(MonetaryAmount("0.65", "ETH"), MonetaryAmount("1300.50", "EUR"), OrderBookLine::Type::kBid),
OrderBookLine(MonetaryAmount("0.24", "ETH"), MonetaryAmount("1301", "EUR"), OrderBookLine::Type::kBid),
OrderBookLine(MonetaryAmount("0.11", "ETH"), MonetaryAmount("1301.50", "EUR"), OrderBookLine::Type::kBid),
OrderBookLine(MonetaryAmount("0.11", "ETH"), MonetaryAmount("1301.50", "EUR"), OrderBookLine::Type::kAsk),
OrderBookLine(MonetaryAmount("1.4009", "ETH"), MonetaryAmount("1302", "EUR"), OrderBookLine::Type::kAsk),
OrderBookLine(MonetaryAmount("3.78", "ETH"), MonetaryAmount("1302.50", "EUR"), OrderBookLine::Type::kAsk),
OrderBookLine(MonetaryAmount("0.24", "ETH"), MonetaryAmount("1302.50", "EUR"), OrderBookLine::Type::kAsk),
OrderBookLine(MonetaryAmount("56.10001267", "ETH"), MonetaryAmount("1303", "EUR"),
OrderBookLine::Type::kAsk)})};
};

TEST_F(MarketOrderBookTestDuplicatedLines, NumberOfElements) {
EXPECT_EQ(marketOrderBook.size(), 5);
EXPECT_EQ(marketOrderBook.nbAskPrices(), 3);
EXPECT_EQ(marketOrderBook.nbBidPrices(), 2);
}

TEST_F(MarketOrderBookTestDuplicatedLines, MiddleElements) {
EXPECT_EQ(marketOrderBook.lowestAskPrice(), MonetaryAmount("1302", "EUR"));
EXPECT_EQ(marketOrderBook.highestBidPrice(), MonetaryAmount("1301", "EUR"));
}

TEST_F(MarketOrderBookTestDuplicatedLines, SummedAmountAsk) {
EXPECT_EQ(marketOrderBook[2].amount, MonetaryAmount("4.02", "ETH"));
}

class MarketOrderBookTestCase2 : public ::testing::Test {
protected:
TimePoint time;
Expand Down

0 comments on commit 92b3b77

Please sign in to comment.