From d8b18e4ec9dd0163268e341fc2e460a2390fc63f Mon Sep 17 00:00:00 2001 From: Stephane Janel Date: Wed, 16 Oct 2024 22:56:50 +0200 Subject: [PATCH] Rename json into json::container. Migrate generalconfig to glaze::json --- src/api-objects/src/apikeysprovider.cpp | 4 +- src/api/common/include/binance-common-api.hpp | 6 +- src/api/common/src/binance-common-api.cpp | 34 +- src/api/common/src/commonapi.cpp | 12 +- src/api/common/src/fiatconverter.cpp | 14 +- src/api/common/src/withdrawalfees-crawler.cpp | 14 +- .../common/test/exchangepublicapi_test.cpp | 4 +- src/api/common/test/fiatconverter_test.cpp | 4 +- src/api/common/test/ssl_sha_test.cpp | 1 - .../exchanges/include/binancepublicapi.hpp | 4 +- .../exchanges/include/bithumbprivateapi.hpp | 2 +- .../exchanges/include/bithumbpublicapi.hpp | 2 +- src/api/exchanges/include/huobiprivateapi.hpp | 2 +- src/api/exchanges/include/huobipublicapi.hpp | 6 +- .../exchanges/include/krakenprivateapi.hpp | 4 +- .../exchanges/include/kucoinprivateapi.hpp | 2 +- src/api/exchanges/src/binanceprivateapi.cpp | 105 +-- src/api/exchanges/src/binancepublicapi.cpp | 61 +- src/api/exchanges/src/bithumbprivateapi.cpp | 111 +-- src/api/exchanges/src/bithumbpublicapi.cpp | 45 +- src/api/exchanges/src/huobiprivateapi.cpp | 65 +- src/api/exchanges/src/huobipublicapi.cpp | 56 +- src/api/exchanges/src/krakenprivateapi.cpp | 28 +- src/api/exchanges/src/krakenpublicapi.cpp | 36 +- src/api/exchanges/src/kucoinprivateapi.cpp | 54 +- src/api/exchanges/src/kucoinpublicapi.cpp | 36 +- src/api/exchanges/src/upbitprivateapi.cpp | 62 +- src/api/exchanges/src/upbitpublicapi.cpp | 38 +- .../include/apioutputtype.hpp | 16 +- .../include/coincentercommandtype.hpp | 62 ++ src/basic-objects/include/currencycode.hpp | 20 +- src/basic-objects/include/file.hpp | 5 +- .../include/generic-object-json.hpp | 46 ++ src/basic-objects/include/market.hpp | 18 +- src/basic-objects/include/monetaryamount.hpp | 18 +- src/basic-objects/include/reader.hpp | 4 +- src/basic-objects/include/writer.hpp | 14 +- .../src/apioutputtype.cpp | 6 +- .../src/coincentercommandtype.cpp | 19 +- src/basic-objects/src/file.cpp | 19 +- src/basic-objects/src/market.cpp | 9 +- src/basic-objects/src/reader.cpp | 6 +- src/basic-objects/src/writer.cpp | 17 + src/basic-objects/test/currencycode_test.cpp | 68 +- .../test/monetaryamount_test.cpp | 26 +- .../include/balanceperexchangeportfolio.hpp | 4 +- src/engine/include/coincenterinfo_create.hpp | 1 + src/engine/include/exchangesorchestrator.hpp | 7 +- src/engine/include/queryresultprinter.hpp | 12 +- .../src/balanceperexchangeportfolio.cpp | 18 +- .../src/coincenter-commands-iterator.cpp | 2 +- .../src/coincenter-commands-processor.cpp | 54 +- src/engine/src/coincenter.cpp | 12 +- src/engine/src/coincentercommand.cpp | 22 +- src/engine/src/coincentercommandfactory.cpp | 6 +- src/engine/src/coincentercommands.cpp | 42 +- src/engine/src/coincenterinfo_create.cpp | 52 +- src/engine/src/coincenteroptions.cpp | 10 +- src/engine/src/exchangesorchestrator.cpp | 7 +- src/engine/src/queryresultprinter.cpp | 651 +++++++++--------- src/engine/src/transferablecommandresult.cpp | 4 +- .../test/coincentercommandfactory_test.cpp | 46 +- src/engine/test/coincenteroptions_test.cpp | 11 +- .../exchangesorchestrator_private_test.cpp | 3 +- .../exchangesorchestrator_public_test.cpp | 3 +- .../test/exchangesorchestrator_trade_test.cpp | 3 +- .../test/queryresultprinter_base_test.hpp | 11 +- .../test/queryresultprinter_private_test.cpp | 136 ++-- .../test/queryresultprinter_public_test.cpp | 140 ++-- .../test/transferablecommandresult_test.cpp | 28 +- src/http-request/include/curloptions.hpp | 4 +- src/http-request/include/request-retry.hpp | 13 +- src/objects/include/coincentercommandtype.hpp | 46 -- src/objects/include/coincenterinfo.hpp | 20 +- src/objects/include/exchangeconfigmap.hpp | 4 +- src/objects/include/exchangeconfigparser.hpp | 13 +- src/objects/include/generalconfig.hpp | 43 -- src/objects/include/generalconfigdefault.hpp | 55 -- src/objects/include/logginginfo.hpp | 4 +- src/objects/include/requestsconfig.hpp | 15 - src/objects/include/trading-config.hpp | 19 - src/objects/src/coincenterinfo.cpp | 18 +- src/objects/src/exchangeconfigdefault.hpp | 10 +- src/objects/src/exchangeconfigmap.cpp | 12 +- src/objects/src/exchangeconfigparser.cpp | 17 +- src/objects/src/generalconfig.cpp | 45 -- src/objects/src/logginginfo.cpp | 31 +- src/objects/src/requestsconfig.cpp | 18 - src/objects/src/wallet.cpp | 5 +- src/objects/test/coincenterinfo_test.cpp | 7 +- src/objects/test/logginginfo_test.cpp | 4 +- src/objects/test/writer_mock.hpp | 2 +- src/schema/CMakeLists.txt | 21 + src/schema/include/deposit-addresses.hpp | 6 +- src/schema/include/duration-schema.hpp | 75 ++ src/schema/include/general-config.hpp | 32 + src/schema/include/log-config.hpp | 29 + src/schema/include/read-json.hpp | 31 +- src/schema/include/requests-config.hpp | 13 + src/schema/include/size-bytes-schema.hpp | 72 ++ src/schema/include/trading-config.hpp | 28 + src/schema/include/write-json.hpp | 24 + src/schema/src/deposit-addresses.cpp | 13 +- src/schema/src/general-config.cpp | 15 + src/schema/test/deposit-addresses_test.cpp | 3 + src/schema/test/duration-schema_test.cpp | 75 ++ src/schema/test/general-config_test.cpp | 58 ++ src/schema/test/size-bytes-schema_test.cpp | 71 ++ src/tech/include/cct_json-container.hpp | 17 + src/tech/include/cct_json-serialization.hpp | 10 +- src/tech/include/cct_json.hpp | 17 - src/tech/include/durationstring.hpp | 4 + src/tech/include/stringconv.hpp | 13 + src/tech/include/unitsparser.hpp | 6 + src/tech/src/durationstring.cpp | 45 +- src/tech/src/unitsparser.cpp | 108 ++- src/tech/test/durationstring_test.cpp | 37 + src/tech/test/unitsparser_test.cpp | 23 + 118 files changed, 2157 insertions(+), 1564 deletions(-) rename src/{objects => basic-objects}/include/apioutputtype.hpp (61%) create mode 100644 src/basic-objects/include/coincentercommandtype.hpp create mode 100644 src/basic-objects/include/generic-object-json.hpp rename src/{objects => basic-objects}/src/apioutputtype.cpp (81%) rename src/{objects => basic-objects}/src/coincentercommandtype.cpp (61%) create mode 100644 src/basic-objects/src/writer.cpp delete mode 100644 src/objects/include/coincentercommandtype.hpp delete mode 100644 src/objects/include/generalconfig.hpp delete mode 100644 src/objects/include/generalconfigdefault.hpp delete mode 100644 src/objects/include/requestsconfig.hpp delete mode 100644 src/objects/include/trading-config.hpp delete mode 100644 src/objects/src/generalconfig.cpp delete mode 100644 src/objects/src/requestsconfig.cpp create mode 100644 src/schema/include/duration-schema.hpp create mode 100644 src/schema/include/general-config.hpp create mode 100644 src/schema/include/log-config.hpp create mode 100644 src/schema/include/requests-config.hpp create mode 100644 src/schema/include/size-bytes-schema.hpp create mode 100644 src/schema/include/trading-config.hpp create mode 100644 src/schema/include/write-json.hpp create mode 100644 src/schema/src/general-config.cpp create mode 100644 src/schema/test/duration-schema_test.cpp create mode 100644 src/schema/test/general-config_test.cpp create mode 100644 src/schema/test/size-bytes-schema_test.cpp create mode 100644 src/tech/include/cct_json-container.hpp delete mode 100644 src/tech/include/cct_json.hpp diff --git a/src/api-objects/src/apikeysprovider.cpp b/src/api-objects/src/apikeysprovider.cpp index f73dafb6..7d5e23d1 100644 --- a/src/api-objects/src/apikeysprovider.cpp +++ b/src/api-objects/src/apikeysprovider.cpp @@ -8,7 +8,7 @@ #include "accountowner.hpp" #include "apikey.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "exchangename.hpp" @@ -81,7 +81,7 @@ APIKeysProvider::APIKeysMap APIKeysProvider::ParseAPIKeys(std::string_view dataD std::string_view secretFileName = GetSecretFileName(runMode); File secretsFile(dataDir, File::Type::kSecret, secretFileName, settings::AreTestKeysRequested(runMode) ? File::IfError::kThrow : File::IfError::kNoThrow); - json jsonData = secretsFile.readAllJson(); + json::container jsonData = secretsFile.readAllJson(); for (auto& [publicExchangeName, keyObj] : jsonData.items()) { const auto& exchangesWithoutSecrets = exchangeSecretsInfo.exchangesWithoutSecrets(); if (std::ranges::find(exchangesWithoutSecrets, ExchangeName(publicExchangeName)) != diff --git a/src/api/common/include/binance-common-api.hpp b/src/api/common/include/binance-common-api.hpp index 4cba3165..1b4e2435 100644 --- a/src/api/common/include/binance-common-api.hpp +++ b/src/api/common/include/binance-common-api.hpp @@ -3,7 +3,7 @@ #include #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "curlhandle.hpp" #include "currencycode.hpp" #include "currencycodeset.hpp" @@ -25,7 +25,7 @@ class BinanceGlobalInfosFunc { BinanceGlobalInfosFunc(AbstractMetricGateway* pMetricGateway, const PermanentCurlOptions& permanentCurlOptions, settings::RunMode runMode); - json operator()(); + json::container operator()(); private: CurlHandle _curlHandle; @@ -45,7 +45,7 @@ class BinanceGlobalInfos { private: friend class BinancePrivate; - static CurrencyExchangeFlatSet ExtractTradableCurrencies(const json& allCoins, + static CurrencyExchangeFlatSet ExtractTradableCurrencies(const json::container& allCoins, const CurrencyCodeSet& excludedCurrencies); std::mutex _mutex; diff --git a/src/api/common/src/binance-common-api.cpp b/src/api/common/src/binance-common-api.cpp index 1cc78dd3..05115fbc 100644 --- a/src/api/common/src/binance-common-api.cpp +++ b/src/api/common/src/binance-common-api.cpp @@ -8,7 +8,7 @@ #include "abstractmetricgateway.hpp" #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "curlhandle.hpp" #include "currencycode.hpp" @@ -27,15 +27,15 @@ namespace cct::api { namespace { -json PublicQuery(CurlHandle& curlHandle, std::string_view method) { +json::container PublicQuery(CurlHandle& curlHandle, std::string_view method) { RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet)); - return requestRetry.queryJson(method, [](const json& jsonResponse) { + return requestRetry.queryJson(method, [](const json::container& jsonResponse) { const auto foundErrorIt = jsonResponse.find("code"); const auto foundMsgIt = jsonResponse.find("msg"); if (foundErrorIt != jsonResponse.end() && foundMsgIt != jsonResponse.end()) { const int statusCode = foundErrorIt->get(); // "1100" for instance - log::warn("Binance error ({}), full json: '{}'", statusCode, jsonResponse.dump()); + log::warn("Binance error ({}), full: '{}'", statusCode, jsonResponse.dump()); return RequestRetry::Status::kResponseError; } return RequestRetry::Status::kResponseOK; @@ -50,18 +50,18 @@ BinanceGlobalInfosFunc::BinanceGlobalInfosFunc(AbstractMetricGateway* pMetricGat settings::RunMode runMode) : _curlHandle(kCryptoFeeBaseUrl, pMetricGateway, permanentCurlOptions, runMode) {} -json BinanceGlobalInfosFunc::operator()() { - json ret = PublicQuery(_curlHandle, "/bapi/capital/v1/public/capital/getNetworkCoinAll"); +json::container BinanceGlobalInfosFunc::operator()() { + json::container ret = PublicQuery(_curlHandle, "/bapi/capital/v1/public/capital/getNetworkCoinAll"); auto dataIt = ret.find("data"); - json dataRet; + json::container dataRet; if (dataIt == ret.end() || !dataIt->is_array()) { log::error("Unexpected reply from binance getNetworkCoinAll, no data array"); - dataRet = json::array_t(); + dataRet = json::container::array_t(); } else { dataRet = std::move(*dataIt); } - const auto endIt = std::remove_if(dataRet.begin(), dataRet.end(), [](const json& el) { + const auto endIt = std::remove_if(dataRet.begin(), dataRet.end(), [](const json::container& el) { return el["coin"].get().size() > CurrencyCode::kMaxLen; }); @@ -70,21 +70,21 @@ json BinanceGlobalInfosFunc::operator()() { dataRet.erase(endIt, dataRet.end()); } - std::sort(dataRet.begin(), dataRet.end(), [](const json& lhs, const json& rhs) { + std::sort(dataRet.begin(), dataRet.end(), [](const json::container& lhs, const json::container& rhs) { return lhs["coin"].get() < rhs["coin"].get(); }); return dataRet; } namespace { -MonetaryAmount ComputeWithdrawalFeesFromNetworkList(CurrencyCode cur, const json& coinElem) { +MonetaryAmount ComputeWithdrawalFeesFromNetworkList(CurrencyCode cur, const json::container& coinElem) { MonetaryAmount withdrawFee(0, cur); auto networkListIt = coinElem.find("networkList"); if (networkListIt == coinElem.end()) { log::error("Unexpected Binance public coin data format, returning 0 monetary amount"); return withdrawFee; } - for (const json& networkListPart : *networkListIt) { + for (const json::container& networkListPart : *networkListIt) { MonetaryAmount fee(networkListPart["withdrawFee"].get(), cur); auto isDefaultIt = networkListPart.find("isDefault"); if (isDefaultIt != networkListPart.end() && isDefaultIt->get()) { @@ -109,7 +109,7 @@ MonetaryAmountByCurrencySet BinanceGlobalInfos::queryWithdrawalFees() { fees.reserve(allCoins.size()); - std::transform(allCoins.begin(), allCoins.end(), std::back_inserter(fees), [](const json& el) { + std::transform(allCoins.begin(), allCoins.end(), std::back_inserter(fees), [](const json::container& el) { CurrencyCode cur(el["coin"].get()); return ComputeWithdrawalFeesFromNetworkList(cur, el); }); @@ -123,7 +123,7 @@ MonetaryAmount BinanceGlobalInfos::queryWithdrawalFee(CurrencyCode currencyCode) const auto& allCoins = _globalInfosCache.get(); const auto curStr = currencyCode.str(); - const auto it = std::partition_point(allCoins.begin(), allCoins.end(), [&curStr](const json& el) { + const auto it = std::partition_point(allCoins.begin(), allCoins.end(), [&curStr](const json::container& el) { return el["coin"].get() < curStr; }); if (it != allCoins.end() && (*it)["coin"].get() == curStr) { @@ -137,10 +137,10 @@ CurrencyExchangeFlatSet BinanceGlobalInfos::queryTradableCurrencies(const Curren return ExtractTradableCurrencies(_globalInfosCache.get(), excludedCurrencies); } -CurrencyExchangeFlatSet BinanceGlobalInfos::ExtractTradableCurrencies(const json& allCoins, +CurrencyExchangeFlatSet BinanceGlobalInfos::ExtractTradableCurrencies(const json::container& allCoins, const CurrencyCodeSet& excludedCurrencies) { CurrencyExchangeVector currencies; - for (const json& coinJson : allCoins) { + for (const json::container& coinJson : allCoins) { CurrencyCode cur(coinJson["coin"].get()); if (excludedCurrencies.contains(cur)) { log::trace("Discard {} excluded by config", cur.str()); @@ -152,7 +152,7 @@ CurrencyExchangeFlatSet BinanceGlobalInfos::ExtractTradableCurrencies(const json log::debug("Several networks found for {}, considering only default network", cur.str()); } const auto it = std::find_if(networkList.begin(), networkList.end(), - [](const json& el) { return el["isDefault"].get(); }); + [](const json::container& el) { return el["isDefault"].get(); }); if (it != networkList.end()) { auto deposit = (*it)["depositEnable"].get() ? CurrencyExchange::Deposit::kAvailable : CurrencyExchange::Deposit::kUnavailable; diff --git a/src/api/common/src/commonapi.cpp b/src/api/common/src/commonapi.cpp index 1a63ca81..9d81eff1 100644 --- a/src/api/common/src/commonapi.cpp +++ b/src/api/common/src/commonapi.cpp @@ -7,7 +7,7 @@ #include #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -44,13 +44,13 @@ CommonAPI::CommonAPI(const CoincenterInfo& coincenterInfo, Duration fiatsUpdateF coincenterInfo.getRunMode()), _withdrawalFeesCrawler(coincenterInfo, withdrawalFeesUpdateFrequency, _cachedResultVault) { if (atInit == AtInit::kLoadFromFileCache) { - json data = GetFiatCacheFile(_coincenterInfo.dataDir()).readAllJson(); + json::container data = GetFiatCacheFile(_coincenterInfo.dataDir()).readAllJson(); if (!data.empty()) { int64_t timeEpoch = data["timeepoch"].get(); auto& fiatsFile = data["fiats"]; CurrencyCodeSet fiats; fiats.reserve(static_cast(fiatsFile.size())); - for (json& val : fiatsFile) { + for (json::container& val : fiatsFile) { log::trace("Reading fiat {} from cache file", val.get()); fiats.emplace_hint(fiats.end(), std::move(val.get_ref())); } @@ -138,12 +138,12 @@ CurrencyCodeVector CommonAPI::FiatsFunc::retrieveFiatsSource1() { return fiatsVec; } static constexpr bool kAllowExceptions = false; - json dataCSV = json::parse(data, nullptr, kAllowExceptions); + json::container dataCSV = json::container::parse(data, nullptr, kAllowExceptions); if (dataCSV.is_discarded()) { log::warn("Error parsing json data of currency codes from source 1"); return fiatsVec; } - for (const json& fiatData : dataCSV) { + for (const json::container& fiatData : dataCSV) { static constexpr std::string_view kCodeKey = "AlphabeticCode"; static constexpr std::string_view kWithdrawalDateKey = "WithdrawalDate"; @@ -216,7 +216,7 @@ void CommonAPI::updateCacheFile() const { data["fiats"].emplace_back(fiatCode.str()); } data["timeepoch"] = TimestampToSecondsSinceEpoch(fiatsPtrLastUpdatedTimePair.second); - fiatsCacheFile.write(data); + fiatsCacheFile.writeJson(data); } _withdrawalFeesCrawler.updateCacheFile(); diff --git a/src/api/common/src/fiatconverter.cpp b/src/api/common/src/fiatconverter.cpp index 05608c30..694690e1 100644 --- a/src/api/common/src/fiatconverter.cpp +++ b/src/api/common/src/fiatconverter.cpp @@ -6,7 +6,7 @@ #include #include -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -33,7 +33,7 @@ string LoadCurrencyConverterAPIKey(std::string_view dataDir) { static constexpr std::string_view kThirdPartySecretFileName = "thirdparty_secret.json"; const File thirdPartySecret(dataDir, File::Type::kSecret, kThirdPartySecretFileName, File::IfError::kNoThrow); - json data = thirdPartySecret.readAllJson(); + json::container data = thirdPartySecret.readAllJson(); auto freeConverterIt = data.find("freecurrencyconverter"); if (freeConverterIt == data.end() || freeConverterIt->get() == kDefaultCommunityKey) { log::warn("Unable to find custom Free Currency Converter key in {}", kThirdPartySecretFileName); @@ -61,7 +61,7 @@ FiatConverter::FiatConverter(const CoincenterInfo& coincenterInfo, Duration rate _ratesUpdateFrequency(ratesUpdateFrequency), _apiKey(LoadCurrencyConverterAPIKey(coincenterInfo.dataDir())), _dataDir(coincenterInfo.dataDir()) { - const json data = fiatsCacheReader.readAllJson(); + const json::container data = fiatsCacheReader.readAllJson(); _pricesMap.reserve(data.size()); for (const auto& [marketStr, rateAndTimeData] : data.items()) { @@ -79,14 +79,14 @@ File FiatConverter::GetRatesCacheFile(std::string_view dataDir) { } void FiatConverter::updateCacheFile() const { - json data; + json::container data; for (const auto& [market, priceTimeValue] : _pricesMap) { const string marketPairStr = market.assetsPairStrUpper('-'); data[marketPairStr]["rate"] = priceTimeValue.rate; data[marketPairStr]["timeepoch"] = TimestampToSecondsSinceEpoch(priceTimeValue.lastUpdatedTime); } - GetRatesCacheFile(_dataDir).write(data); + GetRatesCacheFile(_dataDir).writeJson(data); } std::optional FiatConverter::queryCurrencyRate(Market mk) { @@ -106,7 +106,7 @@ std::optional FiatConverter::queryCurrencyRateSource1(Market mk) { const auto dataStr = _curlHandle1.query("/api/v7/convert", opts); static constexpr bool kAllowExceptions = false; - const auto data = json::parse(dataStr, nullptr, kAllowExceptions); + const auto data = json::container::parse(dataStr, nullptr, kAllowExceptions); //{"query":{"count":1},"results":{"EUR_KRW":{"id":"EUR_KRW","val":1329.475323,"to":"KRW","fr":"EUR"}}} const auto resultsIt = data.find("results"); @@ -124,7 +124,7 @@ std::optional FiatConverter::queryCurrencyRateSource1(Market mk) { std::optional FiatConverter::queryCurrencyRateSource2(Market mk) { const auto dataStr = _curlHandle2.query("", CurlOptions(HttpRequestType::kGet)); static constexpr bool kAllowExceptions = false; - const json jsonData = json::parse(dataStr, nullptr, kAllowExceptions); + const json::container jsonData = json::container::parse(dataStr, nullptr, kAllowExceptions); if (jsonData.is_discarded()) { log::error("Invalid response received from fiat currency converter service's second source"); return {}; diff --git a/src/api/common/src/withdrawalfees-crawler.cpp b/src/api/common/src/withdrawalfees-crawler.cpp index fd16f479..d0c756e2 100644 --- a/src/api/common/src/withdrawalfees-crawler.cpp +++ b/src/api/common/src/withdrawalfees-crawler.cpp @@ -12,7 +12,7 @@ #include "cct_cctype.hpp" #include "cct_const.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -40,7 +40,7 @@ WithdrawalFeesCrawler::WithdrawalFeesCrawler(const CoincenterInfo& coincenterInf CachedResultVault& cachedResultVault) : _coincenterInfo(coincenterInfo), _withdrawalFeesCache(CachedResultOptions(minDurationBetweenQueries, cachedResultVault), coincenterInfo) { - json data = GetWithdrawInfoFile(_coincenterInfo.dataDir()).readAllJson(); + json::container data = GetWithdrawInfoFile(_coincenterInfo.dataDir()).readAllJson(); if (!data.empty()) { const auto nowTime = Clock::now(); for (const auto& [exchangeName, exchangeData] : data.items()) { @@ -114,13 +114,13 @@ WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesF } void WithdrawalFeesCrawler::updateCacheFile() const { - json data; + json::container data; for (const std::string_view exchangeName : kSupportedExchanges) { const auto [withdrawalInfoMapsPtr, latestUpdate] = _withdrawalFeesCache.retrieve(exchangeName); if (withdrawalInfoMapsPtr != nullptr) { const WithdrawalInfoMaps& withdrawalInfoMaps = *withdrawalInfoMapsPtr; - json exchangeData; + json::container exchangeData; exchangeData["timeepoch"] = TimestampToSecondsSinceEpoch(latestUpdate); for (const auto withdrawFee : withdrawalInfoMaps.first) { string curCodeStr = withdrawFee.currencyCode().str(); @@ -132,7 +132,7 @@ void WithdrawalFeesCrawler::updateCacheFile() const { data.emplace(exchangeName, std::move(exchangeData)); } } - GetWithdrawInfoFile(_coincenterInfo.dataDir()).write(data); + GetWithdrawInfoFile(_coincenterInfo.dataDir()).writeJson(data); } WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesFunc::get1( @@ -145,7 +145,7 @@ WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesF if (!withdrawalFeesCsv.empty()) { static constexpr bool kAllowExceptions = false; - const json jsonData = json::parse(withdrawalFeesCsv, nullptr, kAllowExceptions); + const json::container jsonData = json::container::parse(withdrawalFeesCsv, nullptr, kAllowExceptions); const auto exchangesIt = jsonData.find("exchange"); if (jsonData.is_discarded() || exchangesIt == jsonData.end()) { log::error("no exchange data found in source 1 - either site information unavailable or code to be updated"); @@ -157,7 +157,7 @@ WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesF return ret; } - for (const json& feeJson : *feesIt) { + for (const json::container& feeJson : *feesIt) { const auto amountIt = feeJson.find("amount"); if (amountIt == feeJson.end() || !amountIt->is_number_float()) { continue; diff --git a/src/api/common/test/exchangepublicapi_test.cpp b/src/api/common/test/exchangepublicapi_test.cpp index 3e051aba..75c166dc 100644 --- a/src/api/common/test/exchangepublicapi_test.cpp +++ b/src/api/common/test/exchangepublicapi_test.cpp @@ -15,7 +15,7 @@ #include "exchangepublicapi_mock.hpp" #include "exchangepublicapitypes.hpp" #include "fiatconverter.hpp" -#include "generalconfig.hpp" +#include "general-config.hpp" #include "loadconfiguration.hpp" #include "market.hpp" #include "marketorderbook.hpp" @@ -54,7 +54,7 @@ class ExchangePublicTest : public ::testing::Test { protected: settings::RunMode runMode = settings::RunMode::kTestKeys; LoadConfiguration loadConfiguration{kDefaultDataDir, LoadConfiguration::ExchangeConfigFileType::kTest}; - CoincenterInfo coincenterInfo{runMode, loadConfiguration, GeneralConfig(), + CoincenterInfo coincenterInfo{runMode, loadConfiguration, schema::GeneralConfig(), LoggingInfo(), MonitoringInfo(), Reader(), StableCoinReader()}; CommonAPI commonAPI{coincenterInfo, Duration::max()}; FiatConverter fiatConverter{coincenterInfo, Duration::max(), FiatConverterReader()}; diff --git a/src/api/common/test/fiatconverter_test.cpp b/src/api/common/test/fiatconverter_test.cpp index 590c5106..ef1512fe 100644 --- a/src/api/common/test/fiatconverter_test.cpp +++ b/src/api/common/test/fiatconverter_test.cpp @@ -7,7 +7,7 @@ #include #include "besturlpicker.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "coincenterinfo.hpp" #include "curlhandle.hpp" #include "curloptions.hpp" @@ -38,7 +38,7 @@ CurlHandle::CurlHandle([[maybe_unused]] BestURLPicker bestURLPicker, // NOLINTNEXTLINE(readability-convert-member-functions-to-static) std::string_view CurlHandle::query([[maybe_unused]] std::string_view endpoint, const CurlOptions &opts) { - json jsonData; + json::container jsonData; // Rates std::string_view marketStr = opts.postData().get("q"); diff --git a/src/api/common/test/ssl_sha_test.cpp b/src/api/common/test/ssl_sha_test.cpp index 00f6458a..22a1ea21 100644 --- a/src/api/common/test/ssl_sha_test.cpp +++ b/src/api/common/test/ssl_sha_test.cpp @@ -4,7 +4,6 @@ #include #include -#include namespace cct::ssl { TEST(SSLTest, Version) { EXPECT_NE(GetOpenSSLVersion(), ""); } diff --git a/src/api/exchanges/include/binancepublicapi.hpp b/src/api/exchanges/include/binancepublicapi.hpp index 8c90b51b..37631233 100644 --- a/src/api/exchanges/include/binancepublicapi.hpp +++ b/src/api/exchanges/include/binancepublicapi.hpp @@ -5,7 +5,7 @@ #include #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "curlhandle.hpp" #include "currencycode.hpp" #include "currencyexchange.hpp" @@ -83,7 +83,7 @@ class BinancePublic : public ExchangePublic { }; struct ExchangeInfoFunc { - using ExchangeInfoDataByMarket = std::unordered_map; + using ExchangeInfoDataByMarket = std::unordered_map; ExchangeInfoDataByMarket operator()(); diff --git a/src/api/exchanges/include/bithumbprivateapi.hpp b/src/api/exchanges/include/bithumbprivateapi.hpp index c04dc54d..af0b71c0 100644 --- a/src/api/exchanges/include/bithumbprivateapi.hpp +++ b/src/api/exchanges/include/bithumbprivateapi.hpp @@ -3,7 +3,7 @@ #include #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "curlhandle.hpp" #include "exchangeprivateapi.hpp" #include "exchangeprivateapitypes.hpp" diff --git a/src/api/exchanges/include/bithumbpublicapi.hpp b/src/api/exchanges/include/bithumbpublicapi.hpp index a944c256..3e43341b 100644 --- a/src/api/exchanges/include/bithumbpublicapi.hpp +++ b/src/api/exchanges/include/bithumbpublicapi.hpp @@ -30,7 +30,7 @@ class BithumbPublic : public ExchangePublic { static constexpr auto kStatusUnexpectedError = -1; static constexpr auto kStatusNotPresentError = -2; - static int64_t StatusCodeFromJsonResponse(const json& jsonResponse); + static int64_t StatusCodeFromJsonResponse(const json::container& jsonResponse); BithumbPublic(const CoincenterInfo& config, FiatConverter& fiatConverter, CommonAPI& commonAPI); diff --git a/src/api/exchanges/include/huobiprivateapi.hpp b/src/api/exchanges/include/huobiprivateapi.hpp index e7e5acf6..ffe6dedd 100644 --- a/src/api/exchanges/include/huobiprivateapi.hpp +++ b/src/api/exchanges/include/huobiprivateapi.hpp @@ -1,7 +1,7 @@ #pragma once #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "curlhandle.hpp" #include "exchangeprivateapi.hpp" #include "exchangeprivateapitypes.hpp" diff --git a/src/api/exchanges/include/huobipublicapi.hpp b/src/api/exchanges/include/huobipublicapi.hpp index 04ef50fa..dd2c0a01 100644 --- a/src/api/exchanges/include/huobipublicapi.hpp +++ b/src/api/exchanges/include/huobipublicapi.hpp @@ -6,7 +6,7 @@ #include #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "curlhandle.hpp" #include "currencycode.hpp" #include "exchangepublicapi.hpp" @@ -74,7 +74,7 @@ class HuobiPublic : public ExchangePublic { friend class HuobiPrivate; struct TradableCurrenciesFunc { - json operator()(); + json::container operator()(); CurlHandle& _curlHandle; }; @@ -138,7 +138,7 @@ class HuobiPublic : public ExchangePublic { WithdrawParams getWithdrawParams(CurrencyCode cur); - static bool ShouldDiscardChain(CurrencyCode cur, const json& chainDetail); + static bool ShouldDiscardChain(CurrencyCode cur, const json::container& chainDetail); CurlHandle _curlHandle; CurlHandle _healthCheckCurlHandle; diff --git a/src/api/exchanges/include/krakenprivateapi.hpp b/src/api/exchanges/include/krakenprivateapi.hpp index cbb5de45..48aff893 100644 --- a/src/api/exchanges/include/krakenprivateapi.hpp +++ b/src/api/exchanges/include/krakenprivateapi.hpp @@ -3,7 +3,7 @@ #include #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_string.hpp" #include "curlhandle.hpp" #include "exchangeprivateapi.hpp" @@ -66,7 +66,7 @@ class KrakenPrivate : public ExchangePrivate { KrakenPublic& _exchangePublic; }; - json queryOrdersData(int64_t userRef, OrderIdView orderId, QueryOrder queryOrder); + json::container queryOrdersData(int64_t userRef, OrderIdView orderId, QueryOrder queryOrder); OrderInfo queryOrderInfo(OrderIdView orderId, const TradeContext& tradeContext, QueryOrder queryOrder); diff --git a/src/api/exchanges/include/kucoinprivateapi.hpp b/src/api/exchanges/include/kucoinprivateapi.hpp index 762367c5..9954c3e0 100644 --- a/src/api/exchanges/include/kucoinprivateapi.hpp +++ b/src/api/exchanges/include/kucoinprivateapi.hpp @@ -1,7 +1,7 @@ #pragma once #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "curlhandle.hpp" #include "exchangeprivateapi.hpp" #include "exchangeprivateapitypes.hpp" diff --git a/src/api/exchanges/src/binanceprivateapi.cpp b/src/api/exchanges/src/binanceprivateapi.cpp index 7613444e..b4e9859e 100644 --- a/src/api/exchanges/src/binanceprivateapi.cpp +++ b/src/api/exchanges/src/binanceprivateapi.cpp @@ -20,7 +20,7 @@ #include "binancepublicapi.hpp" #include "cachedresult.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_smallvector.hpp" #include "cct_string.hpp" @@ -110,7 +110,7 @@ void SetNonceAndSignature(const APIKey& apiKey, CurlPostData& postData, Duration postData.set_back(kSignatureKey, std::string_view(sha256Hex)); } -bool CheckErrorDoRetry(int statusCode, const json& ret, QueryDelayDir& queryDelayDir, Duration& sleepingTime, +bool CheckErrorDoRetry(int statusCode, const json::container& ret, QueryDelayDir& queryDelayDir, Duration& sleepingTime, Duration& queryDelay) { static constexpr Duration kInitialDurationQueryDelay = milliseconds(200); switch (statusCode) { @@ -171,15 +171,16 @@ bool CheckErrorDoRetry(int statusCode, const json& ret, QueryDelayDir& queryDela } template -json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType requestType, std::string_view endpoint, - Duration& queryDelay, CurlPostDataT&& curlPostData = CurlPostData(), bool throwIfError = true) { +json::container PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType requestType, + std::string_view endpoint, Duration& queryDelay, + CurlPostDataT&& curlPostData = CurlPostData(), bool throwIfError = true) { CurlOptions opts(requestType, std::forward(curlPostData)); opts.mutableHttpHeaders().emplace_back("X-MBX-APIKEY", apiKey.key()); Duration sleepingTime = curlHandle.minDurationBetweenQueries(); int statusCode{}; QueryDelayDir queryDelayDir = QueryDelayDir::kNoDir; - json ret; + json::container ret; for (int retryPos = 0; retryPos < kNbOrderRequestsRetries; ++retryPos) { if (retryPos != 0) { log::trace("Wait {}...", DurationToString(sleepingTime)); @@ -191,7 +192,7 @@ json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType static constexpr bool kAllowExceptions = false; - ret = json::parse(curlHandle.query(endpoint, opts), nullptr, kAllowExceptions); + ret = json::container::parse(curlHandle.query(endpoint, opts), nullptr, kAllowExceptions); if (ret.is_discarded()) { log::error("Badly formatted response from Binance, retry"); continue; @@ -212,7 +213,7 @@ json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType break; } if (throwIfError) { - log::error("Full Binance json error for {}: '{}'", apiKey.name(), ret.dump()); + log::error("Full Binance error for {}: '{}'", apiKey.name(), ret.dump()); throw exception("Error: {}, msg: {}", MonetaryAmount(statusCode), ret["msg"].get()); } return ret; @@ -239,7 +240,7 @@ BinancePrivate::BinancePrivate(const CoincenterInfo& coincenterInfo, BinancePubl _curlHandle, _apiKey, binancePublic, _queryDelay) {} CurrencyExchangeFlatSet BinancePrivate::TradableCurrenciesCache::operator()() { - json allCoins = + json::container allCoins = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/capital/config/getall", _queryDelay); return BinanceGlobalInfos::ExtractTradableCurrencies(allCoins, _exchangePublic.exchangeConfig().excludedCurrenciesAll()); @@ -247,13 +248,14 @@ CurrencyExchangeFlatSet BinancePrivate::TradableCurrenciesCache::operator()() { bool BinancePrivate::validateApiKey() { static constexpr bool throwIfError = false; - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/account/status", _queryDelay, - CurlPostData(), throwIfError); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/account/status", + _queryDelay, CurlPostData(), throwIfError); return result.find("code") == result.end(); } BalancePortfolio BinancePrivate::queryAccountBalance(const BalanceOptions& balanceOptions) { - const json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v3/account", _queryDelay); + const json::container result = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v3/account", _queryDelay); const bool withBalanceInUse = balanceOptions.amountIncludePolicy() == BalanceOptions::AmountIncludePolicy::kWithBalanceInUse; @@ -266,7 +268,7 @@ BalancePortfolio BinancePrivate::queryAccountBalance(const BalanceOptions& balan } balancePortfolio.reserve(static_cast(dataIt->size())); - for (const json& balance : *dataIt) { + for (const json::container& balance : *dataIt) { CurrencyCode currencyCode(balance["asset"].get()); MonetaryAmount amount(balance["free"].get(), currencyCode); @@ -282,8 +284,8 @@ BalancePortfolio BinancePrivate::queryAccountBalance(const BalanceOptions& balan Wallet BinancePrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) { // Limitation : we do not provide network here, we use default in accordance of getTradableCurrenciesService - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/capital/deposit/address", - _queryDelay, {{"coin", currencyCode.str()}}); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/capital/deposit/address", + _queryDelay, {{"coin", currencyCode.str()}}); std::string_view tag(result["tag"].get()); const CoincenterInfo& coincenterInfo = _exchangePublic.coincenterInfo(); bool doCheckWallet = coincenterInfo.exchangeConfig(_exchangePublic.name()).validateDepositAddressesInFile(); @@ -305,13 +307,13 @@ bool BinancePrivate::checkMarketAppendSymbol(Market mk, CurlPostData& params) { namespace { template -void FillOrders(const OrdersConstraints& ordersConstraints, const json& ordersArray, ExchangePublic& exchangePublic, - OrderVectorType& orderVector) { +void FillOrders(const OrdersConstraints& ordersConstraints, const json::container& ordersArray, + ExchangePublic& exchangePublic, OrderVectorType& orderVector) { const auto cur1Str = ordersConstraints.curStr1(); const auto cur2Str = ordersConstraints.curStr2(); MarketSet markets; - for (const json& orderDetails : ordersArray) { + for (const json::container& orderDetails : ordersArray) { std::string_view marketStr = orderDetails["symbol"].get(); // already higher case std::size_t cur1Pos = marketStr.find(cur1Str); if (ordersConstraints.isCurDefined() && cur1Pos == std::string_view::npos) { @@ -379,7 +381,7 @@ ClosedOrderVector BinancePrivate::queryClosedOrders(const OrdersConstraints& clo if (closedOrdersConstraints.isPlacedTimeBeforeDefined()) { params.emplace_back("endTime", TimestampToMillisecondsSinceEpoch(closedOrdersConstraints.placedBefore())); } - const json result = + const json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v3/allOrders", _queryDelay, std::move(params)); FillOrders(closedOrdersConstraints, result, _exchangePublic, closedOrders); @@ -401,7 +403,7 @@ OpenedOrderVector BinancePrivate::queryOpenedOrders(const OrdersConstraints& ope return openedOrders; } } - const json result = + const json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v3/openOrders", _queryDelay, std::move(params)); FillOrders(openedOrdersConstraints, result, _exchangePublic, openedOrders); @@ -419,8 +421,8 @@ int BinancePrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersCons return 0; } if (canUseCancelAllEndpoint) { - json cancelledOrders = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, "/api/v3/openOrders", - _queryDelay, std::move(params)); + json::container cancelledOrders = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, + "/api/v3/openOrders", _queryDelay, std::move(params)); return static_cast(cancelledOrders.size()); } } @@ -441,7 +443,7 @@ int BinancePrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersCons } if (orders.size() > 1 && canUseCancelAllEndpoint) { params.erase("orderId"); - json cancelledOrders = + json::container cancelledOrders = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, "/api/v3/openOrders", _queryDelay, params); nbOrdersCancelled += static_cast(cancelledOrders.size()); } else { @@ -490,11 +492,11 @@ DepositsSet BinancePrivate::queryRecentDeposits(const DepositsConstraints& depos options.emplace_back("txId", depositsConstraints.idSet().front()); } } - json depositStatus = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/capital/deposit/hisrec", - _queryDelay, std::move(options)); + json::container depositStatus = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, + "/sapi/v1/capital/deposit/hisrec", _queryDelay, std::move(options)); Deposits deposits; deposits.reserve(static_cast(depositStatus.size())); - for (json& depositDetail : depositStatus) { + for (json::container& depositDetail : depositStatus) { int statusInt = depositDetail["status"].get(); Deposit::Status status = DepositStatusFromCode(statusInt); @@ -554,7 +556,7 @@ Withdraw::Status WithdrawStatusFromStatusStr(int statusInt, bool logStatus) { } } -TimePoint RetrieveTimeStampFromWithdrawJson(const json& withdrawJson) { +TimePoint RetrieveTimeStampFromWithdrawJson(const json::container& withdrawJson) { int64_t millisecondsSinceEpoch; auto completeTimeIt = withdrawJson.find("completeTime"); if (completeTimeIt != withdrawJson.end()) { @@ -586,9 +588,9 @@ WithdrawsSet BinancePrivate::queryRecentWithdraws(const WithdrawsConstraints& wi // Binance provides field 'withdrawOrderId' tu customize user id, but it's not well documented // so we use Binance generated 'id' instead. // What is important is that the same field is considered in both queries 'launchWithdraw' and 'queryRecentWithdraws' - json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/capital/withdraw/history", - _queryDelay, CreateOptionsFromWithdrawConstraints(withdrawsConstraints)); - for (json& withdrawJson : data) { + json::container data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/capital/withdraw/history", + _queryDelay, CreateOptionsFromWithdrawConstraints(withdrawsConstraints)); + for (json::container& withdrawJson : data) { int statusInt = withdrawJson["status"].get(); Withdraw::Status status = WithdrawStatusFromStatusStr(statusInt, withdrawsConstraints.isCurDefined()); CurrencyCode currencyCode(withdrawJson["coin"].get()); @@ -607,7 +609,8 @@ WithdrawsSet BinancePrivate::queryRecentWithdraws(const WithdrawsConstraints& wi } MonetaryAmountByCurrencySet BinancePrivate::AllWithdrawFeesFunc::operator()() { - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/asset/assetDetail", _queryDelay); + json::container result = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/asset/assetDetail", _queryDelay); MonetaryAmountVector fees; for (const auto& [curCodeStr, withdrawFeeDetails] : result.items()) { if (withdrawFeeDetails["withdrawStatus"].get()) { @@ -619,12 +622,12 @@ MonetaryAmountByCurrencySet BinancePrivate::AllWithdrawFeesFunc::operator()() { } std::optional BinancePrivate::WithdrawFeesFunc::operator()(CurrencyCode currencyCode) { - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/asset/assetDetail", _queryDelay, - {{"asset", currencyCode.str()}}); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/asset/assetDetail", + _queryDelay, {{"asset", currencyCode.str()}}); if (!result.contains(currencyCode.str())) { return {}; } - const json& withdrawFeeDetails = result[currencyCode.str()]; + const json::container& withdrawFeeDetails = result[currencyCode.str()]; if (!withdrawFeeDetails["withdrawStatus"].get()) { log::error("{} is currently unavailable for withdraw from {}", currencyCode, _exchangePublic.name()); } @@ -632,7 +635,7 @@ std::optional BinancePrivate::WithdrawFeesFunc::operator()(Curre } namespace { -TradedAmounts ParseTrades(Market mk, CurrencyCode fromCurrencyCode, const json& fillDetail) { +TradedAmounts ParseTrades(Market mk, CurrencyCode fromCurrencyCode, const json::container& fillDetail) { MonetaryAmount price(fillDetail["price"].get(), mk.quote()); MonetaryAmount quantity(fillDetail["qty"].get(), mk.base()); MonetaryAmount quantityTimesPrice = quantity.toNeutral() * price; @@ -651,12 +654,12 @@ TradedAmounts ParseTrades(Market mk, CurrencyCode fromCurrencyCode, const json& return detailTradedInfo; } -TradedAmounts QueryOrdersAfterPlace(Market mk, CurrencyCode fromCurrencyCode, const json& orderJson) { +TradedAmounts QueryOrdersAfterPlace(Market mk, CurrencyCode fromCurrencyCode, const json::container& orderJson) { CurrencyCode toCurrencyCode(fromCurrencyCode == mk.quote() ? mk.base() : mk.quote()); TradedAmounts ret(fromCurrencyCode, toCurrencyCode); if (orderJson.contains("fills")) { - for (const json& fillDetail : orderJson["fills"]) { + for (const json::container& fillDetail : orderJson["fills"]) { ret += ParseTrades(mk, fromCurrencyCode, fillDetail); } } @@ -688,13 +691,13 @@ PlaceOrderInfo BinancePrivate::placeOrder(MonetaryAmount from, MonetaryAmount vo if (!isSimulation && toCurrencyCode == kBinanceCoinCur) { // Use special Binance Dust transfer log::info("Volume too low for standard trade, but we can use Dust transfer to trade to {}", kBinanceCoinCur); - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/sapi/v1/asset/dust", _queryDelay, - {{"asset", from.currencyStr()}}); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/sapi/v1/asset/dust", + _queryDelay, {{"asset", from.currencyStr()}}); auto transferResultIt = result.find("transferResult"); if (transferResultIt == result.end() || transferResultIt->empty()) { throw exception("Unexpected dust transfer result"); } - const json& res = transferResultIt->front(); + const json::container& res = transferResultIt->front(); placeOrderInfo.orderId = IntegralToString(res["tranId"].get()); // 'transfered' is misspelled (against 'transferred') but the field is really named like this in Binance REST API MonetaryAmount netTransferredAmount(res["transferedAmount"].get(), kBinanceCoinCur); @@ -719,7 +722,8 @@ PlaceOrderInfo BinancePrivate::placeOrder(MonetaryAmount from, MonetaryAmount vo const std::string_view methodName = isSimulation ? "/api/v3/order/test" : "/api/v3/order"; - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, methodName, _queryDelay, placePostData); + json::container result = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, methodName, _queryDelay, placePostData); if (isSimulation) { placeOrderInfo.setClosed(); return placeOrderInfo; @@ -745,8 +749,8 @@ OrderInfo BinancePrivate::queryOrder(OrderIdView orderId, const TradeContext& tr const CurrencyCode toCurrencyCode = tradeContext.side == TradeSide::kBuy ? mk.base() : mk.quote(); const string assetsStr = mk.assetsPairStrUpper(); const std::string_view assets(assetsStr); - json result = PrivateQuery(_curlHandle, _apiKey, requestType, "/api/v3/order", _queryDelay, - {{"symbol", assets}, {"orderId", orderId}}); + json::container result = PrivateQuery(_curlHandle, _apiKey, requestType, "/api/v3/order", _queryDelay, + {{"symbol", assets}, {"orderId", orderId}}); const std::string_view status = result["status"].get(); bool isClosed = false; bool queryClosedOrder = false; @@ -766,7 +770,7 @@ OrderInfo BinancePrivate::queryOrder(OrderIdView orderId, const TradeContext& tr } result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v3/myTrades", _queryDelay, myTradesOpts); int64_t integralOrderId = StringToIntegral(orderId); - for (const json& tradeDetails : result) { + for (const json::container& tradeDetails : result) { if (tradeDetails["orderId"].get() == integralOrderId) { orderInfo.tradedAmounts += ParseTrades(mk, fromCurrencyCode, tradeDetails); } @@ -782,25 +786,26 @@ InitiatedWithdrawInfo BinancePrivate::launchWithdraw(MonetaryAmount grossAmount, if (destinationWallet.hasTag()) { withdrawPostData.emplace_back("addressTag", destinationWallet.tag()); } - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/sapi/v1/capital/withdraw/apply", - _queryDelay, std::move(withdrawPostData)); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/sapi/v1/capital/withdraw/apply", + _queryDelay, std::move(withdrawPostData)); return {std::move(destinationWallet), std::move(result["id"].get_ref()), grossAmount}; } ReceivedWithdrawInfo BinancePrivate::queryWithdrawDelivery(const InitiatedWithdrawInfo& initiatedWithdrawInfo, const SentWithdrawInfo& sentWithdrawInfo) { const CurrencyCode currencyCode = initiatedWithdrawInfo.grossEmittedAmount().currencyCode(); - json depositStatus = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/capital/deposit/hisrec", - _queryDelay, {{"coin", currencyCode.str()}}); + json::container depositStatus = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/capital/deposit/hisrec", _queryDelay, + {{"coin", currencyCode.str()}}); const Wallet& wallet = initiatedWithdrawInfo.receivingWallet(); - auto newEndIt = std::ranges::remove_if(depositStatus, [&wallet](const json& el) { + auto newEndIt = std::ranges::remove_if(depositStatus, [&wallet](const json::container& el) { return el["status"].get() != 1 || el["address"].get() != wallet.address(); }).begin(); depositStatus.erase(newEndIt, depositStatus.end()); - const auto recentDepositFromJsonEl = [currencyCode](const json& el) { + const auto recentDepositFromJsonEl = [currencyCode](const json::container& el) { const MonetaryAmount amountReceived(el["amount"].get(), currencyCode); const TimePoint timestamp{milliseconds(el["insertTime"].get())}; @@ -818,7 +823,7 @@ ReceivedWithdrawInfo BinancePrivate::queryWithdrawDelivery(const InitiatedWithdr return {}; } - json& depositEl = depositStatus[closestDepositPos]; + json::container& depositEl = depositStatus[closestDepositPos]; const RecentDeposit recentDeposit = recentDepositFromJsonEl(depositEl); return {std::move(depositEl["id"].get_ref()), recentDeposit.amount(), recentDeposit.timePoint()}; diff --git a/src/api/exchanges/src/binancepublicapi.cpp b/src/api/exchanges/src/binancepublicapi.cpp index b0b265c9..d423726f 100644 --- a/src/api/exchanges/src/binancepublicapi.cpp +++ b/src/api/exchanges/src/binancepublicapi.cpp @@ -16,7 +16,7 @@ #include "binance-common-api.hpp" #include "cachedresult.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -48,7 +48,8 @@ namespace cct::api { namespace { -json PublicQuery(CurlHandle& curlHandle, std::string_view method, const CurlPostData& curlPostData = CurlPostData()) { +json::container PublicQuery(CurlHandle& curlHandle, std::string_view method, + const CurlPostData& curlPostData = CurlPostData()) { string endpoint(method); if (!curlPostData.empty()) { endpoint.push_back('?'); @@ -56,12 +57,12 @@ json PublicQuery(CurlHandle& curlHandle, std::string_view method, const CurlPost } RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet)); - return requestRetry.queryJson(endpoint, [](const json& jsonResponse) { + return requestRetry.queryJson(endpoint, [](const json::container& jsonResponse) { const auto foundErrorIt = jsonResponse.find("code"); const auto foundMsgIt = jsonResponse.find("msg"); if (foundErrorIt != jsonResponse.end() && foundMsgIt != jsonResponse.end()) { const int statusCode = foundErrorIt->get(); // "1100" for instance - log::warn("Binance error ({}), full json: '{}'", statusCode, jsonResponse.dump()); + log::warn("Binance error ({}), full: '{}'", statusCode, jsonResponse.dump()); return RequestRetry::Status::kResponseError; } return RequestRetry::Status::kResponseOK; @@ -69,7 +70,7 @@ json PublicQuery(CurlHandle& curlHandle, std::string_view method, const CurlPost } template -const json& RetrieveMarketData(const ExchangeInfoDataByMarket& exchangeInfoData, Market mk) { +const json::container& RetrieveMarketData(const ExchangeInfoDataByMarket& exchangeInfoData, Market mk) { auto it = exchangeInfoData.find(mk); if (it == exchangeInfoData.end()) { throw exception("Unable to retrieve {} data", mk); @@ -79,7 +80,7 @@ const json& RetrieveMarketData(const ExchangeInfoDataByMarket& exchangeInfoData, template VolAndPriNbDecimals QueryVolAndPriNbDecimals(const ExchangeInfoDataByMarket& exchangeInfoData, Market mk) { - const json& marketData = RetrieveMarketData(exchangeInfoData, mk); + const json::container& marketData = RetrieveMarketData(exchangeInfoData, mk); return {marketData["baseAssetPrecision"].get(), marketData["quoteAssetPrecision"].get()}; } } // namespace @@ -106,8 +107,8 @@ BinancePublic::BinancePublic(const CoincenterInfo& coincenterInfo, FiatConverter bool BinancePublic::healthCheck() { static constexpr bool kAllowExceptions = false; - json result = json::parse(_commonInfo._curlHandle.query("/api/v3/ping", CurlOptions(HttpRequestType::kGet)), nullptr, - kAllowExceptions); + json::container result = json::container::parse( + _commonInfo._curlHandle.query("/api/v3/ping", CurlOptions(HttpRequestType::kGet)), nullptr, kAllowExceptions); if (result.is_discarded()) { log::error("{} health check response is badly formatted: {}", _name, result.dump()); return false; @@ -148,7 +149,7 @@ MarketSet BinancePublic::MarketsFunc::operator()() { markets.reserve(static_cast(exchangeInfoData.size())); for (const auto& marketJsonPair : exchangeInfoData) { - const json& symbol = marketJsonPair.second; + const json::container& symbol = marketJsonPair.second; std::string_view baseAsset = symbol["baseAsset"].get(); std::string_view quoteAsset = symbol["quoteAsset"].get(); CurrencyCode base(baseAsset); @@ -165,7 +166,7 @@ MarketSet BinancePublic::MarketsFunc::operator()() { BinancePublic::ExchangeInfoFunc::ExchangeInfoDataByMarket BinancePublic::ExchangeInfoFunc::operator()() { ExchangeInfoDataByMarket ret; - json exchangeInfoData = PublicQuery(_commonInfo._curlHandle, "/api/v3/exchangeInfo"); + json::container exchangeInfoData = PublicQuery(_commonInfo._curlHandle, "/api/v3/exchangeInfo"); auto symbolsIt = exchangeInfoData.find("symbols"); if (symbolsIt == exchangeInfoData.end()) { return ret; @@ -195,11 +196,11 @@ BinancePublic::ExchangeInfoFunc::ExchangeInfoDataByMarket BinancePublic::Exchang } MonetaryAmount BinancePublic::sanitizePrice(Market mk, MonetaryAmount pri) { - const json& marketData = RetrieveMarketData(_exchangeConfigCache.get(), mk); + const json::container& marketData = RetrieveMarketData(_exchangeConfigCache.get(), mk); - const json* pPriceFilter = nullptr; + const json::container* pPriceFilter = nullptr; MonetaryAmount ret(pri); - for (const json& filter : marketData["filters"]) { + for (const json::container& filter : marketData["filters"]) { const std::string_view filterType = filter["filterType"].get(); if (filterType == "PRICE_FILTER") { pPriceFilter = std::addressof(filter); @@ -244,7 +245,8 @@ MonetaryAmount BinancePublic::computePriceForNotional(Market mk, int avgPriceMin log::error("Unable to retrieve last trades from {}, use average price instead for notional", mk); } - const json result = PublicQuery(_commonInfo._curlHandle, "/api/v3/avgPrice", {{"symbol", mk.assetsPairStrUpper()}}); + const json::container result = + PublicQuery(_commonInfo._curlHandle, "/api/v3/avgPrice", {{"symbol", mk.assetsPairStrUpper()}}); const auto priceIt = result.find("price"); const std::string_view priceStr = priceIt == result.end() ? std::string_view() : priceIt->get(); @@ -253,15 +255,15 @@ MonetaryAmount BinancePublic::computePriceForNotional(Market mk, int avgPriceMin MonetaryAmount BinancePublic::sanitizeVolume(Market mk, MonetaryAmount vol, MonetaryAmount priceForNotional, bool isTakerOrder) { - const json& marketData = RetrieveMarketData(_exchangeConfigCache.get(), mk); + const json::container& marketData = RetrieveMarketData(_exchangeConfigCache.get(), mk); MonetaryAmount ret(vol); - const json* pMinNotionalFilter = nullptr; - const json* pNotionalFilter = nullptr; - const json* pLotSizeFilter = nullptr; - const json* pMarketLotSizeFilter = nullptr; + const json::container* pMinNotionalFilter = nullptr; + const json::container* pNotionalFilter = nullptr; + const json::container* pLotSizeFilter = nullptr; + const json::container* pMarketLotSizeFilter = nullptr; - for (const json& filter : marketData["filters"]) { + for (const json::container& filter : marketData["filters"]) { const std::string_view filterType = filter["filterType"].get(); if (filterType == "LOT_SIZE") { pLotSizeFilter = std::addressof(filter); @@ -328,7 +330,7 @@ MonetaryAmount BinancePublic::sanitizeVolume(Market mk, MonetaryAmount vol, Mone } } - for (const json* pLotFilterPtr : {pMarketLotSizeFilter, pLotSizeFilter}) { + for (const json::container* pLotFilterPtr : {pMarketLotSizeFilter, pLotSizeFilter}) { if (pLotFilterPtr != nullptr) { // "maxQty": "9000000.00000000", // "minQty": "1.00000000", @@ -366,7 +368,7 @@ MonetaryAmount BinancePublic::sanitizeVolume(Market mk, MonetaryAmount vol, Mone MarketOrderBookMap BinancePublic::AllOrderBooksFunc::operator()(int depth) { MarketOrderBookMap ret; const MarketSet& markets = _marketsCache.get(); - json result = PublicQuery(_commonInfo._curlHandle, "/api/v3/ticker/bookTicker"); + json::container result = PublicQuery(_commonInfo._curlHandle, "/api/v3/ticker/bookTicker"); using BinanceAssetPairToStdMarketMap = std::unordered_map; BinanceAssetPairToStdMarketMap binanceAssetPairToStdMarketMap; binanceAssetPairToStdMarketMap.reserve(markets.size()); @@ -374,7 +376,7 @@ MarketOrderBookMap BinancePublic::AllOrderBooksFunc::operator()(int depth) { binanceAssetPairToStdMarketMap.insert_or_assign(mk.assetsPairStrUpper(), mk); } const auto time = Clock::now(); - for (const json& tickerDetails : result) { + for (const json::container& tickerDetails : result) { string assetsPairStr = tickerDetails["symbol"]; auto it = binanceAssetPairToStdMarketMap.find(assetsPairStr); if (it == binanceAssetPairToStdMarketMap.end()) { @@ -406,7 +408,7 @@ MarketOrderBook BinancePublic::OrderBookFunc::operator()(Market mk, int depth) { MarketOrderBookLines orderBookLines; const CurlPostData postData{{"symbol", mk.assetsPairStrUpper()}, {"limit", *lb}}; - const json asksAndBids = PublicQuery(_commonInfo._curlHandle, "/api/v3/depth", postData); + const json::container asksAndBids = PublicQuery(_commonInfo._curlHandle, "/api/v3/depth", postData); const auto nowTime = Clock::now(); const auto asksIt = asksAndBids.find("asks"); const auto bidsIt = asksAndBids.find("bids"); @@ -429,7 +431,7 @@ MarketOrderBook BinancePublic::OrderBookFunc::operator()(Market mk, int depth) { } MonetaryAmount BinancePublic::TradedVolumeFunc::operator()(Market mk) { - const json result = + const json::container result = PublicQuery(_commonInfo._curlHandle, "/api/v3/ticker/24hr", {{"symbol", mk.assetsPairStrUpper()}}); const auto volumeIt = result.find("volume"); const std::string_view last24hVol = volumeIt == result.end() ? std::string_view() : volumeIt->get(); @@ -445,13 +447,13 @@ PublicTradeVector BinancePublic::queryLastTrades(Market mk, int nbTrades) { nbTrades = kMaxNbLastTrades; } - json result = PublicQuery(_commonInfo._curlHandle, "/api/v3/trades", - {{"symbol", mk.assetsPairStrUpper()}, {"limit", nbTrades}}); + json::container result = PublicQuery(_commonInfo._curlHandle, "/api/v3/trades", + {{"symbol", mk.assetsPairStrUpper()}, {"limit", nbTrades}}); PublicTradeVector ret; ret.reserve(static_cast(result.size())); - for (const json& detail : result) { + for (const json::container& detail : result) { MonetaryAmount amount(detail["qty"].get(), mk.base()); MonetaryAmount price(detail["price"].get(), mk.quote()); int64_t millisecondsSinceEpoch = detail["time"].get(); @@ -464,7 +466,8 @@ PublicTradeVector BinancePublic::queryLastTrades(Market mk, int nbTrades) { } MonetaryAmount BinancePublic::TickerFunc::operator()(Market mk) { - const json data = PublicQuery(_commonInfo._curlHandle, "/api/v3/ticker/price", {{"symbol", mk.assetsPairStrUpper()}}); + const json::container data = + PublicQuery(_commonInfo._curlHandle, "/api/v3/ticker/price", {{"symbol", mk.assetsPairStrUpper()}}); const auto priceIt = data.find("price"); const std::string_view lastPrice = priceIt == data.end() ? std::string_view() : priceIt->get(); return {lastPrice, mk.quote()}; diff --git a/src/api/exchanges/src/bithumbprivateapi.cpp b/src/api/exchanges/src/bithumbprivateapi.cpp index 5856421e..71576679 100644 --- a/src/api/exchanges/src/bithumbprivateapi.cpp +++ b/src/api/exchanges/src/bithumbprivateapi.cpp @@ -21,7 +21,7 @@ #include "cachedresult.hpp" #include "cct_exception.hpp" #include "cct_fixedcapacityvector.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_smallvector.hpp" #include "cct_string.hpp" @@ -123,7 +123,8 @@ void SetHttpHeaders(CurlOptions& opts, const APIKey& apiKey, const auto& signatu } template -bool LoadCurrencyInfoField(const json& currencyOrderInfoJson, std::string_view keyStr, ValueType& val, TimePoint& ts) { +bool LoadCurrencyInfoField(const json::container& currencyOrderInfoJson, std::string_view keyStr, ValueType& val, + TimePoint& ts) { const auto subPartIt = currencyOrderInfoJson.find(keyStr); if (subPartIt != currencyOrderInfoJson.end()) { const auto valIt = subPartIt->find(kValueKeyStr); @@ -146,8 +147,8 @@ bool LoadCurrencyInfoField(const json& currencyOrderInfoJson, std::string_view k } template -json CurrencyOrderInfoField2Json(const ValueType& val, TimePoint ts) { - json data; +json::container CurrencyOrderInfoField2Json(const ValueType& val, TimePoint ts) { + json::container data; if constexpr (std::is_same_v) { data.emplace(kValueKeyStr, val.str()); } else { @@ -159,7 +160,7 @@ json CurrencyOrderInfoField2Json(const ValueType& val, TimePoint ts) { template bool ExtractError(std::string_view findStr1, std::string_view findStr2, std::string_view logStr, std::string_view msg, - std::string_view jsonKeyStr, json& jsonData) { + std::string_view jsonKeyStr, json::container& jsonData) { std::size_t startPos = msg.find(findStr1); if (startPos != std::string_view::npos) { static_assert(std::is_integral_v || std::is_same_v, @@ -226,7 +227,7 @@ void CheckAndLogSynchronizedTime(std::string_view msg) { } } -bool CheckOrderErrors(std::string_view endpoint, std::string_view msg, json& data) { +bool CheckOrderErrors(std::string_view endpoint, std::string_view msg, json::container& data) { const bool isInfoOpenedOrders = endpoint == "/info/orders"; const bool isCancelQuery = endpoint == "/trade/cancel"; const bool isDepositInfo = endpoint == kWalletAddressEndpointStr; @@ -258,13 +259,13 @@ bool CheckOrderErrors(std::string_view endpoint, std::string_view msg, json& dat return false; } -json PrivateQueryProcessWithRetries(CurlHandle& curlHandle, const APIKey& apiKey, std::string_view endpoint, - CurlOptions&& opts) { +json::container PrivateQueryProcessWithRetries(CurlHandle& curlHandle, const APIKey& apiKey, std::string_view endpoint, + CurlOptions&& opts) { RequestRetry requestRetry(curlHandle, std::move(opts)); - json ret = requestRetry.queryJson( + json::container ret = requestRetry.queryJson( endpoint, - [endpoint](json& ret) { + [endpoint](json::container& ret) { const auto errorCode = BithumbPublic::StatusCodeFromJsonResponse(ret); if (errorCode == 0 || errorCode == BithumbPublic::kStatusNotPresentError) { return RequestRetry::Status::kResponseOK; @@ -301,8 +302,8 @@ json PrivateQueryProcessWithRetries(CurlHandle& curlHandle, const APIKey& apiKey } template -json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, std::string_view endpoint, - CurlPostDataT&& curlPostData = CurlPostData()) { +json::container PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, std::string_view endpoint, + CurlPostDataT&& curlPostData = CurlPostData()) { CurlPostData postData(std::forward(curlPostData)); postData.emplace_front("endpoint", endpoint); @@ -326,7 +327,7 @@ BithumbPrivate::BithumbPrivate(const CoincenterInfo& config, BithumbPublic& bith CachedResultOptions(exchangeConfig().getAPICallUpdateFrequency(kDepositWallet), _cachedResultVault), _curlHandle, _apiKey, bithumbPublic) { if (config.getRunMode() != settings::RunMode::kQueryResponseOverriden) { - json data = GetBithumbCurrencyInfoMapCache(_coincenterInfo.dataDir()).readAllJson(); + json::container data = GetBithumbCurrencyInfoMapCache(_coincenterInfo.dataDir()).readAllJson(); for (const auto& [currencyCodeStr, currencyOrderInfoJson] : data.items()) { CurrencyOrderInfo currencyOrderInfo; @@ -344,7 +345,7 @@ BithumbPrivate::BithumbPrivate(const CoincenterInfo& config, BithumbPublic& bith } bool BithumbPrivate::validateApiKey() { - const json jsonResponse = PrivateQuery(_curlHandle, _apiKey, "/info/balance", CurlPostData()); + const json::container jsonResponse = PrivateQuery(_curlHandle, _apiKey, "/info/balance", CurlPostData()); if (jsonResponse.is_discarded()) { return false; } @@ -354,7 +355,7 @@ bool BithumbPrivate::validateApiKey() { } BalancePortfolio BithumbPrivate::queryAccountBalance(const BalanceOptions& balanceOptions) { - json jsonReply = PrivateQuery(_curlHandle, _apiKey, "/info/balance", {{"currency", "all"}}); + json::container jsonReply = PrivateQuery(_curlHandle, _apiKey, "/info/balance", {{"currency", "all"}}); BalancePortfolio balancePortfolio; if (jsonReply.is_discarded()) { @@ -388,7 +389,8 @@ BalancePortfolio BithumbPrivate::queryAccountBalance(const BalanceOptions& balan } Wallet BithumbPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) { - json ret = PrivateQuery(_curlHandle, _apiKey, kWalletAddressEndpointStr, {{"currency", currencyCode.str()}}); + json::container ret = + PrivateQuery(_curlHandle, _apiKey, kWalletAddressEndpointStr, {{"currency", currencyCode.str()}}); if (ret.is_discarded()) { throw exception("Bithumb unexpected reply from wallet address query for {}", currencyCode); } @@ -417,7 +419,7 @@ Wallet BithumbPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) namespace { -TimePoint RetrieveTimePointFromTrxJson(const json& trx, std::string_view fieldName) { +TimePoint RetrieveTimePointFromTrxJson(const json::container& trx, std::string_view fieldName) { // In the official documentation, transfer_date field is an integer. // But in fact (as of 2022) it's a string representation of the integer timestamp. // Let's support both types to be safe. @@ -458,7 +460,7 @@ auto FillOrderCurrencies(const OrdersConstraints& ordersConstraints, ExchangePub // Trick: let's use balance query to guess where we can search for orders, // by looking at "is_use" amounts to retrieve opened orders or "available" amounts to retrieve closed orders. // The only drawback is that we need to make one query for each currency, but it's better than nothing. - const json jsonReply = PrivateQuery(curlHandle, apiKey, "/info/balance", {{"currency", "all"}}); + const json::container jsonReply = PrivateQuery(curlHandle, apiKey, "/info/balance", {{"currency", "all"}}); const auto itemsIt = jsonReply.find("data"); if (jsonReply.is_discarded()) { log::error("Badly formatted {} reply from balance", exchangePublic.name()); @@ -512,7 +514,7 @@ OrderVectorType QueryOrders(const OrdersConstraints& ordersConstraints, Exchange for (CurrencyCode volumeCur : orderCurrencies) { params.set(kOrderCurrencyParamStr, volumeCur.str()); - json jsonReply = PrivateQuery(curlHandle, apiKey, "/info/orders", params); + json::container jsonReply = PrivateQuery(curlHandle, apiKey, "/info/orders", params); auto orderDetailsIt = jsonReply.find("data"); if (jsonReply.is_discarded()) { log::error("Badly formatted {} reply from order details", exchangePublic.name()); @@ -522,7 +524,7 @@ OrderVectorType QueryOrders(const OrdersConstraints& ordersConstraints, Exchange continue; } - for (json& orderDetails : *orderDetailsIt) { + for (json::container& orderDetails : *orderDetailsIt) { TimePoint placedTime = RetrieveTimePointFromTrxJson(orderDetails, "order_date"); if (!ordersConstraints.validatePlacedTime(placedTime)) { continue; @@ -574,7 +576,7 @@ constexpr int kSearchGbDeposit = 4; constexpr int kSearchGbProcessedWithdrawals = 5; constexpr int kSearchGbKRWDeposits = 9; -string GenerateDepositIdFromTrx(TimePoint timestamp, const json& trx) { +string GenerateDepositIdFromTrx(TimePoint timestamp, const json::container& trx) { // Bithumb does not provide any transaction id, let's generate it from currency and timestamp... string id{trx[kOrderCurrencyParamStr].get()}; id.push_back('-'); @@ -582,7 +584,7 @@ string GenerateDepositIdFromTrx(TimePoint timestamp, const json& trx) { return id; } -string GenerateWithdrawIdFromTrx(MonetaryAmount netEmittedAmount, const json& trx) { +string GenerateWithdrawIdFromTrx(MonetaryAmount netEmittedAmount, const json::container& trx) { // We cannot use the timestamp for the withdraw ID because it changes where is switches from the state 'withdrawing' // to the state 'withdraw done' (searchGb 3->5) // There are two fields that does not seem to change over time, and we are going to use them to generate our id: @@ -598,9 +600,9 @@ string GenerateWithdrawIdFromTrx(MonetaryAmount netEmittedAmount, const json& tr return B64Encode(withdrawId); } -CurrencyCode CurrencyCodeFromTrx(const json& trx) { return {trx["order_currency"].get()}; } +CurrencyCode CurrencyCodeFromTrx(const json::container& trx) { return {trx["order_currency"].get()}; } -MonetaryAmount RetrieveAmountFromTrxJson(const json& trx) { +MonetaryAmount RetrieveAmountFromTrxJson(const json::container& trx) { // starts with "+ " for a deposit, "- " for a withdraw, return absolute std::string_view amountStr = trx["units"].get(); @@ -613,19 +615,19 @@ MonetaryAmount RetrieveAmountFromTrxJson(const json& trx) { return amount.abs(); } -MonetaryAmount RetrieveFeeFromTrxJson(const json& trx) { +MonetaryAmount RetrieveFeeFromTrxJson(const json::container& trx) { std::string_view feeStr = trx["fee"].get(); // starts with "+ " CurrencyCode currencyCode(trx["fee_currency"].get()); return {feeStr, currencyCode}; } -MonetaryAmount RetrieveNetEmittedAmountFromTrxJson(const json& trx) { +MonetaryAmount RetrieveNetEmittedAmountFromTrxJson(const json::container& trx) { MonetaryAmount grossEmittedAmount = RetrieveAmountFromTrxJson(trx); MonetaryAmount fee = RetrieveFeeFromTrxJson(trx); return grossEmittedAmount - fee; } -Withdraw::Status RetrieveWithdrawStatusFromTrxJson(const json& trx) { +Withdraw::Status RetrieveWithdrawStatusFromTrxJson(const json::container& trx) { const auto searchGb = StringToIntegral(trx["search"].get()); return searchGb == kSearchGbOnGoingWithdrawals ? Withdraw::Status::kProcessing : Withdraw::Status::kSuccess; @@ -640,8 +642,8 @@ enum class UserTransactionEnum : int8_t { }; template -json QueryUserTransactions(BithumbPrivate& exchangePrivate, CurlHandle& curlHandle, const APIKey& apiKey, - const ConstraintsType& constraints, UserTransactionEnum userTransactionEnum) { +json::container QueryUserTransactions(BithumbPrivate& exchangePrivate, CurlHandle& curlHandle, const APIKey& apiKey, + const ConstraintsType& constraints, UserTransactionEnum userTransactionEnum) { SmallVector orderCurrencies; if (constraints.isCurDefined()) { @@ -673,7 +675,7 @@ json QueryUserTransactions(BithumbPrivate& exchangePrivate, CurlHandle& curlHand options.emplace_back(kPaymentCurParamStr, "BTC"); } - json allResults; + json::container allResults; FixedCapacityVector searchGbsVector; switch (userTransactionEnum) { case UserTransactionEnum::kClosedOrders: @@ -715,7 +717,7 @@ json QueryUserTransactions(BithumbPrivate& exchangePrivate, CurlHandle& curlHand for (int searchGb : searchGbsVector) { options.set("searchGb", searchGb); - json jsonReply = PrivateQuery(curlHandle, apiKey, "/info/user_transactions", options); + json::container jsonReply = PrivateQuery(curlHandle, apiKey, "/info/user_transactions", options); auto txrListIt = jsonReply.find("data"); if (jsonReply.is_discarded()) { log::error("Badly formatted {} reply from user transactions", exchangePrivate.exchangeName()); @@ -725,7 +727,7 @@ json QueryUserTransactions(BithumbPrivate& exchangePrivate, CurlHandle& curlHand continue; } - for (json& trx : *txrListIt) { + for (json::container& trx : *txrListIt) { if (!constraints.validateCur(CurrencyCodeFromTrx(trx))) { continue; } @@ -763,11 +765,11 @@ json QueryUserTransactions(BithumbPrivate& exchangePrivate, CurlHandle& curlHand ClosedOrderVector BithumbPrivate::queryClosedOrders(const OrdersConstraints& closedOrdersConstraints) { auto closedOrders = QueryOrders(closedOrdersConstraints, _exchangePublic, _curlHandle, _apiKey); - const json orderTransactionsJson = + const json::container orderTransactionsJson = QueryUserTransactions(*this, _curlHandle, _apiKey, closedOrdersConstraints, UserTransactionEnum::kClosedOrders); closedOrders.reserve(closedOrders.size() + orderTransactionsJson.size()); - for (const json& trx : orderTransactionsJson) { + for (const json::container& trx : orderTransactionsJson) { const TimePoint timestamp = RetrieveTimePointFromTrxJson(trx, "transfer_date"); string id = GenerateDepositIdFromTrx(timestamp, trx); @@ -805,9 +807,10 @@ int BithumbPrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersCons DepositsSet BithumbPrivate::queryRecentDeposits(const DepositsConstraints& depositsConstraints) { Deposits deposits; - json txrList = QueryUserTransactions(*this, _curlHandle, _apiKey, depositsConstraints, UserTransactionEnum::kDeposit); + json::container txrList = + QueryUserTransactions(*this, _curlHandle, _apiKey, depositsConstraints, UserTransactionEnum::kDeposit); deposits.reserve(txrList.size()); - for (const json& trx : txrList) { + for (const json::container& trx : txrList) { const TimePoint timestamp = RetrieveTimePointFromTrxJson(trx, "transfer_date"); string id = GenerateDepositIdFromTrx(timestamp, trx); @@ -823,10 +826,10 @@ DepositsSet BithumbPrivate::queryRecentDeposits(const DepositsConstraints& depos WithdrawsSet BithumbPrivate::queryRecentWithdraws(const WithdrawsConstraints& withdrawsConstraints) { Withdraws withdraws; - json txrList = + json::container txrList = QueryUserTransactions(*this, _curlHandle, _apiKey, withdrawsConstraints, UserTransactionEnum::kAllWithdraws); withdraws.reserve(txrList.size()); - for (const json& trx : txrList) { + for (const json::container& trx : txrList) { const TimePoint timestamp = RetrieveTimePointFromTrxJson(trx, "transfer_date"); const MonetaryAmount fee = RetrieveFeeFromTrxJson(trx); @@ -942,7 +945,7 @@ PlaceOrderInfo BithumbPrivate::placeOrder(MonetaryAmount /*from*/, MonetaryAmoun static constexpr int kNbMaxRetries = 3; bool currencyInfoUpdated = false; for (int nbRetries = 0; nbRetries < kNbMaxRetries; ++nbRetries) { - json result = PrivateQuery(_curlHandle, _apiKey, endpoint, placePostData); + json::container result = PrivateQuery(_curlHandle, _apiKey, endpoint, placePostData); if (result.is_discarded()) { log::error("Unexpected answer from {} place order - reply badly formatted", exchangeName()); break; @@ -1037,8 +1040,8 @@ CurlPostData OrderInfoPostData(Market mk, TradeSide side, OrderIdView orderId) { } // namespace void BithumbPrivate::cancelOrderProcess(OrderIdView orderId, const TradeContext& tradeContext) { - json ret = PrivateQuery(_curlHandle, _apiKey, "/trade/cancel", - OrderInfoPostData(tradeContext.mk, tradeContext.side, orderId)); + json::container ret = PrivateQuery(_curlHandle, _apiKey, "/trade/cancel", + OrderInfoPostData(tradeContext.mk, tradeContext.side, orderId)); if (ret.is_discarded()) { log::error("Cancel order process failed for {}, assuming order cancelled", exchangeName()); } @@ -1050,7 +1053,7 @@ OrderInfo BithumbPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext const CurrencyCode toCurrencyCode = tradeContext.toCur(); CurlPostData postData = OrderInfoPostData(mk, tradeContext.side, orderId); - json result = PrivateQuery(_curlHandle, _apiKey, "/info/orders", postData); + json::container result = PrivateQuery(_curlHandle, _apiKey, "/info/orders", postData); if (result.is_discarded()) { log::error("Badly formatted reply from {} query order info, considering order closed", exchangeName()); } @@ -1074,7 +1077,7 @@ OrderInfo BithumbPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext return orderInfo; } - for (const json& contractDetail : (*dataIt)["contract"]) { + for (const json::container& contractDetail : (*dataIt)["contract"]) { // always in base currency MonetaryAmount tradedVol(contractDetail["units"].get(), mk.base()); // always in quote currency @@ -1096,7 +1099,7 @@ OrderInfo BithumbPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext } namespace { -bool CompareTrxByDate(const json& lhs, const json& rhs) { +bool CompareTrxByDate(const json::container& lhs, const json::container& rhs) { const auto lhsTs = RetrieveTimePointFromTrxJson(lhs, "transfer_date"); const auto rhsTs = RetrieveTimePointFromTrxJson(rhs, "transfer_date"); return lhsTs < rhsTs; @@ -1146,20 +1149,20 @@ InitiatedWithdrawInfo BithumbPrivate::launchWithdraw(MonetaryAmount grossAmount, // We have to retrieve the withdraw from the other endpoint used by 'queryRecentWithdraws'. WithdrawsConstraints withdrawConstraints(currencyCode); - json oldWithdraws = + json::container oldWithdraws = QueryUserTransactions(*this, _curlHandle, _apiKey, withdrawConstraints, UserTransactionEnum::kOngoingWithdraws); std::sort(oldWithdraws.begin(), oldWithdraws.end(), CompareTrxByDate); // Actually launch the withdraw - json ret = PrivateQuery(_curlHandle, _apiKey, "/trade/btc_withdrawal", - ComputeLaunchWithdrawCurlPostData(netEmittedAmount, destinationWallet)); + json::container ret = PrivateQuery(_curlHandle, _apiKey, "/trade/btc_withdrawal", + ComputeLaunchWithdrawCurlPostData(netEmittedAmount, destinationWallet)); if (ret.is_discarded()) { log::error("Withdrawal query error for {} - please double check whether withdrawal has been applied or not", exchangeName()); } // Query the withdraws, hopefully we will be able to find our withdraw - json newWithdrawTrx; + json::container newWithdrawTrx; seconds sleepingTime(1); static constexpr int kNbRetriesCatchWindow = 15; for (int retryPos = 0; retryPos < kNbRetriesCatchWindow && newWithdrawTrx.empty(); ++retryPos) { @@ -1169,18 +1172,18 @@ InitiatedWithdrawInfo BithumbPrivate::launchWithdraw(MonetaryAmount grossAmount, std::this_thread::sleep_for(sleepingTime); sleepingTime = (3 * sleepingTime) / 2; } - json currentWithdraws = + json::container currentWithdraws = QueryUserTransactions(*this, _curlHandle, _apiKey, withdrawConstraints, UserTransactionEnum::kOngoingWithdraws); std::sort(currentWithdraws.begin(), currentWithdraws.end(), CompareTrxByDate); // Isolate the new withdraws since the launch of our new withdraw - json newWithdraws; + json::container newWithdraws; std::set_difference(currentWithdraws.begin(), currentWithdraws.end(), oldWithdraws.begin(), oldWithdraws.end(), std::back_inserter(newWithdraws), CompareTrxByDate); log::debug("Isolated {} new withdraws, one of them is probably the one just launched", newWithdraws.size()); - for (json& withdrawTrx : newWithdraws) { + for (json::container& withdrawTrx : newWithdraws) { MonetaryAmount withdrawNetEmittedAmount = RetrieveNetEmittedAmountFromTrxJson(withdrawTrx); if (withdrawNetEmittedAmount.isCloseTo(netEmittedAmount, 0.001)) { log::debug("Found new withdraw {}", withdrawTrx.dump()); @@ -1201,9 +1204,9 @@ InitiatedWithdrawInfo BithumbPrivate::launchWithdraw(MonetaryAmount grossAmount, } void BithumbPrivate::updateCacheFile() const { - json data; + json::container data; for (const auto& [currencyCode, currencyOrderInfo] : _currencyOrderInfoMap) { - json curData; + json::container curData; curData.emplace(kNbDecimalsStr, CurrencyOrderInfoField2Json(currencyOrderInfo.nbDecimals, currencyOrderInfo.lastNbDecimalsUpdatedTime)); @@ -1219,7 +1222,7 @@ void BithumbPrivate::updateCacheFile() const { data.emplace(currencyCode.str(), std::move(curData)); } - GetBithumbCurrencyInfoMapCache(_coincenterInfo.dataDir()).write(data); + GetBithumbCurrencyInfoMapCache(_coincenterInfo.dataDir()).writeJson(data); } } // namespace cct::api diff --git a/src/api/exchanges/src/bithumbpublicapi.cpp b/src/api/exchanges/src/bithumbpublicapi.cpp index d34476b2..62762563 100644 --- a/src/api/exchanges/src/bithumbpublicapi.cpp +++ b/src/api/exchanges/src/bithumbpublicapi.cpp @@ -15,7 +15,7 @@ #include "apiquerytypeenum.hpp" #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -68,21 +68,22 @@ auto ComputeMethodUrl(std::string_view endpoint, CurrencyCode base, CurrencyCode return methodUrl; } -json PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, CurrencyCode base, - CurrencyCode quote = CurrencyCode(), std::string_view urlOpts = "") { +json::container PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, CurrencyCode base, + CurrencyCode quote = CurrencyCode(), std::string_view urlOpts = "") { RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet)); - json jsonResponse = requestRetry.queryJson(ComputeMethodUrl(endpoint, base, quote, urlOpts), [](const json& data) { - const auto statusCode = BithumbPublic::StatusCodeFromJsonResponse(data); - if (statusCode != BithumbPublic::kStatusOK) { - log::warn("Full Bithumb json error ({}): '{}'", statusCode, data.dump()); - return RequestRetry::Status::kResponseError; - } - return RequestRetry::Status::kResponseOK; - }); + json::container jsonResponse = + requestRetry.queryJson(ComputeMethodUrl(endpoint, base, quote, urlOpts), [](const json::container& data) { + const auto statusCode = BithumbPublic::StatusCodeFromJsonResponse(data); + if (statusCode != BithumbPublic::kStatusOK) { + log::warn("Full Bithumb error ({}): '{}'", statusCode, data.dump()); + return RequestRetry::Status::kResponseError; + } + return RequestRetry::Status::kResponseOK; + }); const auto dataIt = jsonResponse.find("data"); - json ret; + json::container ret; if (dataIt != jsonResponse.end()) { ret.swap(*dataIt); } @@ -107,7 +108,7 @@ BithumbPublic::BithumbPublic(const CoincenterInfo& config, FiatConverter& fiatCo CachedResultOptions(exchangeConfig().getAPICallUpdateFrequency(kTradedVolume), _cachedResultVault), _curlHandle) {} -int64_t BithumbPublic::StatusCodeFromJsonResponse(const json& jsonResponse) { +int64_t BithumbPublic::StatusCodeFromJsonResponse(const json::container& jsonResponse) { const auto statusIt = jsonResponse.find("status"); if (statusIt == jsonResponse.end()) { return kStatusNotPresentError; @@ -125,7 +126,7 @@ int64_t BithumbPublic::StatusCodeFromJsonResponse(const json& jsonResponse) { bool BithumbPublic::healthCheck() { static constexpr bool kAllowExceptions = false; - const json jsonResponse = json::parse( + const json::container jsonResponse = json::container::parse( _curlHandle.query("/public/assetsstatus/BTC", CurlOptions(HttpRequestType::kGet)), nullptr, kAllowExceptions); if (jsonResponse.is_discarded()) { log::error("{} health check response is badly formatted", _name); @@ -164,7 +165,7 @@ MonetaryAmount BithumbPublic::queryLastPrice(Market mk) { } CurrencyExchangeFlatSet BithumbPublic::TradableCurrenciesFunc::operator()() { - json result = PublicQuery(_curlHandle, "/public/assetsstatus/", "all"); + json::container result = PublicQuery(_curlHandle, "/public/assetsstatus/", "all"); CurrencyExchangeVector currencies; currencies.reserve(static_cast(result.size() + 1)); for (const auto& [asset, withdrawalDeposit] : result.items()) { @@ -208,7 +209,7 @@ OutputType GetOrderBooks(CurlHandle& curlHandle, const CoincenterInfo& config, c AppendIntegralToString(urlOpts, *optDepth); } - json result = PublicQuery(curlHandle, "/public/orderbook/", base, quote, urlOpts); + json::container result = PublicQuery(curlHandle, "/public/orderbook/", base, quote, urlOpts); if (!result.empty()) { // Note: as of 2021-02-24, Bithumb payment currency is always KRW. Format of json may change once it's not the case // anymore @@ -224,7 +225,7 @@ OutputType GetOrderBooks(CurlHandle& curlHandle, const CoincenterInfo& config, c for (const auto& [baseOrSpecial, asksAndBids] : result.items()) { if (baseOrSpecial != "payment_currency" && baseOrSpecial != "timestamp") { - const json* asksBids[2]; + const json::container* asksBids[2]; CurrencyCode baseCurrencyCode; if (singleMarketQuote && baseOrSpecial == "order_currency") { // single market quote @@ -253,9 +254,9 @@ OutputType GetOrderBooks(CurlHandle& curlHandle, const CoincenterInfo& config, c */ orderBookLines.clear(); orderBookLines.reserve(asksBids[0]->size() + asksBids[1]->size()); - for (const json* asksOrBids : asksBids) { + for (const json::container* asksOrBids : asksBids) { const auto type = asksOrBids == asksBids[0] ? OrderBookLine::Type::kAsk : OrderBookLine::Type::kBid; - for (const json& priceQuantityPair : *asksOrBids) { + for (const json::container& priceQuantityPair : *asksOrBids) { MonetaryAmount amount(priceQuantityPair["quantity"].get(), baseCurrencyCode); MonetaryAmount price(priceQuantityPair["price"].get(), quoteCurrencyCode); @@ -293,7 +294,7 @@ MarketOrderBook BithumbPublic::OrderBookFunc::operator()(Market mk, int depth) { MonetaryAmount BithumbPublic::TradedVolumeFunc::operator()(Market mk) { TimePoint t1 = Clock::now(); - json result = PublicQuery(_curlHandle, "/public/ticker/", mk.base(), mk.quote()); + json::container result = PublicQuery(_curlHandle, "/public/ticker/", mk.base(), mk.quote()); std::string_view last24hVol; const auto dateIt = result.find("date"); if (dateIt != result.end()) { @@ -339,12 +340,12 @@ PublicTradeVector BithumbPublic::queryLastTrades(Market mk, int nbTrades) { string urlOpts("count="); AppendIntegralToString(urlOpts, nbTrades); - json result = PublicQuery(_curlHandle, "/public/transaction_history/", mk.base(), mk.quote(), urlOpts); + json::container result = PublicQuery(_curlHandle, "/public/transaction_history/", mk.base(), mk.quote(), urlOpts); PublicTradeVector ret; ret.reserve(static_cast(result.size())); - for (const json& detail : result) { + for (const json::container& detail : result) { MonetaryAmount amount(detail["units_traded"].get(), mk.base()); MonetaryAmount price(detail["price"].get(), mk.quote()); // Korea time (UTC+9) in this format: "2021-11-29 03:29:35" diff --git a/src/api/exchanges/src/huobiprivateapi.cpp b/src/api/exchanges/src/huobiprivateapi.cpp index 5a8abe59..1aecd569 100644 --- a/src/api/exchanges/src/huobiprivateapi.cpp +++ b/src/api/exchanges/src/huobiprivateapi.cpp @@ -16,7 +16,7 @@ #include "cachedresult.hpp" #include "cct_cctype.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "cct_vector.hpp" @@ -79,7 +79,7 @@ string BuildParamStr(HttpRequestType requestType, std::string_view baseUrl, std: auto ComputePostDataFormat(HttpRequestType requestType, const CurlPostData& postData) { CurlOptions::PostDataFormat postDataFormat = CurlOptions::PostDataFormat::kString; if (!postData.empty() && requestType != HttpRequestType::kGet) { - postDataFormat = CurlOptions::PostDataFormat::kJson; + postDataFormat = CurlOptions::PostDataFormat::json; } return postDataFormat; } @@ -107,8 +107,8 @@ void SetNonceAndSignature(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequ isNotEncoded)); } -json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType requestType, std::string_view endpoint, - CurlPostData&& postData = CurlPostData()) { +json::container PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType requestType, + std::string_view endpoint, CurlPostData&& postData = CurlPostData()) { CurlPostData signaturePostData{ {"AccessKeyId", apiKey.key()}, {"SignatureMethod", "HmacSHA256"}, {"SignatureVersion", 2}}; @@ -120,12 +120,12 @@ json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType RequestRetry requestRetry(curlHandle, CurlOptions(requestType, std::move(postData), postDataFormat), QueryRetryPolicy{.initialRetryDelay = seconds{1}, .nbMaxRetries = 3}); - json ret = requestRetry.queryJson( + json::container ret = requestRetry.queryJson( method, - [](const json& jsonResponse) { + [](const json::container& jsonResponse) { const auto statusIt = jsonResponse.find("status"); if (statusIt != jsonResponse.end() && statusIt->get() != "ok") { - log::warn("Full Huobi json error: '{}'", jsonResponse.dump()); + log::warn("Full Huobi error: '{}'", jsonResponse.dump()); return RequestRetry::Status::kResponseError; } return RequestRetry::Status::kResponseOK; @@ -154,7 +154,8 @@ HuobiPrivate::HuobiPrivate(const CoincenterInfo& coincenterInfo, HuobiPublic& hu _curlHandle, _apiKey, huobiPublic) {} bool HuobiPrivate::validateApiKey() { - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/account/accounts", CurlPostData()); + json::container result = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/account/accounts", CurlPostData()); if (result.empty()) { return false; } @@ -166,7 +167,7 @@ BalancePortfolio HuobiPrivate::queryAccountBalance(const BalanceOptions& balance string method = "/v1/account/accounts/"; AppendIntegralToString(method, _accountIdCache.get()); method.append("/balance"); - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, method); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, method); BalancePortfolio balancePortfolio; if (result.empty()) { return balancePortfolio; @@ -174,7 +175,7 @@ BalancePortfolio HuobiPrivate::queryAccountBalance(const BalanceOptions& balance bool withBalanceInUse = balanceOptions.amountIncludePolicy() == BalanceOptions::AmountIncludePolicy::kWithBalanceInUse; - for (const json& balanceDetail : result["data"]["list"]) { + for (const json::container& balanceDetail : result["data"]["list"]) { std::string_view typeStr = balanceDetail["type"].get(); CurrencyCode currencyCode(balanceDetail["currency"].get()); MonetaryAmount amount(balanceDetail["balance"].get(), currencyCode); @@ -189,8 +190,8 @@ BalancePortfolio HuobiPrivate::queryAccountBalance(const BalanceOptions& balance Wallet HuobiPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) { string lowerCaseCur = ToLower(currencyCode.str()); - json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v2/account/deposit/address", - {{"currency", lowerCaseCur}}); + json::container data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v2/account/deposit/address", + {{"currency", lowerCaseCur}}); string address; std::string_view tag; @@ -201,7 +202,7 @@ Wallet HuobiPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) { auto dataIt = data.find("data"); if (dataIt != data.end()) { - for (json& depositDetail : *dataIt) { + for (json::container& depositDetail : *dataIt) { tag = depositDetail["addressTag"].get(); std::string_view addressView = depositDetail["address"].get(); @@ -258,7 +259,8 @@ ClosedOrderVector HuobiPrivate::queryClosedOrders(const OrdersConstraints& close const std::string_view closedOrdersEndpoint = closedOrdersConstraints.isMarketDefined() ? "/v1/order/orders" : "/v1/order/history"; - json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, closedOrdersEndpoint, std::move(params)); + json::container data = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, closedOrdersEndpoint, std::move(params)); const auto dataIt = data.find("data"); if (dataIt == data.end()) { @@ -268,7 +270,7 @@ ClosedOrderVector HuobiPrivate::queryClosedOrders(const OrdersConstraints& close MarketSet markets; - for (json& orderDetails : *dataIt) { + for (json::container& orderDetails : *dataIt) { string marketStr = ToUpper(orderDetails["symbol"].get()); std::optional optMarket = @@ -324,7 +326,8 @@ OpenedOrderVector HuobiPrivate::queryOpenedOrders(const OrdersConstraints& opene } } - json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/order/openOrders", std::move(params)); + json::container data = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/order/openOrders", std::move(params)); OpenedOrderVector openedOrders; const auto dataIt = data.find("data"); if (dataIt == data.end()) { @@ -332,7 +335,7 @@ OpenedOrderVector HuobiPrivate::queryOpenedOrders(const OrdersConstraints& opene return openedOrders; } - for (const json& orderDetails : *dataIt) { + for (const json::container& orderDetails : *dataIt) { string marketStr = ToUpper(orderDetails["symbol"].get()); std::optional optMarket = @@ -412,11 +415,11 @@ DepositsSet HuobiPrivate::queryRecentDeposits(const DepositsConstraints& deposit } options.emplace_back("size", 500); options.emplace_back("type", "deposit"); - json data = + json::container data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/query/deposit-withdraw", std::move(options)); const auto dataIt = data.find("data"); if (dataIt != data.end()) { - for (const json& depositDetail : *dataIt) { + for (const json::container& depositDetail : *dataIt) { std::string_view statusStr = depositDetail["state"].get(); int64_t id = depositDetail["id"].get(); Deposit::Status status = DepositStatusFromStatusStr(statusStr); @@ -540,11 +543,11 @@ CurlPostData CreateOptionsFromWithdrawConstraints(const WithdrawsConstraints& wi WithdrawsSet HuobiPrivate::queryRecentWithdraws(const WithdrawsConstraints& withdrawsConstraints) { Withdraws withdraws; - json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/query/deposit-withdraw", - CreateOptionsFromWithdrawConstraints(withdrawsConstraints)); + json::container data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/query/deposit-withdraw", + CreateOptionsFromWithdrawConstraints(withdrawsConstraints)); const auto dataIt = data.find("data"); if (dataIt != data.end()) { - for (const json& withdrawDetail : *dataIt) { + for (const json::container& withdrawDetail : *dataIt) { std::string_view statusStr = withdrawDetail["state"].get(); int64_t id = withdrawDetail["id"].get(); Withdraw::Status status = WithdrawStatusFromStatusStr(statusStr, withdrawsConstraints.isCurDefined()); @@ -642,7 +645,7 @@ PlaceOrderInfo HuobiPrivate::placeOrder(MonetaryAmount from, MonetaryAmount volu placePostData.emplace_back("symbol", lowerCaseMarket); placePostData.emplace_back("type", type); - json result = + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/v1/order/orders/place", std::move(placePostData)); auto dataIt = result.find("data"); @@ -675,7 +678,7 @@ OrderInfo HuobiPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext& string endpoint(kBaseUrlOrders); endpoint.append(orderId); - const json res = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, endpoint); + const json::container res = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, endpoint); const auto dataIt = res.find("data"); // Warning: I think Huobi's API has a typo with the 'filled' transformed into 'field' (even documentation is @@ -716,14 +719,14 @@ InitiatedWithdrawInfo HuobiPrivate::launchWithdraw(MonetaryAmount grossAmount, W string lowerCaseCur = ToLower(currencyCode.str()); HuobiPublic& huobiPublic = dynamic_cast(_exchangePublic); - json queryWithdrawAddressJson = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, - "/v2/account/withdraw/address", {{"currency", lowerCaseCur}}); + json::container queryWithdrawAddressJson = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, + "/v2/account/withdraw/address", {{"currency", lowerCaseCur}}); const auto addressDataIt = queryWithdrawAddressJson.find("data"); if (addressDataIt == queryWithdrawAddressJson.end()) { throw exception("Unexpected reply from Huobi withdraw address"); } std::string_view huobiWithdrawAddressName; - for (const json& withdrawAddress : *addressDataIt) { + for (const json::container& withdrawAddress : *addressDataIt) { std::string_view address(withdrawAddress["address"].get()); std::string_view addressTag(withdrawAddress["addressTag"].get()); if (address == destinationWallet.address() && addressTag == destinationWallet.tag()) { @@ -766,8 +769,8 @@ InitiatedWithdrawInfo HuobiPrivate::launchWithdraw(MonetaryAmount grossAmount, W // Strange to have the fee as input parameter of a withdraw... withdrawPostData.emplace_back("fee", withdrawFee.amountStr()); - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/v1/dw/withdraw/api/create", - std::move(withdrawPostData)); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/v1/dw/withdraw/api/create", + std::move(withdrawPostData)); const auto createDataIt = result.find("data"); if (createDataIt == result.end()) { throw exception("Unexpected response from withdraw create for {}", huobiPublic.name()); @@ -777,12 +780,12 @@ InitiatedWithdrawInfo HuobiPrivate::launchWithdraw(MonetaryAmount grossAmount, W } int HuobiPrivate::AccountIdFunc::operator()() { - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/account/accounts"); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/account/accounts"); const auto dataIt = result.find("data"); if (dataIt == result.end()) { throw exception("Unexpected reply from account id query for Huobi"); } - for (const json& accDetails : *dataIt) { + for (const json::container& accDetails : *dataIt) { std::string_view state = accDetails["state"].get(); if (state == "working") { return accDetails["id"].get(); diff --git a/src/api/exchanges/src/huobipublicapi.cpp b/src/api/exchanges/src/huobipublicapi.cpp index 3188108b..a792b214 100644 --- a/src/api/exchanges/src/huobipublicapi.cpp +++ b/src/api/exchanges/src/huobipublicapi.cpp @@ -12,7 +12,7 @@ #include "apiquerytypeenum.hpp" #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -47,7 +47,8 @@ namespace { constexpr std::string_view kHealthCheckBaseUrl[] = {"https://status.huobigroup.com"}; -json PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, const CurlPostData& curlPostData = CurlPostData()) { +json::container PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, + const CurlPostData& curlPostData = CurlPostData()) { string method(endpoint); if (!curlPostData.empty()) { method.push_back('?'); @@ -56,18 +57,18 @@ json PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, const CurlPo RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet)); - json jsonResponse = requestRetry.queryJson(method, [](const json& jsonResponse) { + json::container jsonResponse = requestRetry.queryJson(method, [](const json::container& jsonResponse) { const auto dataIt = jsonResponse.find("data"); if (dataIt == jsonResponse.end()) { const auto tickIt = jsonResponse.find("tick"); if (tickIt == jsonResponse.end()) { - log::warn("Full Huobi json error: '{}'", jsonResponse.dump()); + log::warn("Full Huobi error: '{}'", jsonResponse.dump()); return RequestRetry::Status::kResponseError; } } return RequestRetry::Status::kResponseOK; }); - json ret; + json::container ret; const auto dataIt = jsonResponse.find("data"); if (dataIt != jsonResponse.end()) { ret.swap(*dataIt); @@ -108,8 +109,9 @@ HuobiPublic::HuobiPublic(const CoincenterInfo& config, FiatConverter& fiatConver bool HuobiPublic::healthCheck() { static constexpr bool kAllowExceptions = false; - json result = json::parse(_healthCheckCurlHandle.query("/api/v2/summary.json", CurlOptions(HttpRequestType::kGet)), - nullptr, kAllowExceptions); + json::container result = + json::container::parse(_healthCheckCurlHandle.query("/api/v2/summary.json", CurlOptions(HttpRequestType::kGet)), + nullptr, kAllowExceptions); if (result.is_discarded()) { log::error("{} health check response is badly formatted", _name); return false; @@ -130,9 +132,11 @@ bool HuobiPublic::healthCheck() { return incidentsIt != result.end() && incidentsIt->empty(); } -json HuobiPublic::TradableCurrenciesFunc::operator()() { return PublicQuery(_curlHandle, "/v2/reference/currencies"); } +json::container HuobiPublic::TradableCurrenciesFunc::operator()() { + return PublicQuery(_curlHandle, "/v2/reference/currencies"); +} -bool HuobiPublic::ShouldDiscardChain(CurrencyCode cur, const json& chainDetail) { +bool HuobiPublic::ShouldDiscardChain(CurrencyCode cur, const json::container& chainDetail) { std::string_view chainName = chainDetail["chain"].get(); if (!cur.iequal(chainName) && !cur.iequal(chainDetail["displayName"].get())) { log::debug("Discarding chain '{}' as not supported by {}", chainName, cur); @@ -143,10 +147,10 @@ bool HuobiPublic::ShouldDiscardChain(CurrencyCode cur, const json& chainDetail) HuobiPublic::WithdrawParams HuobiPublic::getWithdrawParams(CurrencyCode cur) { WithdrawParams withdrawParams; - for (const json& curDetail : _tradableCurrenciesCache.get()) { + for (const json::container& curDetail : _tradableCurrenciesCache.get()) { std::string_view curStr = curDetail["currency"].get(); if (cur == CurrencyCode(_coincenterInfo.standardizeCurrencyCode(curStr))) { - for (const json& chainDetail : curDetail["chains"]) { + for (const json::container& chainDetail : curDetail["chains"]) { if (ShouldDiscardChain(cur, chainDetail)) { continue; } @@ -166,7 +170,7 @@ HuobiPublic::WithdrawParams HuobiPublic::getWithdrawParams(CurrencyCode cur) { CurrencyExchangeFlatSet HuobiPublic::queryTradableCurrencies() { CurrencyExchangeVector currencies; - for (const json& curDetail : _tradableCurrenciesCache.get()) { + for (const json::container& curDetail : _tradableCurrenciesCache.get()) { std::string_view statusStr = curDetail["instStatus"].get(); std::string_view curStr = curDetail["currency"].get(); if (statusStr != "normal") { @@ -175,7 +179,7 @@ CurrencyExchangeFlatSet HuobiPublic::queryTradableCurrencies() { } bool foundChainWithSameName = false; CurrencyCode cur(_coincenterInfo.standardizeCurrencyCode(curStr)); - for (const json& chainDetail : curDetail["chains"]) { + for (const json::container& chainDetail : curDetail["chains"]) { if (ShouldDiscardChain(cur, chainDetail)) { continue; } @@ -206,7 +210,7 @@ CurrencyExchangeFlatSet HuobiPublic::queryTradableCurrencies() { } std::pair HuobiPublic::MarketsFunc::operator()() { - json result = PublicQuery(_curlHandle, "/v1/common/symbols"); + json::container result = PublicQuery(_curlHandle, "/v1/common/symbols"); MarketSet markets; MarketInfoMap marketInfoMap; @@ -215,7 +219,7 @@ std::pair HuobiPublic::Marke const CurrencyCodeSet& excludedCurrencies = _exchangeConfig.excludedCurrenciesAll(); - for (const json& marketDetails : result) { + for (const json::container& marketDetails : result) { std::string_view baseAsset = marketDetails["base-currency"].get(); std::string_view quoteAsset = marketDetails["quote-currency"].get(); if (excludedCurrencies.contains(baseAsset) || excludedCurrencies.contains(quoteAsset)) { @@ -274,11 +278,11 @@ std::pair HuobiPublic::Marke MonetaryAmountByCurrencySet HuobiPublic::queryWithdrawalFees() { MonetaryAmountVector fees; - for (const json& curDetail : _tradableCurrenciesCache.get()) { + for (const json::container& curDetail : _tradableCurrenciesCache.get()) { std::string_view curStr = curDetail["currency"].get(); CurrencyCode cur(_coincenterInfo.standardizeCurrencyCode(curStr)); bool foundChainWithSameName = false; - for (const json& chainDetail : curDetail["chains"]) { + for (const json::container& chainDetail : curDetail["chains"]) { if (ShouldDiscardChain(cur, chainDetail)) { continue; } @@ -312,13 +316,13 @@ MonetaryAmountByCurrencySet HuobiPublic::queryWithdrawalFees() { } std::optional HuobiPublic::queryWithdrawalFee(CurrencyCode currencyCode) { - for (const json& curDetail : _tradableCurrenciesCache.get()) { + for (const json::container& curDetail : _tradableCurrenciesCache.get()) { std::string_view curStr = curDetail["currency"].get(); CurrencyCode cur(_coincenterInfo.standardizeCurrencyCode(curStr)); if (cur != currencyCode) { continue; } - for (const json& chainDetail : curDetail["chains"]) { + for (const json::container& chainDetail : curDetail["chains"]) { std::string_view chainName = chainDetail["chain"].get(); if (chainName == cur) { return MonetaryAmount(chainDetail["transactFeeWithdraw"].get(), cur); @@ -339,7 +343,7 @@ MarketOrderBookMap HuobiPublic::AllOrderBooksFunc::operator()(int depth) { } const auto tickerData = PublicQuery(_curlHandle, "/market/tickers"); const auto time = Clock::now(); - for (const json& tickerDetails : tickerData) { + for (const json::container& tickerDetails : tickerData) { string upperMarket = ToUpper(tickerDetails["symbol"].get()); auto it = huobiAssetPairToStdMarketMap.find(upperMarket); if (it == huobiAssetPairToStdMarketMap.end()) { @@ -384,7 +388,7 @@ MarketOrderBook HuobiPublic::OrderBookFunc::operator()(Market mk, int depth) { MarketOrderBookLines orderBookLines; - const json asksAndBids = PublicQuery(_curlHandle, "/market/depth", postData); + const json::container asksAndBids = PublicQuery(_curlHandle, "/market/depth", postData); const auto nowTime = Clock::now(); const auto asksIt = asksAndBids.find("asks"); const auto bidsIt = asksAndBids.find("bids"); @@ -449,7 +453,7 @@ MonetaryAmount HuobiPublic::sanitizeVolume(Market mk, CurrencyCode fromCurrencyC } MonetaryAmount HuobiPublic::TradedVolumeFunc::operator()(Market mk) { - json result = PublicQuery(_curlHandle, "/market/detail/merged", {{"symbol", mk.assetsPairStrLower()}}); + json::container result = PublicQuery(_curlHandle, "/market/detail/merged", {{"symbol", mk.assetsPairStrLower()}}); const auto amountIt = result.find("amountIt"); double last24hVol = amountIt == result.end() ? 0 : amountIt->get(); return MonetaryAmount(last24hVol, mk.base()); @@ -467,16 +471,16 @@ PublicTradeVector HuobiPublic::queryLastTrades(Market mk, int nbTrades) { nbTrades = kNbMaxLastTrades; } - json result = + json::container result = PublicQuery(_curlHandle, "/market/history/trade", {{"symbol", mk.assetsPairStrLower()}, {"size", nbTrades}}); PublicTradeVector ret; ret.reserve(nbTrades); - for (const json& detail : result) { + for (const json::container& detail : result) { const auto dataDetails = detail.find("data"); if (dataDetails != detail.end()) { - for (const json& detail2 : *dataDetails) { + for (const json::container& detail2 : *dataDetails) { const MonetaryAmount amount(detail2["amount"].get(), mk.base()); const MonetaryAmount price(detail2["price"].get(), mk.quote()); const int64_t millisecondsSinceEpoch = detail2["ts"].get(); @@ -499,7 +503,7 @@ PublicTradeVector HuobiPublic::queryLastTrades(Market mk, int nbTrades) { } MonetaryAmount HuobiPublic::TickerFunc::operator()(Market mk) { - json result = PublicQuery(_curlHandle, "/market/trade", {{"symbol", mk.assetsPairStrLower()}}); + json::container result = PublicQuery(_curlHandle, "/market/trade", {{"symbol", mk.assetsPairStrLower()}}); const auto dataIt = result.find("data"); double lastPrice = dataIt == result.end() ? 0 : dataIt->front()["price"].get(); return MonetaryAmount(lastPrice, mk.quote()); diff --git a/src/api/exchanges/src/krakenprivateapi.cpp b/src/api/exchanges/src/krakenprivateapi.cpp index 32ff4a9d..f91e6f77 100644 --- a/src/api/exchanges/src/krakenprivateapi.cpp +++ b/src/api/exchanges/src/krakenprivateapi.cpp @@ -15,7 +15,7 @@ #include "base64.hpp" #include "cachedresult.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -76,9 +76,9 @@ auto PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, std::string_view KrakenErrorEnum err = KrakenErrorEnum::kNoError; - json ret = requestRetry.queryJson( + json::container ret = requestRetry.queryJson( method, - [&err](const json& jsonResponse) { + [&err](const json::container& jsonResponse) { const auto errorIt = jsonResponse.find(kErrorKey); if (errorIt != jsonResponse.end() && !errorIt->empty()) { std::string_view msg = errorIt->front().get(); @@ -121,7 +121,7 @@ auto PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, std::string_view }); auto resultIt = ret.find("result"); - std::pair retPair(json::object_t{}, err); + std::pair retPair(json::container::object_t{}, err); if (resultIt != ret.end()) { retPair.first = std::move(*resultIt); } @@ -222,7 +222,7 @@ Wallet KrakenPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) { WalletCheck walletCheck(coincenterInfo.dataDir(), doCheckWallet); string address; string tag; - for (const json& depositDetail : res) { + for (const json::container& depositDetail : res) { for (const auto& [keyStr, valueStr] : depositDetail.items()) { if (keyStr == "address") { address = valueStr; @@ -313,7 +313,7 @@ ClosedOrderVector KrakenPrivate::queryClosedOrders(const OrdersConstraints& clos if (!closedOrdersConstraints.validateId(orderId)) { continue; } - const json& descrPart = orderDetails["descr"]; + const json::container& descrPart = orderDetails["descr"]; std::string_view marketStr = descrPart["pair"].get(); std::optional optMarket = @@ -366,7 +366,7 @@ OpenedOrderVector KrakenPrivate::queryOpenedOrders(const OrdersConstraints& open MarketSet markets; for (const auto& [id, orderDetails] : openedPartIt->items()) { - const json& descrPart = orderDetails["descr"]; + const json::container& descrPart = orderDetails["descr"]; std::string_view marketStr = descrPart["pair"].get(); std::optional optMarket = @@ -439,7 +439,7 @@ DepositsSet KrakenPrivate::queryRecentDeposits(const DepositsConstraints& deposi options.emplace_back("asset", depositsConstraints.currencyCode().str()); } auto [res, err] = PrivateQuery(_curlHandle, _apiKey, "/private/DepositStatus", options); - for (const json& trx : res) { + for (const json::container& trx : res) { auto additionalNoteIt = trx.find("status-prop"); if (additionalNoteIt != trx.end()) { std::string_view statusNote(additionalNoteIt->get()); @@ -500,7 +500,7 @@ WithdrawsSet KrakenPrivate::queryRecentWithdraws(const WithdrawsConstraints& wit Withdraws withdraws; auto [res, err] = PrivateQuery(_curlHandle, _apiKey, "/private/WithdrawStatus", CreateOptionsFromWithdrawConstraints(withdrawsConstraints)); - for (const json& trx : res) { + for (const json::container& trx : res) { int64_t secondsSinceEpoch = trx["time"].get(); TimePoint timestamp{seconds(secondsSinceEpoch)}; if (!withdrawsConstraints.validateTime(timestamp)) { @@ -624,10 +624,10 @@ OrderInfo KrakenPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext& const CurrencyCode toCurrencyCode = tradeContext.toCur(); const Market mk = tradeContext.mk; - json ordersRes = queryOrdersData(tradeContext.userRef, orderId, queryOrder); + json::container ordersRes = queryOrdersData(tradeContext.userRef, orderId, queryOrder); auto openIt = ordersRes.find("open"); const bool orderInOpenedPart = openIt != ordersRes.end() && openIt->contains(orderId); - const json& orderJson = orderInOpenedPart ? (*openIt)[orderId] : ordersRes["closed"][orderId]; + const json::container& orderJson = orderInOpenedPart ? (*openIt)[orderId] : ordersRes["closed"][orderId]; MonetaryAmount vol(orderJson["vol"].get(), mk.base()); // always in base currency MonetaryAmount tradedVol(orderJson["vol_exec"].get(), mk.base()); // always in base currency OrderInfo orderInfo(TradedAmounts(fromCurrencyCode, toCurrencyCode), !orderInOpenedPart); @@ -649,7 +649,7 @@ OrderInfo KrakenPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext& return orderInfo; } -json KrakenPrivate::queryOrdersData(int64_t userRef, OrderIdView orderId, QueryOrder queryOrder) { +json::container KrakenPrivate::queryOrdersData(int64_t userRef, OrderIdView orderId, QueryOrder queryOrder) { static constexpr int kNbMaxRetriesQueryOrders = 10; int nbRetries = 0; CurlPostData ordersPostData{{"trades", "true"}, {"userref", userRef}}; @@ -657,12 +657,12 @@ json KrakenPrivate::queryOrdersData(int64_t userRef, OrderIdView orderId, QueryO const std::string_view firstQueryFullName = isOpenedFirst ? "/private/OpenOrders" : "/private/ClosedOrders"; do { auto [data, err] = PrivateQuery(_curlHandle, _apiKey, firstQueryFullName, ordersPostData); - const json& firstOrders = data[isOpenedFirst ? "open" : "closed"]; + const json::container& firstOrders = data[isOpenedFirst ? "open" : "closed"]; bool foundOrder = firstOrders.contains(orderId); if (!foundOrder) { const std::string_view secondQueryFullName = isOpenedFirst ? "/private/ClosedOrders" : "/private/OpenOrders"; data.update(PrivateQuery(_curlHandle, _apiKey, secondQueryFullName, ordersPostData).first); - const json& secondOrders = data[isOpenedFirst ? "closed" : "open"]; + const json::container& secondOrders = data[isOpenedFirst ? "closed" : "open"]; foundOrder = secondOrders.contains(orderId); } diff --git a/src/api/exchanges/src/krakenpublicapi.cpp b/src/api/exchanges/src/krakenpublicapi.cpp index 0969ac5a..73f9940c 100644 --- a/src/api/exchanges/src/krakenpublicapi.cpp +++ b/src/api/exchanges/src/krakenpublicapi.cpp @@ -10,7 +10,7 @@ #include "apiquerytypeenum.hpp" #include "cachedresult.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -39,20 +39,20 @@ namespace cct::api { namespace { -json PublicQuery(CurlHandle& curlHandle, std::string_view method, CurlPostData&& postData = CurlPostData()) { +json::container PublicQuery(CurlHandle& curlHandle, std::string_view method, CurlPostData&& postData = CurlPostData()) { RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet, std::move(postData))); - json jsonResponse = requestRetry.queryJson(method, [](const json& jsonResponse) { + json::container jsonResponse = requestRetry.queryJson(method, [](const json::container& jsonResponse) { const auto errorIt = jsonResponse.find("error"); if (errorIt != jsonResponse.end() && !errorIt->empty()) { - log::warn("Full Kraken json error: '{}'", jsonResponse.dump()); + log::warn("Full Kraken error: '{}'", jsonResponse.dump()); return RequestRetry::Status::kResponseError; } return RequestRetry::Status::kResponseOK; }); const auto resultIt = jsonResponse.find("result"); - json ret; + json::container ret; if (resultIt != jsonResponse.end()) { ret.swap(*resultIt); } @@ -117,7 +117,8 @@ KrakenPublic::KrakenPublic(const CoincenterInfo& config, FiatConverter& fiatConv _tradableCurrenciesCache, _curlHandle) {} bool KrakenPublic::healthCheck() { - json result = json::parse(_curlHandle.query("/public/SystemStatus", CurlOptions(HttpRequestType::kGet))); + json::container result = + json::container::parse(_curlHandle.query("/public/SystemStatus", CurlOptions(HttpRequestType::kGet))); auto errorIt = result.find("error"); if (errorIt != result.end() && !errorIt->empty()) { log::error("Error in {} status: {}", _name, errorIt->dump()); @@ -143,7 +144,7 @@ std::optional KrakenPublic::queryWithdrawalFee(CurrencyCode curr } CurrencyExchangeFlatSet KrakenPublic::TradableCurrenciesFunc::operator()() { - json result = PublicQuery(_curlHandle, "/public/Assets"); + json::container result = PublicQuery(_curlHandle, "/public/Assets"); CurrencyExchangeVector currencies; const CurrencyCodeSet& excludedCurrencies = _exchangeConfig.excludedCurrenciesAll(); for (const auto& [krakenAssetName, value] : result.items()) { @@ -166,7 +167,7 @@ CurrencyExchangeFlatSet KrakenPublic::TradableCurrenciesFunc::operator()() { } std::pair KrakenPublic::MarketsFunc::operator()() { - json result = PublicQuery(_curlHandle, "/public/AssetPairs"); + json::container result = PublicQuery(_curlHandle, "/public/AssetPairs"); std::pair ret; ret.first.reserve(static_cast(result.size())); ret.second.reserve(result.size()); @@ -241,7 +242,7 @@ MarketOrderBookMap KrakenPublic::AllOrderBooksFunc::operator()(int depth) { .assetsPairStrUpper(), mk); } - json result = PublicQuery(_curlHandle, "/public/Ticker", {{"pair", allAssetPairs}}); + json::container 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()) { @@ -254,8 +255,8 @@ MarketOrderBookMap KrakenPublic::AllOrderBooksFunc::operator()(int depth) { Market(_coincenterInfo.standardizeCurrencyCode(mk.base()), _coincenterInfo.standardizeCurrencyCode(mk.quote())); // a = ask array(, , ) // b = bid array(, , ) - const json& askDetails = assetPairDetails["a"]; - const json& bidDetails = assetPairDetails["b"]; + const json::container& askDetails = assetPairDetails["a"]; + const json::container& bidDetails = assetPairDetails["b"]; MonetaryAmount askPri(askDetails[0].get(), mk.quote()); MonetaryAmount bidPri(bidDetails[0].get(), mk.quote()); MonetaryAmount askVol(askDetails[2].get(), mk.base()); @@ -290,10 +291,10 @@ MarketOrderBook KrakenPublic::OrderBookFunc::operator()(Market mk, int count) { MarketOrderBookLines orderBookLines; - json result = PublicQuery(_curlHandle, "/public/Depth", {{"pair", krakenAssetPair}, {"count", count}}); + json::container result = PublicQuery(_curlHandle, "/public/Depth", {{"pair", krakenAssetPair}, {"count", count}}); const auto nowTime = Clock::now(); if (!result.empty()) { - const json& entry = result.front(); + const json::container& entry = result.front(); const auto asksIt = entry.find("asks"); const auto bidsIt = entry.find("bids"); @@ -328,7 +329,8 @@ KrakenPublic::TickerFunc::Last24hTradedVolumeAndLatestPricePair KrakenPublic::Ti const Market krakenMarket = GetKrakenMarketOrDefault(_tradableCurrenciesCache.get(), mk); if (krakenMarket.isDefined()) { - const json result = PublicQuery(_curlHandle, "/public/Ticker", {{"pair", krakenMarket.assetsPairStrUpper()}}); + const json::container result = + PublicQuery(_curlHandle, "/public/Ticker", {{"pair", krakenMarket.assetsPairStrUpper()}}); for (const auto& [krakenAssetPair, details] : result.items()) { std::string_view last24hVol = details["v"][1].get(); std::string_view lastTickerPrice = details["c"][0].get(); @@ -345,14 +347,14 @@ PublicTradeVector KrakenPublic::queryLastTrades(Market mk, int nbLastTrades) { const Market krakenMarket = GetKrakenMarketOrDefault(_tradableCurrenciesCache.get(), mk); if (krakenMarket.isDefined()) { - json result = PublicQuery(_curlHandle, "/public/Trades", - {{"pair", krakenMarket.assetsPairStrUpper()}, {"count", nbLastTrades}}); + json::container result = PublicQuery(_curlHandle, "/public/Trades", + {{"pair", krakenMarket.assetsPairStrUpper()}, {"count", nbLastTrades}}); if (!result.empty()) { const auto& lastTrades = result.front(); ret.reserve(static_cast(lastTrades.size())); - for (const json& det : lastTrades) { + for (const json::container& det : lastTrades) { const MonetaryAmount price(det[0].get(), mk.quote()); const MonetaryAmount amount(det[1].get(), mk.base()); const auto millisecondsSinceEpoch = static_cast(det[2].get() * 1000); diff --git a/src/api/exchanges/src/kucoinprivateapi.cpp b/src/api/exchanges/src/kucoinprivateapi.cpp index 58f739ba..7c22d768 100644 --- a/src/api/exchanges/src/kucoinprivateapi.cpp +++ b/src/api/exchanges/src/kucoinprivateapi.cpp @@ -14,7 +14,7 @@ #include "base64.hpp" #include "cachedresult.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "closed-order.hpp" @@ -59,8 +59,9 @@ namespace { constexpr std::string_view kStatusCodeOK = "200000"; -json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType requestType, std::string_view endpoint, - CurlPostData&& postData = CurlPostData(), bool throwIfError = true) { +json::container PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType requestType, + std::string_view endpoint, CurlPostData&& postData = CurlPostData(), + bool throwIfError = true) { string strToSign(Nonce_TimeSinceEpochInMs()); auto nonceSize = strToSign.size(); strToSign.append(HttpRequestTypeToString(requestType)); @@ -73,7 +74,7 @@ json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType strToSign.append(postData.str()); } else { strToSign.append(postData.toJsonStr()); - postDataFormat = CurlOptions::PostDataFormat::kJson; + postDataFormat = CurlOptions::PostDataFormat::json; } } @@ -87,7 +88,7 @@ json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType httpHeaders.emplace_back("KC-API-PASSPHRASE", B64Encode(ssl::Sha256Bin(apiKey.passphrase(), apiKey.privateKey()))); httpHeaders.emplace_back("KC-API-KEY-VERSION", 2); - json ret = json::parse(curlHandle.query(endpoint, opts)); + json::container ret = json::container::parse(curlHandle.query(endpoint, opts)); auto errCodeIt = ret.find("code"); if (errCodeIt != ret.end() && errCodeIt->get() != kStatusCodeOK) { auto msgIt = ret.find("msg"); @@ -98,7 +99,7 @@ json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType return ret; } if (throwIfError) { - log::error("Full Kucoin json error: '{}'", ret.dump()); + log::error("Full Kucoin error: '{}'", ret.dump()); throw exception("Kucoin error: {}, msg: {}", errCodeIt->get(), msg); } } @@ -121,11 +122,11 @@ bool EnsureEnoughAmountIn(CurlHandle& curlHandle, const APIKey& apiKey, Monetary std::string_view accountName) { // Check if enough balance in the 'accountName' account of Kucoin CurrencyCode cur = expectedAmount.currencyCode(); - json res = + json::container res = PrivateQuery(curlHandle, apiKey, HttpRequestType::kGet, "/api/v1/accounts", {{"currency", cur.str()}})["data"]; MonetaryAmount totalAvailableAmount(0, cur); MonetaryAmount amountInTargetAccount = totalAvailableAmount; - for (const json& balanceDetail : res) { + for (const json::container& balanceDetail : res) { std::string_view typeStr = balanceDetail["type"].get(); MonetaryAmount av(balanceDetail["available"].get(), cur); totalAvailableAmount += av; @@ -138,7 +139,7 @@ bool EnsureEnoughAmountIn(CurlHandle& curlHandle, const APIKey& apiKey, Monetary return false; } if (amountInTargetAccount < expectedAmount) { - for (const json& balanceDetail : res) { + for (const json::container& balanceDetail : res) { std::string_view typeStr = balanceDetail["type"].get(); MonetaryAmount av(balanceDetail["available"].get(), cur); if (typeStr != accountName && av != 0) { @@ -169,21 +170,21 @@ KucoinPrivate::KucoinPrivate(const CoincenterInfo& coincenterInfo, KucoinPublic& bool KucoinPrivate::validateApiKey() { constexpr bool throwIfError = false; - json ret = + json::container ret = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v1/accounts", CurlPostData(), throwIfError); auto errCodeIt = ret.find("code"); return errCodeIt == ret.end() || errCodeIt->get() == kStatusCodeOK; } BalancePortfolio KucoinPrivate::queryAccountBalance(const BalanceOptions& balanceOptions) { - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v1/accounts")["data"]; + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v1/accounts")["data"]; BalancePortfolio balancePortfolio; bool withBalanceInUse = balanceOptions.amountIncludePolicy() == BalanceOptions::AmountIncludePolicy::kWithBalanceInUse; const std::string_view amountKey = withBalanceInUse ? "balance" : "available"; balancePortfolio.reserve(static_cast(result.size())); - for (const json& balanceDetail : result) { + for (const json::container& balanceDetail : result) { std::string_view typeStr = balanceDetail["type"].get(); CurrencyCode currencyCode( _coincenterInfo.standardizeCurrencyCode(balanceDetail["currency"].get())); @@ -196,8 +197,8 @@ BalancePortfolio KucoinPrivate::queryAccountBalance(const BalanceOptions& balanc } Wallet KucoinPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) { - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v2/deposit-addresses", - {{"currency", currencyCode.str()}})["data"]; + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v2/deposit-addresses", + {{"currency", currencyCode.str()}})["data"]; ExchangeName exchangeName(_kucoinPublic.name(), _apiKey.name()); if (result.empty()) { log::info("No deposit address for {} in {}, creating one", currencyCode, exchangeName); @@ -243,9 +244,10 @@ void FillOrders(const OrdersConstraints& ordersConstraints, CurlHandle& curlHand if (ordersConstraints.isPlacedTimeBeforeDefined()) { params.emplace_back("endAt", TimestampToMillisecondsSinceEpoch(ordersConstraints.placedBefore())); } - json data = PrivateQuery(curlHandle, apiKey, HttpRequestType::kGet, "/api/v1/orders", std::move(params))["data"]; + json::container data = + PrivateQuery(curlHandle, apiKey, HttpRequestType::kGet, "/api/v1/orders", std::move(params))["data"]; - for (json& orderDetails : data["items"]) { + for (json::container& orderDetails : data["items"]) { const auto marketStr = orderDetails["symbol"].get(); const auto dashPos = marketStr.find('-'); @@ -310,7 +312,8 @@ int KucoinPrivate::cancelOpenedOrders(const OrdersConstraints& openedOrdersConst if (openedOrdersConstraints.isMarketDefined()) { params.emplace_back("symbol", openedOrdersConstraints.market().assetsPairStrUpper('-')); } - json res = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, "/api/v1/orders", std::move(params)); + json::container res = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, "/api/v1/orders", std::move(params)); int nbCancelledOrders = 0; auto dataIt = res.find("data"); if (dataIt != res.end()) { @@ -359,7 +362,7 @@ DepositsSet KucoinPrivate::queryRecentDeposits(const DepositsConstraints& deposi options.emplace_back("txId", depositsConstraints.idSet().front()); } } - json depositJson = + json::container depositJson = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v1/deposits", std::move(options))["data"]; auto itemsIt = depositJson.find("items"); if (itemsIt == depositJson.end()) { @@ -369,7 +372,7 @@ DepositsSet KucoinPrivate::queryRecentDeposits(const DepositsConstraints& deposi Deposits deposits; deposits.reserve(static_cast(itemsIt->size())); - for (const json& depositDetail : *itemsIt) { + for (const json::container& depositDetail : *itemsIt) { CurrencyCode currencyCode(depositDetail["currency"].get()); MonetaryAmount amount(depositDetail["amount"].get(), currencyCode); int64_t millisecondsSinceEpoch = depositDetail["updatedAt"].get(); @@ -437,8 +440,8 @@ CurlPostData CreateOptionsFromWithdrawConstraints(const WithdrawsConstraints& wi } // namespace WithdrawsSet KucoinPrivate::queryRecentWithdraws(const WithdrawsConstraints& withdrawsConstraints) { - json withdrawJson = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v1/withdrawals", - CreateOptionsFromWithdrawConstraints(withdrawsConstraints))["data"]; + json::container withdrawJson = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/api/v1/withdrawals", + CreateOptionsFromWithdrawConstraints(withdrawsConstraints))["data"]; auto itemsIt = withdrawJson.find("items"); if (itemsIt == withdrawJson.end()) { throw exception("Unexpected result from Kucoin withdraw API"); @@ -447,7 +450,7 @@ WithdrawsSet KucoinPrivate::queryRecentWithdraws(const WithdrawsConstraints& wit Withdraws withdraws; withdraws.reserve(static_cast(itemsIt->size())); - for (const json& withdrawDetail : *itemsIt) { + for (const json::container& withdrawDetail : *itemsIt) { CurrencyCode currencyCode(withdrawDetail["currency"].get()); MonetaryAmount netEmittedAmount(withdrawDetail["amount"].get(), currencyCode); MonetaryAmount fee(withdrawDetail["fee"].get(), currencyCode); @@ -518,7 +521,8 @@ PlaceOrderInfo KucoinPrivate::placeOrder(MonetaryAmount from, MonetaryAmount vol params.emplace_back("timeInForce", "GTT"); // Good until cancelled or time expires params.emplace_back("cancelAfter", std::chrono::duration_cast(tradeInfo.options.maxTradeTime()).count() + 1); - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/api/v1/orders", std::move(params))["data"]; + json::container result = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/api/v1/orders", std::move(params))["data"]; placeOrderInfo.orderId = std::move(result["orderId"].get_ref()); return placeOrderInfo; } @@ -540,7 +544,7 @@ OrderInfo KucoinPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext& string endpoint("/api/v1/orders/"); endpoint.append(orderId); - json data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, endpoint)["data"]; + json::container data = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, endpoint)["data"]; MonetaryAmount size(data["size"].get(), mk.base()); MonetaryAmount matchedSize(data["dealSize"].get(), mk.base()); @@ -578,7 +582,7 @@ InitiatedWithdrawInfo KucoinPrivate::launchWithdraw(MonetaryAmount grossAmount, opts.emplace_back("memo", destinationWallet.tag()); } - json result = + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/api/v1/withdrawals", std::move(opts))["data"]; return {std::move(destinationWallet), std::move(result["withdrawalId"].get_ref()), grossAmount}; } diff --git a/src/api/exchanges/src/kucoinpublicapi.cpp b/src/api/exchanges/src/kucoinpublicapi.cpp index cca67b00..07487e69 100644 --- a/src/api/exchanges/src/kucoinpublicapi.cpp +++ b/src/api/exchanges/src/kucoinpublicapi.cpp @@ -11,7 +11,7 @@ #include "apiquerytypeenum.hpp" #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "cct_vector.hpp" @@ -45,18 +45,19 @@ namespace cct::api { namespace { -json PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, const CurlPostData& curlPostData = CurlPostData()) { +json::container PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, + const CurlPostData& curlPostData = CurlPostData()) { RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet, curlPostData)); - json jsonResponse = requestRetry.queryJson(endpoint, [](const json& jsonResponse) { + json::container jsonResponse = requestRetry.queryJson(endpoint, [](const json::container& jsonResponse) { const auto errorIt = jsonResponse.find("code"); if (errorIt != jsonResponse.end() && errorIt->get() != "200000") { - log::warn("Full Kucoin json error ({}): '{}'", errorIt->get(), jsonResponse.dump()); + log::warn("Full Kucoin error ({}): '{}'", errorIt->get(), jsonResponse.dump()); return RequestRetry::Status::kResponseError; } return RequestRetry::Status::kResponseOK; }); - json ret; + json::container ret; const auto dataIt = jsonResponse.find("data"); if (dataIt != jsonResponse.end()) { ret.swap(*dataIt); @@ -87,7 +88,8 @@ KucoinPublic::KucoinPublic(const CoincenterInfo& config, FiatConverter& fiatConv _curlHandle) {} bool KucoinPublic::healthCheck() { - json result = json::parse(_curlHandle.query("/api/v1/status", CurlOptions(HttpRequestType::kGet))); + json::container result = + json::container::parse(_curlHandle.query("/api/v1/status", CurlOptions(HttpRequestType::kGet))); auto dataIt = result.find("data"); if (dataIt == result.end()) { log::error("Unexpected answer from {} status: {}", _name, result.dump()); @@ -104,10 +106,10 @@ bool KucoinPublic::healthCheck() { } KucoinPublic::TradableCurrenciesFunc::CurrencyInfoSet KucoinPublic::TradableCurrenciesFunc::operator()() { - json result = PublicQuery(_curlHandle, "/api/v1/currencies"); + json::container result = PublicQuery(_curlHandle, "/api/v1/currencies"); vector currencyInfos; currencyInfos.reserve(static_cast(result.size())); - for (const json& curDetail : result) { + for (const json::container& curDetail : result) { std::string_view curStr = curDetail["currency"].get(); CurrencyCode cur(_coincenterInfo.standardizeCurrencyCode(curStr)); CurrencyExchange currencyExchange( @@ -137,7 +139,7 @@ CurrencyExchangeFlatSet KucoinPublic::queryTradableCurrencies() { } std::pair KucoinPublic::MarketsFunc::operator()() { - json result = PublicQuery(_curlHandle, "/api/v1/symbols"); + json::container result = PublicQuery(_curlHandle, "/api/v1/symbols"); MarketSet markets; MarketInfoMap marketInfoMap; @@ -146,7 +148,7 @@ std::pair KucoinPublic::Mar const CurrencyCodeSet& excludedCurrencies = _exchangeConfig.excludedCurrenciesAll(); - for (const json& marketDetails : result) { + for (const json::container& marketDetails : result) { const std::string_view baseAsset = marketDetails["baseCurrency"].get(); const std::string_view quoteAsset = marketDetails["quoteCurrency"].get(); const bool isEnabled = marketDetails["enableTrading"].get(); @@ -208,13 +210,13 @@ std::optional KucoinPublic::queryWithdrawalFee(CurrencyCode curr MarketOrderBookMap KucoinPublic::AllOrderBooksFunc::operator()(int depth) { MarketOrderBookMap ret; const auto& [markets, marketInfoMap] = _marketsCache.get(); - const json data = PublicQuery(_curlHandle, "/api/v1/market/allTickers"); + const json::container data = PublicQuery(_curlHandle, "/api/v1/market/allTickers"); const auto time = Clock::now(); const auto tickerIt = data.find("ticker"); if (tickerIt == data.end()) { return ret; } - for (const json& tickerDetails : *tickerIt) { + for (const json::container& tickerDetails : *tickerIt) { Market mk(tickerDetails["symbol"].get(), '-'); if (!markets.contains(mk)) { log::debug("Market {} is not present", mk); @@ -272,7 +274,7 @@ MarketOrderBook KucoinPublic::OrderBookFunc::operator()(Market mk, int depth) { MarketOrderBookLines orderBookLines; - const json asksAndBids = PublicQuery(_curlHandle, endpoint, GetSymbolPostData(mk)); + const json::container asksAndBids = PublicQuery(_curlHandle, endpoint, GetSymbolPostData(mk)); const auto nowTime = Clock::now(); const auto asksIt = asksAndBids.find("asks"); const auto bidsIt = asksAndBids.find("bids"); @@ -333,7 +335,7 @@ MonetaryAmount KucoinPublic::sanitizeVolume(Market mk, MonetaryAmount vol) { } MonetaryAmount KucoinPublic::TradedVolumeFunc::operator()(Market mk) { - const json result = PublicQuery(_curlHandle, "/api/v1/market/stats", GetSymbolPostData(mk)); + const json::container result = PublicQuery(_curlHandle, "/api/v1/market/stats", GetSymbolPostData(mk)); const auto volIt = result.find("vol"); const std::string_view amountStr = volIt == result.end() ? std::string_view() : volIt->get(); return {amountStr, mk.base()}; @@ -345,13 +347,13 @@ PublicTradeVector KucoinPublic::queryLastTrades(Market mk, int nbTrades) { log::warn("Maximum number of last trades to query from {} is {}", name(), kMaxNbLastTrades); } - json result = PublicQuery(_curlHandle, "/api/v1/market/histories", GetSymbolPostData(mk)); + json::container result = PublicQuery(_curlHandle, "/api/v1/market/histories", GetSymbolPostData(mk)); PublicTradeVector ret; ret.reserve(std::min(static_cast(result.size()), static_cast(nbTrades))); - for (const json& detail : result | std::ranges::views::take(nbTrades)) { + for (const json::container& detail : result | std::ranges::views::take(nbTrades)) { const MonetaryAmount amount(detail["size"].get(), mk.base()); const MonetaryAmount price(detail["price"].get(), mk.quote()); // time is in nanoseconds @@ -365,7 +367,7 @@ PublicTradeVector KucoinPublic::queryLastTrades(Market mk, int nbTrades) { } MonetaryAmount KucoinPublic::TickerFunc::operator()(Market mk) { - const json result = PublicQuery(_curlHandle, "/api/v1/market/orderbook/level1", GetSymbolPostData(mk)); + const json::container result = PublicQuery(_curlHandle, "/api/v1/market/orderbook/level1", GetSymbolPostData(mk)); const auto priceIt = result.find("price"); const std::string_view amountStr = priceIt == result.end() ? std::string_view() : priceIt->get(); return {amountStr, mk.quote()}; diff --git a/src/api/exchanges/src/upbitprivateapi.cpp b/src/api/exchanges/src/upbitprivateapi.cpp index 92d7eb0d..622f6db4 100644 --- a/src/api/exchanges/src/upbitprivateapi.cpp +++ b/src/api/exchanges/src/upbitprivateapi.cpp @@ -17,7 +17,7 @@ #include "balanceportfolio.hpp" #include "cachedresult.hpp" #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "closed-order.hpp" @@ -66,8 +66,9 @@ namespace { enum class IfError : int8_t { kThrow, kNoThrow }; template -json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType requestType, std::string_view endpoint, - CurlPostDataT&& curlPostData = CurlPostData(), IfError ifError = IfError::kThrow) { +json::container PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType requestType, + std::string_view endpoint, CurlPostDataT&& curlPostData = CurlPostData(), + IfError ifError = IfError::kThrow) { CurlOptions opts(requestType, std::forward(curlPostData)); auto jsonWebToken = jwt::create() @@ -89,11 +90,11 @@ json PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType opts.mutableHttpHeaders().emplace_back("Authorization", authStr); - json ret = json::parse(curlHandle.query(endpoint, opts)); + json::container ret = json::container::parse(curlHandle.query(endpoint, opts)); if (ifError == IfError::kThrow) { auto errorIt = ret.find("error"); if (errorIt != ret.end()) { - log::error("Full Upbit json error: '{}'", ret.dump()); + log::error("Full Upbit error: '{}'", ret.dump()); if (errorIt->contains("name")) { throw exception(std::move((*errorIt)["name"].get_ref())); } @@ -122,7 +123,7 @@ UpbitPrivate::UpbitPrivate(const CoincenterInfo& config, UpbitPublic& upbitPubli _curlHandle, _apiKey, upbitPublic) {} bool UpbitPrivate::validateApiKey() { - json ret = + json::container ret = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/api_keys", CurlPostData(), IfError::kNoThrow); return !ret.empty() && ret.find("error") == ret.end(); } @@ -130,8 +131,8 @@ bool UpbitPrivate::validateApiKey() { CurrencyExchangeFlatSet UpbitPrivate::TradableCurrenciesFunc::operator()() { const CurrencyCodeSet& excludedCurrencies = _exchangeConfig.excludedCurrenciesAll(); CurrencyExchangeVector currencies; - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/status/wallet"); - for (const json& curDetails : result) { + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/status/wallet"); + for (const json::container& curDetails : result) { CurrencyCode cur(curDetails["currency"].get()); CurrencyCode networkName(curDetails["net_type"].get()); if (cur != networkName) { @@ -172,11 +173,11 @@ BalancePortfolio UpbitPrivate::queryAccountBalance(const BalanceOptions& balance BalancePortfolio balancePortfolio; - json ret = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/accounts"); + json::container ret = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/accounts"); balancePortfolio.reserve(static_cast(ret.size())); - for (const json& accountDetail : ret) { + for (const json::container& accountDetail : ret) { const CurrencyCode currencyCode(accountDetail["currency"].get()); MonetaryAmount availableAmount(accountDetail["balance"].get(), currencyCode); @@ -191,8 +192,8 @@ BalancePortfolio UpbitPrivate::queryAccountBalance(const BalanceOptions& balance Wallet UpbitPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) { CurlPostData postData{{"currency", currencyCode.str()}, {"net_type", currencyCode.str()}}; - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/deposits/coin_address", postData, - IfError::kNoThrow); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/deposits/coin_address", + postData, IfError::kNoThrow); bool generateDepositAddressNeeded = false; auto errorIt = result.find("error"); if (errorIt != result.end()) { @@ -206,7 +207,7 @@ Wallet UpbitPrivate::DepositWalletFunc::operator()(CurrencyCode currencyCode) { } } if (generateDepositAddressNeeded) { - json genCoinAddressResult = + json::container genCoinAddressResult = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/v1/deposits/generate_coin_address", postData); if (genCoinAddressResult.contains("success")) { log::info("Successfully generated address"); @@ -270,11 +271,11 @@ void FillOrders(const OrdersConstraints& ordersConstraints, CurlHandle& curlHand nbOrdersRetrieved == kMaxNbOrdersPerPage && page < kNbMaxPagesToRetrieve;) { params.set("page", ++page); - json data = PrivateQuery(curlHandle, apiKey, HttpRequestType::kGet, "/v1/orders", params); + json::container data = PrivateQuery(curlHandle, apiKey, HttpRequestType::kGet, "/v1/orders", params); nbOrdersRetrieved = static_cast(data.size()); - for (json& orderDetails : data) { + for (json::container& orderDetails : data) { const auto marketStr = orderDetails["market"].get(); const auto dashPos = marketStr.find('-'); @@ -397,12 +398,12 @@ DepositsSet UpbitPrivate::queryRecentDeposits(const DepositsConstraints& deposit // To make sure we retrieve all results, ask for next page when maximum results per page is returned for (int nbResults = kNbResultsPerPage, page = 1; nbResults == kNbResultsPerPage; ++page) { options.set("page", page); - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/deposits", options); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/deposits", options); if (deposits.empty()) { deposits.reserve(static_cast(result.size())); } nbResults = static_cast(result.size()); - for (json& trx : result) { + for (json::container& trx : result) { CurrencyCode currencyCode(trx["currency"].get()); MonetaryAmount amount(trx["amount"].get(), currencyCode); // 'done_at' string is in this format: "2019-01-04T13:48:09+09:00" @@ -470,12 +471,12 @@ WithdrawsSet UpbitPrivate::queryRecentWithdraws(const WithdrawsConstraints& with // To make sure we retrieve all results, ask for next page when maximum results per page is returned for (int nbResults = kNbResultsPerPage, page = 1; nbResults == kNbResultsPerPage; ++page) { options.set("page", page); - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/withdraws", options); + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/withdraws", options); if (withdraws.empty()) { withdraws.reserve(static_cast(result.size())); } nbResults = static_cast(result.size()); - for (json& trx : result) { + for (json::container& trx : result) { CurrencyCode currencyCode(trx["currency"].get()); MonetaryAmount netEmittedAmount(trx["amount"].get(), currencyCode); MonetaryAmount withdrawFee(trx["fee"].get(), currencyCode); @@ -503,7 +504,7 @@ WithdrawsSet UpbitPrivate::queryRecentWithdraws(const WithdrawsConstraints& with } namespace { -bool IsOrderClosed(const json& orderJson) { +bool IsOrderClosed(const json::container& orderJson) { std::string_view state = orderJson["state"].get(); if (state == "done" || state == "cancel") { return true; @@ -515,7 +516,7 @@ bool IsOrderClosed(const json& orderJson) { return true; } -OrderInfo ParseOrderJson(const json& orderJson, CurrencyCode fromCurrencyCode, Market mk) { +OrderInfo ParseOrderJson(const json::container& orderJson, CurrencyCode fromCurrencyCode, Market mk) { OrderInfo orderInfo(TradedAmounts(fromCurrencyCode, fromCurrencyCode == mk.base() ? mk.quote() : mk.base()), IsOrderClosed(orderJson)); @@ -524,7 +525,7 @@ OrderInfo ParseOrderJson(const json& orderJson, CurrencyCode fromCurrencyCode, M CurrencyCode feeCurrencyCode(mk.quote()); MonetaryAmount fee(orderJson["paid_fee"].get(), feeCurrencyCode); - for (const json& orderDetails : orderJson["trades"]) { + for (const json::container& orderDetails : orderJson["trades"]) { MonetaryAmount tradedVol(orderDetails["volume"].get(), mk.base()); // always in base currency MonetaryAmount price(orderDetails["price"].get(), mk.quote()); // always in quote currency MonetaryAmount tradedCost(orderDetails["funds"].get(), mk.quote()); @@ -606,7 +607,8 @@ PlaceOrderInfo UpbitPrivate::placeOrder(MonetaryAmount from, MonetaryAmount volu placePostData.emplace_back("price", price.amountStr()); } - json placeOrderRes = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/v1/orders", placePostData); + json::container placeOrderRes = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/v1/orders", placePostData); placeOrderInfo.orderInfo = ParseOrderJson(placeOrderRes, fromCurrencyCode, mk); placeOrderInfo.orderId = std::move(placeOrderRes["uuid"].get_ref()); @@ -614,7 +616,7 @@ PlaceOrderInfo UpbitPrivate::placeOrder(MonetaryAmount from, MonetaryAmount volu // Upbit takes some time to match the market order - We should wait that it has been matched bool takerOrderNotClosed = isTakerStrategy && !placeOrderInfo.orderInfo.isClosed; while (takerOrderNotClosed) { - json orderRes = + json::container orderRes = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/order", {{"uuid", placeOrderInfo.orderId}}); placeOrderInfo.orderInfo = ParseOrderJson(orderRes, fromCurrencyCode, mk); @@ -626,7 +628,7 @@ PlaceOrderInfo UpbitPrivate::placeOrder(MonetaryAmount from, MonetaryAmount volu OrderInfo UpbitPrivate::cancelOrder(OrderIdView orderId, const TradeContext& tradeContext) { CurlPostData postData{{"uuid", orderId}}; - json orderRes = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, "/v1/order", postData); + json::container orderRes = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kDelete, "/v1/order", postData); bool cancelledOrderClosed = IsOrderClosed(orderRes); while (!cancelledOrderClosed) { orderRes = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/order", postData); @@ -636,15 +638,17 @@ OrderInfo UpbitPrivate::cancelOrder(OrderIdView orderId, const TradeContext& tra } OrderInfo UpbitPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext& tradeContext) { - json orderRes = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/order", {{"uuid", orderId}}); + json::container orderRes = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/order", {{"uuid", orderId}}); const CurrencyCode fromCurrencyCode(tradeContext.fromCur()); return ParseOrderJson(orderRes, fromCurrencyCode, tradeContext.mk); } std::optional UpbitPrivate::WithdrawFeesFunc::operator()(CurrencyCode currencyCode) { auto curStr = currencyCode.str(); - json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/withdraws/chance", - {{"currency", std::string_view{curStr}}, {"net_type", std::string_view{curStr}}}); + json::container result = + PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/withdraws/chance", + {{"currency", std::string_view{curStr}}, {"net_type", std::string_view{curStr}}}); std::string_view amountStr = result["currency"]["withdraw_fee"].get(); return MonetaryAmount(amountStr, currencyCode); } @@ -661,7 +665,7 @@ InitiatedWithdrawInfo UpbitPrivate::launchWithdraw(MonetaryAmount grossAmount, W withdrawPostData.emplace_back("secondary_address", destinationWallet.tag()); } - json result = + json::container result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/v1/withdraws/coin", std::move(withdrawPostData)); return {std::move(destinationWallet), std::move(result["uuid"].get_ref()), grossAmount}; } diff --git a/src/api/exchanges/src/upbitpublicapi.cpp b/src/api/exchanges/src/upbitpublicapi.cpp index 15da7ece..7f4c56ff 100644 --- a/src/api/exchanges/src/upbitpublicapi.cpp +++ b/src/api/exchanges/src/upbitpublicapi.cpp @@ -11,7 +11,7 @@ #include "apiquerytypeenum.hpp" #include "cachedresult.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" @@ -42,17 +42,18 @@ namespace cct::api { namespace { -json PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, CurlPostData&& postData = CurlPostData()) { +json::container PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, + CurlPostData&& postData = CurlPostData()) { RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet, std::move(postData))); - return requestRetry.queryJson(endpoint, [](const json& jsonResponse) { + return requestRetry.queryJson(endpoint, [](const json::container& jsonResponse) { const auto foundErrorIt = jsonResponse.find("error"); if (foundErrorIt != jsonResponse.end()) { const auto statusCodeIt = jsonResponse.find("name"); const long statusCode = statusCodeIt == jsonResponse.end() ? -1 : statusCodeIt->get(); const auto msgIt = jsonResponse.find("message"); const std::string_view msg = msgIt == jsonResponse.end() ? "Unknown" : msgIt->get(); - log::warn("Upbit error ({}, '{}'), full json: '{}'", statusCode, msg, jsonResponse.dump()); + log::warn("Upbit error ({}, '{}'), full: '{}'", statusCode, msg, jsonResponse.dump()); return RequestRetry::Status::kResponseError; } return RequestRetry::Status::kResponseOK; @@ -86,9 +87,9 @@ UpbitPublic::UpbitPublic(const CoincenterInfo& config, FiatConverter& fiatConver bool UpbitPublic::healthCheck() { static constexpr auto kAllowExceptions = false; - json result = - json::parse(_curlHandle.query("/v1/ticker", CurlOptions(HttpRequestType::kGet, {{"markets", "KRW-BTC"}})), - nullptr, kAllowExceptions); + json::container result = json::container::parse( + _curlHandle.query("/v1/ticker", CurlOptions(HttpRequestType::kGet, {{"markets", "KRW-BTC"}})), nullptr, + kAllowExceptions); if (result.is_discarded()) { log::error("{} health check response badly formatted", _name); return false; @@ -133,11 +134,11 @@ bool UpbitPublic::CheckCurrencyCode(CurrencyCode standardCode, const CurrencyCod } MarketSet UpbitPublic::MarketsFunc::operator()() { - json result = PublicQuery(_curlHandle, "/v1/market/all", {{"isDetails", "true"}}); + json::container result = PublicQuery(_curlHandle, "/v1/market/all", {{"isDetails", "true"}}); const CurrencyCodeSet& excludedCurrencies = _exchangeConfig.excludedCurrenciesAll(); MarketSet ret; ret.reserve(static_cast(result.size())); - for (const json& marketDetails : result) { + for (const json::container& marketDetails : result) { std::string_view marketStr = marketDetails["market"].get(); std::string_view marketWarningStr = marketDetails["market_warning"].get(); if (marketWarningStr != "NONE") { @@ -168,7 +169,7 @@ MarketSet UpbitPublic::MarketsFunc::operator()() { MonetaryAmountByCurrencySet UpbitPublic::WithdrawalFeesFunc::operator()() { MonetaryAmountVector fees; File withdrawFeesFile(_dataDir, File::Type::kStatic, "withdrawfees.json", File::IfError::kThrow); - json jsonData = withdrawFeesFile.readAllJson(); + json::container jsonData = withdrawFeesFile.readAllJson(); for (const auto& [coin, value] : jsonData[_name].items()) { CurrencyCode coinAcro(coin); MonetaryAmount ma(value.get(), coinAcro); @@ -182,13 +183,13 @@ MonetaryAmountByCurrencySet UpbitPublic::WithdrawalFeesFunc::operator()() { namespace { template -OutputType ParseOrderBooks(const json& result, int depth) { +OutputType ParseOrderBooks(const json::container& result, int depth) { OutputType ret; const auto time = Clock::now(); MarketOrderBookLines orderBookLines; - for (const json& marketDetails : result) { + for (const json::container& marketDetails : result) { std::string_view marketStr = marketDetails["market"].get(); std::size_t dashPos = marketStr.find('-'); if (dashPos == std::string_view::npos) { @@ -206,7 +207,7 @@ OutputType ParseOrderBooks(const json& result, int depth) { orderBookLines.clear(); orderBookLines.reserve(orderBookLinesJson.size() * 2U); - for (const json& orderbookDetails : orderBookLinesJson | std::ranges::views::take(depth)) { + for (const json::container& orderbookDetails : orderBookLinesJson | std::ranges::views::take(depth)) { // Amounts are not strings, but doubles MonetaryAmount askPri(orderbookDetails["ask_price"].get(), quote); MonetaryAmount bidPri(orderbookDetails["bid_price"].get(), quote); @@ -255,18 +256,20 @@ MarketOrderBook UpbitPublic::OrderBookFunc::operator()(Market mk, int depth) { } MonetaryAmount UpbitPublic::TradedVolumeFunc::operator()(Market mk) { - json result = PublicQuery(_curlHandle, "/v1/candles/days", {{"count", 1}, {"market", ReverseMarketStr(mk)}}); + json::container result = + PublicQuery(_curlHandle, "/v1/candles/days", {{"count", 1}, {"market", ReverseMarketStr(mk)}}); double last24hVol = result.empty() ? 0 : result.front()["candle_acc_trade_volume"].get(); return MonetaryAmount(last24hVol, mk.base()); } PublicTradeVector UpbitPublic::queryLastTrades(Market mk, int nbTrades) { - json result = PublicQuery(_curlHandle, "/v1/trades/ticks", {{"count", nbTrades}, {"market", ReverseMarketStr(mk)}}); + json::container result = + PublicQuery(_curlHandle, "/v1/trades/ticks", {{"count", nbTrades}, {"market", ReverseMarketStr(mk)}}); PublicTradeVector ret; ret.reserve(static_cast(result.size())); - for (const json& detail : result) { + for (const json::container& detail : result) { MonetaryAmount amount(detail["trade_volume"].get(), mk.base()); MonetaryAmount price(detail["trade_price"].get(), mk.quote()); int64_t millisecondsSinceEpoch = detail["timestamp"].get(); @@ -279,7 +282,8 @@ PublicTradeVector UpbitPublic::queryLastTrades(Market mk, int nbTrades) { } MonetaryAmount UpbitPublic::TickerFunc::operator()(Market mk) { - json result = PublicQuery(_curlHandle, "/v1/trades/ticks", {{"count", 1}, {"market", ReverseMarketStr(mk)}}); + json::container result = + PublicQuery(_curlHandle, "/v1/trades/ticks", {{"count", 1}, {"market", ReverseMarketStr(mk)}}); double lastPrice = result.empty() ? 0 : result.front()["trade_price"].get(); return MonetaryAmount(lastPrice, mk.quote()); } diff --git a/src/objects/include/apioutputtype.hpp b/src/basic-objects/include/apioutputtype.hpp similarity index 61% rename from src/objects/include/apioutputtype.hpp rename to src/basic-objects/include/apioutputtype.hpp index 6b2e8074..4e35bcd1 100644 --- a/src/objects/include/apioutputtype.hpp +++ b/src/basic-objects/include/apioutputtype.hpp @@ -3,12 +3,14 @@ #include #include +#include "cct_json-serialization.hpp" + namespace cct { enum class ApiOutputType : int8_t { - kNoPrint, - kFormattedTable, - kJson, + off, + table, + json, }; static constexpr std::string_view kApiOutputTypeNoPrintStr = "off"; @@ -17,4 +19,10 @@ static constexpr std::string_view kApiOutputTypeJsonStr = "json"; ApiOutputType ApiOutputTypeFromString(std::string_view str); -} // namespace cct \ No newline at end of file +} // namespace cct + +template <> +struct glz::meta<::cct::ApiOutputType> { + using enum ::cct::ApiOutputType; + static constexpr auto value = enumerate(off, table, json); +}; \ No newline at end of file diff --git a/src/basic-objects/include/coincentercommandtype.hpp b/src/basic-objects/include/coincentercommandtype.hpp new file mode 100644 index 00000000..b5c4b398 --- /dev/null +++ b/src/basic-objects/include/coincentercommandtype.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include +#include + +#include "cct_json-serialization.hpp" + +namespace cct { + +enum class CoincenterCommandType : int8_t { + HealthCheck, + Currencies, + Markets, + Conversion, + ConversionPath, + LastPrice, + Ticker, + Orderbook, + LastTrades, + Last24hTradedVolume, + WithdrawFees, + + Balance, + DepositInfo, + OrdersClosed, + OrdersOpened, + OrdersCancel, + RecentDeposits, + RecentWithdraws, + Trade, + Buy, + Sell, + Withdraw, + DustSweeper, + + MarketData, + Replay, + ReplayMarkets, + + Last +}; + +std::string_view CoincenterCommandTypeToString(CoincenterCommandType type); + +CoincenterCommandType CoincenterCommandTypeFromString(std::string_view str); + +bool IsAnyTrade(CoincenterCommandType type); +} // namespace cct + +template <> +struct glz::meta<::cct::CoincenterCommandType> { + using enum ::cct::CoincenterCommandType; + static constexpr auto value = enumerate(HealthCheck, Currencies, Markets, Conversion, ConversionPath, LastPrice, + Ticker, Orderbook, LastTrades, Last24hTradedVolume, WithdrawFees, + + Balance, DepositInfo, OrdersClosed, OrdersOpened, OrdersCancel, + RecentDeposits, RecentWithdraws, Trade, Buy, Sell, Withdraw, DustSweeper, + + MarketData, Replay, ReplayMarkets, + + Last); +}; diff --git a/src/basic-objects/include/currencycode.hpp b/src/basic-objects/include/currencycode.hpp index 284b230f..c5b9778a 100644 --- a/src/basic-objects/include/currencycode.hpp +++ b/src/basic-objects/include/currencycode.hpp @@ -15,6 +15,7 @@ #include "cct_invalid_argument_exception.hpp" #include "cct_json-serialization.hpp" #include "cct_string.hpp" +#include "generic-object-json.hpp" #include "toupperlower.hpp" namespace cct { @@ -206,6 +207,8 @@ class CurrencyCode { return first; } + constexpr size_type strLen() const noexcept { return size(); } + /// Resizes the currency code to a length of 'newSize'. /// If 'newSize' is greater than 'kMaxLen', exception will be raised. /// If 'newSize' is greater than current size, 'newSize' - 'oldSize' 'ch' will be appended to the code. @@ -398,22 +401,7 @@ template <> struct to { template static void op(auto &&value, Ctx &&, B &&b, IX &&ix) { - auto valueLen = value.size(); - bool inQuotes = ix != 0 && b[ix - 1] == ':'; - int64_t additionalSize = (inQuotes ? 2L : 0L) + static_cast(ix) + static_cast(valueLen) - - static_cast(b.size()); - if (additionalSize > 0) { - b.append(additionalSize, ' '); - } - - if (inQuotes) { - b[ix++] = '"'; - } - value.appendTo(b.data() + ix); - ix += valueLen; - if (inQuotes) { - b[ix++] = '"'; - } + ::cct::details::ToJson(value, b, ix); } }; } // namespace glz::detail diff --git a/src/basic-objects/include/file.hpp b/src/basic-objects/include/file.hpp index 2bda4c92..343c55d2 100644 --- a/src/basic-objects/include/file.hpp +++ b/src/basic-objects/include/file.hpp @@ -3,7 +3,6 @@ #include #include -#include "cct_json.hpp" #include "cct_string.hpp" #include "reader.hpp" #include "writer.hpp" @@ -24,7 +23,9 @@ class File : public Reader, public Writer { [[nodiscard]] string readAll() const override; - int write(const json &data, Writer::Mode mode = Writer::Mode::FromStart) const override; + int write(std::string_view data, Writer::Mode mode = Writer::Mode::FromStart) const override; + + bool exists() const; private: string _filePath; diff --git a/src/basic-objects/include/generic-object-json.hpp b/src/basic-objects/include/generic-object-json.hpp new file mode 100644 index 00000000..d9af02e1 --- /dev/null +++ b/src/basic-objects/include/generic-object-json.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include + +#include "cct_cctype.hpp" +#include "cct_json-serialization.hpp" + +namespace cct::details { + +template +constexpr bool JsonWithQuotes(B &&b, IX &&ix) { + if constexpr (Opts.prettify) { + auto begIt = std::reverse_iterator(b.data() + ix); + auto endIt = std::reverse_iterator(b.data()); + auto foundIfNotIt = std::find_if_not(begIt, endIt, [](char ch) { return isspace(ch); }); + + return foundIfNotIt != endIt && *foundIfNotIt == ':'; + } else { + return ix != 0 && b[ix - 1] == ':'; + } +} + +template +constexpr void ToJson(auto &&value, B &&b, IX &&ix) { + auto valueLen = value.strLen(); + bool withQuotes = JsonWithQuotes(b, ix); + + int64_t additionalSize = (withQuotes ? 2L : 0L) + static_cast(ix) + static_cast(valueLen) - + static_cast(b.size()); + if (additionalSize > 0) { + b.append(additionalSize, ' '); + } + + if (withQuotes) { + b[ix++] = '"'; + } + value.appendTo(b.data() + ix); + ix += valueLen; + if (withQuotes) { + b[ix++] = '"'; + } +} + +} // namespace cct::details \ No newline at end of file diff --git a/src/basic-objects/include/market.hpp b/src/basic-objects/include/market.hpp index b25f31cb..a9ff8ea3 100644 --- a/src/basic-objects/include/market.hpp +++ b/src/basic-objects/include/market.hpp @@ -10,6 +10,7 @@ #include "cct_json-serialization.hpp" #include "cct_string.hpp" #include "currencycode.hpp" +#include "generic-object-json.hpp" namespace cct { @@ -171,22 +172,7 @@ template <> struct to { template static void op(auto &&value, Ctx &&, B &&b, IX &&ix) { - auto valueLen = value.size(); - bool inQuotes = ix != 0 && b[ix - 1] == ':'; - int64_t additionalSize = (inQuotes ? 2L : 0L) + static_cast(ix) + static_cast(valueLen) - - static_cast(b.size()); - if (additionalSize > 0) { - b.append(additionalSize, ' '); - } - - if (inQuotes) { - b[ix++] = '"'; - } - value.appendTo(b.data() + ix); - ix += valueLen; - if (inQuotes) { - b[ix++] = '"'; - } + ::cct::details::ToJson(value, b, ix); } }; } // namespace glz::detail diff --git a/src/basic-objects/include/monetaryamount.hpp b/src/basic-objects/include/monetaryamount.hpp index ecc88999..5065e9f3 100644 --- a/src/basic-objects/include/monetaryamount.hpp +++ b/src/basic-objects/include/monetaryamount.hpp @@ -16,6 +16,7 @@ #include "cct_log.hpp" #include "cct_string.hpp" #include "currencycode.hpp" +#include "generic-object-json.hpp" #include "ipow.hpp" #include "ndigits.hpp" @@ -453,22 +454,7 @@ template <> struct to { template static void op(auto &&value, Ctx &&, B &&b, IX &&ix) { - auto valueLen = value.strLen(); - bool inQuotes = ix != 0 && b[ix - 1] == ':'; - int64_t additionalSize = (inQuotes ? 2L : 0L) + static_cast(ix) + static_cast(valueLen) - - static_cast(b.size()); - if (additionalSize > 0) { - b.append(additionalSize, ' '); - } - - if (inQuotes) { - b[ix++] = '"'; - } - value.appendTo(b.data() + ix); - ix += valueLen; - if (inQuotes) { - b[ix++] = '"'; - } + ::cct::details::ToJson(value, b, ix); } }; } // namespace glz::detail \ No newline at end of file diff --git a/src/basic-objects/include/reader.hpp b/src/basic-objects/include/reader.hpp index 8b00d76d..332aae21 100644 --- a/src/basic-objects/include/reader.hpp +++ b/src/basic-objects/include/reader.hpp @@ -1,6 +1,6 @@ #pragma once -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_string.hpp" namespace cct { @@ -15,7 +15,7 @@ class Reader { [[nodiscard]] virtual string readAll() const { return {}; } // Read all content, and constructs a json object from it. - json readAllJson() const; + json::container readAllJson() const; }; } // namespace cct \ No newline at end of file diff --git a/src/basic-objects/include/writer.hpp b/src/basic-objects/include/writer.hpp index ea323ce7..a3559c84 100644 --- a/src/basic-objects/include/writer.hpp +++ b/src/basic-objects/include/writer.hpp @@ -1,8 +1,9 @@ #pragma once #include +#include -#include "cct_json.hpp" +#include "cct_json-container.hpp" namespace cct { @@ -10,10 +11,15 @@ class Writer { public: enum class Mode : int8_t { FromStart, Append }; - // Write json and return number of bytes written - virtual int write([[maybe_unused]] const json &data, [[maybe_unused]] Mode mode) const { return 0; } - virtual ~Writer() = default; + + // Write a string and return number of bytes written + virtual int write([[maybe_unused]] std::string_view data, [[maybe_unused]] Mode mode = Mode::FromStart) const { + return 0; + } + + // Write json and return number of bytes written + int writeJson(const json::container &data, Mode mode = Mode::FromStart) const; }; } // namespace cct \ No newline at end of file diff --git a/src/objects/src/apioutputtype.cpp b/src/basic-objects/src/apioutputtype.cpp similarity index 81% rename from src/objects/src/apioutputtype.cpp rename to src/basic-objects/src/apioutputtype.cpp index de8e3be8..b513b3c4 100644 --- a/src/objects/src/apioutputtype.cpp +++ b/src/basic-objects/src/apioutputtype.cpp @@ -9,13 +9,13 @@ namespace cct { ApiOutputType ApiOutputTypeFromString(std::string_view str) { auto lowerStr = ToLower(str); if (lowerStr == kApiOutputTypeNoPrintStr) { - return ApiOutputType::kNoPrint; + return ApiOutputType::off; } if (lowerStr == kApiOutputTypeTableStr) { - return ApiOutputType::kFormattedTable; + return ApiOutputType::table; } if (lowerStr == kApiOutputTypeJsonStr) { - return ApiOutputType::kJson; + return ApiOutputType::json; } throw invalid_argument("Unrecognized api output type {}", str); } diff --git a/src/objects/src/coincentercommandtype.cpp b/src/basic-objects/src/coincentercommandtype.cpp similarity index 61% rename from src/objects/src/coincentercommandtype.cpp rename to src/basic-objects/src/coincentercommandtype.cpp index bbb481ef..f836bd40 100644 --- a/src/objects/src/coincentercommandtype.cpp +++ b/src/basic-objects/src/coincentercommandtype.cpp @@ -6,25 +6,20 @@ #include #include "cct_exception.hpp" +#include "cct_json-serialization.hpp" namespace cct { namespace { -constexpr std::string_view kCommandTypeNames[] = { - "HealthCheck", "Currencies", "Markets", "Conversion", "ConversionPath", - "LastPrice", "Ticker", "Orderbook", "LastTrades", "Last24hTradedVolume", - "WithdrawFees", +constexpr auto kCommandTypeNames = json::reflect::keys; - "Balance", "DepositInfo", "OrdersClosed", "OrdersOpened", "OrdersCancel", - "RecentDeposits", "RecentWithdraws", "Trade", "Buy", "Sell", - "Withdraw", "DustSweeper", "MarketData", "Replay", "ReplayMarkets"}; +static_assert(std::size(kCommandTypeNames) == static_cast(CoincenterCommandType::Last) + 1); -static_assert(std::size(kCommandTypeNames) == static_cast(CoincenterCommandType::kLast)); } // namespace std::string_view CoincenterCommandTypeToString(CoincenterCommandType type) { const auto intValue = static_cast>(type); if (intValue < decltype(intValue){} || - intValue >= static_cast>(CoincenterCommandType::kLast)) { + intValue >= static_cast>(CoincenterCommandType::Last)) { throw exception("Unknown command type {}", intValue); } return kCommandTypeNames[intValue]; @@ -40,11 +35,11 @@ CoincenterCommandType CoincenterCommandTypeFromString(std::string_view str) { bool IsAnyTrade(CoincenterCommandType type) { switch (type) { - case CoincenterCommandType::kTrade: + case CoincenterCommandType::Trade: [[fallthrough]]; - case CoincenterCommandType::kBuy: + case CoincenterCommandType::Buy: [[fallthrough]]; - case CoincenterCommandType::kSell: + case CoincenterCommandType::Sell: return true; default: return false; diff --git a/src/basic-objects/src/file.cpp b/src/basic-objects/src/file.cpp index 5ba541cc..b0620bf5 100644 --- a/src/basic-objects/src/file.cpp +++ b/src/basic-objects/src/file.cpp @@ -9,7 +9,6 @@ #include #include "cct_exception.hpp" -#include "cct_json.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "writer.hpp" @@ -62,7 +61,10 @@ string File::readAll() const { return data; } -int File::write(const json& data, Writer::Mode mode) const { +int File::write(std::string_view data, Writer::Mode mode) const { + if (data.empty()) { + return 0; + } log::debug("Opening file {} for writing", _filePath); auto openMode = mode == Writer::Mode::FromStart ? std::ios_base::out : std::ios_base::app; std::ofstream fileOfStream(_filePath.c_str(), openMode); @@ -76,15 +78,8 @@ int File::write(const json& data, Writer::Mode mode) const { return 0; } try { - if (data.empty()) { - static constexpr std::string_view kEmptyJsonStr = "{}"; - fileOfStream << kEmptyJsonStr << '\n'; - return static_cast(kEmptyJsonStr.length()) + 1; - } - const int indent = mode == Writer::Mode::FromStart ? 2 : -1; - string outStr = data.dump(indent); - fileOfStream << outStr << '\n'; - return static_cast(outStr.length()) + 1; + fileOfStream << data << '\n'; + return static_cast(data.length()) + 1; } catch (const std::exception& e) { if (_ifError == IfError::kThrow) { throw e; @@ -94,4 +89,6 @@ int File::write(const json& data, Writer::Mode mode) const { return 0; } +bool File::exists() const { return std::filesystem::exists(std::filesystem::path(std::string_view(_filePath))); } + } // namespace cct \ No newline at end of file diff --git a/src/basic-objects/src/market.cpp b/src/basic-objects/src/market.cpp index a937d083..228dca11 100644 --- a/src/basic-objects/src/market.cpp +++ b/src/basic-objects/src/market.cpp @@ -1,14 +1,10 @@ #include "market.hpp" -#include #include #include #include #include "cct_exception.hpp" -#include "cct_string.hpp" -#include "toupperlower.hpp" -#include "unreachable.hpp" namespace cct { Market::Market(std::string_view marketStrRep, char currencyCodeSep, Type type) { @@ -19,8 +15,9 @@ Market::Market(std::string_view marketStrRep, char currencyCodeSep, Type type) { if (marketStrRep.find(currencyCodeSep, sepPos + 1) != std::string_view::npos) { throw exception("Market string representation {} should have a unique separator {}", marketStrRep, currencyCodeSep); } - _assets.front() = std::string_view(marketStrRep.begin(), marketStrRep.begin() + sepPos); - _assets.back() = std::string_view(marketStrRep.begin() + sepPos + 1, marketStrRep.end()); + + _assets = {std::string_view(marketStrRep.begin(), marketStrRep.begin() + sepPos), + std::string_view(marketStrRep.begin() + sepPos + 1, marketStrRep.end())}; setType(type); } diff --git a/src/basic-objects/src/reader.cpp b/src/basic-objects/src/reader.cpp index 424b8881..925a1710 100644 --- a/src/basic-objects/src/reader.cpp +++ b/src/basic-objects/src/reader.cpp @@ -2,16 +2,16 @@ #include -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_string.hpp" namespace cct { -json Reader::readAllJson() const { +json::container Reader::readAllJson() const { string dataS = readAll(); if (dataS.empty()) { dataS.append("{}"); } - return json::parse(std::move(dataS)); + return json::container::parse(std::move(dataS)); } } // namespace cct \ No newline at end of file diff --git a/src/basic-objects/src/writer.cpp b/src/basic-objects/src/writer.cpp new file mode 100644 index 00000000..9f9269cc --- /dev/null +++ b/src/basic-objects/src/writer.cpp @@ -0,0 +1,17 @@ +#include "writer.hpp" + +#include + +#include "cct_json-container.hpp" +namespace cct { + +int Writer::writeJson(const json::container &data, Mode mode) const { + if (data.empty()) { + return this->write(std::string_view("{}"), mode); + } + const int indent = mode == Writer::Mode::FromStart ? 2 : -1; + const auto str = data.dump(indent); + return this->write(static_cast(str), mode); +} + +} // namespace cct \ No newline at end of file diff --git a/src/basic-objects/test/currencycode_test.cpp b/src/basic-objects/test/currencycode_test.cpp index a438ae8f..c033bc31 100644 --- a/src/basic-objects/test/currencycode_test.cpp +++ b/src/basic-objects/test/currencycode_test.cpp @@ -7,14 +7,14 @@ #include #include "cct_invalid_argument_exception.hpp" +#include "cct_json-serialization.hpp" #include "cct_string.hpp" namespace cct { TEST(CurrencyCodeTest, Neutral) { - CurrencyCode neutral; - EXPECT_EQ("", neutral.str()); - EXPECT_EQ(0U, neutral.size()); + EXPECT_EQ("", CurrencyCode().str()); + EXPECT_EQ(0U, CurrencyCode().size()); } TEST(CurrencyCodeTest, BracketsOperator) { @@ -50,37 +50,39 @@ TEST(CurrencyCodeTest, IsValid) { EXPECT_FALSE(CurrencyCode::IsValid("inv ")); } -TEST(CurrencyCodeTest, AppendIntegralToString) { - { - string str(""); - CurrencyCode("").appendStrTo(str); +TEST(CurrencyCodeTest, AppendIntegralToStringEmpty) { + string str; + CurrencyCode("").appendStrTo(str); - EXPECT_EQ("", str); - } - { - string str("init"); - CurrencyCode("").appendStrTo(str); + EXPECT_TRUE(str.empty()); +} - EXPECT_EQ("init", str); - } - { - string str("init"); - CurrencyCode("a").appendStrTo(str); +TEST(CurrencyCodeTest, AppendIntegralToStringInitEmpty) { + string str("init"); + CurrencyCode("").appendStrTo(str); - EXPECT_EQ("initA", str); - } - { - string str("init2"); - CurrencyCode("67").appendStrTo(str); + EXPECT_EQ("init", str); +} - EXPECT_EQ("init267", str); - } - { - string str(""); - CurrencyCode("EUR").appendStrTo(str); +TEST(CurrencyCodeTest, AppendIntegralToStringInit1) { + string str("init"); + CurrencyCode("a").appendStrTo(str); - EXPECT_EQ("EUR", str); - } + EXPECT_EQ("initA", str); +} + +TEST(CurrencyCodeTest, AppendIntegralToStringInit2) { + string str("init2"); + CurrencyCode("67").appendStrTo(str); + + EXPECT_EQ("init267", str); +} + +TEST(CurrencyCodeTest, AppendIntegralToEmptyString) { + string str; + CurrencyCode("EUR").appendStrTo(str); + + EXPECT_EQ("EUR", str); } TEST(CurrencyCodeTest, ExoticString) { @@ -236,7 +238,7 @@ TEST(CurrencyCodeTest, JsonSerializationValue) { Foo foo{"DOGE"}; string buffer; - auto res = write(foo, buffer); + auto res = json::write(foo, buffer); // NOLINT(readability-implicit-bool-conversion) EXPECT_FALSE(res); @@ -249,7 +251,7 @@ TEST(CurrencyCodeTest, JsonSerializationKey) { CurrencyCodeMap map{{"DOGE", true}, {"BTC", false}}; string buffer; - auto res = write(map, buffer); + auto res = json::write(map, buffer); // NOLINT(readability-implicit-bool-conversion) EXPECT_FALSE(res); @@ -258,7 +260,9 @@ TEST(CurrencyCodeTest, JsonSerializationKey) { TEST(CurrencyCodeTest, JsonDeserialization) { Foo foo; - auto ec = read(foo, R"({"currencyCode":"DOGE"})"); + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::read(foo, R"({"currencyCode":"DOGE"})"); ASSERT_FALSE(ec); diff --git a/src/basic-objects/test/monetaryamount_test.cpp b/src/basic-objects/test/monetaryamount_test.cpp index 292832eb..71797159 100644 --- a/src/basic-objects/test/monetaryamount_test.cpp +++ b/src/basic-objects/test/monetaryamount_test.cpp @@ -8,6 +8,7 @@ #include "cct_exception.hpp" #include "cct_invalid_argument_exception.hpp" +#include "cct_json-serialization.hpp" #include "cct_string.hpp" #include "currencycode.hpp" #include "ipow.hpp" @@ -806,16 +807,33 @@ TEST(MonetaryAmountTest, JsonSerialization) { Foo foo{MonetaryAmount("15.5DOGE")}; string buffer; - auto res = write_json(foo, buffer); + auto ec = json::write(foo, buffer); - EXPECT_FALSE(res); + EXPECT_FALSE(ec); EXPECT_EQ(buffer, R"({"amount":"15.5 DOGE"})"); } +TEST(MonetaryAmountTest, JsonSerializationFormatted) { + Foo foo{MonetaryAmount("43593.78 GLAZE")}; + + string buffer; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::write(foo, buffer); + + EXPECT_FALSE(ec); + + EXPECT_EQ(buffer, R"({ + "amount": "43593.78 GLAZE" +})"); +} + TEST(MonetaryAmountTest, JsonDeserializationValue) { Foo foo; - auto ec = read(foo, R"({"amount":"15.5 DOGE"})"); + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::read(foo, R"({"amount":"15.5 DOGE"})"); ASSERT_FALSE(ec); @@ -828,7 +846,7 @@ TEST(MonetaryAmountTest, JsonSerializationKey) { MonetaryAmountMap map{{MonetaryAmount("15DOGE"), true}, {MonetaryAmount("-0.5605 DOGE"), false}}; string buffer; - auto res = write(map, buffer); + auto res = json::write(map, buffer); // NOLINT(readability-implicit-bool-conversion) EXPECT_FALSE(res); diff --git a/src/engine/include/balanceperexchangeportfolio.hpp b/src/engine/include/balanceperexchangeportfolio.hpp index 96957ee7..a028bdeb 100644 --- a/src/engine/include/balanceperexchangeportfolio.hpp +++ b/src/engine/include/balanceperexchangeportfolio.hpp @@ -1,6 +1,6 @@ #pragma once -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "queryresulttypes.hpp" #include "simpletable.hpp" @@ -15,7 +15,7 @@ class BalancePerExchangePortfolio { SimpleTable getTable(bool wide) const; /// Print in json format. - json printJson(CurrencyCode equiCurrency) const; + json::container printJson(CurrencyCode equiCurrency) const; private: BalancePortfolio computeTotal() const; diff --git a/src/engine/include/coincenterinfo_create.hpp b/src/engine/include/coincenterinfo_create.hpp index bb6f8b10..50d23fd7 100644 --- a/src/engine/include/coincenterinfo_create.hpp +++ b/src/engine/include/coincenterinfo_create.hpp @@ -8,6 +8,7 @@ #include "runmodes.hpp" namespace cct { + CoincenterInfo CoincenterInfo_Create(std::string_view programName, const CoincenterCmdLineOptions &cmdLineOptions, settings::RunMode runMode); diff --git a/src/engine/include/exchangesorchestrator.hpp b/src/engine/include/exchangesorchestrator.hpp index 4498a709..4ab28249 100644 --- a/src/engine/include/exchangesorchestrator.hpp +++ b/src/engine/include/exchangesorchestrator.hpp @@ -16,13 +16,16 @@ namespace cct { class ReplayOptions; -class RequestsConfig; + +namespace schema { +struct RequestsConfig; +} class ExchangesOrchestrator { public: using UniquePublicSelectedExchanges = ExchangeRetriever::UniquePublicSelectedExchanges; - explicit ExchangesOrchestrator(const RequestsConfig &requestsConfig, std::span exchangesSpan); + explicit ExchangesOrchestrator(const schema::RequestsConfig &requestsConfig, std::span exchangesSpan); ExchangeHealthCheckStatus healthCheck(ExchangeNameSpan exchangeNames); diff --git a/src/engine/include/queryresultprinter.hpp b/src/engine/include/queryresultprinter.hpp index 02e4addc..6d69fd76 100644 --- a/src/engine/include/queryresultprinter.hpp +++ b/src/engine/include/queryresultprinter.hpp @@ -6,7 +6,7 @@ #include #include "apioutputtype.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "coincentercommandtype.hpp" #include "currencycode.hpp" @@ -52,18 +52,18 @@ class QueryResultPrinter { void printTrades(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAmount startAmount, bool isPercentageTrade, CurrencyCode toCurrency, const TradeOptions &tradeOptions) const { printTrades(tradeResultPerExchange, startAmount, isPercentageTrade, toCurrency, tradeOptions, - CoincenterCommandType::kTrade); + CoincenterCommandType::Trade); } void printBuyTrades(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAmount endAmount, const TradeOptions &tradeOptions) const { - printTrades(tradeResultPerExchange, endAmount, false, CurrencyCode(), tradeOptions, CoincenterCommandType::kBuy); + printTrades(tradeResultPerExchange, endAmount, false, CurrencyCode(), tradeOptions, CoincenterCommandType::Buy); } void printSellTrades(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAmount startAmount, bool isPercentageTrade, const TradeOptions &tradeOptions) const { printTrades(tradeResultPerExchange, startAmount, isPercentageTrade, CurrencyCode(), tradeOptions, - CoincenterCommandType::kSell); + CoincenterCommandType::Sell); } void printClosedOrders(const ClosedOrdersPerExchange &closedOrdersPerExchange, @@ -118,9 +118,9 @@ class QueryResultPrinter { void printTable(const SimpleTable &table) const; - void printJson(const json &jsonData) const; + void printJson(const json::container &jsonData) const; - void logActivity(CoincenterCommandType commandType, const json &data, bool isSimulationMode = false) const; + void logActivity(CoincenterCommandType commandType, const json::container &data, bool isSimulationMode = false) const; const LoggingInfo &_loggingInfo; std::ostream *_pOs = nullptr; diff --git a/src/engine/src/balanceperexchangeportfolio.cpp b/src/engine/src/balanceperexchangeportfolio.cpp index 4e28c080..fabf185b 100644 --- a/src/engine/src/balanceperexchangeportfolio.cpp +++ b/src/engine/src/balanceperexchangeportfolio.cpp @@ -3,7 +3,7 @@ #include #include "balanceportfolio.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_string.hpp" #include "currencycode.hpp" #include "exchange.hpp" @@ -76,10 +76,10 @@ SimpleTable BalancePerExchangePortfolio::getTable(bool wide) const { } namespace { -json JsonForBalancePortfolio(const BalancePortfolio &balancePortfolio, CurrencyCode equiCurrency) { - json ret = json::object(); +json::container JsonForBalancePortfolio(const BalancePortfolio &balancePortfolio, CurrencyCode equiCurrency) { + json::container ret = json::container::object(); for (const auto &[amount, equiAmount] : balancePortfolio) { - json curData; + json::container curData; curData.emplace("a", amount.amountStr()); if (!equiCurrency.isNeutral()) { curData.emplace("eq", equiAmount.amountStr()); @@ -90,12 +90,12 @@ json JsonForBalancePortfolio(const BalancePortfolio &balancePortfolio, CurrencyC } } // namespace -json BalancePerExchangePortfolio::printJson(CurrencyCode equiCurrency) const { - json exchangePart = json::object(); +json::container BalancePerExchangePortfolio::printJson(CurrencyCode equiCurrency) const { + json::container exchangePart = json::container::object(); for (const auto &[exchangePtr, balancePortfolio] : _balancePerExchange) { auto it = exchangePart.find(exchangePtr->name()); if (it == exchangePart.end()) { - json balancePerExchangeData; + json::container balancePerExchangeData; balancePerExchangeData.emplace(exchangePtr->keyName(), JsonForBalancePortfolio(balancePortfolio, equiCurrency)); exchangePart.emplace(exchangePtr->name(), std::move(balancePerExchangeData)); } else { @@ -104,12 +104,12 @@ json BalancePerExchangePortfolio::printJson(CurrencyCode equiCurrency) const { } BalancePortfolio total = computeTotal(); - json totalPart; + json::container totalPart; totalPart.emplace("cur", JsonForBalancePortfolio(total, equiCurrency)); if (!equiCurrency.isNeutral()) { totalPart.emplace("eq", ComputeTotalSum(total).amountStr()); } - json out; + json::container out; out.emplace("exchange", std::move(exchangePart)); out.emplace("total", std::move(totalPart)); return out; diff --git a/src/engine/src/coincenter-commands-iterator.cpp b/src/engine/src/coincenter-commands-iterator.cpp index 6cf6da54..fa7ff282 100644 --- a/src/engine/src/coincenter-commands-iterator.cpp +++ b/src/engine/src/coincenter-commands-iterator.cpp @@ -37,7 +37,7 @@ bool CommandTypeCanBeGrouped(CoincenterCommandType type) { // Compatible command types need to be explicitly set // For now, only market data is compatible switch (type) { - case CoincenterCommandType::kMarketData: + case CoincenterCommandType::MarketData: return true; default: return false; diff --git a/src/engine/src/coincenter-commands-processor.cpp b/src/engine/src/coincenter-commands-processor.cpp index e0071411..933cd9da 100644 --- a/src/engine/src/coincenter-commands-processor.cpp +++ b/src/engine/src/coincenter-commands-processor.cpp @@ -105,23 +105,23 @@ TransferableCommandResultVector CoincenterCommandsProcessor::processGroupedComma const auto &firstCmd = groupedCommands.front(); // All grouped commands have same type - logic to handle multiple commands in a group should be handled per use case switch (firstCmd.type()) { - case CoincenterCommandType::kHealthCheck: { + case CoincenterCommandType::HealthCheck: { const auto healthCheckStatus = _coincenter.healthCheck(firstCmd.exchangeNames()); _queryResultPrinter.printHealthCheck(healthCheckStatus); break; } - case CoincenterCommandType::kCurrencies: { + case CoincenterCommandType::Currencies: { const auto currenciesPerExchange = _coincenter.getCurrenciesPerExchange(firstCmd.exchangeNames()); _queryResultPrinter.printCurrencies(currenciesPerExchange); break; } - case CoincenterCommandType::kMarkets: { + case CoincenterCommandType::Markets: { const auto marketsPerExchange = _coincenter.getMarketsPerExchange(firstCmd.cur1(), firstCmd.cur2(), firstCmd.exchangeNames()); _queryResultPrinter.printMarkets(firstCmd.cur1(), firstCmd.cur2(), marketsPerExchange, firstCmd.type()); break; } - case CoincenterCommandType::kConversion: { + case CoincenterCommandType::Conversion: { if (firstCmd.amount().isDefault()) { std::array startAmountsPerExchangePos; bool oneSet = false; @@ -151,49 +151,49 @@ TransferableCommandResultVector CoincenterCommandsProcessor::processGroupedComma } break; } - case CoincenterCommandType::kConversionPath: { + case CoincenterCommandType::ConversionPath: { const auto conversionPathPerExchange = _coincenter.getConversionPaths(firstCmd.market(), firstCmd.exchangeNames()); _queryResultPrinter.printConversionPath(firstCmd.market(), conversionPathPerExchange); break; } - case CoincenterCommandType::kLastPrice: { + case CoincenterCommandType::LastPrice: { const auto lastPricePerExchange = _coincenter.getLastPricePerExchange(firstCmd.market(), firstCmd.exchangeNames()); _queryResultPrinter.printLastPrice(firstCmd.market(), lastPricePerExchange); break; } - case CoincenterCommandType::kTicker: { + case CoincenterCommandType::Ticker: { const auto exchangeTickerMaps = _coincenter.getTickerInformation(firstCmd.exchangeNames()); _queryResultPrinter.printTickerInformation(exchangeTickerMaps); break; } - case CoincenterCommandType::kOrderbook: { + case CoincenterCommandType::Orderbook: { const auto marketOrderBooksConversionRates = _coincenter.getMarketOrderBooks( firstCmd.market(), firstCmd.exchangeNames(), firstCmd.cur1(), firstCmd.optDepth()); _queryResultPrinter.printMarketOrderBooks(firstCmd.market(), firstCmd.cur1(), firstCmd.optDepth(), marketOrderBooksConversionRates); break; } - case CoincenterCommandType::kLastTrades: { + case CoincenterCommandType::LastTrades: { const auto lastTradesPerExchange = _coincenter.getLastTradesPerExchange(firstCmd.market(), firstCmd.exchangeNames(), firstCmd.optDepth()); _queryResultPrinter.printLastTrades(firstCmd.market(), firstCmd.optDepth(), lastTradesPerExchange); break; } - case CoincenterCommandType::kLast24hTradedVolume: { + case CoincenterCommandType::Last24hTradedVolume: { const auto tradedVolumePerExchange = _coincenter.getLast24hTradedVolumePerExchange(firstCmd.market(), firstCmd.exchangeNames()); _queryResultPrinter.printLast24hTradedVolume(firstCmd.market(), tradedVolumePerExchange); break; } - case CoincenterCommandType::kWithdrawFees: { + case CoincenterCommandType::WithdrawFees: { const auto withdrawFeesPerExchange = _coincenter.getWithdrawFees(firstCmd.cur1(), firstCmd.exchangeNames()); _queryResultPrinter.printWithdrawFees(withdrawFeesPerExchange, firstCmd.cur1()); break; } - case CoincenterCommandType::kBalance: { + case CoincenterCommandType::Balance: { const auto amountIncludePolicy = firstCmd.withBalanceInUse() ? BalanceOptions::AmountIncludePolicy::kWithBalanceInUse : BalanceOptions::AmountIncludePolicy::kOnlyAvailable; @@ -202,42 +202,42 @@ TransferableCommandResultVector CoincenterCommandsProcessor::processGroupedComma _queryResultPrinter.printBalance(balancePerExchange, firstCmd.cur1()); break; } - case CoincenterCommandType::kDepositInfo: { + case CoincenterCommandType::DepositInfo: { const auto walletPerExchange = _coincenter.getDepositInfo(firstCmd.exchangeNames(), firstCmd.cur1()); _queryResultPrinter.printDepositInfo(firstCmd.cur1(), walletPerExchange); break; } - case CoincenterCommandType::kOrdersClosed: { + case CoincenterCommandType::OrdersClosed: { const auto closedOrdersPerExchange = _coincenter.getClosedOrders(firstCmd.exchangeNames(), firstCmd.ordersConstraints()); _queryResultPrinter.printClosedOrders(closedOrdersPerExchange, firstCmd.ordersConstraints()); break; } - case CoincenterCommandType::kOrdersOpened: { + case CoincenterCommandType::OrdersOpened: { const auto openedOrdersPerExchange = _coincenter.getOpenedOrders(firstCmd.exchangeNames(), firstCmd.ordersConstraints()); _queryResultPrinter.printOpenedOrders(openedOrdersPerExchange, firstCmd.ordersConstraints()); break; } - case CoincenterCommandType::kOrdersCancel: { + case CoincenterCommandType::OrdersCancel: { const auto nbCancelledOrdersPerExchange = _coincenter.cancelOrders(firstCmd.exchangeNames(), firstCmd.ordersConstraints()); _queryResultPrinter.printCancelledOrders(nbCancelledOrdersPerExchange, firstCmd.ordersConstraints()); break; } - case CoincenterCommandType::kRecentDeposits: { + case CoincenterCommandType::RecentDeposits: { const auto depositsPerExchange = _coincenter.getRecentDeposits(firstCmd.exchangeNames(), firstCmd.withdrawsOrDepositsConstraints()); _queryResultPrinter.printRecentDeposits(depositsPerExchange, firstCmd.withdrawsOrDepositsConstraints()); break; } - case CoincenterCommandType::kRecentWithdraws: { + case CoincenterCommandType::RecentWithdraws: { const auto withdrawsPerExchange = _coincenter.getRecentWithdraws(firstCmd.exchangeNames(), firstCmd.withdrawsOrDepositsConstraints()); _queryResultPrinter.printRecentWithdraws(withdrawsPerExchange, firstCmd.withdrawsOrDepositsConstraints()); break; } - case CoincenterCommandType::kTrade: { + case CoincenterCommandType::Trade: { // 2 input styles are possible: // - standard full information with an amount to trade, a destination currency and an optional list of exchanges // where to trade @@ -253,14 +253,14 @@ TransferableCommandResultVector CoincenterCommandsProcessor::processGroupedComma FillTradeTransferableCommandResults(tradeResultPerExchange, transferableResults); break; } - case CoincenterCommandType::kBuy: { + case CoincenterCommandType::Buy: { const auto tradeResultPerExchange = _coincenter.smartBuy(firstCmd.amount(), firstCmd.exchangeNames(), firstCmd.tradeOptions()); _queryResultPrinter.printBuyTrades(tradeResultPerExchange, firstCmd.amount(), firstCmd.tradeOptions()); FillTradeTransferableCommandResults(tradeResultPerExchange, transferableResults); break; } - case CoincenterCommandType::kSell: { + case CoincenterCommandType::Sell: { auto [startAmount, exchangeNames] = ComputeTradeAmountAndExchanges(firstCmd, previousTransferableResults); if (startAmount.isDefault()) { break; @@ -272,7 +272,7 @@ TransferableCommandResultVector CoincenterCommandsProcessor::processGroupedComma FillTradeTransferableCommandResults(tradeResultPerExchange, transferableResults); break; } - case CoincenterCommandType::kWithdrawApply: { + case CoincenterCommandType::Withdraw: { const auto [grossAmount, exchangeName] = ComputeWithdrawAmount(firstCmd, previousTransferableResults); if (grossAmount.isDefault()) { break; @@ -286,12 +286,12 @@ TransferableCommandResultVector CoincenterCommandsProcessor::processGroupedComma deliveredWithdrawInfoWithExchanges.second.receivedAmount()); break; } - case CoincenterCommandType::kDustSweeper: { + case CoincenterCommandType::DustSweeper: { const auto res = _coincenter.dustSweeper(firstCmd.exchangeNames(), firstCmd.cur1()); _queryResultPrinter.printDustSweeper(res, firstCmd.cur1()); break; } - case CoincenterCommandType::kMarketData: { + case CoincenterCommandType::MarketData: { std::array marketPerPublicExchange; for (const auto &cmd : groupedCommands) { if (cmd.exchangeNames().empty()) { @@ -306,7 +306,7 @@ TransferableCommandResultVector CoincenterCommandsProcessor::processGroupedComma _coincenter.queryMarketDataPerExchange(marketPerPublicExchange); break; } - case CoincenterCommandType::kReplay: { + case CoincenterCommandType::Replay: { /// This implementation of AbstractMarketTraderFactory is only provided as an example. /// You can extend coincenter library and: /// - Provide your own algorithms by implementing your own MarketTraderFactory will all your algorithms. @@ -317,11 +317,11 @@ TransferableCommandResultVector CoincenterCommandsProcessor::processGroupedComma firstCmd.exchangeNames()); _queryResultPrinter.printMarketTradingResults(firstCmd.replayOptions().timeWindow(), replayResults, - CoincenterCommandType::kReplay); + CoincenterCommandType::Replay); break; } - case CoincenterCommandType::kReplayMarkets: { + case CoincenterCommandType::ReplayMarkets: { const auto marketTimestampSetsPerExchange = _coincenter.getMarketsAvailableForReplay(firstCmd.replayOptions(), firstCmd.exchangeNames()); _queryResultPrinter.printMarketsForReplay(firstCmd.replayOptions().timeWindow(), marketTimestampSetsPerExchange); diff --git a/src/engine/src/coincenter.cpp b/src/engine/src/coincenter.cpp index 6e7eecea..24f6f4fc 100644 --- a/src/engine/src/coincenter.cpp +++ b/src/engine/src/coincenter.cpp @@ -44,7 +44,7 @@ Coincenter::Coincenter(const CoincenterInfo &coincenterInfo, const ExchangeSecre _apiKeyProvider(coincenterInfo.dataDir(), exchangeSecretsInfo, coincenterInfo.getRunMode()), _metricsExporter(coincenterInfo.metricGatewayPtr()), _exchangePool(coincenterInfo, _fiatConverter, _commonAPI, _apiKeyProvider), - _exchangesOrchestrator(coincenterInfo.requestsConfig(), _exchangePool.exchanges()) {} + _exchangesOrchestrator(coincenterInfo.generalConfig().requests, _exchangePool.exchanges()) {} ExchangeHealthCheckStatus Coincenter::healthCheck(ExchangeNameSpan exchangeNames) { const auto ret = _exchangesOrchestrator.healthCheck(exchangeNames); @@ -364,9 +364,9 @@ MonetaryAmount ComputeStartAmount(CurrencyCode currencyCode, MonetaryAmount conv Coincenter::MarketTraderEngineVector Coincenter::createMarketTraderEngines( const ReplayOptions &replayOptions, Market market, PublicExchangeNameVector &exchangesWithThisMarketData) { - const auto &automationConfig = _coincenterInfo.generalConfig().tradingConfig().automationConfig(); - const auto startBaseAmountEquivalent = automationConfig.startBaseAmountEquivalent(); - const auto startQuoteAmountEquivalent = automationConfig.startQuoteAmountEquivalent(); + const auto &automationConfig = _coincenterInfo.generalConfig().trading.automation; + const auto startBaseAmountEquivalent = automationConfig.startingContext.startBaseAmountEquivalent; + const auto startQuoteAmountEquivalent = automationConfig.startingContext.startQuoteAmountEquivalent; const bool isValidateOnly = replayOptions.replayMode() == ReplayOptions::ReplayMode::kValidateOnly; auto convertedBaseAmountPerExchange = @@ -407,8 +407,8 @@ Coincenter::MarketTraderEngineVector Coincenter::createMarketTraderEngines( MarketTradeRangeStatsPerExchange Coincenter::tradingProcess(const ReplayOptions &replayOptions, std::span marketTraderEngines, ExchangeNameSpan exchangesWithThisMarketData) { - const auto &automationConfig = _coincenterInfo.generalConfig().tradingConfig().automationConfig(); - const auto loadChunkDuration = automationConfig.loadChunkDuration(); + const auto &automationConfig = _coincenterInfo.generalConfig().trading.automation; + const auto loadChunkDuration = automationConfig.deserialization.loadChunkDuration.duration; const auto timeWindow = replayOptions.timeWindow(); MarketTradeRangeStatsPerExchange tradeRangeResultsPerExchange; diff --git a/src/engine/src/coincentercommand.cpp b/src/engine/src/coincentercommand.cpp index d49fd30b..0f1dfba2 100644 --- a/src/engine/src/coincentercommand.cpp +++ b/src/engine/src/coincentercommand.cpp @@ -20,11 +20,11 @@ namespace cct { namespace { bool IsOrderCommand(CoincenterCommandType cmd) { switch (cmd) { - case CoincenterCommandType::kOrdersCancel: // NOLINT(bugprone-branch-clone) + case CoincenterCommandType::OrdersCancel: // NOLINT(bugprone-branch-clone) [[fallthrough]]; - case CoincenterCommandType::kOrdersClosed: + case CoincenterCommandType::OrdersClosed: [[fallthrough]]; - case CoincenterCommandType::kOrdersOpened: + case CoincenterCommandType::OrdersOpened: return true; default: return false; @@ -46,7 +46,7 @@ CoincenterCommand& CoincenterCommand::setOrdersConstraints(OrdersConstraints ord } CoincenterCommand& CoincenterCommand::setDepositsConstraints(DepositsConstraints depositsConstraints) { - if (_type != CoincenterCommandType::kRecentDeposits) { + if (_type != CoincenterCommandType::RecentDeposits) { throw exception("Deposit constraints can only be used for deposits related commands"); } _specialOptions = std::move(depositsConstraints); @@ -54,7 +54,7 @@ CoincenterCommand& CoincenterCommand::setDepositsConstraints(DepositsConstraints } CoincenterCommand& CoincenterCommand::setWithdrawsConstraints(WithdrawsConstraints withdrawsConstraints) { - if (_type != CoincenterCommandType::kRecentWithdraws) { + if (_type != CoincenterCommandType::RecentWithdraws) { throw exception("Withdraw constraints can only be used for withdraws related commands"); } _specialOptions = std::move(withdrawsConstraints); @@ -62,8 +62,8 @@ CoincenterCommand& CoincenterCommand::setWithdrawsConstraints(WithdrawsConstrain } CoincenterCommand& CoincenterCommand::setTradeOptions(TradeOptions tradeOptions) { - if (_type != CoincenterCommandType::kBuy && _type != CoincenterCommandType::kSell && - _type != CoincenterCommandType::kTrade) { + if (_type != CoincenterCommandType::Buy && _type != CoincenterCommandType::Sell && + _type != CoincenterCommandType::Trade) { throw exception("Trade options can only be used for trade related commands"); } _specialOptions = std::move(tradeOptions); @@ -71,7 +71,7 @@ CoincenterCommand& CoincenterCommand::setTradeOptions(TradeOptions tradeOptions) } CoincenterCommand& CoincenterCommand::setWithdrawOptions(WithdrawOptions withdrawOptions) { - if (_type != CoincenterCommandType::kWithdrawApply) { + if (_type != CoincenterCommandType::Withdraw) { throw exception("Withdraw options can only be used for withdraws"); } _specialOptions = std::move(withdrawOptions); @@ -110,8 +110,8 @@ CoincenterCommand& CoincenterCommand::setCur2(CurrencyCode cur2) { } CoincenterCommand& CoincenterCommand::setPercentageAmount(bool value) { - if (_type != CoincenterCommandType::kBuy && _type != CoincenterCommandType::kSell && - _type != CoincenterCommandType::kTrade && _type != CoincenterCommandType::kWithdrawApply) { + if (_type != CoincenterCommandType::Buy && _type != CoincenterCommandType::Sell && + _type != CoincenterCommandType::Trade && _type != CoincenterCommandType::Withdraw) { throw exception("Percentage trade can only be set for trade / buy / sell or withdraw command"); } _isPercentageAmount = value; @@ -119,7 +119,7 @@ CoincenterCommand& CoincenterCommand::setPercentageAmount(bool value) { } CoincenterCommand& CoincenterCommand::withBalanceInUse(bool value) { - if (_type != CoincenterCommandType::kBalance) { + if (_type != CoincenterCommandType::Balance) { throw exception("With balance in use can only be set for Balance command"); } _withBalanceInUse = value; diff --git a/src/engine/src/coincentercommandfactory.cpp b/src/engine/src/coincentercommandfactory.cpp index 6f8ff37d..e8f07749 100644 --- a/src/engine/src/coincentercommandfactory.cpp +++ b/src/engine/src/coincentercommandfactory.cpp @@ -20,7 +20,7 @@ CoincenterCommand CoincenterCommandFactory::CreateMarketCommand(StringOptionPars if (market.isNeutral()) { market = Market(optionParser.parseCurrency(StringOptionParser::FieldIs::kOptional), CurrencyCode()); } - CoincenterCommand ret(CoincenterCommandType::kMarkets); + CoincenterCommand ret(CoincenterCommandType::Markets); ret.setCur1(market.base()); ret.setCur2(market.quote()); ret.setExchangeNames(optionParser.parseExchanges()); @@ -102,7 +102,7 @@ CoincenterCommand CoincenterCommandFactory::createWithdrawApplyCommand(StringOpt } else if (exchanges.size() != 2U) { throw invalid_argument("Exactly 2 exchanges 'from-to' should be provided for withdraw"); } - CoincenterCommand command(CoincenterCommandType::kWithdrawApply); + CoincenterCommand command(CoincenterCommandType::Withdraw); command.setPercentageAmount(amountType == StringOptionParser::AmountType::kPercentage) .setWithdrawOptions(_cmdLineOptions.computeWithdrawOptions()) .setExchangeNames(std::move(exchanges)); @@ -118,7 +118,7 @@ CoincenterCommand CoincenterCommandFactory::createWithdrawApplyAllCommand(String if (exchanges.size() != 2U || cur.isNeutral()) { throw invalid_argument("Withdraw all expects a currency with a from-to pair of exchanges"); } - CoincenterCommand command(CoincenterCommandType::kWithdrawApply); + CoincenterCommand command(CoincenterCommandType::Withdraw); command.setPercentageAmount(true) .setExchangeNames(std::move(exchanges)) .setWithdrawOptions(_cmdLineOptions.computeWithdrawOptions()) diff --git a/src/engine/src/coincentercommands.cpp b/src/engine/src/coincentercommands.cpp index f819a993..aaa9934e 100644 --- a/src/engine/src/coincentercommands.cpp +++ b/src/engine/src/coincentercommands.cpp @@ -51,12 +51,12 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (cmdLineOptions.healthCheck) { optionParser = StringOptionParser(*cmdLineOptions.healthCheck); - _commands.emplace_back(CoincenterCommandType::kHealthCheck).setExchangeNames(optionParser.parseExchanges()); + _commands.emplace_back(CoincenterCommandType::HealthCheck).setExchangeNames(optionParser.parseExchanges()); } if (cmdLineOptions.currencies) { optionParser = StringOptionParser(*cmdLineOptions.currencies); - _commands.emplace_back(CoincenterCommandType::kCurrencies).setExchangeNames(optionParser.parseExchanges()); + _commands.emplace_back(CoincenterCommandType::Currencies).setExchangeNames(optionParser.parseExchanges()); } if (cmdLineOptions.markets) { @@ -66,7 +66,7 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (!cmdLineOptions.orderbook.empty()) { optionParser = StringOptionParser(cmdLineOptions.orderbook); - auto &cmd = _commands.emplace_back(CoincenterCommandType::kOrderbook) + auto &cmd = _commands.emplace_back(CoincenterCommandType::Orderbook) .setMarket(optionParser.parseMarket()) .setExchangeNames(optionParser.parseExchanges()) .setCur1(cmdLineOptions.orderbookCur); @@ -77,7 +77,7 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (cmdLineOptions.ticker) { optionParser = StringOptionParser(*cmdLineOptions.ticker); - _commands.emplace_back(CoincenterCommandType::kTicker).setExchangeNames(optionParser.parseExchanges()); + _commands.emplace_back(CoincenterCommandType::Ticker).setExchangeNames(optionParser.parseExchanges()); } if (!cmdLineOptions.conversion.empty()) { @@ -87,7 +87,7 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (amountType == StringOptionParser::AmountType::kPercentage) { throw invalid_argument("conversion should start with an absolute amount"); } - _commands.emplace_back(CoincenterCommandType::kConversion) + _commands.emplace_back(CoincenterCommandType::Conversion) .setAmount(amount) .setCur1(optionParser.parseCurrency()) .setExchangeNames(optionParser.parseExchanges()); @@ -95,14 +95,14 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (!cmdLineOptions.conversionPath.empty()) { optionParser = StringOptionParser(cmdLineOptions.conversionPath); - _commands.emplace_back(CoincenterCommandType::kConversionPath) + _commands.emplace_back(CoincenterCommandType::ConversionPath) .setMarket(optionParser.parseMarket()) .setExchangeNames(optionParser.parseExchanges()); } if (cmdLineOptions.balance) { optionParser = StringOptionParser(*cmdLineOptions.balance); - _commands.emplace_back(CoincenterCommandType::kBalance) + _commands.emplace_back(CoincenterCommandType::Balance) .setCur1(optionParser.parseCurrency(StringOptionParser::FieldIs::kOptional)) .withBalanceInUse(cmdLineOptions.withBalanceInUse) .setExchangeNames(optionParser.parseExchanges()); @@ -116,29 +116,29 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (!cmdLineOptions.depositInfo.empty()) { optionParser = StringOptionParser(cmdLineOptions.depositInfo); - _commands.emplace_back(CoincenterCommandType::kDepositInfo) + _commands.emplace_back(CoincenterCommandType::DepositInfo) .setCur1(optionParser.parseCurrency()) .setExchangeNames(optionParser.parseExchanges()); } if (cmdLineOptions.closedOrdersInfo) { optionParser = StringOptionParser(*cmdLineOptions.closedOrdersInfo); - _commands.push_back(commandFactory.createOrderCommand(CoincenterCommandType::kOrdersClosed, optionParser)); + _commands.push_back(commandFactory.createOrderCommand(CoincenterCommandType::OrdersClosed, optionParser)); } if (cmdLineOptions.openedOrdersInfo) { optionParser = StringOptionParser(*cmdLineOptions.openedOrdersInfo); - _commands.push_back(commandFactory.createOrderCommand(CoincenterCommandType::kOrdersOpened, optionParser)); + _commands.push_back(commandFactory.createOrderCommand(CoincenterCommandType::OrdersOpened, optionParser)); } if (cmdLineOptions.cancelOpenedOrders) { optionParser = StringOptionParser(*cmdLineOptions.cancelOpenedOrders); - _commands.push_back(commandFactory.createOrderCommand(CoincenterCommandType::kOrdersCancel, optionParser)); + _commands.push_back(commandFactory.createOrderCommand(CoincenterCommandType::OrdersCancel, optionParser)); } if (cmdLineOptions.recentDepositsInfo) { optionParser = StringOptionParser(*cmdLineOptions.recentDepositsInfo); - _commands.emplace_back(CoincenterCommandType::kRecentDeposits) + _commands.emplace_back(CoincenterCommandType::RecentDeposits) .setDepositsConstraints(DepositsConstraints( optionParser.parseCurrency(StringOptionParser::FieldIs::kOptional), cmdLineOptions.minAge, cmdLineOptions.maxAge, DepositsConstraints::IdSet(StringOptionParser(cmdLineOptions.ids).getCSVValues()))) @@ -147,7 +147,7 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (cmdLineOptions.recentWithdrawsInfo) { optionParser = StringOptionParser(*cmdLineOptions.recentWithdrawsInfo); - _commands.emplace_back(CoincenterCommandType::kRecentWithdraws) + _commands.emplace_back(CoincenterCommandType::RecentWithdraws) .setWithdrawsConstraints(WithdrawsConstraints( optionParser.parseCurrency(StringOptionParser::FieldIs::kOptional), cmdLineOptions.minAge, cmdLineOptions.maxAge, WithdrawsConstraints::IdSet(StringOptionParser(cmdLineOptions.ids).getCSVValues()))) @@ -166,28 +166,28 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (!cmdLineOptions.dustSweeper.empty()) { optionParser = StringOptionParser(cmdLineOptions.dustSweeper); - _commands.emplace_back(CoincenterCommandType::kDustSweeper) + _commands.emplace_back(CoincenterCommandType::DustSweeper) .setCur1(optionParser.parseCurrency()) .setExchangeNames(optionParser.parseExchanges()); } if (cmdLineOptions.withdrawFees) { optionParser = StringOptionParser(*cmdLineOptions.withdrawFees); - _commands.emplace_back(CoincenterCommandType::kWithdrawFees) + _commands.emplace_back(CoincenterCommandType::WithdrawFees) .setCur1(optionParser.parseCurrency(StringOptionParser::FieldIs::kOptional)) .setExchangeNames(optionParser.parseExchanges()); } if (!cmdLineOptions.last24hTradedVolume.empty()) { optionParser = StringOptionParser(cmdLineOptions.last24hTradedVolume); - _commands.emplace_back(CoincenterCommandType::kLast24hTradedVolume) + _commands.emplace_back(CoincenterCommandType::Last24hTradedVolume) .setMarket(optionParser.parseMarket()) .setExchangeNames(optionParser.parseExchanges()); } if (!cmdLineOptions.lastTrades.empty()) { optionParser = StringOptionParser(cmdLineOptions.lastTrades); - auto &cmd = _commands.emplace_back(CoincenterCommandType::kLastTrades) + auto &cmd = _commands.emplace_back(CoincenterCommandType::LastTrades) .setMarket(optionParser.parseMarket()) .setExchangeNames(optionParser.parseExchanges()); if (cmdLineOptions.depth != CoincenterCmdLineOptions::kUndefinedDepth) { @@ -197,7 +197,7 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (!cmdLineOptions.lastPrice.empty()) { optionParser = StringOptionParser(cmdLineOptions.lastPrice); - _commands.emplace_back(CoincenterCommandType::kLastPrice) + _commands.emplace_back(CoincenterCommandType::LastPrice) .setMarket(optionParser.parseMarket()) .setExchangeNames(optionParser.parseExchanges()); } @@ -205,7 +205,7 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption if (!cmdLineOptions.marketData.empty()) { optionParser = StringOptionParser(cmdLineOptions.marketData); - _commands.emplace_back(CoincenterCommandType::kMarketData) + _commands.emplace_back(CoincenterCommandType::MarketData) .setMarket(optionParser.parseMarket()) .setExchangeNames(optionParser.parseExchanges()); } @@ -215,7 +215,7 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption auto dur = optionParser.parseDuration(StringOptionParser::FieldIs::kOptional); - auto &cmd = _commands.emplace_back(CoincenterCommandType::kReplay) + auto &cmd = _commands.emplace_back(CoincenterCommandType::Replay) .setReplayOptions(cmdLineOptions.computeReplayOptions(dur)) .setExchangeNames(optionParser.parseExchanges()); @@ -236,7 +236,7 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption timeWindow = TimeWindow(nowTime - dur, nowTime); } - _commands.emplace_back(CoincenterCommandType::kReplayMarkets) + _commands.emplace_back(CoincenterCommandType::ReplayMarkets) .setReplayOptions( ReplayOptions(timeWindow, cmdLineOptions.algorithmNames, ReplayOptions::ReplayMode::kValidateOnly)) .setExchangeNames(optionParser.parseExchanges()); diff --git a/src/engine/src/coincenterinfo_create.cpp b/src/engine/src/coincenterinfo_create.cpp index 2153369e..d67632e0 100644 --- a/src/engine/src/coincenterinfo_create.cpp +++ b/src/engine/src/coincenterinfo_create.cpp @@ -4,45 +4,38 @@ #include #include "apioutputtype.hpp" -#include "automation-config.hpp" -#include "cct_json.hpp" #include "cct_string.hpp" #include "coincenterinfo.hpp" #include "coincenteroptions.hpp" -#include "durationstring.hpp" #include "exchangesecretsinfo.hpp" #include "file.hpp" -#include "generalconfig.hpp" +#include "general-config.hpp" #include "loadconfiguration.hpp" #include "logginginfo.hpp" -#include "monetaryamount.hpp" #include "monitoringinfo.hpp" -#include "requestsconfig.hpp" #include "runmodes.hpp" #include "stringoptionparser.hpp" -#include "timedef.hpp" -#include "trading-config.hpp" namespace cct { namespace { -json LoadGeneralConfigAndOverrideOptionsFromCLI(const CoincenterCmdLineOptions &cmdLineOptions) { - json generalConfigData = GeneralConfig::LoadFile(cmdLineOptions.getDataDir()); +schema::GeneralConfig LoadGeneralConfigAndOverrideOptionsFromCLI(const CoincenterCmdLineOptions &cmdLineOptions) { + schema::GeneralConfig generalConfig = ReadGeneralConfig(cmdLineOptions.getDataDir()); // Override general config options from CLI // Use at method to make sure to throw if key is not already present (it should) if (!cmdLineOptions.apiOutputType.empty()) { - generalConfigData.at("apiOutputType") = cmdLineOptions.apiOutputType; + generalConfig.apiOutputType = ApiOutputTypeFromString(cmdLineOptions.apiOutputType); } if (!cmdLineOptions.logConsole.empty()) { - generalConfigData.at("log").at(LoggingInfo::kJsonFieldConsoleLevelName) = string(cmdLineOptions.logConsole); + generalConfig.log.consoleLevel = string(cmdLineOptions.logConsole); } if (!cmdLineOptions.logFile.empty()) { - generalConfigData.at("log").at(LoggingInfo::kJsonFieldFileLevelName) = string(cmdLineOptions.logFile); + generalConfig.log.fileLevel = string(cmdLineOptions.logFile); } - return generalConfigData; + return generalConfig; } MonitoringInfo MonitoringInfo_Create(std::string_view programName, const CoincenterCmdLineOptions &cmdLineOptions) { @@ -58,36 +51,11 @@ CoincenterInfo CoincenterInfo_Create(std::string_view programName, const Coincen const auto dataDir = cmdLineOptions.getDataDir(); LoggingInfo loggingInfo(LoggingInfo::WithLoggersCreation::kNo, dataDir); - const json generalConfigData = LoadGeneralConfigAndOverrideOptionsFromCLI(cmdLineOptions); - - const Duration fiatConversionQueryRate = - ParseDuration(generalConfigData.at("fiatConversion").at("rate").get()); - const ApiOutputType apiOutputType = - ApiOutputTypeFromString(generalConfigData.at("apiOutputType").get()); + schema::GeneralConfig generalConfig = LoadGeneralConfigAndOverrideOptionsFromCLI(cmdLineOptions); // Create LoggingInfo first as it is a RAII structure re-initializing spdlog loggers. // It will be held by GeneralConfig and then itself by CoincenterInfo though. - const auto &logConfigJsonPart = static_cast(generalConfigData.at("log")); - loggingInfo = LoggingInfo(LoggingInfo::WithLoggersCreation::kYes, dataDir, logConfigJsonPart); - - RequestsConfig requestsConfig( - generalConfigData.at("requests").at("concurrency").at("nbMaxParallelRequests").get()); - - const auto &automationJsonPart = generalConfigData.at("trading").at("automation"); - const auto &deserializationJsonPart = automationJsonPart.at("deserialization"); - const auto &startingContextJsonPart = automationJsonPart.at("startingContext"); - - Duration loadChunkDuration = ParseDuration(deserializationJsonPart.at("loadChunkDuration").get()); - MonetaryAmount startBaseAmountEquivalent{ - startingContextJsonPart.at("startBaseAmountEquivalent").get()}; - MonetaryAmount startQuoteAmountEquivalent{ - startingContextJsonPart.at("startQuoteAmountEquivalent").get()}; - - AutomationConfig automationConfig(loadChunkDuration, startBaseAmountEquivalent, startQuoteAmountEquivalent); - TradingConfig tradingConfig(std::move(automationConfig)); - - GeneralConfig generalConfig(std::move(loggingInfo), std::move(requestsConfig), std::move(tradingConfig), - fiatConversionQueryRate, apiOutputType); + loggingInfo = LoggingInfo(LoggingInfo::WithLoggersCreation::kYes, dataDir, generalConfig.log); const LoadConfiguration loadConfiguration(dataDir, LoadConfiguration::ExchangeConfigFileType::kProd); @@ -97,7 +65,7 @@ CoincenterInfo CoincenterInfo_Create(std::string_view programName, const Coincen const File currencyPrefixesTranslatorFile(dataDir, File::Type::kStatic, "currency_prefix_translator.json", File::IfError::kThrow); - return CoincenterInfo(runMode, loadConfiguration, std::move(generalConfig), + return CoincenterInfo(runMode, loadConfiguration, std::move(generalConfig), std::move(loggingInfo), MonitoringInfo_Create(programName, cmdLineOptions), currencyAcronymsTranslatorFile, stableCoinsFile, currencyPrefixesTranslatorFile); } diff --git a/src/engine/src/coincenteroptions.cpp b/src/engine/src/coincenteroptions.cpp index 6acc64fa..3d3c6cd7 100644 --- a/src/engine/src/coincenteroptions.cpp +++ b/src/engine/src/coincenteroptions.cpp @@ -168,17 +168,17 @@ std::pair CoincenterCmdLineOptions::get throw invalid_argument("Trade price and trade strategy cannot be set together"); } if (!buy.empty()) { - return {buy, CoincenterCommandType::kBuy}; + return {buy, CoincenterCommandType::Buy}; } if (!sell.empty()) { - return {sell, CoincenterCommandType::kSell}; + return {sell, CoincenterCommandType::Sell}; } if (!sellAll.empty()) { - return {sellAll, CoincenterCommandType::kSell}; + return {sellAll, CoincenterCommandType::Sell}; } if (!tradeAll.empty()) { - return {tradeAll, CoincenterCommandType::kTrade}; + return {tradeAll, CoincenterCommandType::Trade}; } - return {trade, CoincenterCommandType::kTrade}; + return {trade, CoincenterCommandType::Trade}; } } // namespace cct diff --git a/src/engine/src/exchangesorchestrator.cpp b/src/engine/src/exchangesorchestrator.cpp index f767090c..ffd174c7 100644 --- a/src/engine/src/exchangesorchestrator.cpp +++ b/src/engine/src/exchangesorchestrator.cpp @@ -41,7 +41,7 @@ #include "ordersconstraints.hpp" #include "queryresulttypes.hpp" #include "replay-options.hpp" -#include "requestsconfig.hpp" +#include "requests-config.hpp" #include "threadpool.hpp" #include "time-window.hpp" #include "trade-range-stats.hpp" @@ -122,9 +122,10 @@ ExchangeRetriever::PublicExchangesVec SelectUniquePublicExchanges(ExchangeRetrie } // namespace -ExchangesOrchestrator::ExchangesOrchestrator(const RequestsConfig &requestsConfig, std::span exchangesSpan) +ExchangesOrchestrator::ExchangesOrchestrator(const schema::RequestsConfig &requestsConfig, + std::span exchangesSpan) : _exchangeRetriever(exchangesSpan), - _threadPool(requestsConfig.nbMaxParallelRequests(static_cast(exchangesSpan.size()))) { + _threadPool(std::min(requestsConfig.concurrency.nbMaxParallelRequests, static_cast(exchangesSpan.size()))) { log::debug("Created a thread pool with {} workers for exchange requests", _threadPool.nbWorkers()); } diff --git a/src/engine/src/queryresultprinter.cpp b/src/engine/src/queryresultprinter.cpp index 3daea981..bfd11cf5 100644 --- a/src/engine/src/queryresultprinter.cpp +++ b/src/engine/src/queryresultprinter.cpp @@ -13,7 +13,7 @@ #include "apioutputtype.hpp" #include "balanceperexchangeportfolio.hpp" #include "cct_const.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "closed-order.hpp" @@ -59,10 +59,10 @@ namespace cct { namespace { -json ToJson(CoincenterCommandType commandType, json &&in, json &&out) { +json::container ToJson(CoincenterCommandType commandType, json::container &&in, json::container &&out) { in.emplace("req", CoincenterCommandTypeToString(commandType)); - json ret; + json::container ret; ret.emplace("in", std::move(in)); ret.emplace("out", std::move(out)); @@ -70,26 +70,26 @@ json ToJson(CoincenterCommandType commandType, json &&in, json &&out) { return ret; } -json HealthCheckJson(const ExchangeHealthCheckStatus &healthCheckPerExchange) { - json in; - json out = json::object(); +json::container HealthCheckJson(const ExchangeHealthCheckStatus &healthCheckPerExchange) { + json::container in; + json::container out = json::container::object(); for (const auto &[e, healthCheckValue] : healthCheckPerExchange) { out.emplace(e->name(), healthCheckValue); } - return ToJson(CoincenterCommandType::kHealthCheck, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::HealthCheck, std::move(in), std::move(out)); } -json CurrenciesJson(const CurrenciesPerExchange ¤ciesPerExchange) { - json in; - json inOpt; +json::container CurrenciesJson(const CurrenciesPerExchange ¤ciesPerExchange) { + json::container in; + json::container inOpt; in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, currencies] : currenciesPerExchange) { - json currenciesForExchange; + json::container currenciesForExchange; for (const CurrencyExchange &cur : currencies) { - json curExchangeJson; + json::container curExchangeJson; curExchangeJson.emplace("code", cur.standardCode().str()); curExchangeJson.emplace("exchangeCode", cur.exchangeCode().str()); @@ -105,12 +105,12 @@ json CurrenciesJson(const CurrenciesPerExchange ¤ciesPerExchange) { out.emplace(e->name(), std::move(currenciesForExchange)); } - return ToJson(CoincenterCommandType::kCurrencies, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::Currencies, std::move(in), std::move(out)); } -json MarketsJson(CurrencyCode cur1, CurrencyCode cur2, const MarketsPerExchange &marketsPerExchange) { - json in; - json inOpt = json::object(); +json::container MarketsJson(CurrencyCode cur1, CurrencyCode cur2, const MarketsPerExchange &marketsPerExchange) { + json::container in; + json::container inOpt = json::container::object(); if (!cur1.isNeutral()) { inOpt.emplace("cur1", cur1.str()); } @@ -119,31 +119,32 @@ json MarketsJson(CurrencyCode cur1, CurrencyCode cur2, const MarketsPerExchange } in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, markets] : marketsPerExchange) { - json marketsForExchange; + json::container marketsForExchange; for (const Market &mk : markets) { marketsForExchange.emplace_back(mk.str()); } out.emplace(e->name(), std::move(marketsForExchange)); } - return ToJson(CoincenterCommandType::kMarkets, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::Markets, std::move(in), std::move(out)); } -json MarketsForReplayJson(TimeWindow timeWindow, const MarketTimestampSetsPerExchange &marketTimestampSetsPerExchange) { - json in; - json inOpt = json::object(); +json::container MarketsForReplayJson(TimeWindow timeWindow, + const MarketTimestampSetsPerExchange &marketTimestampSetsPerExchange) { + json::container in; + json::container inOpt = json::container::object(); if (timeWindow != TimeWindow{}) { inOpt.emplace("timeWindow", timeWindow.str()); } in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, marketTimestampSets] : marketTimestampSetsPerExchange) { - json orderBookMarketsPerExchange; + json::container orderBookMarketsPerExchange; for (const MarketTimestamp &marketTimestamp : marketTimestampSets.orderBooksMarkets) { - json marketTimestampJson; + json::container marketTimestampJson; marketTimestampJson.emplace("market", marketTimestamp.market.str()); marketTimestampJson.emplace("lastTimestamp", TimeToString(marketTimestamp.timePoint)); @@ -151,9 +152,9 @@ json MarketsForReplayJson(TimeWindow timeWindow, const MarketTimestampSetsPerExc orderBookMarketsPerExchange.emplace_back(std::move(marketTimestampJson)); } - json tradesMarketsPerExchange; + json::container tradesMarketsPerExchange; for (const MarketTimestamp &marketTimestamp : marketTimestampSets.tradesMarkets) { - json marketTimestampJson; + json::container marketTimestampJson; marketTimestampJson.emplace("market", marketTimestamp.market.str()); marketTimestampJson.emplace("lastTimestamp", TimeToString(marketTimestamp.timePoint)); @@ -161,7 +162,7 @@ json MarketsForReplayJson(TimeWindow timeWindow, const MarketTimestampSetsPerExc tradesMarketsPerExchange.emplace_back(std::move(marketTimestampJson)); } - json exchangePart; + json::container exchangePart; exchangePart.emplace("orderBooks", std::move(orderBookMarketsPerExchange)); exchangePart.emplace("trades", std::move(tradesMarketsPerExchange)); @@ -169,19 +170,19 @@ json MarketsForReplayJson(TimeWindow timeWindow, const MarketTimestampSetsPerExc out.emplace(e->name(), std::move(exchangePart)); } - return ToJson(CoincenterCommandType::kReplayMarkets, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::ReplayMarkets, std::move(in), std::move(out)); } -json TickerInformationJson(const ExchangeTickerMaps &exchangeTickerMaps) { - json in; - json out = json::object(); +json::container TickerInformationJson(const ExchangeTickerMaps &exchangeTickerMaps) { + json::container in; + json::container out = json::container::object(); for (const auto &[e, marketOrderBookMap] : exchangeTickerMaps) { - json allTickerForExchange; + json::container allTickerForExchange; for (const auto &[mk, marketOrderBook] : marketOrderBookMap) { - json tickerForExchange; + json::container tickerForExchange; tickerForExchange.emplace("pair", mk.str()); - json ask; - json bid; + json::container ask; + json::container bid; ask.emplace("a", marketOrderBook.amountAtAskPrice().amountStr()); ask.emplace("p", marketOrderBook.lowestAskPrice().amountStr()); bid.emplace("a", marketOrderBook.amountAtBidPrice().amountStr()); @@ -191,19 +192,20 @@ json TickerInformationJson(const ExchangeTickerMaps &exchangeTickerMaps) { allTickerForExchange.emplace_back(tickerForExchange); } // Sort rows by market pair for consistent output - std::sort(allTickerForExchange.begin(), allTickerForExchange.end(), [](const json &lhs, const json &rhs) { - return lhs["pair"].get() < rhs["pair"].get(); - }); + std::sort(allTickerForExchange.begin(), allTickerForExchange.end(), + [](const json::container &lhs, const json::container &rhs) { + return lhs["pair"].get() < rhs["pair"].get(); + }); out.emplace(e->name(), std::move(allTickerForExchange)); } - return ToJson(CoincenterCommandType::kTicker, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::Ticker, std::move(in), std::move(out)); } void AppendOrderbookLine(const MarketOrderBook &marketOrderBook, int pos, - std::optional optConversionRate, json &data) { + std::optional optConversionRate, json::container &data) { auto [amount, price] = marketOrderBook[pos]; - json &line = data.emplace_back(); + json::container &line = data.emplace_back(); line.emplace("a", amount.amountStr()); line.emplace("p", price.amountStr()); if (optConversionRate) { @@ -211,10 +213,10 @@ void AppendOrderbookLine(const MarketOrderBook &marketOrderBook, int pos, } } -json MarketOrderBooksJson(Market mk, CurrencyCode equiCurrencyCode, std::optional depth, - const MarketOrderBookConversionRates &marketOrderBooksConversionRates) { - json in; - json inOpt; +json::container MarketOrderBooksJson(Market mk, CurrencyCode equiCurrencyCode, std::optional depth, + const MarketOrderBookConversionRates &marketOrderBooksConversionRates) { + json::container in; + json::container inOpt; inOpt.emplace("pair", mk.str()); if (!equiCurrencyCode.isNeutral()) { inOpt.emplace("equiCurrency", equiCurrencyCode.str()); @@ -224,11 +226,11 @@ json MarketOrderBooksJson(Market mk, CurrencyCode equiCurrencyCode, std::optiona } in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangeName, marketOrderBook, optConversionRate] : marketOrderBooksConversionRates) { - json marketOrderBookForExchange; - json bidsForExchange; - json asksForExchange; + json::container marketOrderBookForExchange; + json::container bidsForExchange; + json::container asksForExchange; marketOrderBookForExchange.emplace("time", TimeToString(marketOrderBook.time())); for (int bidPos = 1; bidPos <= marketOrderBook.nbBidPrices(); ++bidPos) { @@ -242,12 +244,12 @@ json MarketOrderBooksJson(Market mk, CurrencyCode equiCurrencyCode, std::optiona out.emplace(exchangeName, std::move(marketOrderBookForExchange)); } - return ToJson(CoincenterCommandType::kOrderbook, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::Orderbook, std::move(in), std::move(out)); } -json BalanceJson(const BalancePerExchange &balancePerExchange, CurrencyCode equiCurrency) { - json in; - json inOpt = json::object(); +json::container BalanceJson(const BalancePerExchange &balancePerExchange, CurrencyCode equiCurrency) { + json::container in; + json::container inOpt = json::container::object(); if (!equiCurrency.isNeutral()) { inOpt.emplace("equiCurrency", equiCurrency.str()); } @@ -255,18 +257,18 @@ json BalanceJson(const BalancePerExchange &balancePerExchange, CurrencyCode equi BalancePerExchangePortfolio totalBalance(balancePerExchange); - return ToJson(CoincenterCommandType::kBalance, std::move(in), totalBalance.printJson(equiCurrency)); + return ToJson(CoincenterCommandType::Balance, std::move(in), totalBalance.printJson(equiCurrency)); } -json DepositInfoJson(CurrencyCode depositCurrencyCode, const WalletPerExchange &walletPerExchange) { - json in; - json inOpt; +json::container DepositInfoJson(CurrencyCode depositCurrencyCode, const WalletPerExchange &walletPerExchange) { + json::container in; + json::container inOpt; inOpt.emplace("cur", depositCurrencyCode.str()); in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangePtr, wallet] : walletPerExchange) { - json depositPerExchangeData; + json::container depositPerExchangeData; depositPerExchangeData.emplace("address", wallet.address()); if (wallet.hasTag()) { @@ -275,20 +277,20 @@ json DepositInfoJson(CurrencyCode depositCurrencyCode, const WalletPerExchange & auto it = out.find(exchangePtr->name()); if (it == out.end()) { - json depositInfoForExchangeUser; + json::container depositInfoForExchangeUser; depositInfoForExchangeUser.emplace(exchangePtr->keyName(), std::move(depositPerExchangeData)); out.emplace(exchangePtr->name(), std::move(depositInfoForExchangeUser)); } else { it->emplace(exchangePtr->keyName(), std::move(depositPerExchangeData)); } } - return ToJson(CoincenterCommandType::kDepositInfo, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::DepositInfo, std::move(in), std::move(out)); } inline const char *TradeModeToStr(TradeMode tradeMode) { return tradeMode == TradeMode::kReal ? "real" : "simulation"; } -json TradeOptionsToJson(const TradeOptions &tradeOptions) { - json priceOptionsJson; +json::container TradeOptionsToJson(const TradeOptions &tradeOptions) { + json::container priceOptionsJson; const PriceOptions &priceOptions = tradeOptions.priceOptions(); priceOptionsJson.emplace("strategy", PriceStrategyStr(priceOptions.priceStrategy(), false)); if (priceOptions.isFixedPrice()) { @@ -297,7 +299,7 @@ json TradeOptionsToJson(const TradeOptions &tradeOptions) { if (priceOptions.isRelativePrice()) { priceOptionsJson.emplace("relativePrice", priceOptions.relativePrice()); } - json ret; + json::container ret; ret.emplace("price", std::move(priceOptionsJson)); ret.emplace("maxTradeTime", DurationToString(tradeOptions.maxTradeTime())); ret.emplace("minTimeBetweenPriceUpdates", DurationToString(tradeOptions.minTimeBetweenPriceUpdates())); @@ -307,24 +309,25 @@ json TradeOptionsToJson(const TradeOptions &tradeOptions) { return ret; } -json TradesJson(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAmount amount, bool isPercentageTrade, - CurrencyCode toCurrency, const TradeOptions &tradeOptions, CoincenterCommandType commandType) { - json in; - json fromJson; +json::container TradesJson(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAmount amount, + bool isPercentageTrade, CurrencyCode toCurrency, const TradeOptions &tradeOptions, + CoincenterCommandType commandType) { + json::container in; + json::container fromJson; fromJson.emplace("amount", amount.amountStr()); fromJson.emplace("currency", amount.currencyStr()); fromJson.emplace("isPercentage", isPercentageTrade); - json inOpt; + json::container inOpt; switch (commandType) { - case CoincenterCommandType::kBuy: + case CoincenterCommandType::Buy: inOpt.emplace("to", std::move(fromJson)); break; - case CoincenterCommandType::kSell: + case CoincenterCommandType::Sell: inOpt.emplace("from", std::move(fromJson)); break; - case CoincenterCommandType::kTrade: { - json toJson; + case CoincenterCommandType::Trade: { + json::container toJson; toJson.emplace("currency", toCurrency.str()); inOpt.emplace("from", std::move(fromJson)); @@ -338,9 +341,9 @@ json TradesJson(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAm inOpt.emplace("options", TradeOptionsToJson(tradeOptions)); in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangePtr, tradeResult] : tradeResultPerExchange) { - json tradedAmountPerExchangeJson; + json::container tradedAmountPerExchangeJson; tradedAmountPerExchangeJson.emplace("from", tradeResult.from().amountStr()); tradedAmountPerExchangeJson.emplace("status", tradeResult.stateStr()); tradedAmountPerExchangeJson.emplace("tradedFrom", tradeResult.tradedAmounts().from.amountStr()); @@ -348,7 +351,7 @@ json TradesJson(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAm auto it = out.find(exchangePtr->name()); if (it == out.end()) { - json tradedAmountPerExchangeUser; + json::container tradedAmountPerExchangeUser; tradedAmountPerExchangeUser.emplace(exchangePtr->keyName(), std::move(tradedAmountPerExchangeJson)); out.emplace(exchangePtr->name(), std::move(tradedAmountPerExchangeUser)); } else { @@ -359,8 +362,8 @@ json TradesJson(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAm return ToJson(commandType, std::move(in), std::move(out)); } -json OrdersConstraintsToJson(const OrdersConstraints &ordersConstraints) { - json ret; +json::container OrdersConstraintsToJson(const OrdersConstraints &ordersConstraints) { + json::container ret; if (ordersConstraints.isCurDefined()) { ret.emplace("cur1", ordersConstraints.curStr1()); } @@ -374,7 +377,7 @@ json OrdersConstraintsToJson(const OrdersConstraints &ordersConstraints) { ret.emplace("placedAfter", TimeToString(ordersConstraints.placedAfter())); } if (ordersConstraints.isOrderIdDefined()) { - json orderIds = json::array(); + json::container orderIds = json::container::array(); for (const OrderId &orderId : ordersConstraints.orderIdSet()) { orderIds.emplace_back(orderId); } @@ -384,10 +387,10 @@ json OrdersConstraintsToJson(const OrdersConstraints &ordersConstraints) { } template -json OrderJson(const OrderType &orderData) { +json::container OrderJson(const OrderType &orderData) { static_assert(std::is_same_v || std::is_same_v); - json order; + json::container order; order.emplace("id", orderData.id()); order.emplace("pair", orderData.market().str()); order.emplace("placedTime", orderData.placedTimeStr()); @@ -404,25 +407,25 @@ json OrderJson(const OrderType &orderData) { } template -json OrdersJson(CoincenterCommandType coincenterCommandType, const OrdersPerExchangeType &ordersPerExchange, - const OrdersConstraints &ordersConstraints) { - json in; - json inOpt = OrdersConstraintsToJson(ordersConstraints); +json::container OrdersJson(CoincenterCommandType coincenterCommandType, const OrdersPerExchangeType &ordersPerExchange, + const OrdersConstraints &ordersConstraints) { + json::container in; + json::container inOpt = OrdersConstraintsToJson(ordersConstraints); if (!inOpt.empty()) { in.emplace("opt", std::move(inOpt)); } - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangePtr, ordersData] : ordersPerExchange) { - json orders = json::array(); + json::container orders = json::container::array(); for (const auto &orderData : ordersData) { orders.emplace_back(OrderJson(orderData)); } auto it = out.find(exchangePtr->name()); if (it == out.end()) { - json ordersPerExchangeUser; + json::container ordersPerExchangeUser; ordersPerExchangeUser.emplace(exchangePtr->keyName(), std::move(orders)); out.emplace(exchangePtr->name(), std::move(ordersPerExchangeUser)); } else { @@ -433,23 +436,23 @@ json OrdersJson(CoincenterCommandType coincenterCommandType, const OrdersPerExch return ToJson(coincenterCommandType, std::move(in), std::move(out)); } -json OrdersCancelledJson(const NbCancelledOrdersPerExchange &nbCancelledOrdersPerExchange, - const OrdersConstraints &ordersConstraints) { - json in; - json inOpt = OrdersConstraintsToJson(ordersConstraints); +json::container OrdersCancelledJson(const NbCancelledOrdersPerExchange &nbCancelledOrdersPerExchange, + const OrdersConstraints &ordersConstraints) { + json::container in; + json::container inOpt = OrdersConstraintsToJson(ordersConstraints); if (!inOpt.empty()) { in.emplace("opt", std::move(inOpt)); } - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangePtr, nbCancelledOrders] : nbCancelledOrdersPerExchange) { - json cancelledOrdersForAccount; + json::container cancelledOrdersForAccount; cancelledOrdersForAccount.emplace("nb", nbCancelledOrders); auto it = out.find(exchangePtr->name()); if (it == out.end()) { - json cancelledOrdersForExchangeUser; + json::container cancelledOrdersForExchangeUser; cancelledOrdersForExchangeUser.emplace(exchangePtr->keyName(), std::move(cancelledOrdersForAccount)); out.emplace(exchangePtr->name(), std::move(cancelledOrdersForExchangeUser)); } else { @@ -457,14 +460,14 @@ json OrdersCancelledJson(const NbCancelledOrdersPerExchange &nbCancelledOrdersPe } } - return ToJson(CoincenterCommandType::kOrdersCancel, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::OrdersCancel, std::move(in), std::move(out)); } enum class DepositOrWithdrawEnum : int8_t { kDeposit, kWithdraw }; -json DepositsConstraintsToJson(const WithdrawsOrDepositsConstraints &constraints, - DepositOrWithdrawEnum depositOrWithdraw) { - json ret; +json::container DepositsConstraintsToJson(const WithdrawsOrDepositsConstraints &constraints, + DepositOrWithdrawEnum depositOrWithdraw) { + json::container ret; if (constraints.isCurDefined()) { ret.emplace("cur", constraints.currencyCode().str()); } @@ -477,7 +480,7 @@ json DepositsConstraintsToJson(const WithdrawsOrDepositsConstraints &constraints TimeToString(constraints.timeAfter())); } if (constraints.isIdDefined()) { - json depositIds = json::array(); + json::container depositIds = json::container::array(); for (const string &depositId : constraints.idSet()) { depositIds.emplace_back(depositId); } @@ -486,20 +489,20 @@ json DepositsConstraintsToJson(const WithdrawsOrDepositsConstraints &constraints return ret; } -json RecentDepositsJson(const DepositsPerExchange &depositsPerExchange, - const DepositsConstraints &depositsConstraints) { - json in; - json inOpt = DepositsConstraintsToJson(depositsConstraints, DepositOrWithdrawEnum::kDeposit); +json::container RecentDepositsJson(const DepositsPerExchange &depositsPerExchange, + const DepositsConstraints &depositsConstraints) { + json::container in; + json::container inOpt = DepositsConstraintsToJson(depositsConstraints, DepositOrWithdrawEnum::kDeposit); if (!inOpt.empty()) { in.emplace("opt", std::move(inOpt)); } - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangePtr, deposits] : depositsPerExchange) { - json depositsJson = json::array(); + json::container depositsJson = json::container::array(); for (const Deposit &deposit : deposits) { - json &depositJson = depositsJson.emplace_back(); + json::container &depositJson = depositsJson.emplace_back(); depositJson.emplace("id", deposit.id()); depositJson.emplace("cur", deposit.amount().currencyStr()); depositJson.emplace("receivedTime", deposit.timeStr()); @@ -509,7 +512,7 @@ json RecentDepositsJson(const DepositsPerExchange &depositsPerExchange, auto it = out.find(exchangePtr->name()); if (it == out.end()) { - json depositsPerExchangeUser; + json::container depositsPerExchangeUser; depositsPerExchangeUser.emplace(exchangePtr->keyName(), std::move(depositsJson)); out.emplace(exchangePtr->name(), std::move(depositsPerExchangeUser)); } else { @@ -517,23 +520,23 @@ json RecentDepositsJson(const DepositsPerExchange &depositsPerExchange, } } - return ToJson(CoincenterCommandType::kRecentDeposits, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::RecentDeposits, std::move(in), std::move(out)); } -json RecentWithdrawsJson(const WithdrawsPerExchange &withdrawsPerExchange, - const WithdrawsConstraints &withdrawsConstraints) { - json in; - json inOpt = DepositsConstraintsToJson(withdrawsConstraints, DepositOrWithdrawEnum::kWithdraw); +json::container RecentWithdrawsJson(const WithdrawsPerExchange &withdrawsPerExchange, + const WithdrawsConstraints &withdrawsConstraints) { + json::container in; + json::container inOpt = DepositsConstraintsToJson(withdrawsConstraints, DepositOrWithdrawEnum::kWithdraw); if (!inOpt.empty()) { in.emplace("opt", std::move(inOpt)); } - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangePtr, withdraws] : withdrawsPerExchange) { - json withdrawsJson = json::array(); + json::container withdrawsJson = json::container::array(); for (const Withdraw &withdraw : withdraws) { - json &withdrawJson = withdrawsJson.emplace_back(); + json::container &withdrawJson = withdrawsJson.emplace_back(); withdrawJson.emplace("id", withdraw.id()); withdrawJson.emplace("cur", withdraw.amount().currencyStr()); withdrawJson.emplace("sentTime", withdraw.timeStr()); @@ -544,7 +547,7 @@ json RecentWithdrawsJson(const WithdrawsPerExchange &withdrawsPerExchange, auto it = out.find(exchangePtr->name()); if (it == out.end()) { - json withdrawsPerExchangeUser; + json::container withdrawsPerExchangeUser; withdrawsPerExchangeUser.emplace(exchangePtr->keyName(), std::move(withdrawsJson)); out.emplace(exchangePtr->name(), std::move(withdrawsPerExchangeUser)); } else { @@ -552,35 +555,36 @@ json RecentWithdrawsJson(const WithdrawsPerExchange &withdrawsPerExchange, } } - return ToJson(CoincenterCommandType::kRecentWithdraws, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::RecentWithdraws, std::move(in), std::move(out)); } -json ConversionJson(MonetaryAmount amount, CurrencyCode targetCurrencyCode, - const MonetaryAmountPerExchange &conversionPerExchange) { - json in; - json inOpt; +json::container ConversionJson(MonetaryAmount amount, CurrencyCode targetCurrencyCode, + const MonetaryAmountPerExchange &conversionPerExchange) { + json::container in; + json::container inOpt; inOpt.emplace("amount", amount.str()); inOpt.emplace("targetCurrency", targetCurrencyCode.str()); in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, convertedAmount] : conversionPerExchange) { if (convertedAmount != 0) { - json conversionForExchange; + json::container conversionForExchange; conversionForExchange.emplace("convertedAmount", convertedAmount.str()); out.emplace(e->name(), std::move(conversionForExchange)); } } - return ToJson(CoincenterCommandType::kConversion, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::Conversion, std::move(in), std::move(out)); } -json ConversionJson(std::span startAmountPerExchangePos, CurrencyCode targetCurrencyCode, - const MonetaryAmountPerExchange &conversionPerExchange) { - json in; - json inOpt; +json::container ConversionJson(std::span startAmountPerExchangePos, + CurrencyCode targetCurrencyCode, + const MonetaryAmountPerExchange &conversionPerExchange) { + json::container in; + json::container inOpt; - json fromAmounts; + json::container fromAmounts; int publicExchangePos{}; for (MonetaryAmount startAmount : startAmountPerExchangePos) { @@ -594,28 +598,28 @@ json ConversionJson(std::span startAmountPerExchangePos, C inOpt.emplace("targetCurrency", targetCurrencyCode.str()); in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, convertedAmount] : conversionPerExchange) { if (convertedAmount != 0) { - json conversionForExchange; + json::container conversionForExchange; conversionForExchange.emplace("convertedAmount", convertedAmount.str()); out.emplace(e->name(), std::move(conversionForExchange)); } } - return ToJson(CoincenterCommandType::kConversion, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::Conversion, std::move(in), std::move(out)); } -json ConversionPathJson(Market mk, const ConversionPathPerExchange &conversionPathsPerExchange) { - json in; - json inOpt; +json::container ConversionPathJson(Market mk, const ConversionPathPerExchange &conversionPathsPerExchange) { + json::container in; + json::container inOpt; inOpt.emplace("market", mk.str()); in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, conversionPath] : conversionPathsPerExchange) { if (!conversionPath.empty()) { - json conversionPathForExchange; + json::container conversionPathForExchange; for (Market market : conversionPath) { conversionPathForExchange.emplace_back(market.str()); } @@ -623,57 +627,59 @@ json ConversionPathJson(Market mk, const ConversionPathPerExchange &conversionPa } } - return ToJson(CoincenterCommandType::kConversionPath, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::ConversionPath, std::move(in), std::move(out)); } -json WithdrawFeesJson(const MonetaryAmountByCurrencySetPerExchange &withdrawFeePerExchange, CurrencyCode cur) { - json in; - json inOpt = json::object(); +json::container WithdrawFeesJson(const MonetaryAmountByCurrencySetPerExchange &withdrawFeePerExchange, + CurrencyCode cur) { + json::container in; + json::container inOpt = json::container::object(); if (!cur.isNeutral()) { inOpt.emplace("cur", cur.str()); } in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, withdrawFees] : withdrawFeePerExchange) { - json amountsPerExchange = json::array(); + json::container amountsPerExchange = json::container::array(); for (MonetaryAmount ma : withdrawFees) { amountsPerExchange.emplace_back(ma.str()); } out.emplace(e->name(), std::move(amountsPerExchange)); } - return ToJson(CoincenterCommandType::kWithdrawFees, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::WithdrawFees, std::move(in), std::move(out)); } -json Last24hTradedVolumeJson(Market mk, const MonetaryAmountPerExchange &tradedVolumePerExchange) { - json in; - json inOpt; +json::container Last24hTradedVolumeJson(Market mk, const MonetaryAmountPerExchange &tradedVolumePerExchange) { + json::container in; + json::container inOpt; inOpt.emplace("market", mk.str()); in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, tradedVolume] : tradedVolumePerExchange) { out.emplace(e->name(), tradedVolume.amountStr()); } - return ToJson(CoincenterCommandType::kLast24hTradedVolume, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::Last24hTradedVolume, std::move(in), std::move(out)); } -json LastTradesJson(Market mk, std::optional nbLastTrades, const TradesPerExchange &lastTradesPerExchange) { - json in; - json inOpt; +json::container LastTradesJson(Market mk, std::optional nbLastTrades, + const TradesPerExchange &lastTradesPerExchange) { + json::container in; + json::container inOpt; inOpt.emplace("market", mk.str()); if (nbLastTrades) { inOpt.emplace("nb", *nbLastTrades); } in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangePtr, lastTrades] : lastTradesPerExchange) { - json lastTradesJson = json::array(); + json::container lastTradesJson = json::container::array(); for (const PublicTrade &trade : lastTrades) { - json &lastTrade = lastTradesJson.emplace_back(); + json::container &lastTrade = lastTradesJson.emplace_back(); lastTrade.emplace("a", trade.amount().amountStr()); lastTrade.emplace("p", trade.price().amountStr()); lastTrade.emplace("time", trade.timeStr()); @@ -682,41 +688,41 @@ json LastTradesJson(Market mk, std::optional nbLastTrades, const TradesPerE out.emplace(exchangePtr->name(), std::move(lastTradesJson)); } - return ToJson(CoincenterCommandType::kLastTrades, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::LastTrades, std::move(in), std::move(out)); } -json LastPriceJson(Market mk, const MonetaryAmountPerExchange &pricePerExchange) { - json in; - json inOpt; +json::container LastPriceJson(Market mk, const MonetaryAmountPerExchange &pricePerExchange) { + json::container in; + json::container inOpt; inOpt.emplace("market", mk.str()); in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[e, lastPrice] : pricePerExchange) { out.emplace(e->name(), lastPrice.amountStr()); } - return ToJson(CoincenterCommandType::kLastPrice, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::LastPrice, std::move(in), std::move(out)); } -json WithdrawJson(const DeliveredWithdrawInfo &deliveredWithdrawInfo, MonetaryAmount grossAmount, - bool isPercentageWithdraw, const Exchange &fromExchange, const Exchange &toExchange, - const WithdrawOptions &withdrawOptions) { - json in; - json inOpt; +json::container WithdrawJson(const DeliveredWithdrawInfo &deliveredWithdrawInfo, MonetaryAmount grossAmount, + bool isPercentageWithdraw, const Exchange &fromExchange, const Exchange &toExchange, + const WithdrawOptions &withdrawOptions) { + json::container in; + json::container inOpt; inOpt.emplace("cur", grossAmount.currencyStr()); inOpt.emplace("isPercentage", isPercentageWithdraw); inOpt.emplace("syncPolicy", withdrawOptions.withdrawSyncPolicyStr()); in.emplace("opt", std::move(inOpt)); - json from; + json::container from; from.emplace("exchange", fromExchange.name()); from.emplace("account", fromExchange.keyName()); from.emplace("id", deliveredWithdrawInfo.withdrawId()); from.emplace("amount", grossAmount.amountStr()); from.emplace("time", TimeToString(deliveredWithdrawInfo.initiatedTime())); - json to; + json::container to; to.emplace("exchange", toExchange.name()); to.emplace("account", toExchange.keyName()); to.emplace("id", deliveredWithdrawInfo.depositId()); @@ -727,37 +733,38 @@ json WithdrawJson(const DeliveredWithdrawInfo &deliveredWithdrawInfo, MonetaryAm } to.emplace("time", TimeToString(deliveredWithdrawInfo.receivedTime())); - json out; + json::container out; out.emplace("from", std::move(from)); out.emplace("to", std::move(to)); - return ToJson(CoincenterCommandType::kWithdrawApply, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::Withdraw, std::move(in), std::move(out)); } -json DustSweeperJson(const TradedAmountsVectorWithFinalAmountPerExchange &tradedAmountsVectorWithFinalAmountPerExchange, - CurrencyCode currencyCode) { - json in; - json inOpt; +json::container DustSweeperJson( + const TradedAmountsVectorWithFinalAmountPerExchange &tradedAmountsVectorWithFinalAmountPerExchange, + CurrencyCode currencyCode) { + json::container in; + json::container inOpt; inOpt.emplace("cur", currencyCode.str()); in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[exchangePtr, tradedAmountsVectorWithFinalAmount] : tradedAmountsVectorWithFinalAmountPerExchange) { - json tradedAmountsArray = json::array_t(); + json::container tradedAmountsArray = json::container::array_t(); for (const auto &tradedAmounts : tradedAmountsVectorWithFinalAmount.tradedAmountsVector) { - json tradedAmountsData; + json::container tradedAmountsData; tradedAmountsData.emplace("from", tradedAmounts.from.str()); tradedAmountsData.emplace("to", tradedAmounts.to.str()); tradedAmountsArray.push_back(std::move(tradedAmountsData)); } - json tradedInfoPerExchangeData; + json::container tradedInfoPerExchangeData; tradedInfoPerExchangeData.emplace("trades", std::move(tradedAmountsArray)); tradedInfoPerExchangeData.emplace("finalAmount", tradedAmountsVectorWithFinalAmount.finalAmount.str()); auto it = out.find(exchangePtr->name()); if (it == out.end()) { - json dataForExchangeUser; + json::container dataForExchangeUser; dataForExchangeUser.emplace(exchangePtr->keyName(), std::move(tradedInfoPerExchangeData)); out.emplace(exchangePtr->name(), std::move(dataForExchangeUser)); } else { @@ -765,38 +772,38 @@ json DustSweeperJson(const TradedAmountsVectorWithFinalAmountPerExchange &traded } } - return ToJson(CoincenterCommandType::kDustSweeper, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::DustSweeper, std::move(in), std::move(out)); } -json MarketTradingResultsJson(TimeWindow inputTimeWindow, const ReplayResults &replayResults, - CoincenterCommandType commandType) { - json inOpt; +json::container MarketTradingResultsJson(TimeWindow inputTimeWindow, const ReplayResults &replayResults, + CoincenterCommandType commandType) { + json::container inOpt; - json timeStats; + json::container timeStats; timeStats.emplace("from", TimeToString(inputTimeWindow.from())); timeStats.emplace("to", TimeToString(inputTimeWindow.to())); inOpt.emplace("time", std::move(timeStats)); - json in; + json::container in; in.emplace("opt", std::move(inOpt)); - json out = json::object(); + json::container out = json::container::object(); for (const auto &[algorithmName, marketTradingResultPerExchangeVector] : replayResults) { - json algorithmNameResults = json::array_t(); + json::container algorithmNameResults = json::container::array_t(); for (const auto &marketTradingResultPerExchange : marketTradingResultPerExchangeVector) { - json allResults = json::array_t(); + json::container allResults = json::container::array_t(); for (const auto &[exchangePtr, marketGlobalTradingResult] : marketTradingResultPerExchange) { const auto &marketTradingResult = marketGlobalTradingResult.result; const auto &stats = marketGlobalTradingResult.stats; const auto computeTradeRangeResultsStats = [](const TradeRangeResultsStats &tradeRangeResultsStats) { - json stats; + json::container stats; stats.emplace("nb-successful", tradeRangeResultsStats.nbSuccessful); stats.emplace("nb-error", tradeRangeResultsStats.nbError); - json timeStats; + json::container timeStats; timeStats.emplace("from", TimeToString(tradeRangeResultsStats.timeWindow.from())); timeStats.emplace("to", TimeToString(tradeRangeResultsStats.timeWindow.to())); @@ -804,26 +811,26 @@ json MarketTradingResultsJson(TimeWindow inputTimeWindow, const ReplayResults &r return stats; }; - json startAmounts; + json::container startAmounts; startAmounts.emplace("base", marketTradingResult.startBaseAmount().str()); startAmounts.emplace("quote", marketTradingResult.startQuoteAmount().str()); - json orderBookStats = computeTradeRangeResultsStats(stats.marketOrderBookStats); + json::container orderBookStats = computeTradeRangeResultsStats(stats.marketOrderBookStats); - json tradeStats = computeTradeRangeResultsStats(stats.publicTradeStats); + json::container tradeStats = computeTradeRangeResultsStats(stats.publicTradeStats); - json jsonStats; + json::container jsonStats; jsonStats.emplace("order-books", std::move(orderBookStats)); jsonStats.emplace("trades", std::move(tradeStats)); - json marketTradingResultJson; + json::container marketTradingResultJson; marketTradingResultJson.emplace("algorithm", marketTradingResult.algorithmName()); marketTradingResultJson.emplace("market", marketTradingResult.market().str()); marketTradingResultJson.emplace("start-amounts", std::move(startAmounts)); marketTradingResultJson.emplace("profit-and-loss", marketTradingResult.quoteAmountDelta().str()); marketTradingResultJson.emplace("stats", std::move(jsonStats)); - json closedOrdersArray = json::array_t(); + json::container closedOrdersArray = json::container::array_t(); for (const ClosedOrder &closedOrder : marketTradingResult.matchedOrders()) { closedOrdersArray.push_back(OrderJson(closedOrder)); @@ -831,7 +838,7 @@ json MarketTradingResultsJson(TimeWindow inputTimeWindow, const ReplayResults &r marketTradingResultJson.emplace("matched-orders", std::move(closedOrdersArray)); - json exchangeMarketResults; + json::container exchangeMarketResults; exchangeMarketResults.emplace(exchangePtr->name(), std::move(marketTradingResultJson)); allResults.push_back(std::move(exchangeMarketResults)); @@ -865,9 +872,9 @@ QueryResultPrinter::QueryResultPrinter(std::ostream &os, ApiOutputType apiOutput _apiOutputType(apiOutputType) {} void QueryResultPrinter::printHealthCheck(const ExchangeHealthCheckStatus &healthCheckPerExchange) const { - json jsonData = HealthCheckJson(healthCheckPerExchange); + json::container jsonData = HealthCheckJson(healthCheckPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.reserve(1U + healthCheckPerExchange.size()); table.emplace_back("Exchange", "Health Check status"); @@ -877,13 +884,13 @@ void QueryResultPrinter::printHealthCheck(const ExchangeHealthCheckStatus &healt printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kHealthCheck, jsonData); + logActivity(CoincenterCommandType::HealthCheck, jsonData); } namespace { @@ -906,9 +913,9 @@ void Append(string &str, std::string_view exchangeName) { } // namespace void QueryResultPrinter::printCurrencies(const CurrenciesPerExchange ¤ciesPerExchange) const { - json jsonData = CurrenciesJson(currenciesPerExchange); + json::container jsonData = CurrenciesJson(currenciesPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { // Compute all currencies for all exchanges CurrencyCodeVector allCurrencyCodes; @@ -967,21 +974,21 @@ void QueryResultPrinter::printCurrencies(const CurrenciesPerExchange ¤cies printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kCurrencies, jsonData); + logActivity(CoincenterCommandType::Currencies, jsonData); } void QueryResultPrinter::printMarkets(CurrencyCode cur1, CurrencyCode cur2, const MarketsPerExchange &marketsPerExchange, CoincenterCommandType coincenterCommandType) const { - json jsonData = MarketsJson(cur1, cur2, marketsPerExchange); + json::container jsonData = MarketsJson(cur1, cur2, marketsPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { string marketsCol("Markets"); if (!cur1.isNeutral()) { marketsCol.append(" with "); @@ -1001,19 +1008,19 @@ void QueryResultPrinter::printMarkets(CurrencyCode cur1, CurrencyCode cur2, printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } logActivity(coincenterCommandType, jsonData); } void QueryResultPrinter::printTickerInformation(const ExchangeTickerMaps &exchangeTickerMaps) const { - json jsonData = TickerInformationJson(exchangeTickerMaps); + json::container jsonData = TickerInformationJson(exchangeTickerMaps); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.emplace_back("Exchange", "Market", "Bid price", "Bid volume", "Ask price", "Ask volume"); for (const auto &[e, marketOrderBookMap] : exchangeTickerMaps) { @@ -1028,57 +1035,57 @@ void QueryResultPrinter::printTickerInformation(const ExchangeTickerMaps &exchan printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kTicker, jsonData); + logActivity(CoincenterCommandType::Ticker, jsonData); } void QueryResultPrinter::printMarketOrderBooks( Market mk, CurrencyCode equiCurrencyCode, std::optional depth, const MarketOrderBookConversionRates &marketOrderBooksConversionRates) const { - const json jsonData = MarketOrderBooksJson(mk, equiCurrencyCode, depth, marketOrderBooksConversionRates); + const json::container jsonData = MarketOrderBooksJson(mk, equiCurrencyCode, depth, marketOrderBooksConversionRates); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { for (const auto &[exchangeName, marketOrderBook, optConversionRate] : marketOrderBooksConversionRates) { printTable(marketOrderBook.getTable(exchangeName, optConversionRate)); } break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kOrderbook, jsonData); + logActivity(CoincenterCommandType::Orderbook, jsonData); } void QueryResultPrinter::printBalance(const BalancePerExchange &balancePerExchange, CurrencyCode equiCurrency) const { - json jsonData = BalanceJson(balancePerExchange, equiCurrency); + json::container jsonData = BalanceJson(balancePerExchange, equiCurrency); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { BalancePerExchangePortfolio totalBalance(balancePerExchange); printTable(totalBalance.getTable(balancePerExchange.size() > 1)); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kBalance, jsonData); + logActivity(CoincenterCommandType::Balance, jsonData); } void QueryResultPrinter::printDepositInfo(CurrencyCode depositCurrencyCode, const WalletPerExchange &walletPerExchange) const { - json jsonData = DepositInfoJson(depositCurrencyCode, walletPerExchange); + json::container jsonData = DepositInfoJson(depositCurrencyCode, walletPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { string walletStr(depositCurrencyCode.str()); walletStr.append(" address"); SimpleTable table; @@ -1090,21 +1097,22 @@ void QueryResultPrinter::printDepositInfo(CurrencyCode depositCurrencyCode, printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kDepositInfo, jsonData); + logActivity(CoincenterCommandType::DepositInfo, jsonData); } void QueryResultPrinter::printTrades(const TradeResultPerExchange &tradeResultPerExchange, MonetaryAmount amount, bool isPercentageTrade, CurrencyCode toCurrency, const TradeOptions &tradeOptions, CoincenterCommandType commandType) const { - json jsonData = TradesJson(tradeResultPerExchange, amount, isPercentageTrade, toCurrency, tradeOptions, commandType); + json::container jsonData = + TradesJson(tradeResultPerExchange, amount, isPercentageTrade, toCurrency, tradeOptions, commandType); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { string tradedFromStr("Traded from amount ("); tradedFromStr.append(TradeModeToStr(tradeOptions.tradeMode())); tradedFromStr.push_back(')'); @@ -1125,10 +1133,10 @@ void QueryResultPrinter::printTrades(const TradeResultPerExchange &tradeResultPe printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } logActivity(commandType, jsonData, tradeOptions.isSimulation()); @@ -1136,9 +1144,10 @@ void QueryResultPrinter::printTrades(const TradeResultPerExchange &tradeResultPe void QueryResultPrinter::printClosedOrders(const ClosedOrdersPerExchange &closedOrdersPerExchange, const OrdersConstraints &ordersConstraints) const { - json jsonData = OrdersJson(CoincenterCommandType::kOrdersClosed, closedOrdersPerExchange, ordersConstraints); + json::container jsonData = + OrdersJson(CoincenterCommandType::OrdersClosed, closedOrdersPerExchange, ordersConstraints); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.emplace_back("Exchange", "Account", "Exchange Id", "Placed time", "Matched time", "Side", "Price", "Matched Amount"); @@ -1152,20 +1161,21 @@ void QueryResultPrinter::printClosedOrders(const ClosedOrdersPerExchange &closed printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kOrdersClosed, jsonData); + logActivity(CoincenterCommandType::OrdersClosed, jsonData); } void QueryResultPrinter::printOpenedOrders(const OpenedOrdersPerExchange &openedOrdersPerExchange, const OrdersConstraints &ordersConstraints) const { - json jsonData = OrdersJson(CoincenterCommandType::kOrdersOpened, openedOrdersPerExchange, ordersConstraints); + json::container jsonData = + OrdersJson(CoincenterCommandType::OrdersOpened, openedOrdersPerExchange, ordersConstraints); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.emplace_back("Exchange", "Account", "Exchange Id", "Placed time", "Side", "Price", "Matched Amount", "Remaining Amount"); @@ -1179,20 +1189,20 @@ void QueryResultPrinter::printOpenedOrders(const OpenedOrdersPerExchange &opened printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kOrdersOpened, jsonData); + logActivity(CoincenterCommandType::OrdersOpened, jsonData); } void QueryResultPrinter::printCancelledOrders(const NbCancelledOrdersPerExchange &nbCancelledOrdersPerExchange, const OrdersConstraints &ordersConstraints) const { - json jsonData = OrdersCancelledJson(nbCancelledOrdersPerExchange, ordersConstraints); + json::container jsonData = OrdersCancelledJson(nbCancelledOrdersPerExchange, ordersConstraints); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.reserve(1U + nbCancelledOrdersPerExchange.size()); table.emplace_back("Exchange", "Account", "Number of cancelled orders"); @@ -1202,20 +1212,20 @@ void QueryResultPrinter::printCancelledOrders(const NbCancelledOrdersPerExchange printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kOrdersCancel, jsonData); + logActivity(CoincenterCommandType::OrdersCancel, jsonData); } void QueryResultPrinter::printRecentDeposits(const DepositsPerExchange &depositsPerExchange, const DepositsConstraints &depositsConstraints) const { - json jsonData = RecentDepositsJson(depositsPerExchange, depositsConstraints); + json::container jsonData = RecentDepositsJson(depositsPerExchange, depositsConstraints); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.emplace_back("Exchange", "Account", "Exchange Id", "Received time", "Amount", "Status"); for (const auto &[exchangePtr, deposits] : depositsPerExchange) { @@ -1227,20 +1237,20 @@ void QueryResultPrinter::printRecentDeposits(const DepositsPerExchange &deposits printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kRecentDeposits, jsonData); + logActivity(CoincenterCommandType::RecentDeposits, jsonData); } void QueryResultPrinter::printRecentWithdraws(const WithdrawsPerExchange &withdrawsPerExchange, const WithdrawsConstraints &withdrawsConstraints) const { - json jsonData = RecentWithdrawsJson(withdrawsPerExchange, withdrawsConstraints); + json::container jsonData = RecentWithdrawsJson(withdrawsPerExchange, withdrawsConstraints); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.emplace_back("Exchange", "Account", "Exchange Id", "Sent time", "Net Emitted Amount", "Fee", "Status"); for (const auto &[exchangePtr, withdraws] : withdrawsPerExchange) { @@ -1252,20 +1262,20 @@ void QueryResultPrinter::printRecentWithdraws(const WithdrawsPerExchange &withdr printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kRecentWithdraws, jsonData); + logActivity(CoincenterCommandType::RecentWithdraws, jsonData); } void QueryResultPrinter::printConversion(MonetaryAmount amount, CurrencyCode targetCurrencyCode, const MonetaryAmountPerExchange &conversionPerExchange) const { - json jsonData = ConversionJson(amount, targetCurrencyCode, conversionPerExchange); + json::container jsonData = ConversionJson(amount, targetCurrencyCode, conversionPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { string conversionStrHeader = amount.str(); conversionStrHeader.append(" converted into "); targetCurrencyCode.appendStrTo(conversionStrHeader); @@ -1281,21 +1291,21 @@ void QueryResultPrinter::printConversion(MonetaryAmount amount, CurrencyCode tar printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kConversion, jsonData); + logActivity(CoincenterCommandType::Conversion, jsonData); } void QueryResultPrinter::printConversion(std::span startAmountPerExchangePos, CurrencyCode targetCurrencyCode, const MonetaryAmountPerExchange &conversionPerExchange) const { - json jsonData = ConversionJson(startAmountPerExchangePos, targetCurrencyCode, conversionPerExchange); + json::container jsonData = ConversionJson(startAmountPerExchangePos, targetCurrencyCode, conversionPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.reserve(1U + conversionPerExchange.size()); table.emplace_back("Exchange", "From", "To"); @@ -1307,20 +1317,20 @@ void QueryResultPrinter::printConversion(std::span startAm printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kConversion, jsonData); + logActivity(CoincenterCommandType::Conversion, jsonData); } void QueryResultPrinter::printConversionPath(Market mk, const ConversionPathPerExchange &conversionPathsPerExchange) const { - json jsonData = ConversionPathJson(mk, conversionPathsPerExchange); + json::container jsonData = ConversionPathJson(mk, conversionPathsPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { string conversionPathStrHeader("Fastest conversion path for "); conversionPathStrHeader.append(mk.str()); SimpleTable table; @@ -1342,20 +1352,20 @@ void QueryResultPrinter::printConversionPath(Market mk, printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kConversionPath, jsonData); + logActivity(CoincenterCommandType::ConversionPath, jsonData); } void QueryResultPrinter::printWithdrawFees(const MonetaryAmountByCurrencySetPerExchange &withdrawFeesPerExchange, CurrencyCode currencyCode) const { - json jsonData = WithdrawFeesJson(withdrawFeesPerExchange, currencyCode); + json::container jsonData = WithdrawFeesJson(withdrawFeesPerExchange, currencyCode); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { table::Row header("Withdraw fee currency"); CurrencyCodeVector allCurrencyCodes; for (const auto &[e, withdrawFees] : withdrawFeesPerExchange) { @@ -1385,20 +1395,20 @@ void QueryResultPrinter::printWithdrawFees(const MonetaryAmountByCurrencySetPerE printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kWithdrawFees, jsonData); + logActivity(CoincenterCommandType::WithdrawFees, jsonData); } void QueryResultPrinter::printLast24hTradedVolume(Market mk, const MonetaryAmountPerExchange &tradedVolumePerExchange) const { - json jsonData = Last24hTradedVolumeJson(mk, tradedVolumePerExchange); + json::container jsonData = Last24hTradedVolumeJson(mk, tradedVolumePerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { string headerTradedVolume("Last 24h "); headerTradedVolume.append(mk.str()); headerTradedVolume.append(" traded volume"); @@ -1411,20 +1421,20 @@ void QueryResultPrinter::printLast24hTradedVolume(Market mk, printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kLast24hTradedVolume, jsonData); + logActivity(CoincenterCommandType::Last24hTradedVolume, jsonData); } void QueryResultPrinter::printLastTrades(Market mk, std::optional nbLastTrades, const TradesPerExchange &lastTradesPerExchange) const { - json jsonData = LastTradesJson(mk, nbLastTrades, lastTradesPerExchange); + json::container jsonData = LastTradesJson(mk, nbLastTrades, lastTradesPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { for (const auto &[exchangePtr, lastTrades] : lastTradesPerExchange) { string buyTitle = mk.base().str(); string sellTitle = buyTitle; @@ -1474,19 +1484,19 @@ void QueryResultPrinter::printLastTrades(Market mk, std::optional nbLastTra } break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kLastTrades, jsonData); + logActivity(CoincenterCommandType::LastTrades, jsonData); } void QueryResultPrinter::printLastPrice(Market mk, const MonetaryAmountPerExchange &pricePerExchange) const { - json jsonData = LastPriceJson(mk, pricePerExchange); + json::container jsonData = LastPriceJson(mk, pricePerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { string headerLastPrice(mk.str()); headerLastPrice.append(" last price"); SimpleTable table; @@ -1498,13 +1508,13 @@ void QueryResultPrinter::printLastPrice(Market mk, const MonetaryAmountPerExchan printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kLastPrice, jsonData); + logActivity(CoincenterCommandType::LastPrice, jsonData); } void QueryResultPrinter::printWithdraw(const DeliveredWithdrawInfoWithExchanges &deliveredWithdrawInfoWithExchanges, @@ -1513,10 +1523,10 @@ void QueryResultPrinter::printWithdraw(const DeliveredWithdrawInfoWithExchanges MonetaryAmount grossAmount = deliveredWithdrawInfo.grossAmount(); const Exchange &fromExchange = *deliveredWithdrawInfoWithExchanges.first.front(); const Exchange &toExchange = *deliveredWithdrawInfoWithExchanges.first.back(); - json jsonData = + json::container jsonData = WithdrawJson(deliveredWithdrawInfo, grossAmount, isPercentageWithdraw, fromExchange, toExchange, withdrawOptions); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.reserve(3U); @@ -1531,22 +1541,21 @@ void QueryResultPrinter::printWithdraw(const DeliveredWithdrawInfoWithExchanges printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kWithdrawApply, jsonData, - withdrawOptions.mode() == WithdrawOptions::Mode::kSimulation); + logActivity(CoincenterCommandType::Withdraw, jsonData, withdrawOptions.mode() == WithdrawOptions::Mode::kSimulation); } void QueryResultPrinter::printDustSweeper( const TradedAmountsVectorWithFinalAmountPerExchange &tradedAmountsVectorWithFinalAmountPerExchange, CurrencyCode currencyCode) const { - json jsonData = DustSweeperJson(tradedAmountsVectorWithFinalAmountPerExchange, currencyCode); + json::container jsonData = DustSweeperJson(tradedAmountsVectorWithFinalAmountPerExchange, currencyCode); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.reserve(1U + tradedAmountsVectorWithFinalAmountPerExchange.size()); @@ -1566,20 +1575,20 @@ void QueryResultPrinter::printDustSweeper( printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kDustSweeper, jsonData); + logActivity(CoincenterCommandType::DustSweeper, jsonData); } void QueryResultPrinter::printMarketsForReplay(TimeWindow timeWindow, const MarketTimestampSetsPerExchange &marketTimestampSetsPerExchange) { - json jsonData = MarketsForReplayJson(timeWindow, marketTimestampSetsPerExchange); + json::container jsonData = MarketsForReplayJson(timeWindow, marketTimestampSetsPerExchange); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { MarketSet allMarkets = ComputeAllMarkets(marketTimestampSetsPerExchange); SimpleTable table; @@ -1620,20 +1629,20 @@ void QueryResultPrinter::printMarketsForReplay(TimeWindow timeWindow, printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } - logActivity(CoincenterCommandType::kReplayMarkets, jsonData); + logActivity(CoincenterCommandType::ReplayMarkets, jsonData); } void QueryResultPrinter::printMarketTradingResults(TimeWindow inputTimeWindow, const ReplayResults &replayResults, CoincenterCommandType commandType) const { - json jsonData = MarketTradingResultsJson(inputTimeWindow, replayResults, commandType); + json::container jsonData = MarketTradingResultsJson(inputTimeWindow, replayResults, commandType); switch (_apiOutputType) { - case ApiOutputType::kFormattedTable: { + case ApiOutputType::table: { SimpleTable table; table.emplace_back("Algorithm", "Exchange", "Time window", "Market", "Start amounts", "Profit / Loss", "Matched orders", "Stats"); @@ -1688,10 +1697,10 @@ void QueryResultPrinter::printMarketTradingResults(TimeWindow inputTimeWindow, c printTable(table); break; } - case ApiOutputType::kJson: + case ApiOutputType::json: printJson(jsonData); break; - case ApiOutputType::kNoPrint: + case ApiOutputType::off: break; } logActivity(commandType, jsonData); @@ -1711,7 +1720,7 @@ void QueryResultPrinter::printTable(const SimpleTable &table) const { } } -void QueryResultPrinter::printJson(const json &jsonData) const { +void QueryResultPrinter::printJson(const json::container &jsonData) const { string jsonStr = jsonData.dump(); if (_pOs != nullptr) { *_pOs << jsonStr << '\n'; @@ -1720,12 +1729,12 @@ void QueryResultPrinter::printJson(const json &jsonData) const { } } -void QueryResultPrinter::logActivity(CoincenterCommandType commandType, const json &jsonData, +void QueryResultPrinter::logActivity(CoincenterCommandType commandType, const json::container &jsonData, bool isSimulationMode) const { if (_loggingInfo.isCommandTypeTracked(commandType) && (!isSimulationMode || _loggingInfo.alsoLogActivityForSimulatedCommands())) { File activityFile = _loggingInfo.getActivityFile(); - activityFile.write(jsonData, Writer::Mode::Append); + activityFile.writeJson(jsonData, Writer::Mode::Append); } } diff --git a/src/engine/src/transferablecommandresult.cpp b/src/engine/src/transferablecommandresult.cpp index 0c0851c6..b2aa9b82 100644 --- a/src/engine/src/transferablecommandresult.cpp +++ b/src/engine/src/transferablecommandresult.cpp @@ -15,10 +15,10 @@ namespace cct { namespace { struct AmountExchangeNames { + bool operator==(const AmountExchangeNames &) const noexcept = default; + MonetaryAmount amount; ExchangeNames exchangeNames; - - bool operator==(const AmountExchangeNames &) const noexcept = default; }; std::optional AccumulateAmount( diff --git a/src/engine/test/coincentercommandfactory_test.cpp b/src/engine/test/coincentercommandfactory_test.cpp index daa7028c..1f0b629e 100644 --- a/src/engine/test/coincentercommandfactory_test.cpp +++ b/src/engine/test/coincentercommandfactory_test.cpp @@ -32,7 +32,7 @@ class CoincenterCommandFactoryTest : public ::testing::Test { TEST_F(CoincenterCommandFactoryTest, CreateMarketCommandEmpty) { EXPECT_EQ(CoincenterCommandFactory::CreateMarketCommand(inputStr("")), - CoincenterCommand(CoincenterCommandType::kMarkets)); + CoincenterCommand(CoincenterCommandType::Markets)); EXPECT_NO_THROW(optionParser.checkEndParsing()); } @@ -47,42 +47,42 @@ TEST_F(CoincenterCommandFactoryTest, CreateMarketCommandInvalidWrongCurrencySepa } TEST_F(CoincenterCommandFactoryTest, CreateMarketCommandSingleExchange) { - EXPECT_EQ(CoincenterCommandFactory::CreateMarketCommand(inputStr("huobi_user2")), - CoincenterCommand(CoincenterCommandType::kMarkets) - .setExchangeNames(ExchangeNames({ExchangeName("huobi_user2")}))); + EXPECT_EQ( + CoincenterCommandFactory::CreateMarketCommand(inputStr("huobi_user2")), + CoincenterCommand(CoincenterCommandType::Markets).setExchangeNames(ExchangeNames({ExchangeName("huobi_user2")}))); EXPECT_NO_THROW(optionParser.checkEndParsing()); } TEST_F(CoincenterCommandFactoryTest, CreateMarketCommandMarketTest) { EXPECT_EQ(CoincenterCommandFactory::CreateMarketCommand(inputStr("eth-usdt")), - CoincenterCommand(CoincenterCommandType::kMarkets).setCur1("ETH").setCur2("USDT")); + CoincenterCommand(CoincenterCommandType::Markets).setCur1("ETH").setCur2("USDT")); EXPECT_NO_THROW(optionParser.checkEndParsing()); } TEST_F(CoincenterCommandFactoryTest, CreateMarketCommandSingleCurTest) { EXPECT_EQ(CoincenterCommandFactory::CreateMarketCommand(inputStr("XLM,kraken,binance_user1")), - CoincenterCommand(CoincenterCommandType::kMarkets) + CoincenterCommand(CoincenterCommandType::Markets) .setCur1("XLM") .setExchangeNames(ExchangeNames({ExchangeName("kraken"), ExchangeName("binance", "user1")}))); EXPECT_NO_THROW(optionParser.checkEndParsing()); } TEST_F(CoincenterCommandFactoryTest, CreateOrderCommandAll) { - CoincenterCommandType type = CoincenterCommandType::kOrdersOpened; + CoincenterCommandType type = CoincenterCommandType::OrdersOpened; EXPECT_EQ(commandFactory.createOrderCommand(type, inputStr("")), CoincenterCommand(type).setOrdersConstraints(OrdersConstraints{})); EXPECT_NO_THROW(optionParser.checkEndParsing()); } TEST_F(CoincenterCommandFactoryTest, CreateOrderCommandSingleCur) { - CoincenterCommandType type = CoincenterCommandType::kOrdersOpened; + CoincenterCommandType type = CoincenterCommandType::OrdersOpened; EXPECT_EQ(commandFactory.createOrderCommand(type, inputStr("AVAX")), CoincenterCommand(type).setOrdersConstraints(OrdersConstraints("AVAX"))); EXPECT_NO_THROW(optionParser.checkEndParsing()); } TEST_F(CoincenterCommandFactoryTest, CreateOrderCommandMarketWithExchange) { - CoincenterCommandType type = CoincenterCommandType::kOrdersOpened; + CoincenterCommandType type = CoincenterCommandType::OrdersOpened; EXPECT_EQ(commandFactory.createOrderCommand(type, inputStr("AVAX-BTC,huobi")), CoincenterCommand(type) .setOrdersConstraints(OrdersConstraints("AVAX", "BTC")) @@ -91,12 +91,12 @@ TEST_F(CoincenterCommandFactoryTest, CreateOrderCommandMarketWithExchange) { } TEST_F(CoincenterCommandFactoryTest, CreateTradeInvalidNegativeAmount) { - CoincenterCommandType type = CoincenterCommandType::kTrade; + CoincenterCommandType type = CoincenterCommandType::Trade; EXPECT_THROW(commandFactory.createTradeCommand(type, inputStr("-13XRP-BTC,binance_user2")), invalid_argument); } TEST_F(CoincenterCommandFactoryTest, CreateTradeInvalidSeveralTrades) { - CoincenterCommandType type = CoincenterCommandType::kTrade; + CoincenterCommandType type = CoincenterCommandType::Trade; cmdLineOptions.buy = "100%USDT"; // to set isSmartTrade to true, such that currency will not be parsed commandFactory.createTradeCommand(type, inputStr("13XRP-BTC,binance_user2")); @@ -104,7 +104,7 @@ TEST_F(CoincenterCommandFactoryTest, CreateTradeInvalidSeveralTrades) { } TEST_F(CoincenterCommandFactoryTest, CreateTradeAbsolute) { - CoincenterCommandType type = CoincenterCommandType::kTrade; + CoincenterCommandType type = CoincenterCommandType::Trade; EXPECT_EQ(commandFactory.createTradeCommand(type, inputStr("13XRP-BTC,binance_user2")), CoincenterCommand(type) .setTradeOptions(cmdLineOptions.computeTradeOptions()) @@ -116,7 +116,7 @@ TEST_F(CoincenterCommandFactoryTest, CreateTradeAbsolute) { } TEST_F(CoincenterCommandFactoryTest, CreateTradePercentage) { - CoincenterCommandType type = CoincenterCommandType::kTrade; + CoincenterCommandType type = CoincenterCommandType::Trade; EXPECT_EQ(commandFactory.createTradeCommand(type, inputStr("67.906%eth-USDT,huobi,upbit_user1")), CoincenterCommand(type) .setTradeOptions(cmdLineOptions.computeTradeOptions()) @@ -128,7 +128,7 @@ TEST_F(CoincenterCommandFactoryTest, CreateTradePercentage) { } TEST_F(CoincenterCommandFactoryTest, CreateBuyCommand) { - CoincenterCommandType type = CoincenterCommandType::kBuy; + CoincenterCommandType type = CoincenterCommandType::Buy; cmdLineOptions.buy = "whatever"; EXPECT_EQ(commandFactory.createTradeCommand(type, inputStr("804XLM")), CoincenterCommand(type) @@ -138,7 +138,7 @@ TEST_F(CoincenterCommandFactoryTest, CreateBuyCommand) { } TEST_F(CoincenterCommandFactoryTest, CreateSellCommand) { - CoincenterCommandType type = CoincenterCommandType::kSell; + CoincenterCommandType type = CoincenterCommandType::Sell; cmdLineOptions.sell = "whatever"; EXPECT_EQ(commandFactory.createTradeCommand(type, inputStr("0.76BTC,bithumb")), CoincenterCommand(type) @@ -149,13 +149,13 @@ TEST_F(CoincenterCommandFactoryTest, CreateSellCommand) { } TEST_F(CoincenterCommandFactoryTest, CreateSellWithPreviousInvalidCommand) { - CoincenterCommandType type = CoincenterCommandType::kSell; + CoincenterCommandType type = CoincenterCommandType::Sell; cmdLineOptions.sell = "whatever"; EXPECT_THROW(commandFactory.createTradeCommand(type, inputStr("")), invalid_argument); } TEST_F(CoincenterCommandFactoryTest, CreateSellAllCommand) { - CoincenterCommandType type = CoincenterCommandType::kSell; + CoincenterCommandType type = CoincenterCommandType::Sell; cmdLineOptions.sellAll = "whatever"; EXPECT_EQ(commandFactory.createTradeCommand(type, inputStr("DOGE")), CoincenterCommand(type) @@ -179,7 +179,7 @@ TEST_F(CoincenterCommandFactoryTest, CreateWithdrawWithMoreThan2Exchanges) { TEST_F(CoincenterCommandFactoryTest, CreateWithdrawAbsoluteValid) { EXPECT_EQ(commandFactory.createWithdrawApplyCommand(inputStr("5000XRP,binance_user1-kucoin_user2")), - CoincenterCommand(CoincenterCommandType::kWithdrawApply) + CoincenterCommand(CoincenterCommandType::Withdraw) .setWithdrawOptions(cmdLineOptions.computeWithdrawOptions()) .setAmount(MonetaryAmount("5000XRP")) .setExchangeNames(ExchangeNames({ExchangeName("binance", "user1"), ExchangeName("kucoin", "user2")}))); @@ -188,7 +188,7 @@ TEST_F(CoincenterCommandFactoryTest, CreateWithdrawAbsoluteValid) { TEST_F(CoincenterCommandFactoryTest, CreateWithdrawPercentageValid) { EXPECT_EQ(commandFactory.createWithdrawApplyCommand(inputStr("43.25%ltc,bithumb-kraken")), - CoincenterCommand(CoincenterCommandType::kWithdrawApply) + CoincenterCommand(CoincenterCommandType::Withdraw) .setWithdrawOptions(cmdLineOptions.computeWithdrawOptions()) .setAmount(MonetaryAmount("43.25LTC")) .setPercentageAmount(true) @@ -210,7 +210,7 @@ TEST_F(CoincenterCommandFactoryTest, CreateWithdrawAllMoreThan2ExchangesInvalid) TEST_F(CoincenterCommandFactoryTest, CreateWithdrawAllValid) { EXPECT_EQ(commandFactory.createWithdrawApplyAllCommand(inputStr("sol,upbit-kraken")), - CoincenterCommand(CoincenterCommandType::kWithdrawApply) + CoincenterCommand(CoincenterCommandType::Withdraw) .setWithdrawOptions(cmdLineOptions.computeWithdrawOptions()) .setAmount(MonetaryAmount(100, "SOL")) .setPercentageAmount(true) @@ -227,12 +227,12 @@ class CoincenterCommandFactoryWithPreviousTest : public ::testing::Test { StringOptionParser optionParser; CoincenterCmdLineOptions cmdLineOptions; - CoincenterCommand previousCommand{CoincenterCommandType::kTrade}; + CoincenterCommand previousCommand{CoincenterCommandType::Trade}; CoincenterCommandFactory commandFactory{cmdLineOptions, &previousCommand}; }; TEST_F(CoincenterCommandFactoryWithPreviousTest, CreateSellWithPreviousCommand) { - CoincenterCommandType type = CoincenterCommandType::kSell; + CoincenterCommandType type = CoincenterCommandType::Sell; cmdLineOptions.sell = "whatever"; EXPECT_EQ(commandFactory.createTradeCommand(type, inputStr("")), CoincenterCommand(type).setTradeOptions(cmdLineOptions.computeTradeOptions())); @@ -249,7 +249,7 @@ TEST_F(CoincenterCommandFactoryWithPreviousTest, CreateWithdrawInvalidMoreThan1E TEST_F(CoincenterCommandFactoryWithPreviousTest, CreateWithdrawWithPreviousValid) { EXPECT_EQ(commandFactory.createWithdrawApplyCommand(inputStr("kraken_user1")), - CoincenterCommand(CoincenterCommandType::kWithdrawApply) + CoincenterCommand(CoincenterCommandType::Withdraw) .setWithdrawOptions(cmdLineOptions.computeWithdrawOptions()) .setExchangeNames(ExchangeNames({ExchangeName("kraken", "user1")}))); EXPECT_NO_THROW(optionParser.checkEndParsing()); diff --git a/src/engine/test/coincenteroptions_test.cpp b/src/engine/test/coincenteroptions_test.cpp index f7d1da6f..52726a97 100644 --- a/src/engine/test/coincenteroptions_test.cpp +++ b/src/engine/test/coincenteroptions_test.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -131,26 +132,26 @@ TEST_F(CoincenterCmdLineOptionsTest, ComputeTradeArgStrInvalid) { TEST_F(CoincenterCmdLineOptionsTest, ComputeTradeArgStrTrade) { opts.trade = "some value"; - EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.trade, CoincenterCommandType::kTrade)); + EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.trade, CoincenterCommandType::Trade)); } TEST_F(CoincenterCmdLineOptionsTest, ComputeTradeArgStrTradeAll) { opts.tradeAll = "some value"; - EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.tradeAll, CoincenterCommandType::kTrade)); + EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.tradeAll, CoincenterCommandType::Trade)); } TEST_F(CoincenterCmdLineOptionsTest, ComputeTradeArgStrSellAll) { opts.sellAll = "some value"; - EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.sellAll, CoincenterCommandType::kSell)); + EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.sellAll, CoincenterCommandType::Sell)); } TEST_F(CoincenterCmdLineOptionsTest, ComputeTradeArgStrSell) { opts.sell = "some value"; - EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.sell, CoincenterCommandType::kSell)); + EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.sell, CoincenterCommandType::Sell)); } TEST_F(CoincenterCmdLineOptionsTest, ComputeTradeArgStrBuy) { opts.buy = "some value"; - EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.buy, CoincenterCommandType::kBuy)); + EXPECT_EQ(opts.getTradeArgStr(), std::make_pair(opts.buy, CoincenterCommandType::Buy)); } } // namespace cct diff --git a/src/engine/test/exchangesorchestrator_private_test.cpp b/src/engine/test/exchangesorchestrator_private_test.cpp index 4e14ac5a..cb8c3431 100644 --- a/src/engine/test/exchangesorchestrator_private_test.cpp +++ b/src/engine/test/exchangesorchestrator_private_test.cpp @@ -20,6 +20,7 @@ #include "opened-order.hpp" #include "ordersconstraints.hpp" #include "queryresulttypes.hpp" +#include "requests-config.hpp" #include "timedef.hpp" #include "tradeside.hpp" #include "wallet.hpp" @@ -34,7 +35,7 @@ using Type = CurrencyExchange::Type; class ExchangeOrchestratorTest : public ExchangesBaseTest { protected: - ExchangesOrchestrator exchangesOrchestrator{RequestsConfig{}, std::span(&this->exchange1, 8)}; + ExchangesOrchestrator exchangesOrchestrator{schema::RequestsConfig{}, std::span(&this->exchange1, 8)}; BalanceOptions balanceOptions; WithdrawOptions withdrawOptions{Duration{}, WithdrawSyncPolicy::kSynchronous, WithdrawOptions::Mode::kReal}; }; diff --git a/src/engine/test/exchangesorchestrator_public_test.cpp b/src/engine/test/exchangesorchestrator_public_test.cpp index a3b725f6..2ea3e78c 100644 --- a/src/engine/test/exchangesorchestrator_public_test.cpp +++ b/src/engine/test/exchangesorchestrator_public_test.cpp @@ -17,6 +17,7 @@ #include "exchangesorchestrator.hpp" #include "market.hpp" #include "queryresulttypes.hpp" +#include "requests-config.hpp" namespace cct { @@ -25,7 +26,7 @@ using UniquePublicSelectedExchanges = ExchangeRetriever::UniquePublicSelectedExc class ExchangeOrchestratorTest : public ExchangesBaseTest { protected: - ExchangesOrchestrator exchangesOrchestrator{RequestsConfig{}, std::span(&this->exchange1, 8)}; + ExchangesOrchestrator exchangesOrchestrator{schema::RequestsConfig{}, std::span(&this->exchange1, 8)}; }; TEST_F(ExchangeOrchestratorTest, HealthCheck) { diff --git a/src/engine/test/exchangesorchestrator_trade_test.cpp b/src/engine/test/exchangesorchestrator_trade_test.cpp index 573f565f..72b1d431 100644 --- a/src/engine/test/exchangesorchestrator_trade_test.cpp +++ b/src/engine/test/exchangesorchestrator_trade_test.cpp @@ -22,6 +22,7 @@ #include "priceoptions.hpp" #include "priceoptionsdef.hpp" #include "queryresulttypes.hpp" +#include "requests-config.hpp" #include "timedef.hpp" #include "tradedamounts.hpp" #include "tradedefinitions.hpp" @@ -37,7 +38,7 @@ using PlaceOrderInfo = api::PlaceOrderInfo; class ExchangeOrchestratorTest : public ExchangesBaseTest { protected: - ExchangesOrchestrator exchangesOrchestrator{RequestsConfig{}, std::span(&this->exchange1, 8)}; + ExchangesOrchestrator exchangesOrchestrator{schema::RequestsConfig{}, std::span(&this->exchange1, 8)}; }; /// For the trade tests, 'exchangeprivateapi_test' already tests a lot of complex trade options. diff --git a/src/engine/test/queryresultprinter_base_test.hpp b/src/engine/test/queryresultprinter_base_test.hpp index aeca809a..6c510929 100644 --- a/src/engine/test/queryresultprinter_base_test.hpp +++ b/src/engine/test/queryresultprinter_base_test.hpp @@ -8,7 +8,7 @@ #include #include "apioutputtype.hpp" -#include "cct_json.hpp" +#include "cct_json-serialization.hpp" #include "exchangedata_test.hpp" #include "queryresultprinter.hpp" #include "timedef.hpp" @@ -37,7 +37,14 @@ class QueryResultPrinterTest : public ExchangesBaseTest { void expectJson(std::string_view expected) const { ASSERT_FALSE(expected.empty()); expected.remove_prefix(1); // skip first newline char of expected string - EXPECT_EQ(json::parse(ss.view()), json::parse(expected)); + + glz::json_t lhs; + glz::json_t rhs; + + ASSERT_FALSE(glz::read_json(lhs, ss.view())); + ASSERT_FALSE(glz::read_json(rhs, expected)); + + EXPECT_EQ(lhs.dump(), rhs.dump()); } QueryResultPrinter basicQueryResultPrinter(ApiOutputType apiOutputType) { diff --git a/src/engine/test/queryresultprinter_private_test.cpp b/src/engine/test/queryresultprinter_private_test.cpp index 21b7a40d..b99dd482 100644 --- a/src/engine/test/queryresultprinter_private_test.cpp +++ b/src/engine/test/queryresultprinter_private_test.cpp @@ -41,7 +41,7 @@ class QueryResultPrinterEmptyBalanceNoEquiCurTest : public QueryResultPrinterTes }; TEST_F(QueryResultPrinterEmptyBalanceNoEquiCurTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::table).printBalance(balancePerExchange, equiCur); static constexpr std::string_view kExpected = R"( +----------+--------------------------+-------------------+-----------------+ | Currency | Total amount on selected | binance_testuser1 | huobi_testuser2 | @@ -51,7 +51,7 @@ TEST_F(QueryResultPrinterEmptyBalanceNoEquiCurTest, FormattedTable) { } TEST_F(QueryResultPrinterEmptyBalanceNoEquiCurTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printBalance(BalancePerExchange{}, equiCur); + basicQueryResultPrinter(ApiOutputType::json).printBalance(BalancePerExchange{}, equiCur); static constexpr std::string_view kExpected = R"( { "in": { @@ -69,7 +69,7 @@ TEST_F(QueryResultPrinterEmptyBalanceNoEquiCurTest, EmptyJson) { } TEST_F(QueryResultPrinterEmptyBalanceNoEquiCurTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::json).printBalance(balancePerExchange, equiCur); static constexpr std::string_view kExpected = R"( { "in": { @@ -94,7 +94,7 @@ TEST_F(QueryResultPrinterEmptyBalanceNoEquiCurTest, Json) { } TEST_F(QueryResultPrinterEmptyBalanceNoEquiCurTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::off).printBalance(balancePerExchange, equiCur); expectNoStr(); } @@ -107,7 +107,7 @@ class QueryResultPrinterBalanceNoEquiCurTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterBalanceNoEquiCurTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::table).printBalance(balancePerExchange, equiCur); static constexpr std::string_view kExpected = R"( +----------+--------------------------+-------------------+-----------------+-------------------+ | Currency | Total amount on selected | binance_testuser1 | huobi_testuser2 | bithumb_testuser1 | @@ -127,7 +127,7 @@ TEST_F(QueryResultPrinterBalanceNoEquiCurTest, FormattedTable) { } TEST_F(QueryResultPrinterBalanceNoEquiCurTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printBalance(BalancePerExchange{}, equiCur); + basicQueryResultPrinter(ApiOutputType::json).printBalance(BalancePerExchange{}, equiCur); static constexpr std::string_view kExpected = R"( { "in": { @@ -145,7 +145,7 @@ TEST_F(QueryResultPrinterBalanceNoEquiCurTest, EmptyJson) { } TEST_F(QueryResultPrinterBalanceNoEquiCurTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::json).printBalance(balancePerExchange, equiCur); static constexpr std::string_view kExpected = R"( { "in": { @@ -233,7 +233,7 @@ TEST_F(QueryResultPrinterBalanceNoEquiCurTest, Json) { } TEST_F(QueryResultPrinterBalanceNoEquiCurTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::off).printBalance(balancePerExchange, equiCur); expectNoStr(); } @@ -279,7 +279,7 @@ class QueryResultPrinterBalanceEquiCurTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterBalanceEquiCurTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::table).printBalance(balancePerExchange, equiCur); static constexpr std::string_view kExpected = R"( +----------+--------------------------+--------------+-------------------+-----------------+-------------------+-----------------+ | Currency | Total amount on selected | Total EUR eq | binance_testuser1 | huobi_testuser2 | bithumb_testuser1 | huobi_testuser1 | @@ -297,7 +297,7 @@ TEST_F(QueryResultPrinterBalanceEquiCurTest, FormattedTable) { } TEST_F(QueryResultPrinterBalanceEquiCurTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printBalance(BalancePerExchange{}, equiCur); + basicQueryResultPrinter(ApiOutputType::json).printBalance(BalancePerExchange{}, equiCur); static constexpr std::string_view kExpected = R"( { "in": { @@ -318,7 +318,7 @@ TEST_F(QueryResultPrinterBalanceEquiCurTest, EmptyJson) { } TEST_F(QueryResultPrinterBalanceEquiCurTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::json).printBalance(balancePerExchange, equiCur); static constexpr std::string_view kExpected = R"( { "in": { @@ -393,7 +393,7 @@ TEST_F(QueryResultPrinterBalanceEquiCurTest, Json) { } TEST_F(QueryResultPrinterBalanceEquiCurTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printBalance(balancePerExchange, equiCur); + basicQueryResultPrinter(ApiOutputType::off).printBalance(balancePerExchange, equiCur); expectNoStr(); } @@ -408,7 +408,7 @@ class QueryResultPrinterDepositInfoWithoutTagTest : public QueryResultPrinterTes }; TEST_F(QueryResultPrinterDepositInfoWithoutTagTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printDepositInfo(depositCurrencyCode, walletPerExchange); + basicQueryResultPrinter(ApiOutputType::table).printDepositInfo(depositCurrencyCode, walletPerExchange); static constexpr std::string_view kExpected = R"( +----------+-----------+---------------+-----------------+ | Exchange | Account | ETH address | Destination Tag | @@ -422,7 +422,7 @@ TEST_F(QueryResultPrinterDepositInfoWithoutTagTest, FormattedTable) { } TEST_F(QueryResultPrinterDepositInfoWithoutTagTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printDepositInfo(depositCurrencyCode, WalletPerExchange{}); + basicQueryResultPrinter(ApiOutputType::json).printDepositInfo(depositCurrencyCode, WalletPerExchange{}); static constexpr std::string_view kExpected = R"( { "in": { @@ -437,7 +437,7 @@ TEST_F(QueryResultPrinterDepositInfoWithoutTagTest, EmptyJson) { } TEST_F(QueryResultPrinterDepositInfoWithoutTagTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printDepositInfo(depositCurrencyCode, walletPerExchange); + basicQueryResultPrinter(ApiOutputType::json).printDepositInfo(depositCurrencyCode, walletPerExchange); static constexpr std::string_view kExpected = R"( { "in": { @@ -463,7 +463,7 @@ TEST_F(QueryResultPrinterDepositInfoWithoutTagTest, Json) { } TEST_F(QueryResultPrinterDepositInfoWithoutTagTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printDepositInfo(depositCurrencyCode, walletPerExchange); + basicQueryResultPrinter(ApiOutputType::off).printDepositInfo(depositCurrencyCode, walletPerExchange); expectNoStr(); } @@ -478,7 +478,7 @@ class QueryResultPrinterDepositInfoWithTagTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterDepositInfoWithTagTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printDepositInfo(depositCurrencyCode, walletPerExchange); + basicQueryResultPrinter(ApiOutputType::table).printDepositInfo(depositCurrencyCode, walletPerExchange); static constexpr std::string_view kExpected = R"( +----------+-----------+---------------+-----------------+ | Exchange | Account | XRP address | Destination Tag | @@ -491,7 +491,7 @@ TEST_F(QueryResultPrinterDepositInfoWithTagTest, FormattedTable) { } TEST_F(QueryResultPrinterDepositInfoWithTagTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printDepositInfo(depositCurrencyCode, WalletPerExchange{}); + basicQueryResultPrinter(ApiOutputType::json).printDepositInfo(depositCurrencyCode, WalletPerExchange{}); static constexpr std::string_view kExpected = R"( { "in": { @@ -506,7 +506,7 @@ TEST_F(QueryResultPrinterDepositInfoWithTagTest, EmptyJson) { } TEST_F(QueryResultPrinterDepositInfoWithTagTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printDepositInfo(depositCurrencyCode, walletPerExchange); + basicQueryResultPrinter(ApiOutputType::json).printDepositInfo(depositCurrencyCode, walletPerExchange); static constexpr std::string_view kExpected = R"( { "in": { @@ -532,7 +532,7 @@ TEST_F(QueryResultPrinterDepositInfoWithTagTest, Json) { } TEST_F(QueryResultPrinterDepositInfoWithTagTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printDepositInfo(depositCurrencyCode, walletPerExchange); + basicQueryResultPrinter(ApiOutputType::off).printDepositInfo(depositCurrencyCode, walletPerExchange); expectNoStr(); } @@ -551,7 +551,7 @@ class QueryResultPrinterTradesAmountTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterTradesAmountTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printTrades(tradeResultPerExchange, startAmount, isPercentageTrade, toCurrency, defaultTradeOptions); static constexpr std::string_view kExpected = R"( +----------+-----------+---------+---------------------------+-------------------------+-----------+ @@ -567,7 +567,7 @@ TEST_F(QueryResultPrinterTradesAmountTest, FormattedTable) { } TEST_F(QueryResultPrinterTradesAmountTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printTrades(TradeResultPerExchange{}, startAmount, isPercentageTrade, toCurrency, defaultTradeOptions); static constexpr std::string_view kExpected = R"( { @@ -600,7 +600,7 @@ TEST_F(QueryResultPrinterTradesAmountTest, EmptyJson) { } TEST_F(QueryResultPrinterTradesAmountTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printTrades(tradeResultPerExchange, startAmount, isPercentageTrade, toCurrency, defaultTradeOptions); static constexpr std::string_view kExpected = R"( { @@ -656,7 +656,7 @@ TEST_F(QueryResultPrinterTradesAmountTest, Json) { } TEST_F(QueryResultPrinterTradesAmountTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printTrades(tradeResultPerExchange, startAmount, isPercentageTrade, toCurrency, defaultTradeOptions); expectNoStr(); } @@ -673,7 +673,7 @@ class QueryResultPrinterTradesPercentageTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterTradesPercentageTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printTrades(tradeResultPerExchange, startAmount, isPercentageTrade, toCurrency, defaultTradeOptions); static constexpr std::string_view kExpected = R"( +----------+-----------+--------------+---------------------------+-------------------------+---------+ @@ -686,7 +686,7 @@ TEST_F(QueryResultPrinterTradesPercentageTest, FormattedTable) { } TEST_F(QueryResultPrinterTradesPercentageTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printTrades(TradeResultPerExchange{}, startAmount, isPercentageTrade, toCurrency, tradeOptions); static constexpr std::string_view kExpected = R"( { @@ -719,7 +719,7 @@ TEST_F(QueryResultPrinterTradesPercentageTest, EmptyJson) { } TEST_F(QueryResultPrinterTradesPercentageTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printTrades(tradeResultPerExchange, startAmount, isPercentageTrade, toCurrency, tradeOptions); static constexpr std::string_view kExpected = R"( { @@ -761,7 +761,7 @@ TEST_F(QueryResultPrinterTradesPercentageTest, Json) { } TEST_F(QueryResultPrinterTradesPercentageTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printTrades(tradeResultPerExchange, startAmount, isPercentageTrade, toCurrency, tradeOptions); expectNoStr(); } @@ -774,8 +774,7 @@ class QueryResultPrinterSmartBuyTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterSmartBuyTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printBuyTrades(tradeResultPerExchange, endAmount, defaultTradeOptions); + basicQueryResultPrinter(ApiOutputType::table).printBuyTrades(tradeResultPerExchange, endAmount, defaultTradeOptions); static constexpr std::string_view kExpected = R"( +----------+-----------+-------------+---------------------------+-------------------------+----------+ | Exchange | Account | From | Traded from amount (real) | Traded to amount (real) | Status | @@ -787,8 +786,7 @@ TEST_F(QueryResultPrinterSmartBuyTest, FormattedTable) { } TEST_F(QueryResultPrinterSmartBuyTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) - .printBuyTrades(TradeResultPerExchange{}, endAmount, defaultTradeOptions); + basicQueryResultPrinter(ApiOutputType::json).printBuyTrades(TradeResultPerExchange{}, endAmount, defaultTradeOptions); static constexpr std::string_view kExpected = R"( { "in": { @@ -817,7 +815,7 @@ TEST_F(QueryResultPrinterSmartBuyTest, EmptyJson) { } TEST_F(QueryResultPrinterSmartBuyTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printBuyTrades(tradeResultPerExchange, endAmount, defaultTradeOptions); + basicQueryResultPrinter(ApiOutputType::json).printBuyTrades(tradeResultPerExchange, endAmount, defaultTradeOptions); static constexpr std::string_view kExpected = R"( { "in": { @@ -855,8 +853,7 @@ TEST_F(QueryResultPrinterSmartBuyTest, Json) { } TEST_F(QueryResultPrinterSmartBuyTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) - .printBuyTrades(tradeResultPerExchange, endAmount, defaultTradeOptions); + basicQueryResultPrinter(ApiOutputType::off).printBuyTrades(tradeResultPerExchange, endAmount, defaultTradeOptions); expectNoStr(); } @@ -873,7 +870,7 @@ class QueryResultPrinterSmartSellTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterSmartSellTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printSellTrades(tradeResultPerExchange, startAmount, isPercentageTrade, defaultTradeOptions); static constexpr std::string_view kExpected = R"( +----------+-----------+----------+---------------------------+-------------------------+----------+ @@ -889,7 +886,7 @@ TEST_F(QueryResultPrinterSmartSellTest, FormattedTable) { } TEST_F(QueryResultPrinterSmartSellTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printSellTrades(TradeResultPerExchange{}, startAmount, isPercentageTrade, defaultTradeOptions); static constexpr std::string_view kExpected = R"( { @@ -919,7 +916,7 @@ TEST_F(QueryResultPrinterSmartSellTest, EmptyJson) { } TEST_F(QueryResultPrinterSmartSellTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printSellTrades(tradeResultPerExchange, startAmount, isPercentageTrade, defaultTradeOptions); static constexpr std::string_view kExpected = R"( { @@ -972,7 +969,7 @@ TEST_F(QueryResultPrinterSmartSellTest, Json) { } TEST_F(QueryResultPrinterSmartSellTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printSellTrades(tradeResultPerExchange, startAmount, isPercentageTrade, defaultTradeOptions); expectNoStr(); } @@ -997,7 +994,7 @@ class QueryResultPrinterClosedOrdersNoConstraintsTest : public QueryResultPrinte }; TEST_F(QueryResultPrinterClosedOrdersNoConstraintsTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printClosedOrders(closedOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::table).printClosedOrders(closedOrdersPerExchange, ordersConstraints); static constexpr std::string_view kExpected = R"( +----------+-----------+-------------+----------------------+----------------------+------+-----------------+------------------+ | Exchange | Account | Exchange Id | Placed time | Matched time | Side | Price | Matched Amount | @@ -1013,7 +1010,7 @@ TEST_F(QueryResultPrinterClosedOrdersNoConstraintsTest, FormattedTable) { } TEST_F(QueryResultPrinterClosedOrdersNoConstraintsTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printClosedOrders(ClosedOrdersPerExchange{}, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::json).printClosedOrders(ClosedOrdersPerExchange{}, ordersConstraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1025,7 +1022,7 @@ TEST_F(QueryResultPrinterClosedOrdersNoConstraintsTest, EmptyJson) { } TEST_F(QueryResultPrinterClosedOrdersNoConstraintsTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printClosedOrders(closedOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::json).printClosedOrders(closedOrdersPerExchange, ordersConstraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1096,7 +1093,7 @@ TEST_F(QueryResultPrinterClosedOrdersNoConstraintsTest, Json) { } TEST_F(QueryResultPrinterClosedOrdersNoConstraintsTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printClosedOrders(closedOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::off).printClosedOrders(closedOrdersPerExchange, ordersConstraints); expectNoStr(); } @@ -1128,7 +1125,7 @@ class QueryResultPrinterOpenedOrdersNoConstraintsTest : public QueryResultPrinte }; TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printOpenedOrders(openedOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::table).printOpenedOrders(openedOrdersPerExchange, ordersConstraints); static constexpr std::string_view kExpected = R"( +----------+-----------+-------------+----------------------+------+-----------------+------------------+------------------+ | Exchange | Account | Exchange Id | Placed time | Side | Price | Matched Amount | Remaining Amount | @@ -1144,7 +1141,7 @@ TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, FormattedTable) { } TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printOpenedOrders(OpenedOrdersPerExchange{}, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::json).printOpenedOrders(OpenedOrdersPerExchange{}, ordersConstraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1156,7 +1153,7 @@ TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, EmptyJson) { } TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printOpenedOrders(openedOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::json).printOpenedOrders(openedOrdersPerExchange, ordersConstraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1227,7 +1224,7 @@ TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, Json) { } TEST_F(QueryResultPrinterOpenedOrdersNoConstraintsTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printOpenedOrders(openedOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::off).printOpenedOrders(openedOrdersPerExchange, ordersConstraints); expectNoStr(); } @@ -1250,7 +1247,7 @@ class QueryResultPrinterRecentDepositsNoConstraintsTest : public QueryResultPrin }; TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printRecentDeposits(depositsPerExchange, constraints); + basicQueryResultPrinter(ApiOutputType::table).printRecentDeposits(depositsPerExchange, constraints); static constexpr std::string_view kExpected = R"( +----------+-----------+-------------+----------------------+-----------------+------------+ | Exchange | Account | Exchange Id | Received time | Amount | Status | @@ -1266,7 +1263,7 @@ TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, FormattedTable) { } TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printRecentDeposits(DepositsPerExchange{}, constraints); + basicQueryResultPrinter(ApiOutputType::json).printRecentDeposits(DepositsPerExchange{}, constraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1278,7 +1275,7 @@ TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, EmptyJson) { } TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printRecentDeposits(depositsPerExchange, constraints); + basicQueryResultPrinter(ApiOutputType::json).printRecentDeposits(depositsPerExchange, constraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1339,7 +1336,7 @@ TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, Json) { } TEST_F(QueryResultPrinterRecentDepositsNoConstraintsTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printRecentDeposits(depositsPerExchange, constraints); + basicQueryResultPrinter(ApiOutputType::off).printRecentDeposits(depositsPerExchange, constraints); expectNoStr(); } @@ -1366,7 +1363,7 @@ class QueryResultPrinterRecentWithdrawsNoConstraintsTest : public QueryResultPri }; TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printRecentWithdraws(withdrawsPerExchange, constraints); + basicQueryResultPrinter(ApiOutputType::table).printRecentWithdraws(withdrawsPerExchange, constraints); static constexpr std::string_view kExpected = R"( +----------+-----------+-------------+----------------------+--------------------+-------------+------------+ | Exchange | Account | Exchange Id | Sent time | Net Emitted Amount | Fee | Status | @@ -1382,7 +1379,7 @@ TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, FormattedTable) { } TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printRecentWithdraws(WithdrawsPerExchange{}, constraints); + basicQueryResultPrinter(ApiOutputType::json).printRecentWithdraws(WithdrawsPerExchange{}, constraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1394,7 +1391,7 @@ TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, EmptyJson) { } TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printRecentWithdraws(withdrawsPerExchange, constraints); + basicQueryResultPrinter(ApiOutputType::json).printRecentWithdraws(withdrawsPerExchange, constraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1461,7 +1458,7 @@ TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, Json) { } TEST_F(QueryResultPrinterRecentWithdrawsNoConstraintsTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printRecentWithdraws(withdrawsPerExchange, constraints); + basicQueryResultPrinter(ApiOutputType::off).printRecentWithdraws(withdrawsPerExchange, constraints); expectNoStr(); } @@ -1473,8 +1470,7 @@ class QueryResultPrinterCancelOrdersTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterCancelOrdersTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printCancelledOrders(nbCancelledOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::table).printCancelledOrders(nbCancelledOrdersPerExchange, ordersConstraints); static constexpr std::string_view kExpected = R"( +----------+-----------+----------------------------+ | Exchange | Account | Number of cancelled orders | @@ -1489,7 +1485,7 @@ TEST_F(QueryResultPrinterCancelOrdersTest, FormattedTable) { } TEST_F(QueryResultPrinterCancelOrdersTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printCancelledOrders(NbCancelledOrdersPerExchange{}, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::json).printCancelledOrders(NbCancelledOrdersPerExchange{}, ordersConstraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1501,7 +1497,7 @@ TEST_F(QueryResultPrinterCancelOrdersTest, EmptyJson) { } TEST_F(QueryResultPrinterCancelOrdersTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printCancelledOrders(nbCancelledOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::json).printCancelledOrders(nbCancelledOrdersPerExchange, ordersConstraints); static constexpr std::string_view kExpected = R"( { "in": { @@ -1532,8 +1528,7 @@ TEST_F(QueryResultPrinterCancelOrdersTest, Json) { } TEST_F(QueryResultPrinterCancelOrdersTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) - .printCancelledOrders(nbCancelledOrdersPerExchange, ordersConstraints); + basicQueryResultPrinter(ApiOutputType::off).printCancelledOrders(nbCancelledOrdersPerExchange, ordersConstraints); expectNoStr(); } @@ -1563,7 +1558,7 @@ class QueryResultPrinterWithdrawAmountTest : public QueryResultPrinterWithdrawTe }; TEST_F(QueryResultPrinterWithdrawAmountTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printWithdraw(deliveredWithdrawInfoWithExchanges, isPercentageWithdraw, withdrawOptions); static constexpr std::string_view kExpected = R"( +----------+-----------+-------------------------+-----------------------+--------------------------+ @@ -1577,7 +1572,7 @@ TEST_F(QueryResultPrinterWithdrawAmountTest, FormattedTable) { } TEST_F(QueryResultPrinterWithdrawAmountTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printWithdraw(deliveredWithdrawInfoWithExchanges, isPercentageWithdraw, withdrawOptions); static constexpr std::string_view kExpected = R"( { @@ -1612,7 +1607,7 @@ TEST_F(QueryResultPrinterWithdrawAmountTest, Json) { } TEST_F(QueryResultPrinterWithdrawAmountTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printWithdraw(deliveredWithdrawInfoWithExchanges, isPercentageWithdraw, withdrawOptions); expectNoStr(); } @@ -1623,7 +1618,7 @@ class QueryResultPrinterWithdrawPercentageTest : public QueryResultPrinterWithdr }; TEST_F(QueryResultPrinterWithdrawPercentageTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printWithdraw(deliveredWithdrawInfoWithExchanges, isPercentageWithdraw, withdrawOptions); static constexpr std::string_view kExpected = R"( +----------+-----------+-------------------------+-----------------------+--------------------------+ @@ -1637,7 +1632,7 @@ TEST_F(QueryResultPrinterWithdrawPercentageTest, FormattedTable) { } TEST_F(QueryResultPrinterWithdrawPercentageTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printWithdraw(deliveredWithdrawInfoWithExchanges, isPercentageWithdraw, withdrawOptions); static constexpr std::string_view kExpected = R"( { @@ -1672,7 +1667,7 @@ TEST_F(QueryResultPrinterWithdrawPercentageTest, Json) { } TEST_F(QueryResultPrinterWithdrawPercentageTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printWithdraw(deliveredWithdrawInfoWithExchanges, isPercentageWithdraw, withdrawOptions); expectNoStr(); } @@ -1694,8 +1689,7 @@ class QueryResultPrinterDustSweeperTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterDustSweeperTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printDustSweeper(tradedAmountsVectorWithFinalAmountPerExchange, cur); + basicQueryResultPrinter(ApiOutputType::table).printDustSweeper(tradedAmountsVectorWithFinalAmountPerExchange, cur); static constexpr std::string_view kExpected = R"( +----------+-----------+-----------------------------+--------------+ | Exchange | Account | Trades | Final Amount | @@ -1711,7 +1705,7 @@ TEST_F(QueryResultPrinterDustSweeperTest, FormattedTable) { } TEST_F(QueryResultPrinterDustSweeperTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printDustSweeper(tradedAmountsVectorWithFinalAmountPerExchange, cur); + basicQueryResultPrinter(ApiOutputType::json).printDustSweeper(tradedAmountsVectorWithFinalAmountPerExchange, cur); static constexpr std::string_view kExpected = R"( { "in": { @@ -1757,7 +1751,7 @@ TEST_F(QueryResultPrinterDustSweeperTest, Json) { } TEST_F(QueryResultPrinterDustSweeperTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printDustSweeper(tradedAmountsVectorWithFinalAmountPerExchange, cur); + basicQueryResultPrinter(ApiOutputType::off).printDustSweeper(tradedAmountsVectorWithFinalAmountPerExchange, cur); expectNoStr(); } diff --git a/src/engine/test/queryresultprinter_public_test.cpp b/src/engine/test/queryresultprinter_public_test.cpp index 3dcb92d6..24a20d8f 100644 --- a/src/engine/test/queryresultprinter_public_test.cpp +++ b/src/engine/test/queryresultprinter_public_test.cpp @@ -39,7 +39,7 @@ class QueryResultPrinterHealthCheckTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterHealthCheckTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printHealthCheck(healthCheckPerExchange); + basicQueryResultPrinter(ApiOutputType::table).printHealthCheck(healthCheckPerExchange); static constexpr std::string_view kExpected = R"( +----------+---------------------+ | Exchange | Health Check status | @@ -53,7 +53,7 @@ TEST_F(QueryResultPrinterHealthCheckTest, FormattedTable) { } TEST_F(QueryResultPrinterHealthCheckTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printHealthCheck(ExchangeHealthCheckStatus{}); + basicQueryResultPrinter(ApiOutputType::json).printHealthCheck(ExchangeHealthCheckStatus{}); static constexpr std::string_view kExpected = R"( { "in": { @@ -65,7 +65,7 @@ TEST_F(QueryResultPrinterHealthCheckTest, EmptyJson) { } TEST_F(QueryResultPrinterHealthCheckTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printHealthCheck(healthCheckPerExchange); + basicQueryResultPrinter(ApiOutputType::json).printHealthCheck(healthCheckPerExchange); static constexpr std::string_view kExpected = R"( { "in": { @@ -80,7 +80,7 @@ TEST_F(QueryResultPrinterHealthCheckTest, Json) { } TEST_F(QueryResultPrinterHealthCheckTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printHealthCheck(healthCheckPerExchange); + basicQueryResultPrinter(ApiOutputType::off).printHealthCheck(healthCheckPerExchange); expectNoStr(); } @@ -119,7 +119,7 @@ class QueryResultPrinterCurrenciesTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterCurrenciesTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printCurrencies(currenciesPerExchange); + basicQueryResultPrinter(ApiOutputType::table).printCurrencies(currenciesPerExchange); static constexpr std::string_view kExpected = R"( +----------+-----------------------+---------------------------------------+-------------+-----------------------+-------------------+---------+ | Currency | Supported exchanges | Exchange code(s) | Alt code(s) | Can deposit to | Can withdraw from | Is fiat | @@ -134,7 +134,7 @@ TEST_F(QueryResultPrinterCurrenciesTest, FormattedTable) { } TEST_F(QueryResultPrinterCurrenciesTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printCurrencies(CurrenciesPerExchange{}); + basicQueryResultPrinter(ApiOutputType::json).printCurrencies(CurrenciesPerExchange{}); static constexpr std::string_view kExpected = R"( { @@ -148,7 +148,7 @@ TEST_F(QueryResultPrinterCurrenciesTest, EmptyJson) { } TEST_F(QueryResultPrinterCurrenciesTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printCurrencies(currenciesPerExchange); + basicQueryResultPrinter(ApiOutputType::json).printCurrencies(currenciesPerExchange); static constexpr std::string_view kExpected = R"( { @@ -242,8 +242,8 @@ class QueryResultPrinterMarketsTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterMarketsTest, FormattedTableNoCurrency) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printMarkets(CurrencyCode(), CurrencyCode(), marketsPerExchange, CoincenterCommandType::kMarkets); + basicQueryResultPrinter(ApiOutputType::table) + .printMarkets(CurrencyCode(), CurrencyCode(), marketsPerExchange, CoincenterCommandType::Markets); static constexpr std::string_view kExpected = R"( +----------+---------+ | Exchange | Markets | @@ -258,8 +258,8 @@ TEST_F(QueryResultPrinterMarketsTest, FormattedTableNoCurrency) { } TEST_F(QueryResultPrinterMarketsTest, FormattedTableOneCurrency) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printMarkets(cur1, CurrencyCode(), marketsPerExchange, CoincenterCommandType::kMarkets); + basicQueryResultPrinter(ApiOutputType::table) + .printMarkets(cur1, CurrencyCode(), marketsPerExchange, CoincenterCommandType::Markets); // We only test the title line here, it's normal that all markets are printed (they come from marketsPerExchange and // are not filtered again inside the print function) static constexpr std::string_view kExpected = R"( @@ -276,8 +276,8 @@ TEST_F(QueryResultPrinterMarketsTest, FormattedTableOneCurrency) { } TEST_F(QueryResultPrinterMarketsTest, FormattedTableTwoCurrencies) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printMarkets(cur1, cur2, marketsPerExchange, CoincenterCommandType::kMarkets); + basicQueryResultPrinter(ApiOutputType::table) + .printMarkets(cur1, cur2, marketsPerExchange, CoincenterCommandType::Markets); static constexpr std::string_view kExpected = R"( +----------+----------------------+ | Exchange | Markets with XRP-BTC | @@ -292,8 +292,8 @@ TEST_F(QueryResultPrinterMarketsTest, FormattedTableTwoCurrencies) { } TEST_F(QueryResultPrinterMarketsTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) - .printMarkets(cur1, CurrencyCode(), MarketsPerExchange{}, CoincenterCommandType::kMarkets); + basicQueryResultPrinter(ApiOutputType::json) + .printMarkets(cur1, CurrencyCode(), MarketsPerExchange{}, CoincenterCommandType::Markets); static constexpr std::string_view kExpected = R"( { "in": { @@ -308,8 +308,8 @@ TEST_F(QueryResultPrinterMarketsTest, EmptyJson) { } TEST_F(QueryResultPrinterMarketsTest, JsonNoCurrency) { - basicQueryResultPrinter(ApiOutputType::kJson) - .printMarkets(CurrencyCode(), CurrencyCode(), marketsPerExchange, CoincenterCommandType::kMarkets); + basicQueryResultPrinter(ApiOutputType::json) + .printMarkets(CurrencyCode(), CurrencyCode(), marketsPerExchange, CoincenterCommandType::Markets); static constexpr std::string_view kExpected = R"( { "in": { @@ -334,8 +334,8 @@ TEST_F(QueryResultPrinterMarketsTest, JsonNoCurrency) { } TEST_F(QueryResultPrinterMarketsTest, JsonOneCurrency) { - basicQueryResultPrinter(ApiOutputType::kJson) - .printMarkets(cur1, CurrencyCode(), marketsPerExchange, CoincenterCommandType::kMarkets); + basicQueryResultPrinter(ApiOutputType::json) + .printMarkets(cur1, CurrencyCode(), marketsPerExchange, CoincenterCommandType::Markets); static constexpr std::string_view kExpected = R"( { "in": { @@ -361,8 +361,8 @@ TEST_F(QueryResultPrinterMarketsTest, JsonOneCurrency) { } TEST_F(QueryResultPrinterMarketsTest, JsonTwoCurrencies) { - basicQueryResultPrinter(ApiOutputType::kJson) - .printMarkets(cur1, cur2, marketsPerExchange, CoincenterCommandType::kMarkets); + basicQueryResultPrinter(ApiOutputType::json) + .printMarkets(cur1, cur2, marketsPerExchange, CoincenterCommandType::Markets); static constexpr std::string_view kExpected = R"( { "in": { @@ -389,8 +389,8 @@ TEST_F(QueryResultPrinterMarketsTest, JsonTwoCurrencies) { } TEST_F(QueryResultPrinterMarketsTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) - .printMarkets(cur1, CurrencyCode(), marketsPerExchange, CoincenterCommandType::kMarkets); + basicQueryResultPrinter(ApiOutputType::off) + .printMarkets(cur1, CurrencyCode(), marketsPerExchange, CoincenterCommandType::Markets); expectNoStr(); } @@ -403,7 +403,7 @@ class QueryResultPrinterTickerTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterTickerTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printTickerInformation(exchangeTickerMaps); + basicQueryResultPrinter(ApiOutputType::table).printTickerInformation(exchangeTickerMaps); static constexpr std::string_view kExpected = R"( +----------+---------+--------------+------------+--------------+------------+ | Exchange | Market | Bid price | Bid volume | Ask price | Ask volume | @@ -417,7 +417,7 @@ TEST_F(QueryResultPrinterTickerTest, FormattedTable) { } TEST_F(QueryResultPrinterTickerTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printTickerInformation(ExchangeTickerMaps{}); + basicQueryResultPrinter(ApiOutputType::json).printTickerInformation(ExchangeTickerMaps{}); static constexpr std::string_view kExpected = R"( { "in": { @@ -429,7 +429,7 @@ TEST_F(QueryResultPrinterTickerTest, EmptyJson) { } TEST_F(QueryResultPrinterTickerTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printTickerInformation(exchangeTickerMaps); + basicQueryResultPrinter(ApiOutputType::json).printTickerInformation(exchangeTickerMaps); static constexpr std::string_view kExpected = R"( { "in": { @@ -479,7 +479,7 @@ TEST_F(QueryResultPrinterTickerTest, Json) { } TEST_F(QueryResultPrinterTickerTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printTickerInformation(exchangeTickerMaps); + basicQueryResultPrinter(ApiOutputType::off).printTickerInformation(exchangeTickerMaps); expectNoStr(); } @@ -493,7 +493,7 @@ class QueryResultPrinterMarketOrderBookTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterMarketOrderBookTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printMarketOrderBooks(mk, CurrencyCode{}, d, marketOrderBookConversionRates); static constexpr std::string_view kExpected = R"( +-----------------------+----------------------------+----------------------+ @@ -521,7 +521,7 @@ TEST_F(QueryResultPrinterMarketOrderBookTest, FormattedTable) { } TEST_F(QueryResultPrinterMarketOrderBookTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printMarketOrderBooks(mk, CurrencyCode{}, d, MarketOrderBookConversionRates{}); static constexpr std::string_view kExpected = R"( { @@ -538,7 +538,7 @@ TEST_F(QueryResultPrinterMarketOrderBookTest, EmptyJson) { } TEST_F(QueryResultPrinterMarketOrderBookTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printMarketOrderBooks(mk, CurrencyCode{}, d, marketOrderBookConversionRates); static constexpr std::string_view kExpected = R"( { @@ -618,7 +618,7 @@ TEST_F(QueryResultPrinterMarketOrderBookTest, Json) { } TEST_F(QueryResultPrinterMarketOrderBookTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printMarketOrderBooks(mk, CurrencyCode{}, d, marketOrderBookConversionRates); expectNoStr(); } @@ -633,7 +633,7 @@ class QueryResultPrinterConversionSingleAmountTest : public QueryResultPrinterTe }; TEST_F(QueryResultPrinterConversionSingleAmountTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printConversion(fromAmount, targetCurrencyCode, monetaryAmountPerExchange); static constexpr std::string_view kExpected = R"( +----------+-------------------------------+ @@ -648,7 +648,7 @@ TEST_F(QueryResultPrinterConversionSingleAmountTest, FormattedTable) { } TEST_F(QueryResultPrinterConversionSingleAmountTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printConversion(fromAmount, targetCurrencyCode, MonetaryAmountPerExchange{}); static constexpr std::string_view kExpected = R"( { @@ -665,7 +665,7 @@ TEST_F(QueryResultPrinterConversionSingleAmountTest, EmptyJson) { } TEST_F(QueryResultPrinterConversionSingleAmountTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printConversion(fromAmount, targetCurrencyCode, monetaryAmountPerExchange); static constexpr std::string_view kExpected = R"( { @@ -692,7 +692,7 @@ TEST_F(QueryResultPrinterConversionSingleAmountTest, Json) { } TEST_F(QueryResultPrinterConversionSingleAmountTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printConversion(fromAmount, targetCurrencyCode, monetaryAmountPerExchange); expectNoStr(); } @@ -714,7 +714,7 @@ class QueryResultPrinterConversionSeveralAmountTest : public QueryResultPrinterT }; TEST_F(QueryResultPrinterConversionSeveralAmountTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printConversion(fromAmounts, targetCurrencyCode, monetaryAmountPerExchange); static constexpr std::string_view kExpected = R"( +----------+---------+--------------+ @@ -729,7 +729,7 @@ TEST_F(QueryResultPrinterConversionSeveralAmountTest, FormattedTable) { } TEST_F(QueryResultPrinterConversionSeveralAmountTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printConversion(fromAmounts, targetCurrencyCode, MonetaryAmountPerExchange{}); static constexpr std::string_view kExpected = R"( { @@ -750,7 +750,7 @@ TEST_F(QueryResultPrinterConversionSeveralAmountTest, EmptyJson) { } TEST_F(QueryResultPrinterConversionSeveralAmountTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printConversion(fromAmounts, targetCurrencyCode, monetaryAmountPerExchange); static constexpr std::string_view kExpected = R"( { @@ -781,7 +781,7 @@ TEST_F(QueryResultPrinterConversionSeveralAmountTest, Json) { } TEST_F(QueryResultPrinterConversionSeveralAmountTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printConversion(fromAmounts, targetCurrencyCode, monetaryAmountPerExchange); expectNoStr(); } @@ -796,7 +796,7 @@ class QueryResultPrinterConversionPathTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterConversionPathTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printConversionPath(marketForPath, conversionPathPerExchange); + basicQueryResultPrinter(ApiOutputType::table).printConversionPath(marketForPath, conversionPathPerExchange); static constexpr std::string_view kExpected = R"( +----------+-------------------------------------+ | Exchange | Fastest conversion path for XLM-XRP | @@ -809,7 +809,7 @@ TEST_F(QueryResultPrinterConversionPathTest, FormattedTable) { } TEST_F(QueryResultPrinterConversionPathTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printConversionPath(marketForPath, ConversionPathPerExchange{}); + basicQueryResultPrinter(ApiOutputType::json).printConversionPath(marketForPath, ConversionPathPerExchange{}); static constexpr std::string_view kExpected = R"( { "in": { @@ -824,7 +824,7 @@ TEST_F(QueryResultPrinterConversionPathTest, EmptyJson) { } TEST_F(QueryResultPrinterConversionPathTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printConversionPath(marketForPath, conversionPathPerExchange); + basicQueryResultPrinter(ApiOutputType::json).printConversionPath(marketForPath, conversionPathPerExchange); static constexpr std::string_view kExpected = R"( { "in": { @@ -848,7 +848,7 @@ TEST_F(QueryResultPrinterConversionPathTest, Json) { } TEST_F(QueryResultPrinterConversionPathTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printConversionPath(marketForPath, conversionPathPerExchange); + basicQueryResultPrinter(ApiOutputType::off).printConversionPath(marketForPath, conversionPathPerExchange); expectNoStr(); } @@ -861,7 +861,7 @@ class QueryResultPrinterWithdrawFeeTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterWithdrawFeeTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); + basicQueryResultPrinter(ApiOutputType::table).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); static constexpr std::string_view kExpected = R"( +-----------------------+----------+-----------+ | Withdraw fee currency | bithumb | huobi | @@ -874,7 +874,7 @@ TEST_F(QueryResultPrinterWithdrawFeeTest, FormattedTable) { } TEST_F(QueryResultPrinterWithdrawFeeTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printWithdrawFees(MonetaryAmountByCurrencySetPerExchange{}, curWithdrawFee); static constexpr std::string_view kExpected = R"( { @@ -888,7 +888,7 @@ TEST_F(QueryResultPrinterWithdrawFeeTest, EmptyJson) { } TEST_F(QueryResultPrinterWithdrawFeeTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); + basicQueryResultPrinter(ApiOutputType::json).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); static constexpr std::string_view kExpected = R"( { "in": { @@ -909,7 +909,7 @@ TEST_F(QueryResultPrinterWithdrawFeeTest, Json) { } TEST_F(QueryResultPrinterWithdrawFeeTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); + basicQueryResultPrinter(ApiOutputType::off).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); expectNoStr(); } @@ -921,7 +921,7 @@ class QueryResultPrinterLast24HoursTradedVolumeTest : public QueryResultPrinterT }; TEST_F(QueryResultPrinterLast24HoursTradedVolumeTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) + basicQueryResultPrinter(ApiOutputType::table) .printLast24hTradedVolume(marketLast24hTradedVolume, monetaryAmountPerExchange); static constexpr std::string_view kExpected = R"( +----------+--------------------------------+ @@ -935,7 +935,7 @@ TEST_F(QueryResultPrinterLast24HoursTradedVolumeTest, FormattedTable) { } TEST_F(QueryResultPrinterLast24HoursTradedVolumeTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printLast24hTradedVolume(marketLast24hTradedVolume, MonetaryAmountPerExchange{}); static constexpr std::string_view kExpected = R"( { @@ -951,7 +951,7 @@ TEST_F(QueryResultPrinterLast24HoursTradedVolumeTest, EmptyJson) { } TEST_F(QueryResultPrinterLast24HoursTradedVolumeTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson) + basicQueryResultPrinter(ApiOutputType::json) .printLast24hTradedVolume(marketLast24hTradedVolume, monetaryAmountPerExchange); static constexpr std::string_view kExpected = R"( { @@ -970,7 +970,7 @@ TEST_F(QueryResultPrinterLast24HoursTradedVolumeTest, Json) { } TEST_F(QueryResultPrinterLast24HoursTradedVolumeTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) + basicQueryResultPrinter(ApiOutputType::off) .printLast24hTradedVolume(marketLast24hTradedVolume, monetaryAmountPerExchange); expectNoStr(); } @@ -997,8 +997,7 @@ class QueryResultPrinterLastTradesVolumeTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterLastTradesVolumeTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printLastTrades(marketLastTrades, nbLastTrades, lastTradesPerExchange); + basicQueryResultPrinter(ApiOutputType::table).printLastTrades(marketLastTrades, nbLastTrades, lastTradesPerExchange); static constexpr std::string_view kExpected = R"( +----------------------+--------------------+--------------------------+-------------------+ | binance trades | ETH buys | Price in USDT | ETH sells | @@ -1031,7 +1030,7 @@ TEST_F(QueryResultPrinterLastTradesVolumeTest, FormattedTable) { } TEST_F(QueryResultPrinterLastTradesVolumeTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printLastTrades(marketLastTrades, nbLastTrades, TradesPerExchange{}); + basicQueryResultPrinter(ApiOutputType::json).printLastTrades(marketLastTrades, nbLastTrades, TradesPerExchange{}); static constexpr std::string_view kExpected = R"( { "in": { @@ -1047,7 +1046,7 @@ TEST_F(QueryResultPrinterLastTradesVolumeTest, EmptyJson) { } TEST_F(QueryResultPrinterLastTradesVolumeTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printLastTrades(marketLastTrades, nbLastTrades, lastTradesPerExchange); + basicQueryResultPrinter(ApiOutputType::json).printLastTrades(marketLastTrades, nbLastTrades, lastTradesPerExchange); static constexpr std::string_view kExpected = R"( { "in": { @@ -1118,8 +1117,7 @@ TEST_F(QueryResultPrinterLastTradesVolumeTest, Json) { } TEST_F(QueryResultPrinterLastTradesVolumeTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint) - .printLastTrades(marketLastTrades, nbLastTrades, lastTradesPerExchange); + basicQueryResultPrinter(ApiOutputType::off).printLastTrades(marketLastTrades, nbLastTrades, lastTradesPerExchange); expectNoStr(); } @@ -1132,7 +1130,7 @@ class QueryResultPrinterLastPriceTest : public QueryResultPrinterTest { }; TEST_F(QueryResultPrinterLastPriceTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printLastPrice(marketLastPrice, monetaryAmountPerExchange); + basicQueryResultPrinter(ApiOutputType::table).printLastPrice(marketLastPrice, monetaryAmountPerExchange); static constexpr std::string_view kExpected = R"( +----------+--------------------+ | Exchange | XRP-KRW last price | @@ -1146,7 +1144,7 @@ TEST_F(QueryResultPrinterLastPriceTest, FormattedTable) { } TEST_F(QueryResultPrinterLastPriceTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printLastPrice(marketLastPrice, MonetaryAmountPerExchange{}); + basicQueryResultPrinter(ApiOutputType::json).printLastPrice(marketLastPrice, MonetaryAmountPerExchange{}); static constexpr std::string_view kExpected = R"( { "in": { @@ -1161,7 +1159,7 @@ TEST_F(QueryResultPrinterLastPriceTest, EmptyJson) { } TEST_F(QueryResultPrinterLastPriceTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printLastPrice(marketLastPrice, monetaryAmountPerExchange); + basicQueryResultPrinter(ApiOutputType::json).printLastPrice(marketLastPrice, monetaryAmountPerExchange); static constexpr std::string_view kExpected = R"( { "in": { @@ -1180,7 +1178,7 @@ TEST_F(QueryResultPrinterLastPriceTest, Json) { } TEST_F(QueryResultPrinterLastPriceTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printLastPrice(marketLastPrice, monetaryAmountPerExchange); + basicQueryResultPrinter(ApiOutputType::off).printLastPrice(marketLastPrice, monetaryAmountPerExchange); expectNoStr(); } @@ -1217,8 +1215,7 @@ class QueryResultPrinterReplayMarketsTest : public QueryResultPrinterReplayBaseT }; TEST_F(QueryResultPrinterReplayMarketsTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printMarketsForReplay(timeWindow, marketTimestampSetsPerExchange); + basicQueryResultPrinter(ApiOutputType::table).printMarketsForReplay(timeWindow, marketTimestampSetsPerExchange); static constexpr std::string_view kExpected = R"( +-----------+--------------------------------+--------------------------------+ | Markets | Last order books timestamp | Last trades timestamp | @@ -1240,7 +1237,7 @@ TEST_F(QueryResultPrinterReplayMarketsTest, FormattedTable) { } TEST_F(QueryResultPrinterReplayMarketsTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printMarketsForReplay(timeWindow, MarketTimestampSetsPerExchange{}); + basicQueryResultPrinter(ApiOutputType::json).printMarketsForReplay(timeWindow, MarketTimestampSetsPerExchange{}); static constexpr std::string_view kExpected = R"json( { "in": { @@ -1255,7 +1252,7 @@ TEST_F(QueryResultPrinterReplayMarketsTest, EmptyJson) { } TEST_F(QueryResultPrinterReplayMarketsTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printMarketsForReplay(timeWindow, marketTimestampSetsPerExchange); + basicQueryResultPrinter(ApiOutputType::json).printMarketsForReplay(timeWindow, marketTimestampSetsPerExchange); static constexpr std::string_view kExpected = R"json( { "in": { @@ -1328,7 +1325,7 @@ TEST_F(QueryResultPrinterReplayMarketsTest, Json) { } TEST_F(QueryResultPrinterReplayMarketsTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printMarketsForReplay(timeWindow, marketTimestampSetsPerExchange); + basicQueryResultPrinter(ApiOutputType::off).printMarketsForReplay(timeWindow, marketTimestampSetsPerExchange); expectNoStr(); } @@ -1377,12 +1374,11 @@ class QueryResultPrinterReplayTest : public QueryResultPrinterReplayBaseTest { ReplayResults replayResults{{alg1Name, {marketTradingResultPerExchange1}}, {alg2Name, {marketTradingResultPerExchange1, marketTradingResultPerExchange2}}}; - CoincenterCommandType commandType{CoincenterCommandType::kReplay}; + CoincenterCommandType commandType{CoincenterCommandType::Replay}; }; TEST_F(QueryResultPrinterReplayTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable) - .printMarketTradingResults(timeWindow, replayResults, commandType); + basicQueryResultPrinter(ApiOutputType::table).printMarketTradingResults(timeWindow, replayResults, commandType); static constexpr std::string_view kExpected = R"( +------------+----------+----------------------+----------+---------------+---------------+------------------------------------------------------+------------------------------+ | Algorithm | Exchange | Time window | Market | Start amounts | Profit / Loss | Matched orders | Stats | @@ -1415,7 +1411,7 @@ TEST_F(QueryResultPrinterReplayTest, FormattedTable) { } TEST_F(QueryResultPrinterReplayTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printMarketTradingResults(timeWindow, ReplayResults{}, commandType); + basicQueryResultPrinter(ApiOutputType::json).printMarketTradingResults(timeWindow, ReplayResults{}, commandType); static constexpr std::string_view kExpected = R"json( { "in": { @@ -1434,7 +1430,7 @@ TEST_F(QueryResultPrinterReplayTest, EmptyJson) { } TEST_F(QueryResultPrinterReplayTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printMarketTradingResults(timeWindow, replayResults, commandType); + basicQueryResultPrinter(ApiOutputType::json).printMarketTradingResults(timeWindow, replayResults, commandType); static constexpr std::string_view kExpected = R"json( { "in": { @@ -1786,7 +1782,7 @@ TEST_F(QueryResultPrinterReplayTest, Json) { } TEST_F(QueryResultPrinterReplayTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printMarketTradingResults(timeWindow, replayResults, commandType); + basicQueryResultPrinter(ApiOutputType::off).printMarketTradingResults(timeWindow, replayResults, commandType); expectNoStr(); } diff --git a/src/engine/test/transferablecommandresult_test.cpp b/src/engine/test/transferablecommandresult_test.cpp index abac0ba8..e3d551be 100644 --- a/src/engine/test/transferablecommandresult_test.cpp +++ b/src/engine/test/transferablecommandresult_test.cpp @@ -40,21 +40,21 @@ class TransferableCommandResultTest : public ::testing::Test { TEST_F(TransferableCommandResultTest, ComputeTradeAmountAndExchangesUniqueAmount) { const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}}; - EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::kTrade), previousResults), + EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::Trade), previousResults), std::make_pair(MonetaryAmount{50, "DOGE"}, ExchangeNames({exchangeName11}))); } TEST_F(TransferableCommandResultTest, ComputeTradeAmountAndExchangesDoubleAmountsSameExchange) { const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}, TransferableCommandResult{exchangeName11, amount12}}; - EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::kTrade), previousResults), + EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::Trade), previousResults), std::make_pair(MonetaryAmount{60, "DOGE"}, ExchangeNames({exchangeName11}))); } TEST_F(TransferableCommandResultTest, ComputeTradeAmountAndExchangesDoubleAmountsDifferentExchanges) { const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}, TransferableCommandResult{exchangeName22, amount12}}; - EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::kTrade), previousResults), + EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::Trade), previousResults), std::make_pair(MonetaryAmount{60, "DOGE"}, ExchangeNames({exchangeName11, exchangeName22}))); } @@ -62,21 +62,21 @@ TEST_F(TransferableCommandResultTest, ComputeTradeAmountAndExchangesTripleAmount const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}, TransferableCommandResult{exchangeName11, amount12}, TransferableCommandResult{exchangeName21, amount13}}; - EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::kTrade), previousResults), + EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::Trade), previousResults), std::make_pair(MonetaryAmount{65, "DOGE"}, ExchangeNames({exchangeName11, exchangeName21}))); } TEST_F(TransferableCommandResultTest, ComputeTradeAmountAndExchangesDoubleAmountsInvalid) { const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}, TransferableCommandResult{exchangeName22, amount21}}; - EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::kTrade), previousResults), + EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::Trade), previousResults), std::make_pair(MonetaryAmount(), ExchangeNames())); } TEST_F(TransferableCommandResultTest, ComputeTradeAmountAndExchangesWithFullInformation) { const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}, TransferableCommandResult{exchangeName22, amount21}}; - EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::kTrade, MonetaryAmount(100, "DOGE")), + EXPECT_EQ(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::Trade, MonetaryAmount(100, "DOGE")), previousResults), std::make_pair(MonetaryAmount(100, "DOGE"), ExchangeNames())); } @@ -85,10 +85,10 @@ TEST_F(TransferableCommandResultTest, ComputeTradeAmountAndExchangesUnexpectedSi const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}, TransferableCommandResult{exchangeName22, amount21}}; - EXPECT_THROW(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::kTrade, MonetaryAmount(), true), + EXPECT_THROW(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::Trade, MonetaryAmount(), true), previousResults), exception); - EXPECT_THROW(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::kTrade, MonetaryAmount(), false, + EXPECT_THROW(ComputeTradeAmountAndExchanges(createCommand(CoincenterCommandType::Trade, MonetaryAmount(), false, ExchangeNames({exchangeName11})), previousResults), exception); @@ -98,7 +98,7 @@ TEST_F(TransferableCommandResultTest, ComputeWithdrawAmountInvalidSingleExchange const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}}; EXPECT_THROW(ComputeWithdrawAmount( - createCommand(CoincenterCommandType::kTrade, amount12, false, ExchangeNames({exchangeName11})), + createCommand(CoincenterCommandType::Trade, amount12, false, ExchangeNames({exchangeName11})), previousResults), exception); } @@ -107,7 +107,7 @@ TEST_F(TransferableCommandResultTest, ComputeWithdrawAmountValidSingleExchange) const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}}; EXPECT_EQ(ComputeWithdrawAmount( - createCommand(CoincenterCommandType::kTrade, MonetaryAmount(), false, ExchangeNames({exchangeName12})), + createCommand(CoincenterCommandType::Trade, MonetaryAmount(), false, ExchangeNames({exchangeName12})), previousResults), std::make_pair(amount11, exchangeName11)); } @@ -117,7 +117,7 @@ TEST_F(TransferableCommandResultTest, ComputeWithdrawAmountInvalidSingleExchange TransferableCommandResult{exchangeName21, amount12}}; EXPECT_EQ(ComputeWithdrawAmount( - createCommand(CoincenterCommandType::kTrade, MonetaryAmount(), false, ExchangeNames({exchangeName12})), + createCommand(CoincenterCommandType::Trade, MonetaryAmount(), false, ExchangeNames({exchangeName12})), previousResults), std::make_pair(MonetaryAmount(), ExchangeName())); } @@ -125,7 +125,7 @@ TEST_F(TransferableCommandResultTest, ComputeWithdrawAmountInvalidSingleExchange TEST_F(TransferableCommandResultTest, ComputeWithdrawAmountInvalidTooManyExchanges) { const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}}; - EXPECT_THROW(ComputeWithdrawAmount(createCommand(CoincenterCommandType::kTrade, amount12, false, + EXPECT_THROW(ComputeWithdrawAmount(createCommand(CoincenterCommandType::Trade, amount12, false, ExchangeNames({exchangeName11, exchangeName12, exchangeName22})), previousResults), exception); @@ -134,13 +134,13 @@ TEST_F(TransferableCommandResultTest, ComputeWithdrawAmountInvalidTooManyExchang TEST_F(TransferableCommandResultTest, ComputeWithdrawAmountInvalidNoExchange) { const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}}; - EXPECT_THROW(ComputeWithdrawAmount(createCommand(CoincenterCommandType::kTrade), previousResults), exception); + EXPECT_THROW(ComputeWithdrawAmount(createCommand(CoincenterCommandType::Trade), previousResults), exception); } TEST_F(TransferableCommandResultTest, ComputeWithdrawAmountValidDoubleExchange) { const TransferableCommandResult previousResults[] = {TransferableCommandResult{exchangeName11, amount11}}; - EXPECT_EQ(ComputeWithdrawAmount(createCommand(CoincenterCommandType::kTrade, amount22, false, + EXPECT_EQ(ComputeWithdrawAmount(createCommand(CoincenterCommandType::Trade, amount22, false, ExchangeNames({exchangeName12, exchangeName21})), previousResults), std::make_pair(amount22, exchangeName12)); diff --git a/src/http-request/include/curloptions.hpp b/src/http-request/include/curloptions.hpp index 521cf5ab..9237d752 100644 --- a/src/http-request/include/curloptions.hpp +++ b/src/http-request/include/curloptions.hpp @@ -18,7 +18,7 @@ class CurlOptions { using HttpHeaders = FlatKeyValueString<'\0', ':'>; enum class Verbose : int8_t { kOff, kOn }; - enum class PostDataFormat : int8_t { kString, kJson }; + enum class PostDataFormat : int8_t { kString, json }; explicit CurlOptions(HttpRequestType requestType, Verbose verbose = Verbose::kOff) : _verbose(verbose == Verbose::kOn), _requestType(requestType) {} @@ -26,7 +26,7 @@ class CurlOptions { CurlOptions(HttpRequestType requestType, CurlPostData postData, PostDataFormat postDataFormat = PostDataFormat::kString, Verbose verbose = Verbose::kOff) : _postdata(std::move(postData)), _verbose(verbose == Verbose::kOn), _requestType(requestType) { - if (postDataFormat == PostDataFormat::kJson) { + if (postDataFormat == PostDataFormat::json) { setPostDataInJsonFormat(); } } diff --git a/src/http-request/include/request-retry.hpp b/src/http-request/include/request-retry.hpp index 3055b6cf..3960d896 100644 --- a/src/http-request/include/request-retry.hpp +++ b/src/http-request/include/request-retry.hpp @@ -5,7 +5,7 @@ #include #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_type_traits.hpp" #include "curlhandle.hpp" @@ -31,7 +31,7 @@ class RequestRetry { /// responseStatus should be a functor taking a single json by const reference argument, returning Status::kResponseOK /// if success, Status::kResponseError in case of error. template - json queryJson(const StringType &endpoint, ResponseStatusT responseStatus) { + json::container queryJson(const StringType &endpoint, ResponseStatusT responseStatus) { return queryJson(endpoint, responseStatus, [](CurlOptions &) {}); } @@ -42,10 +42,11 @@ class RequestRetry { /// postDataUpdateFunc is a functor that takes the embedded CurlOptions's reference as single argument and updates it /// before each query template - json queryJson(const StringType &endpoint, ResponseStatusT responseStatus, PostDataFuncT postDataUpdateFunc) { + json::container queryJson(const StringType &endpoint, ResponseStatusT responseStatus, + PostDataFuncT postDataUpdateFunc) { decltype(_queryRetryPolicy.nbMaxRetries) nbRetries = 0; auto sleepingTime = _queryRetryPolicy.initialRetryDelay; - json ret; + json::container ret; do { if (nbRetries != 0) { @@ -58,7 +59,7 @@ class RequestRetry { postDataUpdateFunc(_curlOptions); static constexpr bool kAllowExceptions = false; - ret = json::parse(_curlHandle.query(endpoint, _curlOptions), nullptr, kAllowExceptions); + ret = json::container::parse(_curlHandle.query(endpoint, _curlOptions), nullptr, kAllowExceptions); } while ((ret.is_discarded() || responseStatus(ret) == Status::kResponseError) && ++nbRetries <= _queryRetryPolicy.nbMaxRetries); @@ -67,7 +68,7 @@ class RequestRetry { switch (_queryRetryPolicy.tooManyFailuresPolicy) { case QueryRetryPolicy::TooManyFailuresPolicy::kReturnEmpty: log::error("Too many query errors, returning empty result"); - ret = json::object(); + ret = json::container::object(); break; case QueryRetryPolicy::TooManyFailuresPolicy::kThrowException: throw exception("Too many query errors"); diff --git a/src/objects/include/coincentercommandtype.hpp b/src/objects/include/coincentercommandtype.hpp deleted file mode 100644 index 49967dc6..00000000 --- a/src/objects/include/coincentercommandtype.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include - -namespace cct { - -enum class CoincenterCommandType : int8_t { - kHealthCheck, - kCurrencies, - kMarkets, - kConversion, - kConversionPath, - kLastPrice, - kTicker, - kOrderbook, - kLastTrades, - kLast24hTradedVolume, - kWithdrawFees, - - kBalance, - kDepositInfo, - kOrdersClosed, - kOrdersOpened, - kOrdersCancel, - kRecentDeposits, - kRecentWithdraws, - kTrade, - kBuy, - kSell, - kWithdrawApply, - kDustSweeper, - - kMarketData, - kReplay, - kReplayMarkets, - - kLast -}; - -std::string_view CoincenterCommandTypeToString(CoincenterCommandType type); - -CoincenterCommandType CoincenterCommandTypeFromString(std::string_view str); - -bool IsAnyTrade(CoincenterCommandType type); -} // namespace cct diff --git a/src/objects/include/coincenterinfo.hpp b/src/objects/include/coincenterinfo.hpp index 6a186fb1..d515bec5 100644 --- a/src/objects/include/coincenterinfo.hpp +++ b/src/objects/include/coincenterinfo.hpp @@ -12,8 +12,9 @@ #include "currencycode.hpp" #include "exchangeconfig.hpp" #include "exchangeconfigmap.hpp" -#include "generalconfig.hpp" +#include "general-config.hpp" #include "loadconfiguration.hpp" +#include "logginginfo.hpp" #include "monitoringinfo.hpp" #include "reader.hpp" #include "runmodes.hpp" @@ -30,8 +31,8 @@ class CoincenterInfo { using StableCoinsMap = std::unordered_map; explicit CoincenterInfo(settings::RunMode runMode, const LoadConfiguration &loadConfiguration = LoadConfiguration(), - GeneralConfig &&generalConfig = GeneralConfig(), - MonitoringInfo &&monitoringInfo = MonitoringInfo(), + schema::GeneralConfig &&generalConfig = schema::GeneralConfig(), + LoggingInfo &&loggingInfo = LoggingInfo(), MonitoringInfo &&monitoringInfo = MonitoringInfo(), const Reader ¤cyAcronymsReader = Reader(), const Reader &stableCoinsReader = Reader(), const Reader ¤cyPrefixesReader = Reader()); @@ -61,15 +62,13 @@ class CoincenterInfo { AbstractMetricGateway *metricGatewayPtr() const { return _metricGatewayPtr.get(); } - const GeneralConfig &generalConfig() const { return _generalConfig; } + const schema::GeneralConfig &generalConfig() const { return _generalConfig; } - const LoggingInfo &loggingInfo() const { return _generalConfig.loggingInfo(); } + const LoggingInfo &loggingInfo() const { return _loggingInfo; } - const RequestsConfig &requestsConfig() const { return _generalConfig.requestsConfig(); } + ApiOutputType apiOutputType() const { return _generalConfig.apiOutputType; } - ApiOutputType apiOutputType() const { return _generalConfig.apiOutputType(); } - - Duration fiatConversionQueryRate() const { return _generalConfig.fiatConversionQueryRate(); } + Duration fiatConversionQueryRate() const { return _generalConfig.fiatConversion.rate.duration; } private: CurrencyEquivalentAcronymMap _currencyEquiAcronymMap; @@ -78,7 +77,8 @@ class CoincenterInfo { ExchangeConfigMap _exchangeConfigMap; settings::RunMode _runMode; string _dataDir; - GeneralConfig _generalConfig; + schema::GeneralConfig _generalConfig; + LoggingInfo _loggingInfo; std::unique_ptr _metricGatewayPtr; MonitoringInfo _monitoringInfo; int _minPrefixLen = std::numeric_limits::max(); diff --git a/src/objects/include/exchangeconfigmap.hpp b/src/objects/include/exchangeconfigmap.hpp index 4f3bc77a..dcf0df95 100644 --- a/src/objects/include/exchangeconfigmap.hpp +++ b/src/objects/include/exchangeconfigmap.hpp @@ -3,7 +3,7 @@ #include #include -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "exchangeconfig.hpp" namespace cct { @@ -15,5 +15,5 @@ static constexpr std::string_view kPreferredPaymentCurrenciesOptName = "preferre using ExchangeConfigMap = std::map>; /// @brief Builds the exchange info map based on given json -ExchangeConfigMap ComputeExchangeConfigMap(std::string_view fileName, const json &jsonData); +ExchangeConfigMap ComputeExchangeConfigMap(std::string_view fileName, const json::container &jsonData); } // namespace cct \ No newline at end of file diff --git a/src/objects/include/exchangeconfigparser.hpp b/src/objects/include/exchangeconfigparser.hpp index 67b87a8b..848a5e78 100644 --- a/src/objects/include/exchangeconfigparser.hpp +++ b/src/objects/include/exchangeconfigparser.hpp @@ -4,7 +4,7 @@ #include "cct_exception.hpp" #include "cct_fixedcapacityvector.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_string.hpp" #include "cct_vector.hpp" #include "currencycode.hpp" @@ -16,7 +16,7 @@ namespace cct { class LoadConfiguration; -json LoadExchangeConfigData(const LoadConfiguration& loadConfiguration); +json::container LoadExchangeConfigData(const LoadConfiguration& loadConfiguration); /// Represents a top level option in the exchange config file class TopLevelOption { @@ -31,7 +31,8 @@ class TopLevelOption { /// @param optionName top level option name /// @param defaultJsonData the json containing the personal exchange config data /// @param personalJsonData the json containing the personal exchange config data - TopLevelOption(std::string_view optionName, const json& defaultJsonData, const json& personalJsonData); + TopLevelOption(std::string_view optionName, const json::container& defaultJsonData, + const json::container& personalJsonData); /// Get the first defined string of given sub option name, traversing the config options from bottom to up. std::string_view getStr(std::string_view exchangeName, std::string_view subOptionName1, @@ -70,10 +71,10 @@ class TopLevelOption { return getArray(exchangeName, subOptionName1, subOptionName2); } - const json& getReadValues() const { return _readValues; } + const json::container& getReadValues() const { return _readValues; } private: - using JsonIt = json::const_iterator; + using JsonIt = json::container::const_iterator; struct DataSource { JsonIt exchangeIt(std::string_view exchangeName) const { @@ -114,7 +115,7 @@ class TopLevelOption { return ret; } - json _readValues; + json::container _readValues; FixedCapacityVector _orderedDataSource; }; } // namespace cct \ No newline at end of file diff --git a/src/objects/include/generalconfig.hpp b/src/objects/include/generalconfig.hpp deleted file mode 100644 index 1a30b897..00000000 --- a/src/objects/include/generalconfig.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -#include "apioutputtype.hpp" -#include "cct_json.hpp" -#include "logginginfo.hpp" -#include "requestsconfig.hpp" -#include "timedef.hpp" -#include "trading-config.hpp" - -namespace cct { - -class GeneralConfig { - public: - static constexpr std::string_view kFilename = "generalconfig.json"; - - static json LoadFile(std::string_view dataDir); - - GeneralConfig() = default; - - GeneralConfig(LoggingInfo &&loggingInfo, RequestsConfig &&requestsConfig, TradingConfig &&tradingConfig, - Duration fiatConversionQueryRate, ApiOutputType apiOutputType); - - const LoggingInfo &loggingInfo() const { return _loggingInfo; } - - const RequestsConfig &requestsConfig() const { return _requestsConfig; } - - const TradingConfig &tradingConfig() const { return _tradingConfig; } - - ApiOutputType apiOutputType() const { return _apiOutputType; } - - Duration fiatConversionQueryRate() const { return _fiatConversionQueryRate; } - - private: - LoggingInfo _loggingInfo{LoggingInfo::WithLoggersCreation::kYes}; - RequestsConfig _requestsConfig; - TradingConfig _tradingConfig; - Duration _fiatConversionQueryRate = std::chrono::hours(8); - ApiOutputType _apiOutputType = ApiOutputType::kFormattedTable; -}; - -} // namespace cct \ No newline at end of file diff --git a/src/objects/include/generalconfigdefault.hpp b/src/objects/include/generalconfigdefault.hpp deleted file mode 100644 index 460e0ec5..00000000 --- a/src/objects/include/generalconfigdefault.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include "cct_json.hpp" - -namespace cct { -struct GeneralConfigDefault { - static json Prod() { - // Use a static method instead of an inline static const variable to avoid the infamous 'static initialization order - // fiasco' problem. - - static const json kProd = R"( -{ - "apiOutputType": "table", - "fiatConversion": { - "rate": "8h" - }, - "log": { - "activityTracking": { - "commandTypes": [ - "Trade", - "Buy", - "Sell", - "Withdraw", - "DustSweeper" - ], - "dateFileNameFormat": "%Y-%m", - "withSimulatedCommands": false - }, - "consoleLevel": "info", - "fileLevel": "debug", - "maxFileSize": "5Mi", - "maxNbFiles": 20 - }, - "requests": { - "concurrency": { - "nbMaxParallelRequests": 1 - } - }, - "trading": { - "automation": { - "deserialization": { - "loadChunkDuration": "1w" - }, - "startingContext": { - "startBaseAmountEquivalent": "1000 EUR", - "startQuoteAmountEquivalent": "1000 EUR" - } - } - } -} -)"_json; - return kProd; - } -}; -} // namespace cct \ No newline at end of file diff --git a/src/objects/include/logginginfo.hpp b/src/objects/include/logginginfo.hpp index 6fa1e048..4fff7959 100644 --- a/src/objects/include/logginginfo.hpp +++ b/src/objects/include/logginginfo.hpp @@ -5,11 +5,11 @@ #include "cct_const.hpp" #include "cct_flatset.hpp" -#include "cct_json.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "coincentercommandtype.hpp" #include "file.hpp" +#include "log-config.hpp" namespace cct { @@ -32,7 +32,7 @@ class LoggingInfo { std::string_view dataDir = kDefaultDataDir); /// Creates a logging info from general config json file. - LoggingInfo(WithLoggersCreation withLoggersCreation, std::string_view dataDir, const json &generalConfigJsonLogPart); + LoggingInfo(WithLoggersCreation withLoggersCreation, std::string_view dataDir, const schema::LogConfig &logConfig); LoggingInfo(const LoggingInfo &) = delete; LoggingInfo(LoggingInfo &&rhs) noexcept; diff --git a/src/objects/include/requestsconfig.hpp b/src/objects/include/requestsconfig.hpp deleted file mode 100644 index 375a2277..00000000 --- a/src/objects/include/requestsconfig.hpp +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -namespace cct { - -class RequestsConfig { - public: - explicit RequestsConfig(int nbMaxParallelRequests = 1); - - int nbMaxParallelRequests(int nbMaxAccounts) const; - - private: - int _nbMaxParallelRequests; -}; - -} // namespace cct \ No newline at end of file diff --git a/src/objects/include/trading-config.hpp b/src/objects/include/trading-config.hpp deleted file mode 100644 index b265e9dc..00000000 --- a/src/objects/include/trading-config.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include "automation-config.hpp" - -namespace cct { -class TradingConfig { - public: - TradingConfig() noexcept = default; - - TradingConfig(AutomationConfig automationConfig) : _automationConfig(std::move(automationConfig)) {} - - const AutomationConfig &automationConfig() const { return _automationConfig; } - - private: - AutomationConfig _automationConfig; -}; -} // namespace cct \ No newline at end of file diff --git a/src/objects/src/coincenterinfo.cpp b/src/objects/src/coincenterinfo.cpp index b02d16a0..6234d17f 100644 --- a/src/objects/src/coincenterinfo.cpp +++ b/src/objects/src/coincenterinfo.cpp @@ -6,15 +6,16 @@ #include #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "currencycode.hpp" #include "exchangeconfig.hpp" #include "exchangeconfigmap.hpp" #include "exchangeconfigparser.hpp" -#include "generalconfig.hpp" +#include "general-config.hpp" #include "loadconfiguration.hpp" +#include "logginginfo.hpp" #include "monitoringinfo.hpp" #include "reader.hpp" #include "runmodes.hpp" @@ -32,7 +33,7 @@ namespace cct { namespace { CoincenterInfo::CurrencyEquivalentAcronymMap ComputeCurrencyEquivalentAcronymMap( const Reader& currencyAcronymsTranslatorReader) { - json jsonData = currencyAcronymsTranslatorReader.readAllJson(); + json::container jsonData = currencyAcronymsTranslatorReader.readAllJson(); CoincenterInfo::CurrencyEquivalentAcronymMap map; map.reserve(jsonData.size()); for (const auto& [key, value] : jsonData.items()) { @@ -43,7 +44,7 @@ CoincenterInfo::CurrencyEquivalentAcronymMap ComputeCurrencyEquivalentAcronymMap } CoincenterInfo::StableCoinsMap ComputeStableCoinsMap(const Reader& stableCoinsReader) { - json jsonData = stableCoinsReader.readAllJson(); + json::container jsonData = stableCoinsReader.readAllJson(); CoincenterInfo::StableCoinsMap ret; for (const auto& [key, value] : jsonData.items()) { log::trace("Stable Crypto {} <=> {}", key, value.get()); @@ -61,9 +62,9 @@ using MetricGatewayType = VoidMetricGateway; } // namespace CoincenterInfo::CoincenterInfo(settings::RunMode runMode, const LoadConfiguration& loadConfiguration, - GeneralConfig&& generalConfig, MonitoringInfo&& monitoringInfo, - const Reader& currencyAcronymsReader, const Reader& stableCoinsReader, - const Reader& currencyPrefixesReader) + schema::GeneralConfig&& generalConfig, LoggingInfo&& loggingInfo, + MonitoringInfo&& monitoringInfo, const Reader& currencyAcronymsReader, + const Reader& stableCoinsReader, const Reader& currencyPrefixesReader) : _currencyEquiAcronymMap(ComputeCurrencyEquivalentAcronymMap(currencyAcronymsReader)), _stableCoinsMap(ComputeStableCoinsMap(stableCoinsReader)), _exchangeConfigMap(ComputeExchangeConfigMap(loadConfiguration.exchangeConfigFileName(), @@ -71,11 +72,12 @@ CoincenterInfo::CoincenterInfo(settings::RunMode runMode, const LoadConfiguratio _runMode(runMode), _dataDir(loadConfiguration.dataDir()), _generalConfig(std::move(generalConfig)), + _loggingInfo(std::move(loggingInfo)), _metricGatewayPtr(_runMode == settings::RunMode::kProd && monitoringInfo.useMonitoring() ? new MetricGatewayType(monitoringInfo) : nullptr), _monitoringInfo(std::move(monitoringInfo)) { - json jsonData = currencyPrefixesReader.readAllJson(); + json::container jsonData = currencyPrefixesReader.readAllJson(); for (auto& [prefix, acronym_prefix] : jsonData.items()) { log::trace("Currency prefix {} <=> {}", prefix, acronym_prefix.get()); _minPrefixLen = std::min(_minPrefixLen, static_cast(prefix.length())); diff --git a/src/objects/src/exchangeconfigdefault.hpp b/src/objects/src/exchangeconfigdefault.hpp index 93e48258..73e3a466 100644 --- a/src/objects/src/exchangeconfigdefault.hpp +++ b/src/objects/src/exchangeconfigdefault.hpp @@ -1,14 +1,14 @@ #pragma once -#include "cct_json.hpp" +#include "cct_json-container.hpp" namespace cct { struct ExchangeConfigDefault { - static json Prod() { + static json::container Prod() { // Use a static method instead of an inline static const variable to avoid the infamous 'static initialization order // fiasco' problem. - static const json kProd = R"( + static const json::container kProd = R"( { "asset": { "default": { @@ -148,11 +148,11 @@ struct ExchangeConfigDefault { } /// ExchangeInfos for tests only. Some tests rely on provided values so changing them may make them fail. - static json Test() { + static json::container Test() { // Use a static method instead of an inline static const variable to avoid the infamous 'static initialization order // fiasco' problem. - static const json kTest = R"( + static const json::container kTest = R"( { "asset": { "default": { diff --git a/src/objects/src/exchangeconfigmap.cpp b/src/objects/src/exchangeconfigmap.cpp index 16f9e6f6..e76f337b 100644 --- a/src/objects/src/exchangeconfigmap.cpp +++ b/src/objects/src/exchangeconfigmap.cpp @@ -5,7 +5,7 @@ #include #include "cct_const.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "exchangeconfig.hpp" @@ -21,10 +21,10 @@ namespace cct { -ExchangeConfigMap ComputeExchangeConfigMap(std::string_view fileName, const json &jsonData) { +ExchangeConfigMap ComputeExchangeConfigMap(std::string_view fileName, const json::container &jsonData) { ExchangeConfigMap map; - const json &prodDefault = ExchangeConfigDefault::Prod(); + const json::container &prodDefault = ExchangeConfigDefault::Prod(); TopLevelOption assetTopLevelOption(TopLevelOption::kAssetsOptionStr, prodDefault, jsonData); TopLevelOption queryTopLevelOption(TopLevelOption::kQueryOptionStr, prodDefault, jsonData); @@ -98,16 +98,16 @@ ExchangeConfigMap ComputeExchangeConfigMap(std::string_view fileName, const json } // namespace cct // Print json unused values - json readValues; + json::container readValues; readValues.emplace(TopLevelOption::kAssetsOptionStr, assetTopLevelOption.getReadValues()); readValues.emplace(TopLevelOption::kQueryOptionStr, queryTopLevelOption.getReadValues()); readValues.emplace(TopLevelOption::kTradeFeesOptionStr, tradeFeesTopLevelOption.getReadValues()); readValues.emplace(TopLevelOption::kWithdrawOptionStr, withdrawTopLevelOption.getReadValues()); - json diffJson = json::diff(jsonData, readValues); + json::container diffJson = json::container::diff(jsonData, readValues); - for (json &diffElem : diffJson) { + for (json::container &diffElem : diffJson) { std::string_view diffType = diffElem["op"].get(); string jsonPath = std::move(diffElem["path"].get_ref()); diff --git a/src/objects/src/exchangeconfigparser.cpp b/src/objects/src/exchangeconfigparser.cpp index 15a8b982..4bc7bfa3 100644 --- a/src/objects/src/exchangeconfigparser.cpp +++ b/src/objects/src/exchangeconfigparser.cpp @@ -5,7 +5,7 @@ #include #include "cct_exception.hpp" -#include "cct_json.hpp" +#include "cct_json-container.hpp" #include "cct_log.hpp" #include "cct_string.hpp" #include "currencycodevector.hpp" @@ -21,17 +21,17 @@ constexpr std::string_view kDefaultPart = "default"; constexpr std::string_view kExchangePart = "exchange"; } // namespace -json LoadExchangeConfigData(const LoadConfiguration& loadConfiguration) { +json::container LoadExchangeConfigData(const LoadConfiguration& loadConfiguration) { switch (loadConfiguration.exchangeConfigFileType()) { case LoadConfiguration::ExchangeConfigFileType::kProd: { std::string_view filename = loadConfiguration.exchangeConfigFileName(); File exchangeConfigFile(loadConfiguration.dataDir(), File::Type::kStatic, filename, File::IfError::kNoThrow); - json jsonData = ExchangeConfigDefault::Prod(); - json exchangeConfigJsonData = exchangeConfigFile.readAllJson(); + json::container jsonData = ExchangeConfigDefault::Prod(); + json::container exchangeConfigJsonData = exchangeConfigFile.readAllJson(); if (exchangeConfigJsonData.empty()) { // Create a file with default values. User can then update them as he wishes. log::warn("No {} file found. Creating a default one which can be updated freely at your convenience", filename); - exchangeConfigFile.write(jsonData); + exchangeConfigFile.writeJson(jsonData); return jsonData; } for (std::string_view optName : {TopLevelOption::kAssetsOptionStr, TopLevelOption::kQueryOptionStr, @@ -51,8 +51,9 @@ json LoadExchangeConfigData(const LoadConfiguration& loadConfiguration) { } } -TopLevelOption::TopLevelOption(std::string_view optionName, const json& defaultJsonData, const json& personalJsonData) { - for (const json* jsonData : {std::addressof(personalJsonData), std::addressof(defaultJsonData)}) { +TopLevelOption::TopLevelOption(std::string_view optionName, const json::container& defaultJsonData, + const json::container& personalJsonData) { + for (const json::container* jsonData : {std::addressof(personalJsonData), std::addressof(defaultJsonData)}) { JsonIt optIt = jsonData->find(optionName); if (optIt != jsonData->end()) { bool isPersonal = jsonData == std::addressof(personalJsonData); @@ -103,7 +104,7 @@ TopLevelOption::JsonIt TopLevelOption::get(std::string_view exchangeName, std::s void TopLevelOption::setReadValue(const DataSource& dataSource, std::string_view exchangeName, std::string_view subOptionName1, std::string_view subOptionName2, JsonIt valueIt) { - json emptyJson; + json::container emptyJson; bool isExchange = dataSource.isExchange; auto readValuesExchangePartIt = _readValues.emplace(isExchange ? kExchangePart : kDefaultPart, emptyJson).first; if (isExchange) { diff --git a/src/objects/src/generalconfig.cpp b/src/objects/src/generalconfig.cpp deleted file mode 100644 index 96494ec1..00000000 --- a/src/objects/src/generalconfig.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "generalconfig.hpp" - -#include -#include - -#include "apioutputtype.hpp" -#include "cct_json.hpp" -#include "cct_log.hpp" -#include "file.hpp" -#include "generalconfigdefault.hpp" -#include "logginginfo.hpp" -#include "requestsconfig.hpp" -#include "timedef.hpp" -#include "trading-config.hpp" - -namespace cct { - -GeneralConfig::GeneralConfig(LoggingInfo &&loggingInfo, RequestsConfig &&requestsConfig, TradingConfig &&tradingConfig, - Duration fiatConversionQueryRate, ApiOutputType apiOutputType) - : _loggingInfo(std::move(loggingInfo)), - _requestsConfig(std::move(requestsConfig)), - _tradingConfig(std::move(tradingConfig)), - _fiatConversionQueryRate(fiatConversionQueryRate), - _apiOutputType(apiOutputType) {} - -json GeneralConfig::LoadFile(std::string_view dataDir) { - File generalConfigFile(dataDir, File::Type::kStatic, GeneralConfig::kFilename, File::IfError::kNoThrow); - json jsonData = GeneralConfigDefault::Prod(); - json generalConfigJsonData = generalConfigFile.readAllJson(); - if (generalConfigJsonData.empty()) { - // Create a file with default values. User can then update them as he wishes. - log::warn("No {} file found. Creating a default one which can be updated freely at your convenience", - GeneralConfig::kFilename); - generalConfigFile.write(jsonData); - } else { - jsonData.update(generalConfigJsonData, true); - if (jsonData != generalConfigJsonData) { - log::warn("File {} updated with default values of all supported options", GeneralConfig::kFilename); - generalConfigFile.write(jsonData); - } - } - return jsonData; -} - -} // namespace cct \ No newline at end of file diff --git a/src/objects/src/logginginfo.cpp b/src/objects/src/logginginfo.cpp index 36d73441..3a672ff0 100644 --- a/src/objects/src/logginginfo.cpp +++ b/src/objects/src/logginginfo.cpp @@ -11,15 +11,13 @@ #include #include "cct_fixedcapacityvector.hpp" -#include "cct_json.hpp" #include "cct_log.hpp" #include "cct_string.hpp" -#include "coincentercommandtype.hpp" #include "file.hpp" +#include "log-config.hpp" #include "parseloglevel.hpp" #include "timedef.hpp" #include "timestring.hpp" -#include "unitsparser.hpp" namespace cct { @@ -30,28 +28,25 @@ LoggingInfo::LoggingInfo(WithLoggersCreation withLoggersCreation, std::string_vi } LoggingInfo::LoggingInfo(WithLoggersCreation withLoggersCreation, std::string_view dataDir, - const json &generalConfigJsonLogPart) + const schema::LogConfig &logConfig) : _dataDir(dataDir), - _maxFileSizeLogFileInBytes(ParseNumberOfBytes(generalConfigJsonLogPart["maxFileSize"].get())), - _maxNbLogFiles(generalConfigJsonLogPart["maxNbFiles"].get()), - _logLevelConsolePos( - LogPosFromLogStr(generalConfigJsonLogPart[LoggingInfo::kJsonFieldConsoleLevelName].get())), - _logLevelFilePos( - LogPosFromLogStr(generalConfigJsonLogPart[LoggingInfo::kJsonFieldFileLevelName].get())) { + _maxFileSizeLogFileInBytes(logConfig.maxFileSize.sizeInBytes), + _maxNbLogFiles(logConfig.maxNbFiles), + _logLevelConsolePos(LogPosFromLogStr(logConfig.consoleLevel)), + _logLevelFilePos(LogPosFromLogStr(logConfig.fileLevel)) { if (withLoggersCreation == WithLoggersCreation::kYes) { createLoggers(); } - const json &activityTrackingPart = generalConfigJsonLogPart["activityTracking"]; - const json &commandTypes = activityTrackingPart["commandTypes"]; + const schema::ActivityTrackingConfig &activityTrackingConfig = logConfig.activityTracking; - _trackedCommandTypes.reserve(static_cast(commandTypes.size())); - std::ranges::transform( - commandTypes, std::inserter(_trackedCommandTypes, _trackedCommandTypes.end()), - [](const json &elem) { return CoincenterCommandTypeFromString(elem.get()); }); + _trackedCommandTypes.reserve( + static_cast(activityTrackingConfig.commandTypes.size())); + std::ranges::copy(activityTrackingConfig.commandTypes, + std::inserter(_trackedCommandTypes, _trackedCommandTypes.end())); - _dateFormatStrActivityFiles = activityTrackingPart["dateFileNameFormat"]; - _alsoLogActivityForSimulatedCommands = activityTrackingPart["withSimulatedCommands"].get(); + _dateFormatStrActivityFiles = activityTrackingConfig.dateFileNameFormat; + _alsoLogActivityForSimulatedCommands = activityTrackingConfig.withSimulatedCommands; } LoggingInfo::LoggingInfo(LoggingInfo &&rhs) noexcept diff --git a/src/objects/src/requestsconfig.cpp b/src/objects/src/requestsconfig.cpp deleted file mode 100644 index 1ebcf961..00000000 --- a/src/objects/src/requestsconfig.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "requestsconfig.hpp" - -#include - -#include "cct_invalid_argument_exception.hpp" - -namespace cct { -RequestsConfig::RequestsConfig(int nbMaxParallelRequests) : _nbMaxParallelRequests(nbMaxParallelRequests) { - if (nbMaxParallelRequests < 1) { - throw invalid_argument("Maximum number of parallel requests should be at least 1"); - } -} - -int RequestsConfig::nbMaxParallelRequests(int nbMaxAccounts) const { - return std::min(_nbMaxParallelRequests, nbMaxAccounts); -} - -} // namespace cct \ No newline at end of file diff --git a/src/objects/src/wallet.cpp b/src/objects/src/wallet.cpp index af624b27..fd98e701 100644 --- a/src/objects/src/wallet.cpp +++ b/src/objects/src/wallet.cpp @@ -1,7 +1,6 @@ #include "wallet.hpp" #include -#include #include #include @@ -23,13 +22,13 @@ bool Wallet::ValidateWallet(WalletCheck walletCheck, const ExchangeName &exchang log::debug("No wallet validation from file, consider OK"); return true; } - DepositAddresses depositAddresses = ReadDepositAddresses(walletCheck.dataDir()); + auto depositAddresses = ReadDepositAddresses(walletCheck.dataDir()); auto exchangeNameIt = depositAddresses.find(exchangeName.name()); if (exchangeNameIt == depositAddresses.end()) { log::warn("No deposit addresses found in {} for {}", kDepositAddressesFileName, exchangeName); return false; } - const ExchangeDepositAddresses &exchangeDepositAddresses = exchangeNameIt->second; + const auto &exchangeDepositAddresses = exchangeNameIt->second; bool uniqueKeyName = true; for (const auto &[privateExchangeKeyName, accountDepositAddresses] : exchangeDepositAddresses) { if (exchangeName.keyName().empty()) { diff --git a/src/objects/test/coincenterinfo_test.cpp b/src/objects/test/coincenterinfo_test.cpp index 9945e063..412b4484 100644 --- a/src/objects/test/coincenterinfo_test.cpp +++ b/src/objects/test/coincenterinfo_test.cpp @@ -6,7 +6,7 @@ #include "cct_const.hpp" #include "cct_string.hpp" #include "currencycode.hpp" -#include "generalconfig.hpp" +#include "general-config.hpp" #include "loadconfiguration.hpp" #include "monitoringinfo.hpp" #include "reader_mock.hpp" @@ -36,8 +36,9 @@ class CoincenterInfoTest : public ::testing::Test { MockReader currencyPrefixesReader; CoincenterInfo createCoincenterInfo() const { - return CoincenterInfo(settings::RunMode::kTestKeysWithProxy, loadConfiguration, GeneralConfig(), MonitoringInfo(), - currencyAcronymsReader, stableCoinsReader, currencyPrefixesReader); + return CoincenterInfo(settings::RunMode::kTestKeysWithProxy, loadConfiguration, schema::GeneralConfig(), + LoggingInfo(), MonitoringInfo(), currencyAcronymsReader, stableCoinsReader, + currencyPrefixesReader); } }; diff --git a/src/objects/test/logginginfo_test.cpp b/src/objects/test/logginginfo_test.cpp index 0cf55738..abacc3c2 100644 --- a/src/objects/test/logginginfo_test.cpp +++ b/src/objects/test/logginginfo_test.cpp @@ -6,7 +6,7 @@ #include "cct_const.hpp" #include "cct_log.hpp" -#include "generalconfigdefault.hpp" +#include "log-config.hpp" namespace cct { TEST(LoggingInfo, SimpleConstructor) { @@ -20,7 +20,7 @@ TEST(LoggingInfo, SimpleConstructor) { } TEST(LoggingInfo, ConstructorFromJson) { - LoggingInfo loggingInfo(LoggingInfo::WithLoggersCreation::kYes, kDefaultDataDir, GeneralConfigDefault::Prod()["log"]); + LoggingInfo loggingInfo(LoggingInfo::WithLoggersCreation::kYes, kDefaultDataDir, schema::LogConfig()); log::info("test"); } diff --git a/src/objects/test/writer_mock.hpp b/src/objects/test/writer_mock.hpp index ce198abd..2f441c72 100644 --- a/src/objects/test/writer_mock.hpp +++ b/src/objects/test/writer_mock.hpp @@ -8,7 +8,7 @@ namespace cct { class MockWriter : public Writer { public: - MOCK_METHOD(int, write, (const json &, Writer::Mode), (const override)); + MOCK_METHOD(int, write, (const json::container &, Writer::Mode), (const override)); }; } // namespace cct \ No newline at end of file diff --git a/src/schema/CMakeLists.txt b/src/schema/CMakeLists.txt index d4772378..b09c45c2 100644 --- a/src/schema/CMakeLists.txt +++ b/src/schema/CMakeLists.txt @@ -9,4 +9,25 @@ add_unit_test( test/deposit-addresses_test.cpp LIBRARIES coincenter_schema +) + +add_unit_test( + duration-schema_test + test/duration-schema_test.cpp + LIBRARIES + coincenter_schema +) + +add_unit_test( + general-config_test + test/general-config_test.cpp + LIBRARIES + coincenter_schema +) + +add_unit_test( + size-bytes-schema_test + test/size-bytes-schema_test.cpp + LIBRARIES + coincenter_schema ) \ No newline at end of file diff --git a/src/schema/include/deposit-addresses.hpp b/src/schema/include/deposit-addresses.hpp index 9cb5ac43..ee5385b0 100644 --- a/src/schema/include/deposit-addresses.hpp +++ b/src/schema/include/deposit-addresses.hpp @@ -8,12 +8,16 @@ namespace cct { +namespace schema { + using AccountDepositAddresses = std::map>; using ExchangeDepositAddresses = std::map>; using DepositAddresses = std::map>; -DepositAddresses ReadDepositAddresses(std::string_view dataDir); +} // namespace schema + +schema::DepositAddresses ReadDepositAddresses(std::string_view dataDir); } // namespace cct diff --git a/src/schema/include/duration-schema.hpp b/src/schema/include/duration-schema.hpp new file mode 100644 index 00000000..d1337592 --- /dev/null +++ b/src/schema/include/duration-schema.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include + +#include "cct_hash.hpp" +#include "cct_json-serialization.hpp" +#include "durationstring.hpp" +#include "generic-object-json.hpp" +#include "timedef.hpp" + +namespace cct::schema { + +struct Duration { + auto operator<=>(const Duration &) const noexcept = default; + + ::cct::Duration duration{}; +}; + +} // namespace cct::schema + +namespace std { +template <> +struct hash<::cct::schema::Duration> { + auto operator()(const ::cct::schema::Duration &val) const { + return ::cct::HashValue64( + static_cast(std::chrono::duration_cast(val.duration).count())); + } +}; +} // namespace std + +template <> +struct glz::meta<::cct::schema::Duration> { + static constexpr auto value{&::cct::schema::Duration::duration}; +}; + +namespace glz::detail { +template <> +struct from { + template + static void op(auto &&value, is_context auto &&, It &&it, End &&end) { + // used as a value. As a key, the first quote will not be present. + auto endIt = std::find(*it == '"' ? ++it : it, end, '"'); + value.duration = ::cct::ParseDuration(std::string_view(it, endIt)); + it = ++endIt; + } +}; + +template <> +struct to { + template + static void op(auto &&value, Ctx &&, B &&b, IX &&ix) { + char buf[30]; + static constexpr int kNbSignificantUnits = 10; + auto adjustedBuf = ::cct::DurationToBuffer(value.duration, buf, kNbSignificantUnits); + auto valueLen = adjustedBuf.size(); + bool withQuotes = ::cct::details::JsonWithQuotes(b, ix); + int64_t additionalSize = (withQuotes ? 2L : 0L) + static_cast(ix) + static_cast(valueLen) - + static_cast(b.size()); + if (additionalSize > 0) { + b.append(additionalSize, ' '); + } + + if (withQuotes) { + b[ix++] = '"'; + } + std::ranges::copy(adjustedBuf, b.data() + ix); + ix += valueLen; + if (withQuotes) { + b[ix++] = '"'; + } + } +}; +} // namespace glz::detail \ No newline at end of file diff --git a/src/schema/include/general-config.hpp b/src/schema/include/general-config.hpp new file mode 100644 index 00000000..b511ee6e --- /dev/null +++ b/src/schema/include/general-config.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "apioutputtype.hpp" +#include "duration-schema.hpp" +#include "log-config.hpp" +#include "requests-config.hpp" +#include "trading-config.hpp" + +namespace cct { + +namespace schema { + +struct FiatConversionConfig { + Duration rate{std::chrono::hours(8)}; +}; + +struct GeneralConfig { + ApiOutputType apiOutputType{ApiOutputType::table}; + FiatConversionConfig fiatConversion; + LogConfig log; + RequestsConfig requests; + TradingConfig trading; +}; + +} // namespace schema + +schema::GeneralConfig ReadGeneralConfig(std::string_view dataDir); + +} // namespace cct \ No newline at end of file diff --git a/src/schema/include/log-config.hpp b/src/schema/include/log-config.hpp new file mode 100644 index 00000000..30177bb4 --- /dev/null +++ b/src/schema/include/log-config.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "cct_smallvector.hpp" +#include "cct_string.hpp" +#include "coincentercommandtype.hpp" +#include "size-bytes-schema.hpp" + +namespace cct { +namespace schema { + +struct ActivityTrackingConfig { + SmallVector commandTypes{CoincenterCommandType::Trade, CoincenterCommandType::Buy, + CoincenterCommandType::Sell, CoincenterCommandType::Withdraw, + CoincenterCommandType::DustSweeper}; + string dateFileNameFormat{"%Y-%m"}; + bool withSimulatedCommands{false}; +}; + +struct LogConfig { + ActivityTrackingConfig activityTracking; + string consoleLevel{"info"}; + string fileLevel{"debug"}; + SizeBytes maxFileSize{5 * 1024 * 1024}; // 5Mi + int32_t maxNbFiles{20}; +}; +} // namespace schema +} // namespace cct \ No newline at end of file diff --git a/src/schema/include/read-json.hpp b/src/schema/include/read-json.hpp index d6778037..42f9191e 100644 --- a/src/schema/include/read-json.hpp +++ b/src/schema/include/read-json.hpp @@ -2,24 +2,30 @@ #include "cct_exception.hpp" #include "cct_json-serialization.hpp" +#include "file.hpp" #include "reader.hpp" +#include "write-json.hpp" namespace cct { namespace { -constexpr auto JsonOptions = opts{.raw_string = true}; +constexpr auto JsonOptions = json::opts{.raw_string = true}; // NOLINT(readability-implicit-bool-conversion) } -template -T ReadJsonOrThrow(std::string_view strContent) { - T outObject; - - auto ec = read(outObject, strContent); +void ReadJsonOrThrow(std::string_view strContent, auto &outObject) { + auto ec = json::read(outObject, strContent); if (ec) { - throw exception("Error while reading json content: {}", format_error(ec, strContent)); + std::string_view prefixJsonContent = strContent.substr(0, std::min(strContent.size(), 20)); + throw exception("Error while reading json content '{}{}': {}", prefixJsonContent, + prefixJsonContent.size() < strContent.size() ? "..." : "", json::format_error(ec, strContent)); } +} +template +T ReadJsonOrThrow(std::string_view strContent) { + T outObject; + ReadJsonOrThrow(strContent, outObject); return outObject; } @@ -28,4 +34,15 @@ T ReadJsonOrThrow(const Reader &reader) { return ReadJsonOrThrow(reader.readAll()); } +template +T ReadJsonOrCreateFile(const File &file) { + T outObject; + if (file.exists()) { + ReadJsonOrThrow(file.readAll(), outObject); + } else { + file.write(WriteJsonOrThrow(outObject)); + } + return outObject; +} + } // namespace cct \ No newline at end of file diff --git a/src/schema/include/requests-config.hpp b/src/schema/include/requests-config.hpp new file mode 100644 index 00000000..87b35951 --- /dev/null +++ b/src/schema/include/requests-config.hpp @@ -0,0 +1,13 @@ +#pragma once + +namespace cct::schema { + +struct ConcurrencyConfig { + int nbMaxParallelRequests{1}; +}; + +struct RequestsConfig { + ConcurrencyConfig concurrency; +}; + +} // namespace cct::schema \ No newline at end of file diff --git a/src/schema/include/size-bytes-schema.hpp b/src/schema/include/size-bytes-schema.hpp new file mode 100644 index 00000000..4db70dc3 --- /dev/null +++ b/src/schema/include/size-bytes-schema.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include + +#include "cct_hash.hpp" +#include "cct_json-serialization.hpp" +#include "generic-object-json.hpp" +#include "unitsparser.hpp" + +namespace cct::schema { + +struct SizeBytes { + auto operator<=>(const SizeBytes &) const noexcept = default; + + int64_t sizeInBytes{}; +}; + +} // namespace cct::schema + +namespace std { +template <> +struct hash<::cct::schema::SizeBytes> { + auto operator()(const ::cct::schema::SizeBytes &val) const { + return ::cct::HashValue64(static_cast(val.sizeInBytes)); + } +}; +} // namespace std + +template <> +struct glz::meta<::cct::schema::SizeBytes> { + static constexpr auto value{&::cct::schema::SizeBytes::sizeInBytes}; +}; + +namespace glz::detail { +template <> +struct from { + template + static void op(auto &&value, is_context auto &&, It &&it, End &&end) { + // used as a value. As a key, the first quote will not be present. + auto endIt = std::find(*it == '"' ? ++it : it, end, '"'); + value.sizeInBytes = ::cct::ParseNumberOfBytes(std::string_view(it, endIt)); + it = ++endIt; + } +}; + +template <> +struct to { + template + static void op(auto &&value, Ctx &&, B &&b, IX &&ix) { + char buf[30]; + auto adjustedBuf = ::cct::BytesToStr(value.sizeInBytes, buf); + auto valueLen = adjustedBuf.size(); + bool withQuotes = ::cct::details::JsonWithQuotes(b, ix); + int64_t additionalSize = (withQuotes ? 2L : 0L) + static_cast(ix) + static_cast(valueLen) - + static_cast(b.size()); + if (additionalSize > 0) { + b.append(additionalSize, ' '); + } + + if (withQuotes) { + b[ix++] = '"'; + } + std::ranges::copy(adjustedBuf, b.data() + ix); + ix += valueLen; + if (withQuotes) { + b[ix++] = '"'; + } + } +}; +} // namespace glz::detail \ No newline at end of file diff --git a/src/schema/include/trading-config.hpp b/src/schema/include/trading-config.hpp new file mode 100644 index 00000000..d0c868c3 --- /dev/null +++ b/src/schema/include/trading-config.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include "duration-schema.hpp" +#include "monetaryamount.hpp" + +namespace cct::schema { + +struct DeserializationConfig { + Duration loadChunkDuration{std::chrono::weeks(1)}; +}; + +struct StartingContextConfig { + MonetaryAmount startBaseAmountEquivalent{1000, "EUR"}; + MonetaryAmount startQuoteAmountEquivalent{1000, "EUR"}; +}; + +struct AutomationConfig { + DeserializationConfig deserialization; + StartingContextConfig startingContext; +}; + +struct TradingConfig { + AutomationConfig automation; +}; + +} // namespace cct::schema \ No newline at end of file diff --git a/src/schema/include/write-json.hpp b/src/schema/include/write-json.hpp new file mode 100644 index 00000000..9d656421 --- /dev/null +++ b/src/schema/include/write-json.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "cct_exception.hpp" +#include "cct_json-serialization.hpp" +#include "cct_string.hpp" +#include "writer.hpp" + +namespace cct { + +template +string WriteJsonOrThrow(const auto &obj) { + string buf; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::write(obj, buf); + + if (ec) { + throw exception("Error while writing json content: {}", format_error(ec, buf)); + } + + return buf; +} + +} // namespace cct \ No newline at end of file diff --git a/src/schema/src/deposit-addresses.cpp b/src/schema/src/deposit-addresses.cpp index d2139cfb..cdf8cd75 100644 --- a/src/schema/src/deposit-addresses.cpp +++ b/src/schema/src/deposit-addresses.cpp @@ -1,19 +1,16 @@ #include "deposit-addresses.hpp" +#include + #include "cct_const.hpp" #include "file.hpp" #include "read-json.hpp" namespace cct { -namespace { -File GetDepositAddressesFile(std::string_view dataDir) { - return {dataDir, File::Type::kSecret, kDepositAddressesFileName, File::IfError::kNoThrow}; -} -} // namespace - -DepositAddresses ReadDepositAddresses(std::string_view dataDir) { - return ReadJsonOrThrow(GetDepositAddressesFile(dataDir)); +schema::DepositAddresses ReadDepositAddresses(std::string_view dataDir) { + return ReadJsonOrThrow( + File{dataDir, File::Type::kSecret, kDepositAddressesFileName, File::IfError::kNoThrow}); } } // namespace cct \ No newline at end of file diff --git a/src/schema/src/general-config.cpp b/src/schema/src/general-config.cpp new file mode 100644 index 00000000..b234b405 --- /dev/null +++ b/src/schema/src/general-config.cpp @@ -0,0 +1,15 @@ +#include "general-config.hpp" + +#include + +#include "file.hpp" +#include "read-json.hpp" + +namespace cct { + +schema::GeneralConfig ReadGeneralConfig(std::string_view dataDir) { + return ReadJsonOrCreateFile( + File{dataDir, File::Type::kStatic, "generalconfig.json", File::IfError::kNoThrow}); +} + +} // namespace cct \ No newline at end of file diff --git a/src/schema/test/deposit-addresses_test.cpp b/src/schema/test/deposit-addresses_test.cpp index 0aaeb6c3..c57dc8f3 100644 --- a/src/schema/test/deposit-addresses_test.cpp +++ b/src/schema/test/deposit-addresses_test.cpp @@ -2,10 +2,12 @@ #include +#include "cct_string.hpp" #include "read-json.hpp" #include "reader.hpp" namespace cct::schema { + TEST(DepositAddressesTest, NominalCase) { class NominalCase : public Reader { [[nodiscard]] string readAll() const override { @@ -47,4 +49,5 @@ TEST(DepositAddressesTest, NominalCase) { EXPECT_EQ(depositAddresses.at("kraken").at("user2").at("EUR"), "0x1234567890abcdef3"); EXPECT_EQ(depositAddresses.at("kraken").at("user2").at("ETH"), "0xETHaddress"); } + } // namespace cct::schema \ No newline at end of file diff --git a/src/schema/test/duration-schema_test.cpp b/src/schema/test/duration-schema_test.cpp new file mode 100644 index 00000000..2d4b3c3c --- /dev/null +++ b/src/schema/test/duration-schema_test.cpp @@ -0,0 +1,75 @@ +#include "duration-schema.hpp" + +#include + +#include +#include +#include + +#include "cct_json-serialization.hpp" +#include "cct_string.hpp" + +namespace cct::schema { + +using UnorderedMap = std::unordered_map; +using Map = std::map; + +TEST(DurationSchemaTest, FromJsonKey) { + UnorderedMap map; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::read(map, R"({"2w56h":true,"1009s17ms":false})"); + + ASSERT_FALSE(ec); + + EXPECT_EQ(map.size(), 2); + EXPECT_EQ(map.at(Duration{std::chrono::weeks(2) + std::chrono::hours(56)}), true); + EXPECT_EQ(map.at(Duration{std::chrono::seconds(1009) + std::chrono::milliseconds(17)}), false); +} + +TEST(DurationSchemaTest, ToJsonKey) { + Map map{{Duration{std::chrono::weeks(2) + std::chrono::hours(56)}, true}, + {Duration{std::chrono::seconds(1009) + std::chrono::milliseconds(17)}, false}}; + + string str; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::write(map, str); + + ASSERT_FALSE(ec); + + EXPECT_EQ(str, R"({"16min49s17ms":false,"2w2d8h":true})"); +} + +struct Foo { + Duration dur; +}; + +TEST(DurationSchemaTest, ToJsonValue) { + Foo foo; + foo.dur.duration = + std::chrono::days(34) + std::chrono::hours(6) + std::chrono::minutes(42) + std::chrono::seconds(56); + + string str; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::write(foo, str); + + ASSERT_FALSE(ec); + + EXPECT_EQ(str, R"({"dur":"1mon3d20h13min50s"})"); +} + +TEST(DurationSchemaTest, FromJsonValue) { + Foo foo; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::read(foo, R"({"dur":"34d6h42min56s"})"); + + ASSERT_FALSE(ec); + + EXPECT_EQ(foo.dur.duration, + std::chrono::days(34) + std::chrono::hours(6) + std::chrono::minutes(42) + std::chrono::seconds(56)); +} + +} // namespace cct::schema \ No newline at end of file diff --git a/src/schema/test/general-config_test.cpp b/src/schema/test/general-config_test.cpp new file mode 100644 index 00000000..90b29ec0 --- /dev/null +++ b/src/schema/test/general-config_test.cpp @@ -0,0 +1,58 @@ +#include "general-config.hpp" + +#include + +#include "write-json.hpp" + +namespace cct { + +TEST(GeneralConfig, WriteMinified) { + EXPECT_EQ( + WriteJsonOrThrow(schema::GeneralConfig{}), + R"({"apiOutputType":"table","fiatConversion":{"rate":"8h"},"log":{"activityTracking":{"commandTypes":["Trade","Buy","Sell","Withdraw","DustSweeper"],"dateFileNameFormat":"%Y-%m","withSimulatedCommands":false},"consoleLevel":"info","fileLevel":"debug","maxFileSize":"5Mi","maxNbFiles":20},"requests":{"concurrency":{"nbMaxParallelRequests":1}},"trading":{"automation":{"deserialization":{"loadChunkDuration":"1w"},"startingContext":{"startBaseAmountEquivalent":"1000 EUR","startQuoteAmountEquivalent":"1000 EUR"}}}})"); +} + +TEST(GeneralConfig, WriteFormatted) { + EXPECT_EQ(WriteJsonOrThrow(schema::GeneralConfig{}), + R"({ + "apiOutputType": "table", + "fiatConversion": { + "rate": "8h" + }, + "log": { + "activityTracking": { + "commandTypes": [ + "Trade", + "Buy", + "Sell", + "Withdraw", + "DustSweeper" + ], + "dateFileNameFormat": "%Y-%m", + "withSimulatedCommands": false + }, + "consoleLevel": "info", + "fileLevel": "debug", + "maxFileSize": "5Mi", + "maxNbFiles": 20 + }, + "requests": { + "concurrency": { + "nbMaxParallelRequests": 1 + } + }, + "trading": { + "automation": { + "deserialization": { + "loadChunkDuration": "1w" + }, + "startingContext": { + "startBaseAmountEquivalent": "1000 EUR", + "startQuoteAmountEquivalent": "1000 EUR" + } + } + } +})"); +} + +} // namespace cct \ No newline at end of file diff --git a/src/schema/test/size-bytes-schema_test.cpp b/src/schema/test/size-bytes-schema_test.cpp new file mode 100644 index 00000000..653c4646 --- /dev/null +++ b/src/schema/test/size-bytes-schema_test.cpp @@ -0,0 +1,71 @@ +#include "size-bytes-schema.hpp" + +#include + +#include +#include + +#include "cct_json-serialization.hpp" +#include "cct_string.hpp" + +namespace cct::schema { + +using UnorderedMap = std::unordered_map; +using Map = std::map; + +TEST(SizeBytesSchemaTest, FromJsonKey) { + UnorderedMap map; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::read(map, R"({"11Ki772":true,"9Mi424Ki200":false})"); + + ASSERT_FALSE(ec); + + EXPECT_EQ(map.size(), 2); + EXPECT_EQ(map.at(SizeBytes{12036}), true); + EXPECT_EQ(map.at(SizeBytes{9871560}), false); +} + +TEST(SizeBytesSchemaTest, ToJsonKey) { + Map map{{SizeBytes{12036}, true}, {SizeBytes{9871560}, false}}; + + string str; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::write(map, str); + + ASSERT_FALSE(ec); + + EXPECT_EQ(str, R"({"11Ki772":true,"9Mi424Ki200":false})"); +} + +struct Foo { + SizeBytes size; +}; + +TEST(SizeBytesSchemaTest, ToJsonValue) { + Foo foo; + foo.size.sizeInBytes = 2415919104; + + string str; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::write(foo, str); + + ASSERT_FALSE(ec); + + EXPECT_EQ(str, R"({"size":"2Gi256Mi"})"); +} + +TEST(SizeBytesSchemaTest, FromJsonValue) { + Foo foo; + + // NOLINTNEXTLINE(readability-implicit-bool-conversion) + auto ec = json::read(foo, R"({"size":"2Gi256Mi"})"); + + ASSERT_FALSE(ec); + + EXPECT_EQ(foo.size.sizeInBytes, 2415919104); +} + +} // namespace cct::schema \ No newline at end of file diff --git a/src/tech/include/cct_json-container.hpp b/src/tech/include/cct_json-container.hpp new file mode 100644 index 00000000..dd8cf84b --- /dev/null +++ b/src/tech/include/cct_json-container.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +#include "cct_allocator.hpp" +#include "cct_smallvector.hpp" +#include "cct_string.hpp" +#include "cct_vector.hpp" + +namespace cct::json { + +using container = ::nlohmann::basic_json<::std::map, ::cct::vector, ::cct::string, bool, int64_t, uint64_t, double, + ::cct::allocator, ::nlohmann::adl_serializer, ::cct::SmallVector>; + +} // namespace cct::json diff --git a/src/tech/include/cct_json-serialization.hpp b/src/tech/include/cct_json-serialization.hpp index 725ad358..52ddda41 100644 --- a/src/tech/include/cct_json-serialization.hpp +++ b/src/tech/include/cct_json-serialization.hpp @@ -1,14 +1,14 @@ #pragma once -#include +#include // IWYU pragma: export -namespace cct { +namespace cct::json { using glz::format_error; +using glz::meta; using glz::opts; using glz::read; -using glz::read_json; +using glz::reflect; using glz::write; -using glz::write_json; -} // namespace cct \ No newline at end of file +} // namespace cct::json \ No newline at end of file diff --git a/src/tech/include/cct_json.hpp b/src/tech/include/cct_json.hpp deleted file mode 100644 index 143418a2..00000000 --- a/src/tech/include/cct_json.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "cct_allocator.hpp" -#include "cct_smallvector.hpp" -#include "cct_string.hpp" -#include "cct_vector.hpp" - -namespace cct { - -using json = nlohmann::basic_json>; - -} // namespace cct diff --git a/src/tech/include/durationstring.hpp b/src/tech/include/durationstring.hpp index 66b0518c..10bc9fd6 100644 --- a/src/tech/include/durationstring.hpp +++ b/src/tech/include/durationstring.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "cct_string.hpp" @@ -22,4 +23,7 @@ Duration ParseDuration(std::string_view durationStr); /// The 'nbSignificantUnits' parameter allows to specify the number of units to display. string DurationToString(Duration dur, int nbSignificantUnits = 2); +/// Write the duration to given buffer instead of building a string. Returns the actual size of the result buffer. +std::span DurationToBuffer(Duration dur, std::span buffer, int nbSignificantUnits = 2); + } // namespace cct diff --git a/src/tech/include/stringconv.hpp b/src/tech/include/stringconv.hpp index b82dcdd5..4bc844cf 100644 --- a/src/tech/include/stringconv.hpp +++ b/src/tech/include/stringconv.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -84,4 +85,16 @@ inline void AppendIntegralToString(string &str, std::integral auto val) { details::ToChars(str.data() + static_cast(str.size()) - nbDigitsInt, nbDigitsInt, val); } +constexpr std::span IntegralToCharBuffer(std::span buf, std::integral auto val) { + const auto nbDigitsInt = nchars(val); + + if (buf.size() < static_cast(nbDigitsInt)) { + throw exception("Buffer size {} is too small to hold {} digits for integral {}", buf.size(), nbDigitsInt, val); + } + + details::ToChars(buf.data(), nbDigitsInt, val); + + return buf.subspan(0, nbDigitsInt); +} + } // namespace cct \ No newline at end of file diff --git a/src/tech/include/unitsparser.hpp b/src/tech/include/unitsparser.hpp index e7cfd975..d178b799 100644 --- a/src/tech/include/unitsparser.hpp +++ b/src/tech/include/unitsparser.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace cct { @@ -13,4 +14,9 @@ namespace cct { /// https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ int64_t ParseNumberOfBytes(std::string_view sizeStr); +/// Writes to 'buf' the string representation of the number of bytes. +/// If given buffer is too small, it will throw an exception. +/// Returns a span of the buffer containing the string representation. +std::span BytesToStr(int64_t numberOfBytes, std::span buf); + } // namespace cct \ No newline at end of file diff --git a/src/tech/src/durationstring.cpp b/src/tech/src/durationstring.cpp index 8065f1fa..ce18d08c 100644 --- a/src/tech/src/durationstring.cpp +++ b/src/tech/src/durationstring.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -141,13 +142,37 @@ bool AdjustWithUnit(UnitDuration unitDuration, Duration &dur, int &nbSignificant return false; } +bool AdjustWithUnit(UnitDuration unitDuration, Duration &dur, int &nbSignificantUnits, std::span &ret) { + if (dur >= unitDuration.second) { + const auto countInThisDurationUnit = + std::chrono::duration_cast(dur).count() / unitDuration.second.count(); + auto actualBuf = IntegralToCharBuffer(ret, countInThisDurationUnit); + ret = ret.subspan(actualBuf.size()); + + if (ret.size() < unitDuration.first.size()) { + throw invalid_argument("Buffer is too small to store unit"); + } + + std::ranges::copy(unitDuration.first, ret.begin()); + ret = ret.subspan(unitDuration.first.size()); + + dur -= countInThisDurationUnit * unitDuration.second; + if (--nbSignificantUnits == 0) { + return true; + } + } + return false; +} + +constexpr std::string_view kUndefStr = ""; + } // namespace string DurationToString(Duration dur, int nbSignificantUnits) { string ret; if (dur == kUndefinedDuration) { - ret.append(""); + ret.append(kUndefStr); } else { std::ranges::find_if(kDurationUnits, [&dur, &nbSignificantUnits, &ret](const auto &unitDuration) { return AdjustWithUnit(unitDuration, dur, nbSignificantUnits, ret); @@ -157,4 +182,22 @@ string DurationToString(Duration dur, int nbSignificantUnits) { return ret; } +std::span DurationToBuffer(Duration dur, std::span buffer, int nbSignificantUnits) { + if (dur == kUndefinedDuration) { + if (buffer.size() < kUndefStr.size()) { + throw invalid_argument("Buffer is too small to store ''"); + } + auto inOutRes = std::ranges::copy(kUndefStr, buffer.begin()); + return {buffer.begin(), inOutRes.out}; + } + + auto begBuf = buffer.data(); + + std::ranges::find_if(kDurationUnits, [&dur, &nbSignificantUnits, &buffer](const auto &unitDuration) { + return AdjustWithUnit(unitDuration, dur, nbSignificantUnits, buffer); + }); + + return {begBuf, buffer.data()}; +} + } // namespace cct diff --git a/src/tech/src/unitsparser.cpp b/src/tech/src/unitsparser.cpp index 6a9ca318..a343cceb 100644 --- a/src/tech/src/unitsparser.cpp +++ b/src/tech/src/unitsparser.cpp @@ -1,7 +1,12 @@ #include "unitsparser.hpp" +#include +#include #include +#include #include +#include +#include #include "cct_exception.hpp" #include "stringconv.hpp" @@ -9,41 +14,82 @@ namespace cct { int64_t ParseNumberOfBytes(std::string_view sizeStr) { - auto endPos = sizeStr.find_first_not_of("0123456789"); - if (endPos == std::string_view::npos) { - endPos = sizeStr.size(); - } - int64_t nbBytes = StringToIntegral(std::string_view(sizeStr.begin(), sizeStr.begin() + endPos)); - if (nbBytes < 0) { - throw exception("Number of bytes cannot be negative"); + int64_t totalNbBytes = 0; + while (!sizeStr.empty()) { + auto endDigitPos = sizeStr.find_first_not_of("0123456789"); + if (endDigitPos == std::string_view::npos) { + endDigitPos = sizeStr.size(); + } + int64_t nbBytes = StringToIntegral(std::string_view(sizeStr.begin(), sizeStr.begin() + endDigitPos)); + if (nbBytes < 0) { + throw exception("Number of bytes cannot be negative"); + } + sizeStr.remove_prefix(endDigitPos); + + int64_t multiplier = 1; + if (!sizeStr.empty()) { + bool iMultiplier = 1UL < sizeStr.size() && sizeStr[1UL] == 'i'; + int64_t multiplierBase = iMultiplier ? 1024L : 1000L; + switch (sizeStr.front()) { + case '.': + throw exception("Decimal number not accepted for number of bytes parsing"); + case 'T': // NOLINT(bugprone-branch-clone) + multiplier *= multiplierBase; + [[fallthrough]]; + case 'G': + multiplier *= multiplierBase; + [[fallthrough]]; + case 'M': + multiplier *= multiplierBase; + [[fallthrough]]; + case 'K': + [[fallthrough]]; + case 'k': + multiplier *= multiplierBase; + break; + default: + throw exception("Invalid suffix '{}' for number of bytes parsing", sizeStr.front()); + } + sizeStr.remove_prefix(1UL + static_cast(iMultiplier)); + } + totalNbBytes += nbBytes * multiplier; } - int64_t multiplier = 1; - if (endPos != sizeStr.size()) { - bool iMultiplier = endPos + 1 < sizeStr.size() && sizeStr[endPos + 1] == 'i'; - int64_t multiplierBase = iMultiplier ? 1024L : 1000L; - switch (sizeStr[endPos]) { - case '.': - throw exception("Decimal number not accepted for number of bytes parsing"); - case 'T': // NOLINT(bugprone-branch-clone) - multiplier *= multiplierBase; - [[fallthrough]]; - case 'G': - multiplier *= multiplierBase; - [[fallthrough]]; - case 'M': - multiplier *= multiplierBase; - [[fallthrough]]; - case 'K': - [[fallthrough]]; - case 'k': - multiplier *= multiplierBase; - break; - default: - throw exception("Invalid suffix '{}' for number of bytes parsing", sizeStr[endPos]); + + return totalNbBytes; +} + +std::span BytesToStr(int64_t numberOfBytes, std::span buf) { + static constexpr std::pair kUnits[] = { + {static_cast(1024) * 1024 * 1024 * 1024, "Ti"}, + {static_cast(1024) * 1024 * 1024, "Gi"}, + {static_cast(1024) * 1024, "Mi"}, + {static_cast(1024), "Ki"}, + {static_cast(1), ""}}; + + char *begBuf = buf.data(); + + char *endBuf = begBuf + buf.size(); + + for (int unitPos = 0; numberOfBytes > 0; ++unitPos) { + int64_t nbUnits = numberOfBytes / kUnits[unitPos].first; + + if (nbUnits != 0) { + numberOfBytes %= kUnits[unitPos].first; + + auto [ptr, errc] = std::to_chars(begBuf, endBuf, nbUnits); + if (errc != std::errc()) { + throw exception("Unable to decode integral into string"); + } + + if (ptr + kUnits[unitPos].second.size() >= endBuf) { + throw exception("Buffer too small for number of bytes string representation"); + } + + begBuf = std::ranges::copy(kUnits[unitPos].second, ptr).out; } } - return nbBytes * multiplier; + return {buf.data(), begBuf}; } } // namespace cct \ No newline at end of file diff --git a/src/tech/test/durationstring_test.cpp b/src/tech/test/durationstring_test.cpp index 1909aaea..9dfb5a8e 100644 --- a/src/tech/test/durationstring_test.cpp +++ b/src/tech/test/durationstring_test.cpp @@ -3,7 +3,10 @@ #include #include +#include +#include +#include "cct_exception.hpp" #include "cct_invalid_argument_exception.hpp" #include "timedef.hpp" @@ -72,4 +75,38 @@ TEST(DurationString, DurationToStringMicrosecondsTruncated) { EXPECT_EQ(DurationToString(microseconds(31736913078454L), 2), "1y2d"); } +TEST(DurationString, DurationToBufferUndefEnoughBuffer) { + char buffer[10]; + std::span bufSpan(buffer); + + auto actualBuf = DurationToBuffer(kUndefinedDuration, bufSpan); + + EXPECT_EQ(std::string_view(buffer, actualBuf.size()), ""); +} + +TEST(DurationString, DurationToBufferUndefNotEnoughBuffer) { + char buffer[6]; + std::span bufSpan(buffer); + + EXPECT_THROW(DurationToBuffer(kUndefinedDuration, bufSpan), exception); +} + +TEST(DurationString, DurationToBufferNotEnoughBuffer) { + char buffer[7]; + std::span bufSpan(buffer); + + EXPECT_THROW(DurationToBuffer(std::chrono::weeks(2) + std::chrono::days(6) + std::chrono::minutes(57), bufSpan, 3), + exception); +} + +TEST(DurationString, DurationToBufferNominal) { + char buffer[100]; + std::span bufSpan(buffer); + + auto actualBuf = + DurationToBuffer(std::chrono::weeks(2) + std::chrono::days(6) + std::chrono::minutes(57), bufSpan, 3); + + EXPECT_EQ(std::string_view(buffer, actualBuf.size()), "2w6d57min"); +} + } // namespace cct diff --git a/src/tech/test/unitsparser_test.cpp b/src/tech/test/unitsparser_test.cpp index 0d671edb..ab4f4d8e 100644 --- a/src/tech/test/unitsparser_test.cpp +++ b/src/tech/test/unitsparser_test.cpp @@ -2,6 +2,8 @@ #include +#include + #include "cct_exception.hpp" namespace cct { @@ -21,9 +23,30 @@ TEST(UnitsParser, ParseNumberOfBytes1024Multipliers) { EXPECT_EQ(ParseNumberOfBytes("2Ti"), 2199023255552L); } +TEST(UnitsParser, ParseNumberOfBytesSeveralUnits) { + EXPECT_EQ(ParseNumberOfBytes("58"), 58L); + EXPECT_EQ(ParseNumberOfBytes("256Ki58"), 262202L); + EXPECT_EQ(ParseNumberOfBytes("1Mi256Ki58"), 1310778L); + EXPECT_EQ(ParseNumberOfBytes("988Gi1Mi256Ki58"), 1060858232890L); + EXPECT_EQ(ParseNumberOfBytes("4Ti988Gi1Mi256Ki58"), 5458904743994L); +} + TEST(UnitsParser, ParseNumberOfBytesInvalidInput) { EXPECT_THROW(ParseNumberOfBytes("12.5M"), exception); EXPECT_THROW(ParseNumberOfBytes("400m"), exception); EXPECT_THROW(ParseNumberOfBytes("-30"), exception); } + +TEST(UnitsParser, BytesToStrBufferTooSmall) { + char buf[3]; + EXPECT_THROW(BytesToStr(123456789, buf), exception); +} + +TEST(UnitsParser, BytesToStrNominalCase) { + char buf[20]; + auto resultBuf = BytesToStr(1060858233000, buf); + std::string_view resultStr = std::string_view(resultBuf.data(), resultBuf.size()); + EXPECT_EQ(resultStr, "988Gi1Mi256Ki168"); +} + } // namespace cct \ No newline at end of file