Skip to content

Commit

Permalink
Market Order books objects are enriched with timestamp. Also set UTC …
Browse files Browse the repository at this point in the history
…time string as default
  • Loading branch information
sjanel committed Feb 10, 2024
1 parent 025577c commit b4d652a
Show file tree
Hide file tree
Showing 19 changed files with 193 additions and 159 deletions.
4 changes: 4 additions & 0 deletions src/api-objects/include/publictrade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <compare>

#include "cct_string.hpp"
#include "market.hpp"
#include "monetaryamount.hpp"
#include "timedef.hpp"
#include "tradeside.hpp"
Expand All @@ -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; }
Expand Down
11 changes: 6 additions & 5 deletions src/api/common/test/exchangeprivateapi_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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};

Expand Down
7 changes: 4 additions & 3 deletions src/api/common/test/exchangepublicapi_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
5 changes: 3 additions & 2 deletions src/api/exchanges/src/binancepublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -467,7 +468,7 @@ MarketOrderBookMap BinancePublic::AllOrderBooksFunc::operator()(int depth) {
MonetaryAmount askVol(tickerDetails["askQty"].get<std::string_view>(), mk.base());
MonetaryAmount bidVol(tickerDetails["bidQty"].get<std::string_view>(), 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));
}

Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion src/api/exchanges/src/bithumbpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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;
}
Expand Down
8 changes: 5 additions & 3 deletions src/api/exchanges/src/huobipublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string_view>());
auto it = huobiAssetPairToStdMarketMap.find(upperMarket);
if (it == huobiAssetPairToStdMarketMap.end()) {
Expand All @@ -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());
Expand Down Expand Up @@ -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) {
Expand Down
6 changes: 4 additions & 2 deletions src/api/exchanges/src/krakenpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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));
}
}

Expand Down Expand Up @@ -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) {
Expand Down
7 changes: 4 additions & 3 deletions src/api/exchanges/src/kucoinpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ std::optional<MonetaryAmount> 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;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion src/api/exchanges/src/upbitpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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::string_view>();
std::size_t dashPos = marketStr.find('-');
Expand Down Expand Up @@ -211,7 +212,7 @@ MarketOrderBookMap ParseOrderBooks(const json& result, int depth) {
if (static_cast<int>(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;
Expand Down
6 changes: 4 additions & 2 deletions src/engine/src/queryresultprinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -833,7 +835,7 @@ void QueryResultPrinter::printTickerInformation(const ExchangeTickerMaps &exchan
void QueryResultPrinter::printMarketOrderBooks(
Market mk, CurrencyCode equiCurrencyCode, std::optional<int> 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) {
Expand Down Expand Up @@ -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<MonetaryAmount, 2> totalAmounts{MonetaryAmount(0, mk.base()), MonetaryAmount(0, mk.base())};
Expand Down
16 changes: 11 additions & 5 deletions src/engine/test/exchangedata_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "exchange.hpp"
#include "exchangeprivateapi_mock.hpp"
#include "exchangepublicapi_mock.hpp"
#include "timedef.hpp"

namespace cct {

Expand Down Expand Up @@ -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"),
Expand All @@ -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"),
Expand All @@ -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")};
Expand Down
10 changes: 7 additions & 3 deletions src/engine/test/exchangesorchestrator_trade_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit b4d652a

Please sign in to comment.