From b4d652a9741294efc01345ad9f2f4ab6a4177c2e Mon Sep 17 00:00:00 2001 From: Stephane Janel Date: Sat, 10 Feb 2024 13:02:51 +0100 Subject: [PATCH] Market Order books objects are enriched with timestamp. Also set UTC time string as default --- src/api-objects/include/publictrade.hpp | 4 + .../common/test/exchangeprivateapi_test.cpp | 11 +- .../common/test/exchangepublicapi_test.cpp | 7 +- src/api/exchanges/src/binancepublicapi.cpp | 5 +- src/api/exchanges/src/bithumbpublicapi.cpp | 3 +- src/api/exchanges/src/huobipublicapi.cpp | 8 +- src/api/exchanges/src/krakenpublicapi.cpp | 6 +- src/api/exchanges/src/kucoinpublicapi.cpp | 7 +- src/api/exchanges/src/upbitpublicapi.cpp | 3 +- src/engine/src/queryresultprinter.cpp | 6 +- src/engine/test/exchangedata_test.hpp | 16 ++- .../test/exchangesorchestrator_trade_test.cpp | 10 +- .../test/queryresultprinter_private_test.cpp | 112 +++++++++--------- .../test/queryresultprinter_public_test.cpp | 57 ++++----- src/objects/include/marketorderbook.hpp | 13 +- src/objects/src/marketorderbook.cpp | 17 +-- src/objects/test/marketorderbook_test.cpp | 56 ++++----- src/tech/include/timestring.hpp | 8 +- src/tech/src/timestring.cpp | 3 +- 19 files changed, 193 insertions(+), 159 deletions(-) diff --git a/src/api-objects/include/publictrade.hpp b/src/api-objects/include/publictrade.hpp index 350840f6..7eda35cf 100644 --- a/src/api-objects/include/publictrade.hpp +++ b/src/api-objects/include/publictrade.hpp @@ -3,6 +3,7 @@ #include #include "cct_string.hpp" +#include "market.hpp" #include "monetaryamount.hpp" #include "timedef.hpp" #include "tradeside.hpp" @@ -17,7 +18,10 @@ class PublicTrade { TradeSide side() const { return _side; } + Market market() const { return {_amount.currencyCode(), _price.currencyCode()}; } + MonetaryAmount amount() const { return _amount; } + MonetaryAmount price() const { return _price; } TimePoint time() const { return _time; } 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 3f82bc29..707bd1d3 100644 --- a/src/api/exchanges/src/bithumbpublicapi.cpp +++ b/src/api/exchanges/src/bithumbpublicapi.cpp @@ -199,6 +199,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()) { @@ -243,7 +244,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 f6cd3fef..ca836073 100644 --- a/src/api/exchanges/src/krakenpublicapi.cpp +++ b/src/api/exchanges/src/krakenpublicapi.cpp @@ -252,6 +252,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); @@ -273,7 +274,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)); } } @@ -321,7 +323,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/src/queryresultprinter.cpp b/src/engine/src/queryresultprinter.cpp index acf76c12..f4ce97c7 100644 --- a/src/engine/src/queryresultprinter.cpp +++ b/src/engine/src/queryresultprinter.cpp @@ -179,6 +179,8 @@ json MarketOrderBooksJson(Market mk, CurrencyCode equiCurrencyCode, std::optiona json marketOrderBookForExchange; json bidsForExchange; json asksForExchange; + + marketOrderBookForExchange.emplace("time", ToString(marketOrderBook.time())); for (int bidPos = 1; bidPos <= marketOrderBook.nbBidPrices(); ++bidPos) { AppendOrderbookLine(marketOrderBook, -bidPos, optConversionRate, bidsForExchange); } @@ -833,7 +835,7 @@ void QueryResultPrinter::printTickerInformation(const ExchangeTickerMaps &exchan void QueryResultPrinter::printMarketOrderBooks( Market mk, CurrencyCode equiCurrencyCode, std::optional depth, const MarketOrderBookConversionRates &marketOrderBooksConversionRates) const { - json jsonData = MarketOrderBooksJson(mk, equiCurrencyCode, depth, marketOrderBooksConversionRates); + const json jsonData = MarketOrderBooksJson(mk, equiCurrencyCode, depth, marketOrderBooksConversionRates); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { for (const auto &[exchangeName, marketOrderBook, optConversionRate] : marketOrderBooksConversionRates) { @@ -1126,7 +1128,7 @@ void QueryResultPrinter::printLastTrades(Market mk, int nbLastTrades, mk.quote().appendStrTo(priceTitle); string title(exchangePtr->name()); - title.append(" trades - UTC"); + title.append(" trades"); SimpleTable simpleTable(std::move(title), std::move(buyTitle), std::move(priceTitle), std::move(sellTitle)); std::array totalAmounts{MonetaryAmount(0, mk.base()), MonetaryAmount(0, mk.base())}; diff --git a/src/engine/test/exchangedata_test.hpp b/src/engine/test/exchangedata_test.hpp index e9aaa74d..3cd5baa6 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 { @@ -59,9 +60,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"), @@ -72,8 +77,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"), @@ -84,7 +90,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_private_test.cpp b/src/engine/test/queryresultprinter_private_test.cpp index fd63872c..e6da9251 100644 --- a/src/engine/test/queryresultprinter_private_test.cpp +++ b/src/engine/test/queryresultprinter_private_test.cpp @@ -976,15 +976,15 @@ class QueryResultPrinterOpenedOrdersNoConstraintsTest : public QueryResultPrinte TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, FormattedTable) { basicQueryResultPrinter(ApiOutputType::kFormattedTable).printOpenedOrders(openedOrdersPerExchange, ordersConstraints); static constexpr std::string_view kExpected = R"( -+----------+-----------+-------------+---------------------+------+-----------------+------------------+------------------+ -| Exchange | Account | Exchange Id | Placed time | Side | Price | Matched Amount | Remaining Amount | -+----------+-----------+-------------+---------------------+------+-----------------+------------------+------------------+ -| bithumb | testuser1 | id5 | 2002-06-23 07:58:35 | Sell | 0.00000045 USDT | 11235435435 SHIB | 11235435.59 SHIB | -| bithumb | testuser1 | id3 | 2006-07-14 23:58:24 | Buy | 1.31 USDT | 13 XRP | 500.45 XRP | -| huobi | testuser2 | id2 | 2002-06-23 07:58:35 | Sell | 1500.56 USDT | 0.56 ETH | 0.44 ETH | -| huobi | testuser1 | id1 | 1999-03-25 04:46:43 | Buy | 50000 EUR | 0 BTC | 1 BTC | -| huobi | testuser1 | id4 | 2011-10-03 06:49:36 | Sell | 1574564 KRW | 34.56 LTC | 0.4 LTC | -+----------+-----------+-------------+---------------------+------+-----------------+------------------+------------------+ ++----------+-----------+-------------+----------------------+------+-----------------+------------------+------------------+ +| Exchange | Account | Exchange Id | Placed time | Side | Price | Matched Amount | Remaining Amount | ++----------+-----------+-------------+----------------------+------+-----------------+------------------+------------------+ +| bithumb | testuser1 | id5 | 2002-06-23T07:58:35Z | Sell | 0.00000045 USDT | 11235435435 SHIB | 11235435.59 SHIB | +| bithumb | testuser1 | id3 | 2006-07-14T23:58:24Z | Buy | 1.31 USDT | 13 XRP | 500.45 XRP | +| huobi | testuser2 | id2 | 2002-06-23T07:58:35Z | Sell | 1500.56 USDT | 0.56 ETH | 0.44 ETH | +| huobi | testuser1 | id1 | 1999-03-25T04:46:43Z | Buy | 50000 EUR | 0 BTC | 1 BTC | +| huobi | testuser1 | id4 | 2011-10-03T06:49:36Z | Sell | 1574564 KRW | 34.56 LTC | 0.4 LTC | ++----------+-----------+-------------+----------------------+------+-----------------+------------------+------------------+ )"; expectStr(kExpected); } @@ -1018,7 +1018,7 @@ TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, Json) { "id": "id5", "matched": "11235435435", "pair": "SHIB-USDT", - "placedTime": "2002-06-23 07:58:35", + "placedTime": "2002-06-23T07:58:35Z", "price": "0.00000045", "remaining": "11235435.59", "side": "Sell" @@ -1027,7 +1027,7 @@ TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, Json) { "id": "id3", "matched": "13", "pair": "XRP-USDT", - "placedTime": "2006-07-14 23:58:24", + "placedTime": "2006-07-14T23:58:24Z", "price": "1.31", "remaining": "500.45", "side": "Buy" @@ -1040,7 +1040,7 @@ TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, Json) { "id": "id1", "matched": "0", "pair": "BTC-EUR", - "placedTime": "1999-03-25 04:46:43", + "placedTime": "1999-03-25T04:46:43Z", "price": "50000", "remaining": "1", "side": "Buy" @@ -1049,7 +1049,7 @@ TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, Json) { "id": "id4", "matched": "34.56", "pair": "LTC-KRW", - "placedTime": "2011-10-03 06:49:36", + "placedTime": "2011-10-03T06:49:36Z", "price": "1574564", "remaining": "0.4", "side": "Sell" @@ -1060,7 +1060,7 @@ TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, Json) { "id": "id2", "matched": "0.56", "pair": "ETH-USDT", - "placedTime": "2002-06-23 07:58:35", + "placedTime": "2002-06-23T07:58:35Z", "price": "1500.56", "remaining": "0.44", "side": "Sell" @@ -1098,15 +1098,15 @@ class QueryResultPrinterRecentDepositsNoConstraintsTest : public QueryResultPrin TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, FormattedTable) { basicQueryResultPrinter(ApiOutputType::kFormattedTable).printRecentDeposits(depositsPerExchange, constraints); static constexpr std::string_view kExpected = R"( -+----------+-----------+-------------+---------------------+-----------------+------------+ -| Exchange | Account | Exchange Id | Received time | Amount | Status | -+----------+-----------+-------------+---------------------+-----------------+------------+ -| bithumb | testuser1 | id3 | 2006-07-14 23:58:24 | 15020.67 EUR | failed | -| bithumb | testuser1 | id5 | 2011-10-03 06:49:36 | 69204866.9 DOGE | success | -| huobi | testuser2 | id2 | 2002-06-23 07:58:35 | 37 XRP | success | -| huobi | testuser1 | id1 | 1999-03-25 04:46:43 | 0.045 BTC | initial | -| huobi | testuser1 | id4 | 2011-10-03 06:49:36 | 1.31 ETH | processing | -+----------+-----------+-------------+---------------------+-----------------+------------+ ++----------+-----------+-------------+----------------------+-----------------+------------+ +| Exchange | Account | Exchange Id | Received time | Amount | Status | ++----------+-----------+-------------+----------------------+-----------------+------------+ +| bithumb | testuser1 | id3 | 2006-07-14T23:58:24Z | 15020.67 EUR | failed | +| bithumb | testuser1 | id5 | 2011-10-03T06:49:36Z | 69204866.9 DOGE | success | +| huobi | testuser2 | id2 | 2002-06-23T07:58:35Z | 37 XRP | success | +| huobi | testuser1 | id1 | 1999-03-25T04:46:43Z | 0.045 BTC | initial | +| huobi | testuser1 | id4 | 2011-10-03T06:49:36Z | 1.31 ETH | processing | ++----------+-----------+-------------+----------------------+-----------------+------------+ )"; expectStr(kExpected); } @@ -1140,14 +1140,14 @@ TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, Json) { "amount": "15020.67", "cur": "EUR", "id": "id3", - "receivedTime": "2006-07-14 23:58:24", + "receivedTime": "2006-07-14T23:58:24Z", "status": "failed" }, { "amount": "69204866.9", "cur": "DOGE", "id": "id5", - "receivedTime": "2011-10-03 06:49:36", + "receivedTime": "2011-10-03T06:49:36Z", "status": "success" } ] @@ -1158,14 +1158,14 @@ TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, Json) { "amount": "0.045", "cur": "BTC", "id": "id1", - "receivedTime": "1999-03-25 04:46:43", + "receivedTime": "1999-03-25T04:46:43Z", "status": "initial" }, { "amount": "1.31", "cur": "ETH", "id": "id4", - "receivedTime": "2011-10-03 06:49:36", + "receivedTime": "2011-10-03T06:49:36Z", "status": "processing" } ], @@ -1174,7 +1174,7 @@ TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, Json) { "amount": "37", "cur": "XRP", "id": "id2", - "receivedTime": "2002-06-23 07:58:35", + "receivedTime": "2002-06-23T07:58:35Z", "status": "success" } ] @@ -1214,15 +1214,15 @@ class QueryResultPrinterRecentWithdrawsNoConstraintsTest : public QueryResultPri TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, FormattedTable) { basicQueryResultPrinter(ApiOutputType::kFormattedTable).printRecentWithdraws(withdrawsPerExchange, constraints); static constexpr std::string_view kExpected = R"( -+----------+-----------+-------------+---------------------+--------------------+-------------+------------+ -| Exchange | Account | Exchange Id | Sent time | Net Emitted Amount | Fee | Status | -+----------+-----------+-------------+---------------------+--------------------+-------------+------------+ -| bithumb | testuser1 | id3 | 1999-03-25 04:46:43 | 15020.67 EUR | 0.1 EUR | failed | -| bithumb | testuser1 | id5 | 2002-06-23 07:58:35 | 69204866.9 DOGE | 2 DOGE | success | -| huobi | testuser2 | id2 | 2011-10-03 06:49:36 | 37 XRP | 0.02 XRP | success | -| huobi | testuser1 | id4 | 2002-06-23 07:58:35 | 1.31 ETH | 0.001 ETH | processing | -| huobi | testuser1 | id1 | 2006-07-14 23:58:24 | 0.045 BTC | 0.00001 BTC | initial | -+----------+-----------+-------------+---------------------+--------------------+-------------+------------+ ++----------+-----------+-------------+----------------------+--------------------+-------------+------------+ +| Exchange | Account | Exchange Id | Sent time | Net Emitted Amount | Fee | Status | ++----------+-----------+-------------+----------------------+--------------------+-------------+------------+ +| bithumb | testuser1 | id3 | 1999-03-25T04:46:43Z | 15020.67 EUR | 0.1 EUR | failed | +| bithumb | testuser1 | id5 | 2002-06-23T07:58:35Z | 69204866.9 DOGE | 2 DOGE | success | +| huobi | testuser2 | id2 | 2011-10-03T06:49:36Z | 37 XRP | 0.02 XRP | success | +| huobi | testuser1 | id4 | 2002-06-23T07:58:35Z | 1.31 ETH | 0.001 ETH | processing | +| huobi | testuser1 | id1 | 2006-07-14T23:58:24Z | 0.045 BTC | 0.00001 BTC | initial | ++----------+-----------+-------------+----------------------+--------------------+-------------+------------+ )"; expectStr(kExpected); } @@ -1257,7 +1257,7 @@ TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, Json) { "fee": "0.1", "id": "id3", "netEmittedAmount": "15020.67", - "sentTime": "1999-03-25 04:46:43", + "sentTime": "1999-03-25T04:46:43Z", "status": "failed" }, { @@ -1265,7 +1265,7 @@ TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, Json) { "fee": "2", "id": "id5", "netEmittedAmount": "69204866.9", - "sentTime": "2002-06-23 07:58:35", + "sentTime": "2002-06-23T07:58:35Z", "status": "success" } ] @@ -1277,7 +1277,7 @@ TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, Json) { "fee": "0.001", "id": "id4", "netEmittedAmount": "1.31", - "sentTime": "2002-06-23 07:58:35", + "sentTime": "2002-06-23T07:58:35Z", "status": "processing" }, { @@ -1285,7 +1285,7 @@ TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, Json) { "fee": "0.00001", "id": "id1", "netEmittedAmount": "0.045", - "sentTime": "2006-07-14 23:58:24", + "sentTime": "2006-07-14T23:58:24Z", "status": "initial" } ], @@ -1295,7 +1295,7 @@ TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, Json) { "fee": "0.02", "id": "id2", "netEmittedAmount": "37", - "sentTime": "2011-10-03 06:49:36", + "sentTime": "2011-10-03T06:49:36Z", "status": "success" } ] @@ -1412,11 +1412,11 @@ TEST_F(QueryResultPrinterWithdrawAmountTest, FormattedTable) { basicQueryResultPrinter(ApiOutputType::kFormattedTable) .printWithdraw(deliveredWithdrawInfoWithExchanges, isPercentageWithdraw, withdrawOptions); static constexpr std::string_view kExpected = R"( -+---------------+--------------+-----------------------+---------------------+-------------+------------+---------------------+---------------------+ -| From Exchange | From Account | Gross withdraw amount | Initiated time | To Exchange | To Account | Net received amount | Received time | -+---------------+--------------+-----------------------+---------------------+-------------+------------+---------------------+---------------------+ -| binance | testuser1 | 76.55 XRP | 1999-03-25 04:46:43 | huobi | testuser2 | 75.55 XRP | 2002-06-23 07:58:35 | -+---------------+--------------+-----------------------+---------------------+-------------+------------+---------------------+---------------------+ ++---------------+--------------+-----------------------+----------------------+-------------+------------+---------------------+----------------------+ +| From Exchange | From Account | Gross withdraw amount | Initiated time | To Exchange | To Account | Net received amount | Received time | ++---------------+--------------+-----------------------+----------------------+-------------+------------+---------------------+----------------------+ +| binance | testuser1 | 76.55 XRP | 1999-03-25T04:46:43Z | huobi | testuser2 | 75.55 XRP | 2002-06-23T07:58:35Z | ++---------------+--------------+-----------------------+----------------------+-------------+------------+---------------------+----------------------+ )"; expectStr(kExpected); } @@ -1440,9 +1440,9 @@ TEST_F(QueryResultPrinterWithdrawAmountTest, Json) { "account": "testuser1", "exchange": "binance" }, - "initiatedTime": "1999-03-25 04:46:43", + "initiatedTime": "1999-03-25T04:46:43Z", "netReceivedAmount": "75.55", - "receivedTime": "2002-06-23 07:58:35", + "receivedTime": "2002-06-23T07:58:35Z", "to": { "account": "testuser2", "address": "xrpaddress666", @@ -1469,11 +1469,11 @@ TEST_F(QueryResultPrinterWithdrawPercentageTest, FormattedTable) { basicQueryResultPrinter(ApiOutputType::kFormattedTable) .printWithdraw(deliveredWithdrawInfoWithExchanges, isPercentageWithdraw, withdrawOptions); static constexpr std::string_view kExpected = R"( -+---------------+--------------+-----------------------+---------------------+-------------+------------+---------------------+---------------------+ -| From Exchange | From Account | Gross withdraw amount | Initiated time | To Exchange | To Account | Net received amount | Received time | -+---------------+--------------+-----------------------+---------------------+-------------+------------+---------------------+---------------------+ -| binance | testuser1 | 76.55 XRP | 1999-03-25 04:46:43 | huobi | testuser2 | 75.55 XRP | 2002-06-23 07:58:35 | -+---------------+--------------+-----------------------+---------------------+-------------+------------+---------------------+---------------------+ ++---------------+--------------+-----------------------+----------------------+-------------+------------+---------------------+----------------------+ +| From Exchange | From Account | Gross withdraw amount | Initiated time | To Exchange | To Account | Net received amount | Received time | ++---------------+--------------+-----------------------+----------------------+-------------+------------+---------------------+----------------------+ +| binance | testuser1 | 76.55 XRP | 1999-03-25T04:46:43Z | huobi | testuser2 | 75.55 XRP | 2002-06-23T07:58:35Z | ++---------------+--------------+-----------------------+----------------------+-------------+------------+---------------------+----------------------+ )"; expectStr(kExpected); } @@ -1497,9 +1497,9 @@ TEST_F(QueryResultPrinterWithdrawPercentageTest, Json) { "account": "testuser1", "exchange": "binance" }, - "initiatedTime": "1999-03-25 04:46:43", + "initiatedTime": "1999-03-25T04:46:43Z", "netReceivedAmount": "75.55", - "receivedTime": "2002-06-23 07:58:35", + "receivedTime": "2002-06-23T07:58:35Z", "to": { "account": "testuser2", "address": "xrpaddress666", diff --git a/src/engine/test/queryresultprinter_public_test.cpp b/src/engine/test/queryresultprinter_public_test.cpp index fdf06244..e73af89c 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, {}}}; }; @@ -557,7 +558,8 @@ TEST_F(QueryResultPrinterMarketOrderBookTest, Json) { "a": "0.0635", "p": "31056.63" } - ] + ], + "time": "1999-03-25T04:46:43Z" }, "exchangeD": { "ask": [ @@ -587,7 +589,8 @@ TEST_F(QueryResultPrinterMarketOrderBookTest, Json) { "a": "0.0635", "p": "31056.63" } - ] + ], + "time": "1999-03-25T04:46:43Z" } } })"; @@ -815,28 +818,28 @@ TEST_F(QueryResultPrinterLastTradesVolumeTest, FormattedTable) { .printLastTrades(marketLastTrades, nbLastTrades, lastTradesPerExchange); static constexpr std::string_view kExpected = R"( +----------------------+--------------------+--------------------------+-------------------+ -| binance trades - UTC | ETH buys | Price in USDT | ETH sells | +| binance trades | ETH buys | Price in USDT | ETH sells | +----------------------+--------------------+--------------------------+-------------------+ -| 1999-03-25 04:46:43 | 0.13 | 1500.5 | | -| 2002-06-23 07:58:35 | | 1500.5 | 3.7 | -| 2006-07-14 23:58:24 | 0.004 | 1501 | | +| 1999-03-25T04:46:43Z | 0.13 | 1500.5 | | +| 2002-06-23T07:58:35Z | | 1500.5 | 3.7 | +| 2006-07-14T23:58:24Z | 0.004 | 1501 | | +----------------------+--------------------+--------------------------+-------------------+ | Summary | 0.134 ETH (2 buys) | 1500.66666666666666 USDT | 3.7 ETH (1 sells) | +----------------------+--------------------+--------------------------+-------------------+ -+---------------------+--------------------+---------------+--------------------+ -| huobi trades - UTC | ETH buys | Price in USDT | ETH sells | -+---------------------+--------------------+---------------+--------------------+ -| 2011-10-03 06:49:36 | | 1500.5 | 0.13 | -| 2002-06-23 07:58:35 | 0.004 | 1501 | | -+---------------------+--------------------+---------------+--------------------+ -| Summary | 0.004 ETH (1 buys) | 1500.75 USDT | 0.13 ETH (1 sells) | -+---------------------+--------------------+---------------+--------------------+ ++----------------------+--------------------+---------------+--------------------+ +| huobi trades | ETH buys | Price in USDT | ETH sells | ++----------------------+--------------------+---------------+--------------------+ +| 2011-10-03T06:49:36Z | | 1500.5 | 0.13 | +| 2002-06-23T07:58:35Z | 0.004 | 1501 | | ++----------------------+--------------------+---------------+--------------------+ +| Summary | 0.004 ETH (1 buys) | 1500.75 USDT | 0.13 ETH (1 sells) | ++----------------------+--------------------+---------------+--------------------+ +----------------------+---------------------+--------------------------+--------------------+ -| bithumb trades - UTC | ETH buys | Price in USDT | ETH sells | +| bithumb trades | ETH buys | Price in USDT | ETH sells | +----------------------+---------------------+--------------------------+--------------------+ -| 2011-10-03 06:49:36 | | 1500.5 | 0.13 | -| 2002-06-23 07:58:35 | 0.004 | 1501 | | -| 1999-03-25 04:46:43 | 47.78 | 1498 | | +| 2011-10-03T06:49:36Z | | 1500.5 | 0.13 | +| 2002-06-23T07:58:35Z | 0.004 | 1501 | | +| 1999-03-25T04:46:43Z | 47.78 | 1498 | | +----------------------+---------------------+--------------------------+--------------------+ | Summary | 47.784 ETH (2 buys) | 1499.83333333333333 USDT | 0.13 ETH (1 sells) | +----------------------+---------------------+--------------------------+--------------------+ @@ -878,19 +881,19 @@ TEST_F(QueryResultPrinterLastTradesVolumeTest, Json) { "a": "0.13", "p": "1500.5", "side": "Buy", - "time": "1999-03-25 04:46:43" + "time": "1999-03-25T04:46:43Z" }, { "a": "3.7", "p": "1500.5", "side": "Sell", - "time": "2002-06-23 07:58:35" + "time": "2002-06-23T07:58:35Z" }, { "a": "0.004", "p": "1501", "side": "Buy", - "time": "2006-07-14 23:58:24" + "time": "2006-07-14T23:58:24Z" } ], "bithumb": [ @@ -898,19 +901,19 @@ TEST_F(QueryResultPrinterLastTradesVolumeTest, Json) { "a": "0.13", "p": "1500.5", "side": "Sell", - "time": "2011-10-03 06:49:36" + "time": "2011-10-03T06:49:36Z" }, { "a": "0.004", "p": "1501", "side": "Buy", - "time": "2002-06-23 07:58:35" + "time": "2002-06-23T07:58:35Z" }, { "a": "47.78", "p": "1498", "side": "Buy", - "time": "1999-03-25 04:46:43" + "time": "1999-03-25T04:46:43Z" } ], "huobi": [ @@ -918,13 +921,13 @@ TEST_F(QueryResultPrinterLastTradesVolumeTest, Json) { "a": "0.13", "p": "1500.5", "side": "Sell", - "time": "2011-10-03 06:49:36" + "time": "2011-10-03T06:49:36Z" }, { "a": "0.004", "p": "1501", "side": "Buy", - "time": "2002-06-23 07:58:35" + "time": "2002-06-23T07:58:35Z" } ] } diff --git a/src/objects/include/marketorderbook.hpp b/src/objects/include/marketorderbook.hpp index ea9a3184..3effc2ab 100644 --- a/src/objects/include/marketorderbook.hpp +++ b/src/objects/include/marketorderbook.hpp @@ -8,6 +8,7 @@ #include "market.hpp" #include "monetaryamount.hpp" #include "simpletable.hpp" +#include "timedef.hpp" #include "volumeandpricenbdecimals.hpp" namespace cct { @@ -44,16 +45,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; } @@ -214,12 +218,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/src/marketorderbook.cpp b/src/objects/src/marketorderbook.cpp index 749546b4..f8ac4d21 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); } diff --git a/src/tech/include/timestring.hpp b/src/tech/include/timestring.hpp index 9d37f144..54f18f85 100644 --- a/src/tech/include/timestring.hpp +++ b/src/tech/include/timestring.hpp @@ -11,17 +11,19 @@ static constexpr const char* const kTimeYearToSecondSpaceSeparatedFormat = "%Y-% static constexpr const char* const kTimeYearToSecondTSeparatedFormat = "%Y-%m-%dT%H:%M:%S"; +static constexpr const char* const kTimeYearToSecondTSeparatedFormatUTC = "%Y-%m-%dT%H:%M:%SZ"; + /// Nonce represents an increasing value only over time - in string format. /// Mostly for documentation purposes using Nonce = string; -/// Get a string representation of a given time point. +/// Get a string representation of a given time point, printed in UTC ISO 8061 format by default. /// 'format' specifies the string style, with the default argument value given as example: /// 'YYYY-MM-DD HH:MM:SS' -string ToString(TimePoint timePoint, const char* format = kTimeYearToSecondSpaceSeparatedFormat); +string ToString(TimePoint timePoint, const char* format = kTimeYearToSecondTSeparatedFormatUTC); /// Parse a string representation of a given time point and return a time_point. -TimePoint FromString(std::string_view timeStr, const char* format = kTimeYearToSecondSpaceSeparatedFormat); +TimePoint FromString(std::string_view timeStr, const char* format = kTimeYearToSecondTSeparatedFormatUTC); /// Create a Nonce as the number of milliseconds since Epoch time in string format. Nonce Nonce_TimeSinceEpochInMs(Duration delay = Duration{}); diff --git a/src/tech/src/timestring.cpp b/src/tech/src/timestring.cpp index eb2e52e2..1a460f97 100644 --- a/src/tech/src/timestring.cpp +++ b/src/tech/src/timestring.cpp @@ -18,8 +18,7 @@ string ToString(TimePoint timePoint, const char* format) { const std::time_t time = Clock::to_time_t(timePoint); std::tm utc{}; #ifdef CCT_MSVC - errno_t err = gmtime_s(&utc, &time); - if (err) { + if (gmtime_s(&utc, &time)) { throw exception("Issue in gmtime_s"); } const std::tm* pUtc = &utc;