diff --git a/src/api/common/test/exchangeprivateapi_test.cpp b/src/api/common/test/exchangeprivateapi_test.cpp index b10ef710..eb94f3c2 100644 --- a/src/api/common/test/exchangeprivateapi_test.cpp +++ b/src/api/common/test/exchangeprivateapi_test.cpp @@ -98,21 +98,22 @@ class ExchangePrivateTest : public ::testing::Test { VolAndPriNbDecimals volAndPriDec{2, 2}; int depth = 15; + TimePoint time{}; MonetaryAmount askPrice1{"2300.45 EUR"}; MonetaryAmount bidPrice1{"2300.4 EUR"}; MarketOrderBook marketOrderBook1{ - askPrice1, MonetaryAmount("1.09 ETH"), bidPrice1, MonetaryAmount("41 ETH"), volAndPriDec, depth}; + time, askPrice1, MonetaryAmount("1.09 ETH"), bidPrice1, MonetaryAmount("41 ETH"), volAndPriDec, depth}; MonetaryAmount askPrice2{"2300.5 EUR"}; MonetaryAmount bidPrice2{"2300.45 EUR"}; MarketOrderBook marketOrderBook2{ - askPrice2, MonetaryAmount("7.2 ETH"), bidPrice2, MonetaryAmount("1.23 ETH"), volAndPriDec, depth}; + time, askPrice2, MonetaryAmount("7.2 ETH"), bidPrice2, MonetaryAmount("1.23 ETH"), volAndPriDec, depth}; MonetaryAmount askPrice3{"2300.55 EUR"}; MonetaryAmount bidPrice3{"2300.5 EUR"}; MarketOrderBook marketOrderBook3{ - askPrice3, MonetaryAmount("0.96 ETH"), bidPrice3, MonetaryAmount("3.701 ETH"), volAndPriDec, depth}; + time, askPrice3, MonetaryAmount("0.96 ETH"), bidPrice3, MonetaryAmount("3.701 ETH"), volAndPriDec, depth}; }; TEST_F(ExchangePrivateTest, TakerTradeBaseToQuote) { @@ -640,12 +641,12 @@ class ExchangePrivateDustSweeperTest : public ExchangePrivateTest { MonetaryAmount xrpbtcBidPri{31, "BTC", 6}; MonetaryAmount xrpbtcAskPri{32, "BTC", 6}; MarketOrderBook xrpbtcMarketOrderBook{ - xrpbtcAskPri, MonetaryAmount(40, dustCur), xrpbtcBidPri, MonetaryAmount(27909, dustCur, 3), {3, 6}, depth}; + time, xrpbtcAskPri, MonetaryAmount(40, dustCur), xrpbtcBidPri, MonetaryAmount(27909, dustCur, 3), {3, 6}, depth}; MonetaryAmount xrpeurBidPri{5, "EUR", 1}; MonetaryAmount xrpeurAskPri{51, "EUR", 2}; MarketOrderBook xrpeurMarketOrderBook{ - xrpeurAskPri, MonetaryAmount(40, dustCur), xrpeurBidPri, MonetaryAmount(27909, dustCur, 3), {3, 2}, depth}; + time, xrpeurAskPri, MonetaryAmount(40, dustCur), xrpeurBidPri, MonetaryAmount(27909, dustCur, 3), {3, 2}, depth}; MonetaryAmount xrpethBidPri{134567, "EUR", 2}; diff --git a/src/api/common/test/exchangepublicapi_test.cpp b/src/api/common/test/exchangepublicapi_test.cpp index 40fecf8a..dedfde9c 100644 --- a/src/api/common/test/exchangepublicapi_test.cpp +++ b/src/api/common/test/exchangepublicapi_test.cpp @@ -88,25 +88,26 @@ class ExchangePublicConvertTest : public ExchangePublicTest { VolAndPriNbDecimals volAndPriDec1{2, 6}; int depth = 10; + TimePoint time{}; MonetaryAmount askPrice1{"0.000017 BTC"}; MonetaryAmount bidPrice1{"0.000016 BTC"}; MarketOrderBook marketOrderBook1{ - askPrice1, MonetaryAmount(40000, "XLM"), bidPrice1, MonetaryAmount(25000, "XLM"), volAndPriDec1, depth}; + time, askPrice1, MonetaryAmount(40000, "XLM"), bidPrice1, MonetaryAmount(25000, "XLM"), volAndPriDec1, depth}; VolAndPriNbDecimals volAndPriDec2{2, 4}; MonetaryAmount askPrice2{"0.0063 BTC"}; MonetaryAmount bidPrice2{"0.0062 BTC"}; MarketOrderBook marketOrderBook2{ - askPrice2, MonetaryAmount(680, "XRP"), bidPrice2, MonetaryAmount(1479, "XRP"), volAndPriDec2, depth}; + time, askPrice2, MonetaryAmount(680, "XRP"), bidPrice2, MonetaryAmount(1479, "XRP"), volAndPriDec2, depth}; VolAndPriNbDecimals volAndPriDec3{2, 2}; MonetaryAmount askPrice3{"37.5 EUR"}; MonetaryAmount bidPrice3{"37.49 EUR"}; MarketOrderBook marketOrderBook3{ - askPrice3, MonetaryAmount("12.04 SOL"), bidPrice3, MonetaryAmount("0.45 SOL"), volAndPriDec3, depth}; + time, askPrice3, MonetaryAmount("12.04 SOL"), bidPrice3, MonetaryAmount("0.45 SOL"), volAndPriDec3, depth}; MarketOrderBookMap marketOrderBookMap{{Market("XLM", "BTC"), marketOrderBook1}, {Market("XRP", "BTC"), marketOrderBook2}, diff --git a/src/api/exchanges/src/binancepublicapi.cpp b/src/api/exchanges/src/binancepublicapi.cpp index aa7a59f9..3d8468d7 100644 --- a/src/api/exchanges/src/binancepublicapi.cpp +++ b/src/api/exchanges/src/binancepublicapi.cpp @@ -455,6 +455,7 @@ MarketOrderBookMap BinancePublic::AllOrderBooksFunc::operator()(int depth) { for (Market mk : markets) { binanceAssetPairToStdMarketMap.insert_or_assign(mk.assetsPairStrUpper(), mk); } + const auto time = Clock::now(); for (const json& tickerDetails : result) { string assetsPairStr = tickerDetails["symbol"]; auto it = binanceAssetPairToStdMarketMap.find(assetsPairStr); @@ -467,7 +468,7 @@ MarketOrderBookMap BinancePublic::AllOrderBooksFunc::operator()(int depth) { MonetaryAmount askVol(tickerDetails["askQty"].get(), mk.base()); MonetaryAmount bidVol(tickerDetails["bidQty"].get(), mk.base()); - ret.insert_or_assign(mk, MarketOrderBook(askPri, askVol, bidPri, bidVol, + ret.insert_or_assign(mk, MarketOrderBook(time, askPri, askVol, bidPri, bidVol, QueryVolAndPriNbDecimals(_exchangeConfigCache.get(), mk), depth)); } @@ -504,7 +505,7 @@ MarketOrderBook BinancePublic::OrderBookFunc::operator()(Market mk, int depth) { } } - return MarketOrderBook(mk, orderBookLines); + return MarketOrderBook(Clock::now(), mk, orderBookLines); } MonetaryAmount BinancePublic::TradedVolumeFunc::operator()(Market mk) { diff --git a/src/api/exchanges/src/bithumbpublicapi.cpp b/src/api/exchanges/src/bithumbpublicapi.cpp index d7e2fe96..a58df511 100644 --- a/src/api/exchanges/src/bithumbpublicapi.cpp +++ b/src/api/exchanges/src/bithumbpublicapi.cpp @@ -252,6 +252,7 @@ MarketOrderBookMap GetOrderbooks(CurlHandle& curlHandle, const CoincenterInfo& c if (quoteCurrency != "KRW") { log::error("Unexpected Bithumb reply for orderbook. May require code api update"); } + const auto time = Clock::now(); CurrencyCode quoteCurrencyCode(config.standardizeCurrencyCode(quoteCurrency)); const CurrencyCodeSet& excludedCurrencies = exchangeConfig.excludedCurrenciesAll(); for (const auto& [baseOrSpecial, asksAndBids] : result.items()) { @@ -296,7 +297,7 @@ MarketOrderBookMap GetOrderbooks(CurlHandle& curlHandle, const CoincenterInfo& c } } Market market(baseCurrencyCode, quoteCurrencyCode); - ret.insert_or_assign(market, MarketOrderBook(market, orderBookLines)); + ret.insert_or_assign(market, MarketOrderBook(time, market, orderBookLines)); if (singleMarketQuote) { break; } diff --git a/src/api/exchanges/src/huobipublicapi.cpp b/src/api/exchanges/src/huobipublicapi.cpp index 792b1a23..0662acee 100644 --- a/src/api/exchanges/src/huobipublicapi.cpp +++ b/src/api/exchanges/src/huobipublicapi.cpp @@ -335,7 +335,9 @@ MarketOrderBookMap HuobiPublic::AllOrderBooksFunc::operator()(int depth) { for (Market mk : markets) { huobiAssetPairToStdMarketMap.insert_or_assign(mk.assetsPairStrUpper(), mk); } - for (const json& tickerDetails : PublicQuery(_curlHandle, "/market/tickers")) { + const auto tickerData = PublicQuery(_curlHandle, "/market/tickers"); + const auto time = Clock::now(); + for (const json& tickerDetails : tickerData) { string upperMarket = ToUpper(tickerDetails["symbol"].get()); auto it = huobiAssetPairToStdMarketMap.find(upperMarket); if (it == huobiAssetPairToStdMarketMap.end()) { @@ -358,7 +360,7 @@ MarketOrderBookMap HuobiPublic::AllOrderBooksFunc::operator()(int depth) { continue; } - ret.insert_or_assign(mk, MarketOrderBook(askPri, askVol, bidPri, bidVol, volAndPriNbDecimals, depth)); + ret.insert_or_assign(mk, MarketOrderBook(time, askPri, askVol, bidPri, bidVol, volAndPriNbDecimals, depth)); } log::info("Retrieved Huobi ticker information from {} markets", ret.size()); @@ -402,7 +404,7 @@ MarketOrderBook HuobiPublic::OrderBookFunc::operator()(Market mk, int depth) { } } } - return MarketOrderBook(mk, orderBookLines); + return MarketOrderBook(Clock::now(), mk, orderBookLines); } MonetaryAmount HuobiPublic::sanitizePrice(Market mk, MonetaryAmount pri) { diff --git a/src/api/exchanges/src/krakenpublicapi.cpp b/src/api/exchanges/src/krakenpublicapi.cpp index e1872c5f..153d3c73 100644 --- a/src/api/exchanges/src/krakenpublicapi.cpp +++ b/src/api/exchanges/src/krakenpublicapi.cpp @@ -459,6 +459,7 @@ MarketOrderBookMap KrakenPublic::AllOrderBooksFunc::operator()(int depth) { mk); } json result = PublicQuery(_curlHandle, "/public/Ticker", {{"pair", allAssetPairs}}); + const auto time = Clock::now(); for (const auto& [krakenAssetPair, assetPairDetails] : result.items()) { if (krakenAssetPairToStdMarketMap.find(krakenAssetPair) == krakenAssetPairToStdMarketMap.end()) { log::error("Unable to find {}", krakenAssetPair); @@ -480,7 +481,8 @@ MarketOrderBookMap KrakenPublic::AllOrderBooksFunc::operator()(int depth) { const MarketsFunc::MarketInfo& marketInfo = marketInfoMap.find(mk)->second; if (bidVol != 0 && askVol != 0) { - ret.insert_or_assign(mk, MarketOrderBook(askPri, askVol, bidPri, bidVol, marketInfo.volAndPriNbDecimals, depth)); + ret.insert_or_assign( + mk, MarketOrderBook(time, askPri, askVol, bidPri, bidVol, marketInfo.volAndPriNbDecimals, depth)); } } @@ -528,7 +530,7 @@ MarketOrderBook KrakenPublic::OrderBookFunc::operator()(Market mk, int count) { } const auto volAndPriNbDecimals = _marketsCache.get().second.find(mk)->second.volAndPriNbDecimals; - return MarketOrderBook(mk, orderBookLines, volAndPriNbDecimals); + return MarketOrderBook(Clock::now(), mk, orderBookLines, volAndPriNbDecimals); } KrakenPublic::TickerFunc::Last24hTradedVolumeAndLatestPricePair KrakenPublic::TickerFunc::operator()(Market mk) { diff --git a/src/api/exchanges/src/kucoinpublicapi.cpp b/src/api/exchanges/src/kucoinpublicapi.cpp index 0e5608bd..d6e371e3 100644 --- a/src/api/exchanges/src/kucoinpublicapi.cpp +++ b/src/api/exchanges/src/kucoinpublicapi.cpp @@ -209,7 +209,8 @@ std::optional KucoinPublic::queryWithdrawalFee(CurrencyCode curr MarketOrderBookMap KucoinPublic::AllOrderBooksFunc::operator()(int depth) { MarketOrderBookMap ret; const auto& [markets, marketInfoMap] = _marketsCache.get(); - json data = PublicQuery(_curlHandle, "/api/v1/market/allTickers"); + const json data = PublicQuery(_curlHandle, "/api/v1/market/allTickers"); + const auto time = Clock::now(); const auto tickerIt = data.find("ticker"); if (tickerIt == data.end()) { return ret; @@ -251,7 +252,7 @@ MarketOrderBookMap KucoinPublic::AllOrderBooksFunc::operator()(int depth) { VolAndPriNbDecimals volAndPriNbDecimals{marketInfo.baseIncrement.nbDecimals(), marketInfo.priceIncrement.nbDecimals()}; - ret.insert_or_assign(mk, MarketOrderBook(askPri, askVol, bidPri, bidVol, volAndPriNbDecimals, depth)); + ret.insert_or_assign(mk, MarketOrderBook(time, askPri, askVol, bidPri, bidVol, volAndPriNbDecimals, depth)); } log::info("Retrieved Kucoin ticker information from {} markets", ret.size()); @@ -302,7 +303,7 @@ MarketOrderBook KucoinPublic::OrderBookFunc::operator()(Market mk, int depth) { FillOrderBook(mk, depth, true, asksIt->begin(), asksIt->end(), orderBookLines); } - return MarketOrderBook(mk, orderBookLines); + return MarketOrderBook(Clock::now(), mk, orderBookLines); } MonetaryAmount KucoinPublic::sanitizePrice(Market mk, MonetaryAmount pri) { diff --git a/src/api/exchanges/src/upbitpublicapi.cpp b/src/api/exchanges/src/upbitpublicapi.cpp index 7fa5231c..752f3f57 100644 --- a/src/api/exchanges/src/upbitpublicapi.cpp +++ b/src/api/exchanges/src/upbitpublicapi.cpp @@ -179,6 +179,7 @@ MonetaryAmountByCurrencySet UpbitPublic::WithdrawalFeesFunc::operator()() { namespace { MarketOrderBookMap ParseOrderBooks(const json& result, int depth) { MarketOrderBookMap ret; + const auto time = Clock::now(); for (const json& marketDetails : result) { std::string_view marketStr = marketDetails["market"].get(); std::size_t dashPos = marketStr.find('-'); @@ -211,7 +212,7 @@ MarketOrderBookMap ParseOrderBooks(const json& result, int depth) { if (static_cast(orderBookLines.size() / 2) < depth) { log::warn("Upbit does not support orderbook depth larger than {}", orderBookLines.size() / 2); } - ret.insert_or_assign(market, MarketOrderBook(market, orderBookLines)); + ret.insert_or_assign(market, MarketOrderBook(time, market, orderBookLines)); } log::info("Retrieved {} order books from Upbit", ret.size()); return ret; diff --git a/src/engine/test/exchangedata_test.hpp b/src/engine/test/exchangedata_test.hpp index 9c9b46ac..96909b6e 100644 --- a/src/engine/test/exchangedata_test.hpp +++ b/src/engine/test/exchangedata_test.hpp @@ -7,6 +7,7 @@ #include "exchange.hpp" #include "exchangeprivateapi_mock.hpp" #include "exchangepublicapi_mock.hpp" +#include "timedef.hpp" namespace cct { @@ -67,9 +68,13 @@ class ExchangesBaseTest : public ::testing::Test { MonetaryAmount askPrice1{"2300.45EUR"}; MonetaryAmount bidPrice1{"2300.4EUR"}; + + TimePoint time{}; + MarketOrderBook marketOrderBook10{ - askPrice1, MonetaryAmount("1.09ETH"), bidPrice1, MonetaryAmount("41ETH"), volAndPriDec1, depth}; - MarketOrderBook marketOrderBook11{MonetaryAmount{"2301.15EUR"}, + time, askPrice1, MonetaryAmount("1.09ETH"), bidPrice1, MonetaryAmount("41ETH"), volAndPriDec1, depth}; + MarketOrderBook marketOrderBook11{time, + MonetaryAmount{"2301.15EUR"}, MonetaryAmount("0.4ETH"), MonetaryAmount{"2301.05EUR"}, MonetaryAmount("17ETH"), @@ -80,8 +85,9 @@ class ExchangesBaseTest : public ::testing::Test { MonetaryAmount askPrice2{"31056.67 EUR"}; MonetaryAmount bidPrice2{"31056.66 EUR"}; MarketOrderBook marketOrderBook20{ - askPrice2, MonetaryAmount("0.12BTC"), bidPrice2, MonetaryAmount("0.00234 BTC"), volAndPriDec2, depth}; - MarketOrderBook marketOrderBook21{MonetaryAmount{"31051.02 EUR"}, + time, askPrice2, MonetaryAmount("0.12BTC"), bidPrice2, MonetaryAmount("0.00234 BTC"), volAndPriDec2, depth}; + MarketOrderBook marketOrderBook21{time, + MonetaryAmount{"31051.02 EUR"}, MonetaryAmount("0.409BTC"), MonetaryAmount{"31051.01 EUR"}, MonetaryAmount("1.9087 BTC"), @@ -92,7 +98,7 @@ class ExchangesBaseTest : public ::testing::Test { MonetaryAmount askPrice3{"0.37 BTC"}; MonetaryAmount bidPrice3{"0.36 BTC"}; MarketOrderBook marketOrderBook3{ - askPrice3, MonetaryAmount("916.4XRP"), bidPrice3, MonetaryAmount("3494XRP"), volAndPriDec3, depth}; + time, askPrice3, MonetaryAmount("916.4XRP"), bidPrice3, MonetaryAmount("3494XRP"), volAndPriDec3, depth}; const MonetaryAmount amounts1[4] = {MonetaryAmount("1500XRP"), MonetaryAmount("15BTC"), MonetaryAmount("1.5ETH"), MonetaryAmount("5000USDT")}; diff --git a/src/engine/test/exchangesorchestrator_trade_test.cpp b/src/engine/test/exchangesorchestrator_trade_test.cpp index 1dcf5d91..604621ec 100644 --- a/src/engine/test/exchangesorchestrator_trade_test.cpp +++ b/src/engine/test/exchangesorchestrator_trade_test.cpp @@ -164,7 +164,8 @@ class ExchangeOrchestratorTradeTest : public ExchangeOrchestratorTest { MonetaryAmount deltaPri(1, pri.currencyCode(), volAndPriDec1.priNbDecimals); MonetaryAmount askPrice = side == TradeSide::kBuy ? pri : pri + deltaPri; MonetaryAmount bidPrice = side == TradeSide::kSell ? pri : pri - deltaPri; - MarketOrderBook marketOrderbook{askPrice, maxVol, bidPrice, maxVol, volAndPriDec1, MarketOrderBook::kDefaultDepth}; + MarketOrderBook marketOrderbook{ + time, askPrice, maxVol, bidPrice, maxVol, volAndPriDec1, MarketOrderBook::kDefaultDepth}; TradedAmounts tradedAmounts(from, tradedTo); OrderId orderId("OrderId # 0"); @@ -243,8 +244,11 @@ class ExchangeOrchestratorTradeTest : public ExchangeOrchestratorTest { MonetaryAmount askPri2 = side == TradeSide::kBuy ? pri2 : pri2 + deltaPri2; MonetaryAmount bidPri1 = side == TradeSide::kSell ? pri1 : pri1 - deltaPri1; MonetaryAmount bidPri2 = side == TradeSide::kSell ? pri2 : pri2 - deltaPri2; - MarketOrderBook marketOrderbook1{askPri1, maxVol1, bidPri1, maxVol1, volAndPriDec1, MarketOrderBook::kDefaultDepth}; - MarketOrderBook marketOrderbook2{askPri2, maxVol2, bidPri2, maxVol2, volAndPriDec1, MarketOrderBook::kDefaultDepth}; + TimePoint time{}; + MarketOrderBook marketOrderbook1{ + time, askPri1, maxVol1, bidPri1, maxVol1, volAndPriDec1, MarketOrderBook::kDefaultDepth}; + MarketOrderBook marketOrderbook2{ + time, askPri2, maxVol2, bidPri2, maxVol2, volAndPriDec1, MarketOrderBook::kDefaultDepth}; TradedAmounts tradedAmounts1(from, vol2); TradedAmounts tradedAmounts2(MonetaryAmount(from, interCur), tradedTo2); diff --git a/src/engine/test/queryresultprinter_public_test.cpp b/src/engine/test/queryresultprinter_public_test.cpp index fdf06244..9851d3c3 100644 --- a/src/engine/test/queryresultprinter_public_test.cpp +++ b/src/engine/test/queryresultprinter_public_test.cpp @@ -467,7 +467,8 @@ class QueryResultPrinterMarketOrderBookTest : public QueryResultPrinterTest { protected: Market mk{"BTC", "EUR"}; int d = 3; - MarketOrderBook mob{askPrice2, MonetaryAmount("0.12BTC"), bidPrice2, MonetaryAmount("0.00234 BTC"), volAndPriDec2, d}; + MarketOrderBook mob{tp1, askPrice2, MonetaryAmount("0.12BTC"), bidPrice2, MonetaryAmount("0.00234 BTC"), + volAndPriDec2, d}; MarketOrderBookConversionRates marketOrderBookConversionRates{{"exchangeA", mob, {}}, {"exchangeD", mob, {}}}; }; diff --git a/src/objects/include/marketorderbook.hpp b/src/objects/include/marketorderbook.hpp index 27c7fbaa..c9638ab7 100644 --- a/src/objects/include/marketorderbook.hpp +++ b/src/objects/include/marketorderbook.hpp @@ -9,6 +9,7 @@ #include "market.hpp" #include "monetaryamount.hpp" #include "simpletable.hpp" +#include "timedef.hpp" #include "volumeandpricenbdecimals.hpp" namespace cct { @@ -45,16 +46,19 @@ class MarketOrderBook { using AmountPerPriceVec = SmallVector; + /// Constructs an empty MarketOrderBook MarketOrderBook() noexcept = default; /// Constructs a new MarketOrderBook given a market and a list of amounts and prices. /// @param volAndPriNbDecimals optional to force number of decimals of amounts - explicit MarketOrderBook(Market market, OrderBookLineSpan orderLines = OrderBookLineSpan(), + explicit MarketOrderBook(TimePoint timeStamp, Market market, OrderBookLineSpan orderLines = OrderBookLineSpan(), VolAndPriNbDecimals volAndPriNbDecimals = VolAndPriNbDecimals()); /// Constructs a MarketOrderBook based on simple ticker information and price / amount precision - MarketOrderBook(MonetaryAmount askPrice, MonetaryAmount askVolume, MonetaryAmount bidPrice, MonetaryAmount bidVolume, - VolAndPriNbDecimals volAndPriNbDecimals, int depth = kDefaultDepth); + MarketOrderBook(TimePoint timeStamp, MonetaryAmount askPrice, MonetaryAmount askVolume, MonetaryAmount bidPrice, + MonetaryAmount bidVolume, VolAndPriNbDecimals volAndPriNbDecimals, int depth = kDefaultDepth); + + TimePoint time() const { return _time; } Market market() const { return _market; } @@ -217,12 +221,13 @@ class MarketOrderBook { /// This simulates a trade at market price. std::optional convertQuoteAmountToBase(MonetaryAmount amountInQuoteCurrency) const; + TimePoint _time{}; Market _market; - VolAndPriNbDecimals _volAndPriNbDecimals; AmountPriceVector _orders; int _highestBidPricePos = 0; int _lowestAskPricePos = 0; bool _isArtificiallyExtended = false; + VolAndPriNbDecimals _volAndPriNbDecimals; }; } // namespace cct diff --git a/src/objects/include/publictrade.hpp b/src/objects/include/publictrade.hpp index 6dc0ad11..87d909fd 100644 --- a/src/objects/include/publictrade.hpp +++ b/src/objects/include/publictrade.hpp @@ -18,7 +18,7 @@ class PublicTrade { TradeSide side() const { return _side; } - Market market() const { return Market(_amount.currencyCode(), _price.currencyCode()); } + Market market() const { return {_amount.currencyCode(), _price.currencyCode()}; } MonetaryAmount amount() const { return _amount; } MonetaryAmount price() const { return _price; } diff --git a/src/objects/src/marketorderbook.cpp b/src/objects/src/marketorderbook.cpp index c5f1bc3e..5ba5609a 100644 --- a/src/objects/src/marketorderbook.cpp +++ b/src/objects/src/marketorderbook.cpp @@ -24,8 +24,9 @@ namespace cct { -MarketOrderBook::MarketOrderBook(Market market, OrderBookLineSpan orderLines, VolAndPriNbDecimals volAndPriNbDecimals) - : _market(market), _volAndPriNbDecimals(volAndPriNbDecimals) { +MarketOrderBook::MarketOrderBook(TimePoint timeStamp, Market market, OrderBookLineSpan orderLines, + VolAndPriNbDecimals volAndPriNbDecimals) + : _time(timeStamp), _market(market), _volAndPriNbDecimals(volAndPriNbDecimals) { const int nbPrices = static_cast(orderLines.size()); _orders.reserve(nbPrices); if (_volAndPriNbDecimals == VolAndPriNbDecimals()) { @@ -74,11 +75,13 @@ MarketOrderBook::MarketOrderBook(Market market, OrderBookLineSpan orderLines, Vo } } -MarketOrderBook::MarketOrderBook(MonetaryAmount askPrice, MonetaryAmount askVolume, MonetaryAmount bidPrice, - MonetaryAmount bidVolume, VolAndPriNbDecimals volAndPriNbDecimals, int depth) - : _market(askVolume.currencyCode(), askPrice.currencyCode()), - _volAndPriNbDecimals(volAndPriNbDecimals), - _isArtificiallyExtended(depth > 1) { +MarketOrderBook::MarketOrderBook(TimePoint timeStamp, MonetaryAmount askPrice, MonetaryAmount askVolume, + MonetaryAmount bidPrice, MonetaryAmount bidVolume, + VolAndPriNbDecimals volAndPriNbDecimals, int depth) + : _time(timeStamp), + _market(askVolume.currencyCode(), askPrice.currencyCode()), + _isArtificiallyExtended(depth > 1), + _volAndPriNbDecimals(volAndPriNbDecimals) { if (depth <= 0) { throw exception("Invalid depth, should be strictly positive"); } diff --git a/src/objects/test/marketorderbook_test.cpp b/src/objects/test/marketorderbook_test.cpp index 4ebbd23d..196aab6b 100644 --- a/src/objects/test/marketorderbook_test.cpp +++ b/src/objects/test/marketorderbook_test.cpp @@ -9,6 +9,7 @@ #include "cct_exception.hpp" #include "market.hpp" #include "monetaryamount.hpp" +#include "timedef.hpp" namespace cct { namespace { @@ -20,12 +21,12 @@ inline bool operator==(const AmountAtPrice &lhs, const AmountAtPrice &rhs) { return lhs.amount == rhs.amount && lhs.price == rhs.price; } -TEST(MarketOrderBookTest, Basic) { EXPECT_TRUE(MarketOrderBook(Market("ETH", "EUR"), {}).empty()); } +TEST(MarketOrderBookTest, Basic) { EXPECT_TRUE(MarketOrderBook(Clock::now(), Market("ETH", "EUR"), {}).empty()); } class MarketOrderBookTestCase1 : public ::testing::Test { protected: MarketOrderBook marketOrderBook{ - Market("ETH", "EUR"), + Clock::now(), Market("ETH", "EUR"), std::array{ OrderBookLine(MonetaryAmount("0.65", "ETH"), MonetaryAmount("1300.50", "EUR"), false), OrderBookLine(MonetaryAmount("0.24", "ETH"), MonetaryAmount("1301", "EUR"), false), @@ -127,11 +128,9 @@ TEST_F(MarketOrderBookTestCase1, Convert) { class MarketOrderBookTestCase2 : public ::testing::Test { protected: - void SetUp() override {} - void TearDown() override {} - + TimePoint time{}; MarketOrderBook marketOrderBook{ - Market("APM", "KRW"), + time, Market("APM", "KRW"), std::array{ OrderBookLine(MonetaryAmount("1991.3922", "APM"), MonetaryAmount("57.8", "KRW"), true), OrderBookLine(MonetaryAmount("90184.3951", "APM"), MonetaryAmount("57.81", "KRW"), true), @@ -158,11 +157,9 @@ TEST_F(MarketOrderBookTestCase2, ConvertQuoteAmountToBase) { class MarketOrderBookTestCase3 : public ::testing::Test { protected: - void SetUp() override {} - void TearDown() override {} - + TimePoint time{}; MarketOrderBook marketOrderBook{ - Market("XLM", "BTC"), + time, Market("XLM", "BTC"), std::array{ OrderBookLine(MonetaryAmount("126881.164", "XLM"), MonetaryAmount("0.000007130", "BTC"), true), OrderBookLine(MonetaryAmount("95716.519", "XLM"), MonetaryAmount("0.000007120", "BTC"), true), @@ -182,10 +179,9 @@ TEST_F(MarketOrderBookTestCase3, Convert) { class MarketOrderBookTestCaseExtended1 : public ::testing::Test { protected: - void SetUp() override {} - void TearDown() override {} - - MarketOrderBook marketOrderBook{MonetaryAmount("2300.45 EUR"), + TimePoint time{}; + MarketOrderBook marketOrderBook{time, + MonetaryAmount("2300.45 EUR"), MonetaryAmount("193.09 ADA"), MonetaryAmount("2300.4 EUR"), MonetaryAmount("41 ADA"), @@ -204,44 +200,44 @@ TEST_F(MarketOrderBookTestCaseExtended1, Convert) { } TEST(MarketOrderBookExtendedTest, ComputeVolAndPriNbDecimalsFromTickerInfo) { - MarketOrderBook marketOrderBook(MonetaryAmount("12355.00002487 XLM"), MonetaryAmount("193.0900000000078 ADA"), - MonetaryAmount("12355.00002486 XLM"), MonetaryAmount("504787104.7801 ADA"), {4, 8}, - 10); + MarketOrderBook marketOrderBook(Clock::now(), MonetaryAmount("12355.00002487 XLM"), + MonetaryAmount("193.0900000000078 ADA"), MonetaryAmount("12355.00002486 XLM"), + MonetaryAmount("504787104.7801 ADA"), {4, 8}, 10); EXPECT_EQ(marketOrderBook.highestBidPrice(), MonetaryAmount("12355.00002486 XLM")); EXPECT_EQ(marketOrderBook.lowestAskPrice(), MonetaryAmount("12355.00002487 XLM")); } TEST(MarketOrderBookExtendedTest, InvalidPrice) { - EXPECT_NO_THROW(MarketOrderBook(MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), + EXPECT_NO_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), MonetaryAmount("5ADA"), {0, 0})); - EXPECT_THROW(MarketOrderBook(MonetaryAmount("1XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), + EXPECT_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("1XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), MonetaryAmount("5ADA"), {0, 0}), exception); } TEST(MarketOrderBookExtendedTest, InvalidDepth) { - EXPECT_NO_THROW(MarketOrderBook(MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), + EXPECT_NO_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), MonetaryAmount("5ADA"), {0, 0})); - EXPECT_THROW(MarketOrderBook(MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), + EXPECT_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), MonetaryAmount("5ADA"), {0, 0}, 0), exception); - EXPECT_NO_THROW(MarketOrderBook(MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), + EXPECT_NO_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), MonetaryAmount("5ADA"), {2, 2})); - EXPECT_THROW(MarketOrderBook(MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), + EXPECT_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("2XLM"), MonetaryAmount("1ADA"), MonetaryAmount("1XLM"), MonetaryAmount("5ADA"), {2, 2}, -1), exception); } TEST(MarketOrderBookExtendedTest, InvalidNumberOfDecimals) { - EXPECT_NO_THROW(MarketOrderBook(MonetaryAmount("0.03XLM"), MonetaryAmount("1ADA"), MonetaryAmount("0.02XLM"), - MonetaryAmount("5ADA"), {8, 8})); - EXPECT_THROW(MarketOrderBook(MonetaryAmount("0.03XLM"), MonetaryAmount("1ADA"), MonetaryAmount("0.02XLM"), - MonetaryAmount("5ADA"), {8, 1}), + EXPECT_NO_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("0.03XLM"), MonetaryAmount("1ADA"), + MonetaryAmount("0.02XLM"), MonetaryAmount("5ADA"), {8, 8})); + EXPECT_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("0.03XLM"), MonetaryAmount("1ADA"), + MonetaryAmount("0.02XLM"), MonetaryAmount("5ADA"), {8, 1}), exception); - EXPECT_NO_THROW(MarketOrderBook(MonetaryAmount("2XLM"), MonetaryAmount("0.04ADA"), MonetaryAmount("1XLM"), - MonetaryAmount("0.03ADA"), {8, 8})); - EXPECT_THROW(MarketOrderBook(MonetaryAmount("2XLM"), MonetaryAmount("0.04ADA"), MonetaryAmount("1XLM"), + EXPECT_NO_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("2XLM"), MonetaryAmount("0.04ADA"), + MonetaryAmount("1XLM"), MonetaryAmount("0.03ADA"), {8, 8})); + EXPECT_THROW(MarketOrderBook(Clock::now(), MonetaryAmount("2XLM"), MonetaryAmount("0.04ADA"), MonetaryAmount("1XLM"), MonetaryAmount("0.03ADA"), {1, 8}), exception); }