From c124e10b0b7dcffe6837ab665a10216b89763a29 Mon Sep 17 00:00:00 2001 From: Stephane Janel Date: Sun, 24 Nov 2024 14:39:59 +0100 Subject: [PATCH] [Refactoring] - Use glaze for file read, remove readAllJson from Reader --- src/api/common/include/commonapi.hpp | 5 +- .../common/include/withdrawalfees-crawler.hpp | 13 ++- src/api/common/src/commonapi.cpp | 38 +++--- src/api/common/src/withdrawal-fees-schema.hpp | 3 +- src/api/common/src/withdrawalfees-crawler.cpp | 38 +++--- .../test/withdrawalfees-crawler_test.cpp | 5 +- .../exchanges/include/bithumbprivateapi.hpp | 23 ++-- .../exchanges/include/bithumbpublicapi.hpp | 4 +- src/api/exchanges/include/krakenpublicapi.hpp | 4 +- src/api/exchanges/src/bithumbprivateapi.cpp | 108 ++++++------------ src/api/exchanges/src/bithumbpublicapi.cpp | 2 +- src/api/exchanges/src/krakenpublicapi.cpp | 2 +- src/api/exchanges/src/upbitpublicapi.cpp | 20 +++- .../src/withdraw-fees-file-schema.hpp | 14 +++ src/basic-objects/include/reader.hpp | 4 - src/basic-objects/src/reader.cpp | 17 --- 16 files changed, 136 insertions(+), 164 deletions(-) create mode 100644 src/api/exchanges/src/withdraw-fees-file-schema.hpp delete mode 100644 src/basic-objects/src/reader.cpp diff --git a/src/api/common/include/commonapi.hpp b/src/api/common/include/commonapi.hpp index ecaf8112..59f9f741 100644 --- a/src/api/common/include/commonapi.hpp +++ b/src/api/common/include/commonapi.hpp @@ -9,6 +9,7 @@ #include "binance-common-api.hpp" #include "cache-file-updator-interface.hpp" #include "cachedresult.hpp" +#include "cct_const.hpp" #include "curlhandle.hpp" #include "currencycode.hpp" #include "currencycodeset.hpp" @@ -38,10 +39,10 @@ class CommonAPI : public CacheFileUpdatorInterface { /// Information here: https://en.wikipedia.org/wiki/Fiat_money bool queryIsCurrencyCodeFiat(CurrencyCode currencyCode); - std::optional tryQueryWithdrawalFee(std::string_view exchangeName, CurrencyCode currencyCode); + std::optional tryQueryWithdrawalFee(ExchangeNameEnum exchangeNameEnum, CurrencyCode currencyCode); /// Query withdrawal fees from crawler sources. It's not guaranteed to work though. - MonetaryAmountByCurrencySet tryQueryWithdrawalFees(std::string_view exchangeName); + MonetaryAmountByCurrencySet tryQueryWithdrawalFees(ExchangeNameEnum exchangeNameEnum); BinanceGlobalInfos &getBinanceGlobalInfos() { return _binanceGlobalInfos; } diff --git a/src/api/common/include/withdrawalfees-crawler.hpp b/src/api/common/include/withdrawalfees-crawler.hpp index 1a93ae3f..3ba8e323 100644 --- a/src/api/common/include/withdrawalfees-crawler.hpp +++ b/src/api/common/include/withdrawalfees-crawler.hpp @@ -7,6 +7,7 @@ #include "cache-file-updator-interface.hpp" #include "cachedresult.hpp" #include "cachedresultvault.hpp" +#include "cct_const.hpp" #include "coincenterinfo.hpp" #include "curlhandle.hpp" #include "currencycode.hpp" @@ -26,7 +27,9 @@ class WithdrawalFeesCrawler : public CacheFileUpdatorInterface { using WithdrawalMinMap = std::unordered_map; using WithdrawalInfoMaps = std::pair; - const WithdrawalInfoMaps& get(std::string_view exchangeName) { return _withdrawalFeesCache.get(exchangeName); } + const WithdrawalInfoMaps& get(ExchangeNameEnum exchangeNameEnum) { + return _withdrawalFeesCache.get(exchangeNameEnum); + } void updateCacheFile() const override; @@ -35,18 +38,18 @@ class WithdrawalFeesCrawler : public CacheFileUpdatorInterface { public: explicit WithdrawalFeesFunc(const CoincenterInfo& coincenterInfo); - WithdrawalInfoMaps operator()(std::string_view exchangeName); + WithdrawalInfoMaps operator()(ExchangeNameEnum exchangeNameEnum); private: - WithdrawalInfoMaps get1(std::string_view exchangeName); - WithdrawalInfoMaps get2(std::string_view exchangeName); + WithdrawalInfoMaps get1(ExchangeNameEnum exchangeNameEnum); + WithdrawalInfoMaps get2(ExchangeNameEnum exchangeNameEnum); CurlHandle _curlHandle1; CurlHandle _curlHandle2; }; const CoincenterInfo& _coincenterInfo; - CachedResult _withdrawalFeesCache; + CachedResult _withdrawalFeesCache; }; } // namespace cct \ No newline at end of file diff --git a/src/api/common/src/commonapi.cpp b/src/api/common/src/commonapi.cpp index 470c69b7..2933db37 100644 --- a/src/api/common/src/commonapi.cpp +++ b/src/api/common/src/commonapi.cpp @@ -69,32 +69,33 @@ CurrencyCodeSet CommonAPI::queryFiats() { bool CommonAPI::queryIsCurrencyCodeFiat(CurrencyCode currencyCode) { return queryFiats().contains(currencyCode); } -MonetaryAmountByCurrencySet CommonAPI::tryQueryWithdrawalFees(std::string_view exchangeName) { +MonetaryAmountByCurrencySet CommonAPI::tryQueryWithdrawalFees(ExchangeNameEnum exchangeNameEnum) { MonetaryAmountByCurrencySet ret; { std::lock_guard guard(_globalMutex); - ret = _withdrawalFeesCrawler.get(exchangeName).first; + ret = _withdrawalFeesCrawler.get(exchangeNameEnum).first; } if (ret.empty()) { - log::warn("Taking binance withdrawal fees for {} as crawler failed to retrieve data", exchangeName); + log::warn("Taking binance withdrawal fees for {} as crawler failed to retrieve data", + kSupportedExchanges[static_cast(exchangeNameEnum)]); ret = _binanceGlobalInfos.queryWithdrawalFees(); } return ret; } -std::optional CommonAPI::tryQueryWithdrawalFee(std::string_view exchangeName, +std::optional CommonAPI::tryQueryWithdrawalFee(ExchangeNameEnum exchangeNameEnum, CurrencyCode currencyCode) { { std::lock_guard guard(_globalMutex); - const auto& withdrawalFees = _withdrawalFeesCrawler.get(exchangeName).first; + const auto& withdrawalFees = _withdrawalFeesCrawler.get(exchangeNameEnum).first; auto it = withdrawalFees.find(currencyCode); if (it != withdrawalFees.end()) { return *it; } } - log::warn("Taking binance withdrawal fee for {} and currency {} as crawler failed to retrieve data", exchangeName, - currencyCode); + log::warn("Taking binance withdrawal fee for {} and currency {} as crawler failed to retrieve data", + kSupportedExchanges[static_cast(exchangeNameEnum)], currencyCode); MonetaryAmount withdrawFee = _binanceGlobalInfos.queryWithdrawalFee(currencyCode); if (withdrawFee.isDefault()) { return {}; @@ -213,24 +214,19 @@ CurrencyCodeVector CommonAPI::FiatsFunc::retrieveFiatsSource2() { void CommonAPI::updateCacheFile() const { const auto fiatsCacheFile = GetFiatCacheFile(_coincenterInfo.dataDir()); - auto fiatsData = fiatsCacheFile.readAllJson(); + auto fiatsDataStr = fiatsCacheFile.readAll(); + schema::FiatsCache fiatsData; + ReadExactJsonOrThrow(fiatsDataStr, fiatsData); const auto fiatsPtrLastUpdatedTimePair = _fiatsCache.retrieve(); - const auto timeEpochIt = fiatsData.find("timeepoch"); - bool updateFiatsCache = true; - if (timeEpochIt != fiatsData.end()) { - const int64_t lastTimeFileUpdated = timeEpochIt->get(); - if (TimePoint(seconds(lastTimeFileUpdated)) >= fiatsPtrLastUpdatedTimePair.second) { - updateFiatsCache = false; - } - } - if (updateFiatsCache) { - fiatsData.clear(); + if (TimePoint(seconds(fiatsData.timeepoch)) < fiatsPtrLastUpdatedTimePair.second) { + // update fiats cache file + fiatsData.fiats.clear(); if (fiatsPtrLastUpdatedTimePair.first != nullptr) { for (CurrencyCode fiatCode : *fiatsPtrLastUpdatedTimePair.first) { - fiatsData["fiats"].emplace_back(fiatCode.str()); + fiatsData.fiats.emplace_back(fiatCode.str()); } - fiatsData["timeepoch"] = TimestampToSecondsSinceEpoch(fiatsPtrLastUpdatedTimePair.second); - fiatsCacheFile.writeJson(fiatsData); + fiatsData.timeepoch = TimestampToSecondsSinceEpoch(fiatsPtrLastUpdatedTimePair.second); + fiatsCacheFile.write(WriteMiniJsonOrThrow(fiatsData)); } } diff --git a/src/api/common/src/withdrawal-fees-schema.hpp b/src/api/common/src/withdrawal-fees-schema.hpp index 85a5eaaa..43f156ab 100644 --- a/src/api/common/src/withdrawal-fees-schema.hpp +++ b/src/api/common/src/withdrawal-fees-schema.hpp @@ -3,6 +3,7 @@ #include #include +#include "cct_const.hpp" #include "cct_string.hpp" #include "cct_vector.hpp" #include "currencycode.hpp" @@ -20,7 +21,7 @@ struct WithdrawInfoFileItem { std::unordered_map assets; }; -using WithdrawInfoFile = std::unordered_map; +using WithdrawInfoFile = std::unordered_map; struct WithdrawFeesCrawlerExchangeFeesCoinSource1 { string symbol; diff --git a/src/api/common/src/withdrawalfees-crawler.cpp b/src/api/common/src/withdrawalfees-crawler.cpp index 8e26792a..37a66ea6 100644 --- a/src/api/common/src/withdrawalfees-crawler.cpp +++ b/src/api/common/src/withdrawalfees-crawler.cpp @@ -49,12 +49,14 @@ WithdrawalFeesCrawler::WithdrawalFeesCrawler(const CoincenterInfo& coincenterInf ReadExactJsonOrThrow(data, withdrawInfoFileContent); const auto nowTime = Clock::now(); - for (const auto& [exchangeName, exchangeData] : withdrawInfoFileContent) { + for (const auto& [exchangeNameEnum, exchangeData] : withdrawInfoFileContent) { TimePoint lastUpdatedTime(seconds(exchangeData.timeepoch)); if (nowTime - lastUpdatedTime < minDurationBetweenQueries) { // we can reuse file data WithdrawalInfoMaps withdrawalInfoMaps; + std::string_view exchangeName = kSupportedExchanges[static_cast(exchangeNameEnum)]; + for (const auto& [cur, val] : exchangeData.assets) { MonetaryAmount withdrawMin(val.min, cur); MonetaryAmount withdrawFee(val.fee, cur); @@ -66,15 +68,7 @@ WithdrawalFeesCrawler::WithdrawalFeesCrawler(const CoincenterInfo& coincenterInf withdrawalInfoMaps.second.insert_or_assign(cur, withdrawMin); } - // Warning: we store a std::string_view in the cache, and 'exchangeName' will be destroyed at the end - // of this function. So we need to retrieve the 'constant' std::string_view of this exchange (in static memory) - // to store in the cache. - auto constantExchangeNameSVIt = std::ranges::find(kSupportedExchanges, exchangeName); - if (constantExchangeNameSVIt == std::end(kSupportedExchanges)) { - throw exception("unknown exchange name {}", exchangeName); - } - - _withdrawalFeesCache.set(std::move(withdrawalInfoMaps), lastUpdatedTime, *constantExchangeNameSVIt); + _withdrawalFeesCache.set(std::move(withdrawalInfoMaps), lastUpdatedTime, exchangeNameEnum); } } } @@ -92,14 +86,15 @@ WithdrawalFeesCrawler::WithdrawalFeesFunc::WithdrawalFeesFunc(const CoincenterIn coincenterInfo.getRunMode()) {} WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesFunc::operator()( - std::string_view exchangeName) { + ExchangeNameEnum exchangeNameEnum) { static constexpr auto kNbSources = 2; ThreadPool threadPool(kNbSources); - std::array results{ - threadPool.enqueue([this](std::string_view exchangeName) { return get1(exchangeName); }, exchangeName), - threadPool.enqueue([this](std::string_view exchangeName) { return get2(exchangeName); }, exchangeName)}; + std::array results{threadPool.enqueue([this](ExchangeNameEnum exchangeNameEnum) { return get1(exchangeNameEnum); }, + exchangeNameEnum), + threadPool.enqueue([this](ExchangeNameEnum exchangeNameEnum) { return get2(exchangeNameEnum); }, + exchangeNameEnum)}; auto [withdrawFees1, withdrawMinMap1] = results[0].get(); @@ -111,7 +106,7 @@ WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesF } if (withdrawFees1.empty() || withdrawMinMap1.empty()) { - log::error("Unable to parse {} withdrawal fees", exchangeName); + log::error("Unable to parse {} withdrawal fees", kSupportedExchanges[static_cast(exchangeNameEnum)]); } return std::make_pair(std::move(withdrawFees1), std::move(withdrawMinMap1)); @@ -119,13 +114,14 @@ WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesF void WithdrawalFeesCrawler::updateCacheFile() const { schema::WithdrawInfoFile withdrawInfoFile; - for (const std::string_view exchangeName : kSupportedExchanges) { - const auto [withdrawalInfoMapsPtr, latestUpdate] = _withdrawalFeesCache.retrieve(exchangeName); + for (int exchangeNamePos = 0; exchangeNamePos < kNbSupportedExchanges; ++exchangeNamePos) { + auto exchangeNameEnum = static_cast(exchangeNamePos); + const auto [withdrawalInfoMapsPtr, latestUpdate] = _withdrawalFeesCache.retrieve(exchangeNameEnum); if (withdrawalInfoMapsPtr != nullptr) { const WithdrawalInfoMaps& withdrawalInfoMaps = *withdrawalInfoMapsPtr; schema::WithdrawInfoFileItem& withdrawInfoFileItem = - withdrawInfoFile.emplace(std::make_pair(exchangeName, schema::WithdrawInfoFileItem{})).first->second; + withdrawInfoFile.emplace(std::make_pair(exchangeNameEnum, schema::WithdrawInfoFileItem{})).first->second; withdrawInfoFileItem.timeepoch = TimestampToSecondsSinceEpoch(latestUpdate); for (const auto withdrawFee : withdrawalInfoMaps.first) { CurrencyCode cur = withdrawFee.currencyCode(); @@ -146,7 +142,8 @@ void WithdrawalFeesCrawler::updateCacheFile() const { } WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesFunc::get1( - std::string_view exchangeName) { + ExchangeNameEnum exchangeNameEnum) { + std::string_view exchangeName = kSupportedExchanges[static_cast(exchangeNameEnum)]; string path(exchangeName); path.append(".json"); std::string_view dataStr = _curlHandle1.query(path, CurlOptions(HttpRequestType::kGet)); @@ -188,7 +185,8 @@ WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesF } WithdrawalFeesCrawler::WithdrawalInfoMaps WithdrawalFeesCrawler::WithdrawalFeesFunc::get2( - std::string_view exchangeName) { + ExchangeNameEnum exchangeNameEnum) { + std::string_view exchangeName = kSupportedExchanges[static_cast(exchangeNameEnum)]; std::string_view withdrawalFeesCsv = _curlHandle2.query(exchangeName, CurlOptions(HttpRequestType::kGet)); static constexpr std::string_view kBeginTableTitle = "Deposit & Withdrawal fees"; diff --git a/src/api/common/test/withdrawalfees-crawler_test.cpp b/src/api/common/test/withdrawalfees-crawler_test.cpp index 6b349169..2e1ae9fb 100644 --- a/src/api/common/test/withdrawalfees-crawler_test.cpp +++ b/src/api/common/test/withdrawalfees-crawler_test.cpp @@ -23,8 +23,9 @@ class WithdrawalFeesCrawlerTest : public ::testing::Test { }; TEST_F(WithdrawalFeesCrawlerTest, WithdrawalFeesCrawlerService) { - for (const std::string_view exchangeName : kSupportedExchanges) { - const auto [amountByCurrencySet, withdrawalMinMap] = withdrawalFeesCrawler.get(exchangeName); + for (int exchangeNamePos = 0; exchangeNamePos < kNbSupportedExchanges; ++exchangeNamePos) { + const auto [amountByCurrencySet, withdrawalMinMap] = + withdrawalFeesCrawler.get(static_cast(exchangeNamePos)); if (!withdrawalMinMap.empty()) { return; diff --git a/src/api/exchanges/include/bithumbprivateapi.hpp b/src/api/exchanges/include/bithumbprivateapi.hpp index af0b71c0..703decc1 100644 --- a/src/api/exchanges/include/bithumbprivateapi.hpp +++ b/src/api/exchanges/include/bithumbprivateapi.hpp @@ -70,14 +70,19 @@ class BithumbPrivate : public ExchangePrivate { void cancelOrderProcess(OrderIdView orderId, const TradeContext& tradeContext); struct CurrencyOrderInfo { - int8_t nbDecimals{}; - TimePoint lastNbDecimalsUpdatedTime; - MonetaryAmount minOrderSize; - TimePoint lastMinOrderSizeUpdatedTime; - MonetaryAmount minOrderPrice; - TimePoint lastMinOrderPriceUpdatedTime; - MonetaryAmount maxOrderPrice; - TimePoint lastMaxOrderPriceUpdatedTime; + struct MonetaryAmountWithTs { + int64_t ts; + MonetaryAmount val; + }; + struct DecimalsWithTs { + int64_t ts; + int8_t val; + }; + + DecimalsWithTs nbDecimals; + MonetaryAmountWithTs minOrderSize; + MonetaryAmountWithTs minOrderPrice; + MonetaryAmountWithTs maxOrderPrice; }; using CurrencyOrderInfoMap = std::unordered_map; @@ -88,4 +93,4 @@ class BithumbPrivate : public ExchangePrivate { CachedResult _depositWalletsCache; }; } // namespace api -} // namespace cct \ No newline at end of file +} // namespace cct diff --git a/src/api/exchanges/include/bithumbpublicapi.hpp b/src/api/exchanges/include/bithumbpublicapi.hpp index 43eead87..ce705aad 100644 --- a/src/api/exchanges/include/bithumbpublicapi.hpp +++ b/src/api/exchanges/include/bithumbpublicapi.hpp @@ -45,7 +45,9 @@ class BithumbPublic : public ExchangePublic { MarketPriceMap queryAllPrices() override { return MarketPriceMapFromMarketOrderBookMap(_allOrderBooksCache.get()); } - MonetaryAmountByCurrencySet queryWithdrawalFees() override { return _commonApi.tryQueryWithdrawalFees(name()); } + MonetaryAmountByCurrencySet queryWithdrawalFees() override { + return _commonApi.tryQueryWithdrawalFees(exchangeNameEnum()); + } std::optional queryWithdrawalFee(CurrencyCode currencyCode) override; diff --git a/src/api/exchanges/include/krakenpublicapi.hpp b/src/api/exchanges/include/krakenpublicapi.hpp index cc492b49..034ffaa5 100644 --- a/src/api/exchanges/include/krakenpublicapi.hpp +++ b/src/api/exchanges/include/krakenpublicapi.hpp @@ -19,8 +19,6 @@ class CommonAPI; class KrakenPublic : public ExchangePublic { public: - static constexpr std::string_view kExchangeName = "kraken"; - KrakenPublic(const CoincenterInfo& config, FiatConverter& fiatConverter, CommonAPI& commonAPI); bool healthCheck() override; @@ -38,7 +36,7 @@ class KrakenPublic : public ExchangePublic { MarketPriceMap queryAllPrices() override { return MarketPriceMapFromMarketOrderBookMap(_allOrderBooksCache.get(1)); } MonetaryAmountByCurrencySet queryWithdrawalFees() override { - return _commonApi.tryQueryWithdrawalFees(kExchangeName); + return _commonApi.tryQueryWithdrawalFees(exchangeNameEnum()); } std::optional queryWithdrawalFee(CurrencyCode currencyCode) override; diff --git a/src/api/exchanges/src/bithumbprivateapi.cpp b/src/api/exchanges/src/bithumbprivateapi.cpp index 98bd9130..c3cc52df 100644 --- a/src/api/exchanges/src/bithumbprivateapi.cpp +++ b/src/api/exchanges/src/bithumbprivateapi.cpp @@ -48,6 +48,7 @@ #include "orderid.hpp" #include "ordersconstraints.hpp" #include "permanentcurloptions.hpp" +#include "read-json.hpp" #include "request-retry.hpp" #include "runmodes.hpp" #include "ssl_sha.hpp" @@ -63,6 +64,7 @@ #include "withdrawinfo.hpp" #include "withdrawordeposit.hpp" #include "withdrawsconstraints.hpp" +#include "write-json.hpp" namespace cct::api { namespace { @@ -121,9 +123,7 @@ void SetHttpHeaders(CurlOptions& opts, const APIKey& apiKey, const auto& signatu httpHeaders.emplace_back(kApiClientType, kApiClientTypeValue); } -template -bool LoadCurrencyInfoField(const json::container& currencyOrderInfoJson, std::string_view keyStr, ValueType& val, - TimePoint& ts) { +bool LoadCurrencyInfoField(const json::container& currencyOrderInfoJson, std::string_view keyStr, auto& valTs) { const auto subPartIt = currencyOrderInfoJson.find(keyStr); if (subPartIt != currencyOrderInfoJson.end()) { const auto valIt = subPartIt->find(kValueKeyStr); @@ -132,14 +132,15 @@ bool LoadCurrencyInfoField(const json::container& currencyOrderInfoJson, std::st log::warn("Unexpected format of Bithumb cache detected - do not use (will be automatically updated)"); return false; } + using ValueType = std::remove_cvref_t; if constexpr (std::is_same_v) { - val = MonetaryAmount(valIt->get()); - log::trace("Loaded {} for '{}' from cache file", val.str(), keyStr); + valTs.val = MonetaryAmount(valIt->get()); + log::trace("Loaded {} for '{}' from cache file", valTs.val.str(), keyStr); } else { - val = valIt->get(); - log::trace("Loaded {} for '{}' from cache file", val, keyStr); + valTs.val = valIt->get(); + log::trace("Loaded {} for '{}' from cache file", valTs.val, keyStr); } - ts = TimePoint(seconds(tsIt->get())); + valTs.ts = tsIt->get(); return true; } return false; @@ -326,21 +327,7 @@ BithumbPrivate::BithumbPrivate(const CoincenterInfo& config, BithumbPublic& bith _cachedResultVault), _curlHandle, _apiKey, bithumbPublic) { if (config.getRunMode() != settings::RunMode::kQueryResponseOverriden) { - json::container data = GetBithumbCurrencyInfoMapCache(_coincenterInfo.dataDir()).readAllJson(); - for (const auto& [currencyCodeStr, currencyOrderInfoJson] : data.items()) { - CurrencyOrderInfo currencyOrderInfo; - - LoadCurrencyInfoField(currencyOrderInfoJson, kNbDecimalsStr, currencyOrderInfo.nbDecimals, - currencyOrderInfo.lastNbDecimalsUpdatedTime); - LoadCurrencyInfoField(currencyOrderInfoJson, kMinOrderSizeJsonKeyStr, currencyOrderInfo.minOrderSize, - currencyOrderInfo.lastMinOrderSizeUpdatedTime); - LoadCurrencyInfoField(currencyOrderInfoJson, kMinOrderPriceJsonKeyStr, currencyOrderInfo.minOrderPrice, - currencyOrderInfo.lastMinOrderPriceUpdatedTime); - LoadCurrencyInfoField(currencyOrderInfoJson, kMaxOrderPriceJsonKeyStr, currencyOrderInfo.maxOrderPrice, - currencyOrderInfo.lastMaxOrderPriceUpdatedTime); - - _currencyOrderInfoMap.insert_or_assign(CurrencyCode(currencyCodeStr), std::move(currencyOrderInfo)); - } + ReadExactJsonOrThrow(GetBithumbCurrencyInfoMapCache(_coincenterInfo.dataDir()).readAll(), _currencyOrderInfoMap); } } @@ -879,11 +866,12 @@ PlaceOrderInfo BithumbPrivate::placeOrder(MonetaryAmount /*from*/, MonetaryAmoun auto currencyOrderInfoIt = _currencyOrderInfoMap.find(mk.base()); auto nowTime = Clock::now(); + auto tsToTimePoint = [](int64_t ts) { return TimePoint{seconds(ts)}; }; CurrencyOrderInfo currencyOrderInfo; if (currencyOrderInfoIt != _currencyOrderInfoMap.end()) { currencyOrderInfo = currencyOrderInfoIt->second; - if (currencyOrderInfo.lastNbDecimalsUpdatedTime + _currencyOrderInfoRefreshTime > nowTime) { - int8_t nbMaxDecimalsUnits = currencyOrderInfo.nbDecimals; + if (tsToTimePoint(currencyOrderInfo.nbDecimals.ts) + _currencyOrderInfoRefreshTime > nowTime) { + int8_t nbMaxDecimalsUnits = currencyOrderInfo.nbDecimals.val; volume.truncate(nbMaxDecimalsUnits); if (volume == 0) { log::warn("No trade of {} into {} because min number of decimals is {} for this market", volume, toCurrencyCode, @@ -895,13 +883,13 @@ PlaceOrderInfo BithumbPrivate::placeOrder(MonetaryAmount /*from*/, MonetaryAmoun if (!isTakerStrategy) { MonetaryAmount minOrderPrice = price; MonetaryAmount maxOrderPrice = price; - if (currencyOrderInfo.lastMinOrderPriceUpdatedTime + _currencyOrderInfoRefreshTime > nowTime && - currencyOrderInfo.minOrderPrice.currencyCode() == price.currencyCode()) { - minOrderPrice = currencyOrderInfo.minOrderPrice; + if (tsToTimePoint(currencyOrderInfo.minOrderPrice.ts) + _currencyOrderInfoRefreshTime > nowTime && + currencyOrderInfo.minOrderPrice.val.currencyCode() == price.currencyCode()) { + minOrderPrice = currencyOrderInfo.minOrderPrice.val; } - if (currencyOrderInfo.lastMaxOrderPriceUpdatedTime + _currencyOrderInfoRefreshTime > nowTime && - currencyOrderInfo.maxOrderPrice.currencyCode() == price.currencyCode()) { - maxOrderPrice = currencyOrderInfo.maxOrderPrice; + if (tsToTimePoint(currencyOrderInfo.maxOrderPrice.ts) + _currencyOrderInfoRefreshTime > nowTime && + currencyOrderInfo.maxOrderPrice.val.currencyCode() == price.currencyCode()) { + maxOrderPrice = currencyOrderInfo.maxOrderPrice.val; } if (price < minOrderPrice || price > maxOrderPrice) { if (isSimulationWithRealOrder) { @@ -920,8 +908,8 @@ PlaceOrderInfo BithumbPrivate::placeOrder(MonetaryAmount /*from*/, MonetaryAmoun } } - if (currencyOrderInfo.lastMinOrderSizeUpdatedTime + _currencyOrderInfoRefreshTime > nowTime) { - MonetaryAmount size = currencyOrderInfo.minOrderSize; + if (tsToTimePoint(currencyOrderInfo.minOrderSize.ts) + _currencyOrderInfoRefreshTime > nowTime) { + MonetaryAmount size = currencyOrderInfo.minOrderSize.val; CurrencyCode minOrderSizeCur = size.currencyCode(); if (volume.currencyCode() == minOrderSizeCur) { size = volume; @@ -930,9 +918,9 @@ PlaceOrderInfo BithumbPrivate::placeOrder(MonetaryAmount /*from*/, MonetaryAmoun } else { log::error("Unexpected currency for min order size {}", size); } - if (size < currencyOrderInfo.minOrderSize && !isSimulationWithRealOrder) { + if (size < currencyOrderInfo.minOrderSize.val && !isSimulationWithRealOrder) { log::warn("No trade of {} into {} because {} is lower than min order {}", volume, toCurrencyCode, size, - currencyOrderInfo.minOrderSize); + currencyOrderInfo.minOrderSize.val); placeOrderInfo.setClosed(); return placeOrderInfo; } @@ -961,46 +949,42 @@ PlaceOrderInfo BithumbPrivate::placeOrder(MonetaryAmount /*from*/, MonetaryAmoun } currencyInfoUpdated = true; - if (LoadCurrencyInfoField(result, kNbDecimalsStr, currencyOrderInfo.nbDecimals, - currencyOrderInfo.lastNbDecimalsUpdatedTime)) { - volume.truncate(currencyOrderInfo.nbDecimals); + if (LoadCurrencyInfoField(result, kNbDecimalsStr, currencyOrderInfo.nbDecimals)) { + volume.truncate(currencyOrderInfo.nbDecimals.val); if (volume == 0) { log::warn("No trade of {} into {} because volume is 0 after truncating to {} decimals", volume, toCurrencyCode, - static_cast(currencyOrderInfo.nbDecimals)); + static_cast(currencyOrderInfo.nbDecimals.val)); break; } placePostData.set("units", volume.amountStr()); - } else if (LoadCurrencyInfoField(result, kMinOrderSizeJsonKeyStr, currencyOrderInfo.minOrderSize, - currencyOrderInfo.lastMinOrderSizeUpdatedTime)) { - if (!isSimulationWithRealOrder || currencyOrderInfo.minOrderSize.currencyCode() != price.currencyCode()) { + } else if (LoadCurrencyInfoField(result, kMinOrderSizeJsonKeyStr, currencyOrderInfo.minOrderSize)) { + if (!isSimulationWithRealOrder || currencyOrderInfo.minOrderSize.val.currencyCode() != price.currencyCode()) { log::warn("No trade of {} into {} because min order size is {} for this market", volume, toCurrencyCode, - currencyOrderInfo.minOrderSize); + currencyOrderInfo.minOrderSize.val); break; } - volume = MonetaryAmount(currencyOrderInfo.minOrderSize / price, volume.currencyCode()); + volume = MonetaryAmount(currencyOrderInfo.minOrderSize.val / price, volume.currencyCode()); placePostData.set("units", volume.amountStr()); - } else if (LoadCurrencyInfoField(result, kMinOrderPriceJsonKeyStr, currencyOrderInfo.minOrderPrice, - currencyOrderInfo.lastMinOrderPriceUpdatedTime)) { + } else if (LoadCurrencyInfoField(result, kMinOrderPriceJsonKeyStr, currencyOrderInfo.minOrderPrice)) { if (isSimulationWithRealOrder) { if (!isTakerStrategy) { - price = currencyOrderInfo.minOrderPrice; + price = currencyOrderInfo.minOrderPrice.val; placePostData.set("price", price.amountStr()); } } else { log::warn("No trade of {} into {} because min order price is {} for this market", volume, toCurrencyCode, - currencyOrderInfo.minOrderPrice); + currencyOrderInfo.minOrderPrice.val); break; } - } else if (LoadCurrencyInfoField(result, kMaxOrderPriceJsonKeyStr, currencyOrderInfo.maxOrderPrice, - currencyOrderInfo.lastMaxOrderPriceUpdatedTime)) { + } else if (LoadCurrencyInfoField(result, kMaxOrderPriceJsonKeyStr, currencyOrderInfo.maxOrderPrice)) { if (isSimulationWithRealOrder) { if (!isTakerStrategy) { - price = currencyOrderInfo.maxOrderPrice; + price = currencyOrderInfo.maxOrderPrice.val; placePostData.set("price", price.amountStr()); } } else { log::warn("No trade of {} into {} because max order price is {} for this market", volume, toCurrencyCode, - currencyOrderInfo.maxOrderPrice); + currencyOrderInfo.maxOrderPrice.val); break; } } else { @@ -1205,25 +1189,7 @@ InitiatedWithdrawInfo BithumbPrivate::launchWithdraw(MonetaryAmount grossAmount, } void BithumbPrivate::updateCacheFile() const { - json::container data; - for (const auto& [currencyCode, currencyOrderInfo] : _currencyOrderInfoMap) { - json::container curData; - - curData.emplace(kNbDecimalsStr, CurrencyOrderInfoField2Json(currencyOrderInfo.nbDecimals, - currencyOrderInfo.lastNbDecimalsUpdatedTime)); - curData.emplace( - kMinOrderSizeJsonKeyStr, - CurrencyOrderInfoField2Json(currencyOrderInfo.minOrderSize, currencyOrderInfo.lastMinOrderSizeUpdatedTime)); - curData.emplace( - kMinOrderPriceJsonKeyStr, - CurrencyOrderInfoField2Json(currencyOrderInfo.minOrderPrice, currencyOrderInfo.lastMinOrderPriceUpdatedTime)); - curData.emplace( - kMaxOrderPriceJsonKeyStr, - CurrencyOrderInfoField2Json(currencyOrderInfo.maxOrderPrice, currencyOrderInfo.lastMaxOrderPriceUpdatedTime)); - - data.emplace(currencyCode.str(), std::move(curData)); - } - GetBithumbCurrencyInfoMapCache(_coincenterInfo.dataDir()).writeJson(data); + GetBithumbCurrencyInfoMapCache(_coincenterInfo.dataDir()).write(WriteMiniJsonOrThrow(_currencyOrderInfoMap)); } } // namespace cct::api diff --git a/src/api/exchanges/src/bithumbpublicapi.cpp b/src/api/exchanges/src/bithumbpublicapi.cpp index 6f92a1c1..23c5d61a 100644 --- a/src/api/exchanges/src/bithumbpublicapi.cpp +++ b/src/api/exchanges/src/bithumbpublicapi.cpp @@ -156,7 +156,7 @@ MarketSet BithumbPublic::queryTradableMarkets() { } std::optional BithumbPublic::queryWithdrawalFee(CurrencyCode currencyCode) { - return _commonApi.tryQueryWithdrawalFee(name(), currencyCode); + return _commonApi.tryQueryWithdrawalFee(exchangeNameEnum(), currencyCode); } MonetaryAmount BithumbPublic::queryLastPrice(Market mk) { diff --git a/src/api/exchanges/src/krakenpublicapi.cpp b/src/api/exchanges/src/krakenpublicapi.cpp index 9f4d623f..28e71d1c 100644 --- a/src/api/exchanges/src/krakenpublicapi.cpp +++ b/src/api/exchanges/src/krakenpublicapi.cpp @@ -145,7 +145,7 @@ bool KrakenPublic::healthCheck() { } std::optional KrakenPublic::queryWithdrawalFee(CurrencyCode currencyCode) { - return _commonApi.tryQueryWithdrawalFee(kExchangeName, currencyCode); + return _commonApi.tryQueryWithdrawalFee(exchangeNameEnum(), currencyCode); } CurrencyExchangeFlatSet KrakenPublic::TradableCurrenciesFunc::operator()() { diff --git a/src/api/exchanges/src/upbitpublicapi.cpp b/src/api/exchanges/src/upbitpublicapi.cpp index 4749841b..cd992638 100644 --- a/src/api/exchanges/src/upbitpublicapi.cpp +++ b/src/api/exchanges/src/upbitpublicapi.cpp @@ -35,9 +35,11 @@ #include "order-book-line.hpp" #include "permanentcurloptions.hpp" #include "public-trade-vector.hpp" +#include "read-json.hpp" #include "request-retry.hpp" #include "timedef.hpp" #include "tradeside.hpp" +#include "withdraw-fees-file-schema.hpp" namespace cct::api { namespace { @@ -168,13 +170,19 @@ MarketSet UpbitPublic::MarketsFunc::operator()() { MonetaryAmountByCurrencySet UpbitPublic::WithdrawalFeesFunc::operator()() { MonetaryAmountVector fees; File withdrawFeesFile(_dataDir, File::Type::kStatic, "withdrawfees.json", File::IfError::kThrow); - json::container jsonData = withdrawFeesFile.readAllJson(); - for (const auto& [coin, value] : jsonData[_name].items()) { - CurrencyCode coinAcro(coin); - MonetaryAmount ma(value.get(), coinAcro); - log::debug("Updated Upbit withdrawal fees {}", ma); - fees.push_back(ma); + auto jsonDataStr = withdrawFeesFile.readAll(); + schema::WithdrawFeesFile obj; + ReadExactJsonOrThrow(jsonDataStr, obj); + + auto upbitIt = obj.find(ExchangeNameEnum::upbit); + if (upbitIt != obj.end()) { + for (const auto& [cur, value] : upbitIt->second) { + MonetaryAmount ma(value, cur); + log::debug("Updated Upbit withdrawal fees {}", ma); + fees.push_back(ma); + } } + log::info("Updated Upbit withdrawal fees for {} coins", fees.size()); return MonetaryAmountByCurrencySet(std::move(fees)); } diff --git a/src/api/exchanges/src/withdraw-fees-file-schema.hpp b/src/api/exchanges/src/withdraw-fees-file-schema.hpp new file mode 100644 index 00000000..6ddcbcdc --- /dev/null +++ b/src/api/exchanges/src/withdraw-fees-file-schema.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include "cct_const.hpp" +#include "currencycode.hpp" +#include "monetaryamount.hpp" + +namespace cct::schema { + +using WithdrawFeesFilePerExchange = std::unordered_map; +using WithdrawFeesFile = std::unordered_map; + +} // namespace cct::schema \ No newline at end of file diff --git a/src/basic-objects/include/reader.hpp b/src/basic-objects/include/reader.hpp index 332aae21..7cff8128 100644 --- a/src/basic-objects/include/reader.hpp +++ b/src/basic-objects/include/reader.hpp @@ -1,6 +1,5 @@ #pragma once -#include "cct_json-container.hpp" #include "cct_string.hpp" namespace cct { @@ -13,9 +12,6 @@ class Reader { // Read all content and return a string of it. [[nodiscard]] virtual string readAll() const { return {}; } - - // Read all content, and constructs a json object from it. - json::container readAllJson() const; }; } // namespace cct \ No newline at end of file diff --git a/src/basic-objects/src/reader.cpp b/src/basic-objects/src/reader.cpp deleted file mode 100644 index 925a1710..00000000 --- a/src/basic-objects/src/reader.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "reader.hpp" - -#include - -#include "cct_json-container.hpp" -#include "cct_string.hpp" -namespace cct { - -json::container Reader::readAllJson() const { - string dataS = readAll(); - if (dataS.empty()) { - dataS.append("{}"); - } - return json::container::parse(std::move(dataS)); -} - -} // namespace cct \ No newline at end of file