From cdad878ea80e19c8a7834458d77e89edc71a7bd1 Mon Sep 17 00:00:00 2001 From: Stephane Janel Date: Sat, 2 Dec 2023 22:55:41 +0100 Subject: [PATCH] Currency is now optional for withdraw-fee CLI, renamed into withdraw-fees --- README.md | 40 +++++++++--- .../include/exchangepublicapitypes.hpp | 2 - src/api-objects/include/tradeinfo.hpp | 10 +-- src/api/common/include/exchangeprivateapi.hpp | 8 +-- src/api/common/include/exchangepublicapi.hpp | 10 ++- .../common/include/exchangepublicapi_mock.hpp | 7 ++- src/api/common/src/exchangepublicapi.cpp | 12 ++++ .../exchanges/include/binanceprivateapi.hpp | 14 +++-- .../exchanges/include/binancepublicapi.hpp | 5 +- .../exchanges/include/bithumbprivateapi.hpp | 2 +- .../exchanges/include/bithumbpublicapi.hpp | 7 ++- src/api/exchanges/include/huobipublicapi.hpp | 6 +- src/api/exchanges/include/krakenpublicapi.hpp | 9 +-- src/api/exchanges/include/kucoinpublicapi.hpp | 8 +-- src/api/exchanges/include/upbitprivateapi.hpp | 19 +++++- src/api/exchanges/include/upbitpublicapi.hpp | 7 ++- src/api/exchanges/src/binanceprivateapi.cpp | 10 +-- src/api/exchanges/src/binancepublicapi.cpp | 9 +-- src/api/exchanges/src/bithumbprivateapi.cpp | 2 +- src/api/exchanges/src/bithumbpublicapi.cpp | 8 +-- src/api/exchanges/src/huobiprivateapi.cpp | 8 +-- src/api/exchanges/src/huobipublicapi.cpp | 14 +++-- src/api/exchanges/src/krakenpublicapi.cpp | 11 ++-- src/api/exchanges/src/kucoinprivateapi.cpp | 5 +- src/api/exchanges/src/kucoinpublicapi.cpp | 15 +++-- src/api/exchanges/src/upbitprivateapi.cpp | 10 +-- src/api/exchanges/src/upbitpublicapi.cpp | 9 +-- src/api/exchanges/test/commonapi_test.hpp | 4 +- src/api/interface/include/exchange.hpp | 12 +++- .../include/exchangeretrieverbase.hpp | 2 +- src/engine/include/coincenter.hpp | 2 +- src/engine/include/coincenteroptions.hpp | 2 +- src/engine/include/coincenteroptionsdef.hpp | 10 +-- src/engine/include/exchangesorchestrator.hpp | 2 +- src/engine/include/queryresultprinter.hpp | 2 +- src/engine/include/queryresulttypes.hpp | 4 ++ src/engine/src/coincenter.cpp | 5 +- src/engine/src/coincentercommand.cpp | 2 +- src/engine/src/coincentercommands.cpp | 8 +-- src/engine/src/exchangesorchestrator.cpp | 32 +++++++--- src/engine/src/queryresultprinter.cpp | 62 ++++++++++++++----- .../test/queryresultprinter_public_test.cpp | 51 ++++++++------- src/objects/include/coincentercommandtype.hpp | 2 +- .../include/monetaryamountbycurrencyset.hpp | 4 ++ src/objects/src/apioutputtype.cpp | 5 +- src/objects/src/coincentercommandtype.cpp | 8 +-- src/objects/src/coincenterinfo.cpp | 3 +- src/objects/src/exchangename.cpp | 1 + src/tech/include/simpletable.hpp | 2 +- src/tech/include/toupperlower-string.hpp | 23 +++++++ src/tech/include/toupperlower.hpp | 28 ++------- 51 files changed, 343 insertions(+), 200 deletions(-) create mode 100644 src/tech/include/toupperlower-string.hpp diff --git a/README.md b/README.md index cac853f7..64cda8ad 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Main features: - Traded volume - Last price - Last trades +- Withdraw fees **Private requests** @@ -75,6 +76,9 @@ Main features: - [Last price](#last-price) - [Last trades](#last-trades) - [Conversion path](#conversion-path) + - [Withdraw fees](#withdraw-fees) + - [Example 1: query all withdraw fees](#example-1-query-all-withdraw-fees) + - [Example 2: query ETH withdraw fees on Kraken and Kucoin](#example-2-query-eth-withdraw-fees-on-kraken-and-kucoin) - [Private requests](#private-requests) - [Selecting private keys on exchanges](#selecting-private-keys-on-exchanges) - [Balance](#balance) @@ -195,13 +199,14 @@ coincenter balance orderbook XRP-USDT,binance --cur EUR Some commands' input can be deduced from previous commands' output, a bit like piping commands in Linux works. Input commands accepting previous commands' output are: + - Withdraw - Trade - Sell For example: -``` +```bash 1st command 3rd command / \ / \ coincenter buy 1500XLM,binance withdraw kraken sell @@ -255,13 +260,13 @@ It is the first thing that is checked in exchanges unit tests, hence if the heal List all currencies for all supported exchanges -``` +```bash coincenter currencies ``` List all currencies for kucoin and upbit -``` +```bash coincenter currencies kucoin,upbit ``` @@ -318,7 +323,7 @@ In addition, for convenience, you can also specify a currency in which to conver Example: Print ADA (Cardano) - USDT market order book with a depth of 20 on Kraken and Binance -``` +```bash coincenter orderbook ada-usdt,kraken,binance --depth 20 ``` @@ -328,7 +333,7 @@ Fast query last 24h traded volume with `volume-day` option on one market on one, Example: Print last 24h traded volume on market XLM-BTC for all exchanges supporting it -``` +```bash coincenter volume-day xlm-btc ``` @@ -338,7 +343,7 @@ Fast query last traded price with `price` option on one market on one, several o Example: Print last price on market SOL-BTC for all exchanges supporting it -``` +```bash coincenter price sol-btc ``` @@ -349,7 +354,7 @@ You can specify the number of last trades to query (for exchanges supporting thi Example: Print the last 15 trades on DOT-USDT on Binance and Huobi -``` +```bash coincenter last-trades dot-usdt,binance,huobi --n 15 ``` @@ -363,12 +368,31 @@ Option `conversion` is used internally for [multi trade](#multi-trade) but is pr Example: Print the fastest conversion path from Shiba Inu to Solana on all exchanges where such conversion is possible -``` +```bash coincenter conversion shib-sol ``` **Note**: when several conversion paths of same length are possible, it will favor the ones not involving fiat currencies. +### Withdraw fees + +Some exchanges provide a withdraw fees endpoint. Some propose it without an API Key, other require an API Key. `coincenter` uses other sources of data (although less reliable) for exchanges which do not propose withdraw fees. + +You can query all withdraw fees at once, for all exchanges or provided ones. You can also specify a currency to filter fees only for this currency. + +#### Example 1: query all withdraw fees + +```bash +coincenter withdraw-fees +``` + +#### Example 2: query ETH withdraw fees on Kraken and Kucoin + +```bash +coincenter withdraw-fees eth,kraken,kucoin +``` + + ## Private requests These requests will require that you have your secret keys in `data/secret/secret.json` file, for each exchange used. diff --git a/src/api-objects/include/exchangepublicapitypes.hpp b/src/api-objects/include/exchangepublicapitypes.hpp index 427b048d..28fe37ef 100644 --- a/src/api-objects/include/exchangepublicapitypes.hpp +++ b/src/api-objects/include/exchangepublicapitypes.hpp @@ -9,7 +9,6 @@ #include "market.hpp" #include "marketorderbook.hpp" #include "monetaryamount.hpp" -#include "monetaryamountbycurrencyset.hpp" #include "publictrade.hpp" namespace cct { @@ -17,6 +16,5 @@ using MarketSet = FlatSet; using MarketOrderBookMap = std::unordered_map; using MarketPriceMap = std::unordered_map; using MarketsPath = SmallVector; -using WithdrawalFeesSet = MonetaryAmountByCurrencySet; using LastTradesVector = vector; } // namespace cct \ No newline at end of file diff --git a/src/api-objects/include/tradeinfo.hpp b/src/api-objects/include/tradeinfo.hpp index f442df99..e93289e1 100644 --- a/src/api-objects/include/tradeinfo.hpp +++ b/src/api-objects/include/tradeinfo.hpp @@ -1,10 +1,12 @@ #pragma once -#include "cct_string.hpp" +#include + +#include "cct_type_traits.hpp" #include "market.hpp" -#include "monetaryamount.hpp" #include "orderid.hpp" #include "tradedamounts.hpp" +#include "tradedefinitions.hpp" #include "tradeoptions.hpp" namespace cct::api { @@ -28,7 +30,7 @@ struct TradeInfo { }; struct OrderInfo { - bool operator==(const OrderInfo &) const = default; + bool operator==(const OrderInfo &) const noexcept = default; TradedAmounts tradedAmounts; bool isClosed = false; @@ -41,7 +43,7 @@ struct PlaceOrderInfo { TradedAmounts &tradedAmounts() { return orderInfo.tradedAmounts; } const TradedAmounts &tradedAmounts() const { return orderInfo.tradedAmounts; } - bool operator==(const PlaceOrderInfo &) const = default; + bool operator==(const PlaceOrderInfo &) const noexcept = default; using trivially_relocatable = is_trivially_relocatable::type; diff --git a/src/api/common/include/exchangeprivateapi.hpp b/src/api/common/include/exchangeprivateapi.hpp index a9345c07..d6329f93 100644 --- a/src/api/common/include/exchangeprivateapi.hpp +++ b/src/api/common/include/exchangeprivateapi.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -8,7 +7,6 @@ #include "balanceoptions.hpp" #include "balanceportfolio.hpp" #include "cachedresultvault.hpp" -#include "curlhandle.hpp" #include "currencycode.hpp" #include "currencyexchangeflatset.hpp" #include "depositsconstraints.hpp" @@ -19,7 +17,7 @@ #include "exchangepublicapitypes.hpp" #include "market.hpp" #include "monetaryamount.hpp" -#include "order.hpp" +#include "monetaryamountbycurrencyset.hpp" #include "orderid.hpp" #include "ordersconstraints.hpp" #include "tradedamounts.hpp" @@ -105,11 +103,11 @@ class ExchangePrivate : public ExchangeBase { /// Retrieve the fixed withdrawal fees per currency. /// Some exchanges provide this service in the public REST API but not all, hence this private API flavor. - virtual WithdrawalFeesSet queryWithdrawalFees() { return _exchangePublic.queryWithdrawalFees(); } + virtual MonetaryAmountByCurrencySet queryWithdrawalFees() { return _exchangePublic.queryWithdrawalFees(); } /// Retrieve the withdrawal fee of a Currency only /// Some exchanges provide this service in the public REST API but not all, hence this private API flavor. - virtual MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) { + virtual std::optional queryWithdrawalFee(CurrencyCode currencyCode) { return _exchangePublic.queryWithdrawalFee(currencyCode); } diff --git a/src/api/common/include/exchangepublicapi.hpp b/src/api/common/include/exchangepublicapi.hpp index e2600bad..6c3eb721 100644 --- a/src/api/common/include/exchangepublicapi.hpp +++ b/src/api/common/include/exchangepublicapi.hpp @@ -12,8 +12,8 @@ #include "market.hpp" #include "marketorderbook.hpp" #include "monetaryamount.hpp" +#include "monetaryamountbycurrencyset.hpp" #include "priceoptions.hpp" -#include "tradedefinitions.hpp" namespace cct { @@ -70,10 +70,10 @@ class ExchangePublic : public ExchangeBase { /// Retrieve the fixed withdrawal fees per currency. /// Depending on the exchange, this could be retrieved dynamically, /// or, if not possible, should be retrieved from a static source updated regularly. - virtual WithdrawalFeesSet queryWithdrawalFees() = 0; + virtual MonetaryAmountByCurrencySet queryWithdrawalFees() = 0; /// Retrieve the withdrawal fee of a Currency only - virtual MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) = 0; + virtual std::optional queryWithdrawalFee(CurrencyCode currencyCode) = 0; /// Return true if exchange supports official REST API has an endpoint to get withdrawal fees /// For instance, Kraken does not offer such endpoint, we nee to query external sources which may provide inaccurate @@ -162,6 +162,10 @@ class ExchangePublic : public ExchangeBase { CommonAPI &commonAPI() { return _commonApi; } + /// Query withdrawal fee for given currency code. + /// If no data found, return a 0 MonetaryAmount on given currency. + MonetaryAmount queryWithdrawalFeeOrZero(CurrencyCode currencyCode); + protected: friend class ExchangePrivate; diff --git a/src/api/common/include/exchangepublicapi_mock.hpp b/src/api/common/include/exchangepublicapi_mock.hpp index c5679103..7856915c 100644 --- a/src/api/common/include/exchangepublicapi_mock.hpp +++ b/src/api/common/include/exchangepublicapi_mock.hpp @@ -2,10 +2,13 @@ #include +#include + #include "commonapi.hpp" #include "exchangepublicapi.hpp" #include "exchangepublicapitypes.hpp" #include "fiatconverter.hpp" +#include "monetaryamount.hpp" namespace cct::api { class MockExchangePublic : public ExchangePublic { @@ -19,8 +22,8 @@ class MockExchangePublic : public ExchangePublic { MOCK_METHOD(CurrencyExchange, convertStdCurrencyToCurrencyExchange, (CurrencyCode currencyCode), (override)); MOCK_METHOD(MarketSet, queryTradableMarkets, (), (override)); MOCK_METHOD(MarketPriceMap, queryAllPrices, (), (override)); - MOCK_METHOD(WithdrawalFeesSet, queryWithdrawalFees, (), (override)); - MOCK_METHOD(MonetaryAmount, queryWithdrawalFee, (CurrencyCode currencyCode), (override)); + MOCK_METHOD(MonetaryAmountByCurrencySet, queryWithdrawalFees, (), (override)); + MOCK_METHOD(std::optional, queryWithdrawalFee, (CurrencyCode currencyCode), (override)); MOCK_METHOD(bool, isWithdrawalFeesSourceReliable, (), (const override)); MOCK_METHOD(MarketOrderBookMap, queryAllApproximatedOrderBooks, (int depth), (override)); MOCK_METHOD(MarketOrderBook, queryOrderBook, (Market mk, int depth), (override)); diff --git a/src/api/common/src/exchangepublicapi.cpp b/src/api/common/src/exchangepublicapi.cpp index 6ba54523..75418a47 100644 --- a/src/api/common/src/exchangepublicapi.cpp +++ b/src/api/common/src/exchangepublicapi.cpp @@ -325,4 +325,16 @@ Market ExchangePublic::determineMarketFromFilterCurrencies(MarketSet &markets, C return ret; } +MonetaryAmount ExchangePublic::queryWithdrawalFeeOrZero(CurrencyCode currencyCode) { + std::optional optWithdrawFee = queryWithdrawalFee(currencyCode); + MonetaryAmount withdrawFee; + if (optWithdrawFee) { + withdrawFee = *optWithdrawFee; + } else { + log::error("Unable to retrieve withdraw fee for {} on {}, consider 0", currencyCode, name()); + withdrawFee = MonetaryAmount(0, currencyCode); + } + return withdrawFee; +} + } // namespace cct::api \ No newline at end of file diff --git a/src/api/exchanges/include/binanceprivateapi.hpp b/src/api/exchanges/include/binanceprivateapi.hpp index fc548174..b58df4dc 100644 --- a/src/api/exchanges/include/binanceprivateapi.hpp +++ b/src/api/exchanges/include/binanceprivateapi.hpp @@ -1,8 +1,8 @@ #pragma once +#include #include -#include "apikey.hpp" #include "balanceoptions.hpp" #include "balanceportfolio.hpp" #include "cachedresult.hpp" @@ -13,7 +13,6 @@ #include "depositsconstraints.hpp" #include "exchangeprivateapi.hpp" #include "exchangeprivateapitypes.hpp" -#include "exchangepublicapitypes.hpp" #include "httprequesttype.hpp" #include "monetaryamount.hpp" #include "ordersconstraints.hpp" @@ -30,6 +29,7 @@ class ExchangeInfo; class FiatConverter; namespace api { +class APIKey; class BinancePublic; class BinancePrivate : public ExchangePrivate { @@ -54,9 +54,11 @@ class BinancePrivate : public ExchangePrivate { WithdrawsSet queryRecentWithdraws(const WithdrawsConstraints& withdrawsConstraints = WithdrawsConstraints()) override; - WithdrawalFeesSet queryWithdrawalFees() override { return _allWithdrawFeesCache.get(); } + MonetaryAmountByCurrencySet queryWithdrawalFees() override { return _allWithdrawFeesCache.get(); } - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) override { return _withdrawFeesCache.get(currencyCode); } + std::optional queryWithdrawalFee(CurrencyCode currencyCode) override { + return _withdrawFeesCache.get(currencyCode); + } protected: bool isSimulatedOrderSupported() const override { return true; } @@ -111,14 +113,14 @@ class BinancePrivate : public ExchangePrivate { Duration& queryDelay) : BinanceContext(curlHandle, apiKey, exchangePublic, queryDelay) {} - WithdrawalFeesSet operator()(); + MonetaryAmountByCurrencySet operator()(); }; struct WithdrawFeesFunc : public BinanceContext { WithdrawFeesFunc(CurlHandle& curlHandle, const APIKey& apiKey, BinancePublic& exchangePublic, Duration& queryDelay) : BinanceContext(curlHandle, apiKey, exchangePublic, queryDelay) {} - MonetaryAmount operator()(CurrencyCode currencyCode); + std::optional operator()(CurrencyCode currencyCode); }; CurlHandle _curlHandle; diff --git a/src/api/exchanges/include/binancepublicapi.hpp b/src/api/exchanges/include/binancepublicapi.hpp index 8fba33ac..00cf2341 100644 --- a/src/api/exchanges/include/binancepublicapi.hpp +++ b/src/api/exchanges/include/binancepublicapi.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -46,9 +47,9 @@ class BinancePublic : public ExchangePublic { MarketPriceMap queryAllPrices() override { return MarketPriceMapFromMarketOrderBookMap(_allOrderBooksCache.get(1)); } - WithdrawalFeesSet queryWithdrawalFees() override; + MonetaryAmountByCurrencySet queryWithdrawalFees() override; - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) override; + std::optional queryWithdrawalFee(CurrencyCode currencyCode) override; bool isWithdrawalFeesSourceReliable() const override { return true; } diff --git a/src/api/exchanges/include/bithumbprivateapi.hpp b/src/api/exchanges/include/bithumbprivateapi.hpp index 08a517c0..5cb816cf 100644 --- a/src/api/exchanges/include/bithumbprivateapi.hpp +++ b/src/api/exchanges/include/bithumbprivateapi.hpp @@ -15,7 +15,7 @@ namespace cct { class CoincenterInfo; namespace api { - +class APIKey; class BithumbPublic; class BithumbPrivate : public ExchangePrivate { diff --git a/src/api/exchanges/include/bithumbpublicapi.hpp b/src/api/exchanges/include/bithumbpublicapi.hpp index 2db22cde..19c6f5bf 100644 --- a/src/api/exchanges/include/bithumbpublicapi.hpp +++ b/src/api/exchanges/include/bithumbpublicapi.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "cachedresult.hpp" @@ -34,9 +35,9 @@ class BithumbPublic : public ExchangePublic { MarketPriceMap queryAllPrices() override { return MarketPriceMapFromMarketOrderBookMap(_allOrderBooksCache.get()); } - WithdrawalFeesSet queryWithdrawalFees() override { return _withdrawalFeesCache.get(); } + MonetaryAmountByCurrencySet queryWithdrawalFees() override { return _withdrawalFeesCache.get(); } - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) override; + std::optional queryWithdrawalFee(CurrencyCode currencyCode) override; bool isWithdrawalFeesSourceReliable() const override { return true; } @@ -74,7 +75,7 @@ class BithumbPublic : public ExchangePublic { settings::RunMode runMode) : _curlHandle(kFeeUrl, pMetricGateway, permanentCurlOptions, runMode) {} - WithdrawalFeesSet operator()(); + MonetaryAmountByCurrencySet operator()(); CurlHandle _curlHandle; }; diff --git a/src/api/exchanges/include/huobipublicapi.hpp b/src/api/exchanges/include/huobipublicapi.hpp index 47bd7fa2..f74a4073 100644 --- a/src/api/exchanges/include/huobipublicapi.hpp +++ b/src/api/exchanges/include/huobipublicapi.hpp @@ -1,12 +1,12 @@ #pragma once #include +#include #include #include #include "cachedresult.hpp" #include "cct_json.hpp" -#include "cct_string.hpp" #include "curlhandle.hpp" #include "currencycode.hpp" #include "exchangepublicapi.hpp" @@ -42,9 +42,9 @@ class HuobiPublic : public ExchangePublic { MarketPriceMap queryAllPrices() override { return MarketPriceMapFromMarketOrderBookMap(_allOrderBooksCache.get(1)); } - WithdrawalFeesSet queryWithdrawalFees() override; + MonetaryAmountByCurrencySet queryWithdrawalFees() override; - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) override; + std::optional queryWithdrawalFee(CurrencyCode currencyCode) override; bool isWithdrawalFeesSourceReliable() const override { return true; } diff --git a/src/api/exchanges/include/krakenpublicapi.hpp b/src/api/exchanges/include/krakenpublicapi.hpp index 5f2a9d48..d6a45f25 100644 --- a/src/api/exchanges/include/krakenpublicapi.hpp +++ b/src/api/exchanges/include/krakenpublicapi.hpp @@ -1,7 +1,8 @@ #pragma once +#include + #include "cachedresult.hpp" -#include "cct_string.hpp" #include "curlhandle.hpp" #include "exchangepublicapi.hpp" #include "exchangepublicapitypes.hpp" @@ -35,9 +36,9 @@ class KrakenPublic : public ExchangePublic { MarketPriceMap queryAllPrices() override { return MarketPriceMapFromMarketOrderBookMap(_allOrderBooksCache.get(1)); } - WithdrawalFeesSet queryWithdrawalFees() override { return _withdrawalFeesCache.get().first; } + MonetaryAmountByCurrencySet queryWithdrawalFees() override { return _withdrawalFeesCache.get().first; } - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) override; + std::optional queryWithdrawalFee(CurrencyCode currencyCode) override; bool isWithdrawalFeesSourceReliable() const override { return false; } @@ -76,7 +77,7 @@ class KrakenPublic : public ExchangePublic { class WithdrawalFeesFunc { public: using WithdrawalMinMap = std::unordered_map; - using WithdrawalInfoMaps = std::pair; + using WithdrawalInfoMaps = std::pair; WithdrawalFeesFunc(const CoincenterInfo& coincenterInfo, Duration minDurationBetweenQueries); diff --git a/src/api/exchanges/include/kucoinpublicapi.hpp b/src/api/exchanges/include/kucoinpublicapi.hpp index 16bbff04..924a7127 100644 --- a/src/api/exchanges/include/kucoinpublicapi.hpp +++ b/src/api/exchanges/include/kucoinpublicapi.hpp @@ -1,13 +1,11 @@ #pragma once -#include +#include #include #include #include "cachedresult.hpp" #include "cct_flatset.hpp" -#include "cct_json.hpp" -#include "cct_string.hpp" #include "curlhandle.hpp" #include "curlpostdata.hpp" #include "currencycode.hpp" @@ -44,9 +42,9 @@ class KucoinPublic : public ExchangePublic { MarketPriceMap queryAllPrices() override { return MarketPriceMapFromMarketOrderBookMap(_allOrderBooksCache.get(1)); } - WithdrawalFeesSet queryWithdrawalFees() override; + MonetaryAmountByCurrencySet queryWithdrawalFees() override; - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) override; + std::optional queryWithdrawalFee(CurrencyCode currencyCode) override; bool isWithdrawalFeesSourceReliable() const override { return true; } diff --git a/src/api/exchanges/include/upbitprivateapi.hpp b/src/api/exchanges/include/upbitprivateapi.hpp index c7978e57..ae013feb 100644 --- a/src/api/exchanges/include/upbitprivateapi.hpp +++ b/src/api/exchanges/include/upbitprivateapi.hpp @@ -1,16 +1,31 @@ #pragma once +#include + +#include "balanceoptions.hpp" +#include "balanceportfolio.hpp" #include "cachedresult.hpp" #include "curlhandle.hpp" +#include "currencycode.hpp" +#include "currencyexchangeflatset.hpp" +#include "depositsconstraints.hpp" #include "exchangeprivateapi.hpp" #include "exchangeprivateapitypes.hpp" +#include "monetaryamount.hpp" +#include "orderid.hpp" +#include "ordersconstraints.hpp" #include "tradeinfo.hpp" +#include "wallet.hpp" +#include "withdrawinfo.hpp" +#include "withdrawsconstraints.hpp" namespace cct { class CoincenterInfo; namespace api { +class APIKey; +class CommonAPI; class UpbitPublic; class UpbitPrivate : public ExchangePrivate { @@ -35,7 +50,7 @@ class UpbitPrivate : public ExchangePrivate { WithdrawsSet queryRecentWithdraws(const WithdrawsConstraints& withdrawsConstraints = WithdrawsConstraints()) override; - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) override { + std::optional queryWithdrawalFee(CurrencyCode currencyCode) override { return _withdrawalFeesCache.get(currencyCode); } @@ -70,7 +85,7 @@ class UpbitPrivate : public ExchangePrivate { }; struct WithdrawFeesFunc { - MonetaryAmount operator()(CurrencyCode currencyCode); + std::optional operator()(CurrencyCode currencyCode); CurlHandle& _curlHandle; const APIKey& _apiKey; diff --git a/src/api/exchanges/include/upbitpublicapi.hpp b/src/api/exchanges/include/upbitpublicapi.hpp index 81745067..afd9cc4a 100644 --- a/src/api/exchanges/include/upbitpublicapi.hpp +++ b/src/api/exchanges/include/upbitpublicapi.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include "cachedresult.hpp" @@ -33,9 +34,9 @@ class UpbitPublic : public ExchangePublic { MarketPriceMap queryAllPrices() override { return MarketPriceMapFromMarketOrderBookMap(_allOrderBooksCache.get(1)); } - WithdrawalFeesSet queryWithdrawalFees() override { return _withdrawalFeesCache.get(); } + MonetaryAmountByCurrencySet queryWithdrawalFees() override { return _withdrawalFeesCache.get(); } - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) override; + std::optional queryWithdrawalFee(CurrencyCode currencyCode) override; bool isWithdrawalFeesSourceReliable() const override { return true; } @@ -79,7 +80,7 @@ class UpbitPublic : public ExchangePublic { }; struct WithdrawalFeesFunc { - WithdrawalFeesSet operator()(); + MonetaryAmountByCurrencySet operator()(); const string& _name; std::string_view _dataDir; diff --git a/src/api/exchanges/src/binanceprivateapi.cpp b/src/api/exchanges/src/binanceprivateapi.cpp index f5e9d6ce..90030a89 100644 --- a/src/api/exchanges/src/binanceprivateapi.cpp +++ b/src/api/exchanges/src/binanceprivateapi.cpp @@ -542,7 +542,7 @@ WithdrawsSet BinancePrivate::queryRecentWithdraws(const WithdrawsConstraints& wi return withdrawsSet; } -WithdrawalFeesSet BinancePrivate::AllWithdrawFeesFunc::operator()() { +MonetaryAmountByCurrencySet BinancePrivate::AllWithdrawFeesFunc::operator()() { json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/asset/assetDetail", _queryDelay); vector fees; for (const auto& [curCodeStr, withdrawFeeDetails] : result.items()) { @@ -551,20 +551,20 @@ WithdrawalFeesSet BinancePrivate::AllWithdrawFeesFunc::operator()() { fees.emplace_back(withdrawFeeDetails["withdrawFee"].get(), cur); } } - return WithdrawalFeesSet(std::move(fees)); + return MonetaryAmountByCurrencySet(std::move(fees)); } -MonetaryAmount BinancePrivate::WithdrawFeesFunc::operator()(CurrencyCode currencyCode) { +std::optional BinancePrivate::WithdrawFeesFunc::operator()(CurrencyCode currencyCode) { json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/sapi/v1/asset/assetDetail", _queryDelay, {{"asset", currencyCode.str()}}); if (!result.contains(currencyCode.str())) { - throw exception("Unable to find asset information in assetDetail query to Binance"); + return {}; } const json& withdrawFeeDetails = result[currencyCode.str()]; if (!withdrawFeeDetails["withdrawStatus"].get()) { log::error("{} is currently unavailable for withdraw from {}", currencyCode, _exchangePublic.name()); } - return {withdrawFeeDetails["withdrawFee"].get(), currencyCode}; + return MonetaryAmount(withdrawFeeDetails["withdrawFee"].get(), currencyCode); } namespace { diff --git a/src/api/exchanges/src/binancepublicapi.cpp b/src/api/exchanges/src/binancepublicapi.cpp index 61797ec0..d329ea84 100644 --- a/src/api/exchanges/src/binancepublicapi.cpp +++ b/src/api/exchanges/src/binancepublicapi.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -239,7 +240,7 @@ MonetaryAmount ComputeWithdrawalFeesFromNetworkList(CurrencyCode cur, const json } } // namespace -WithdrawalFeesSet BinancePublic::queryWithdrawalFees() { +MonetaryAmountByCurrencySet BinancePublic::queryWithdrawalFees() { vector fees; for (const json& coinJson : _globalInfosCache.get()) { std::string_view coinStr = coinJson["coin"].get(); @@ -254,17 +255,17 @@ WithdrawalFeesSet BinancePublic::queryWithdrawalFees() { log::info("Retrieved {} withdrawal fees for {} coins", _name, fees.size()); assert(!fees.empty()); - return WithdrawalFeesSet(std::move(fees)); + return MonetaryAmountByCurrencySet(std::move(fees)); } -MonetaryAmount BinancePublic::queryWithdrawalFee(CurrencyCode currencyCode) { +std::optional BinancePublic::queryWithdrawalFee(CurrencyCode currencyCode) { for (const json& el : _globalInfosCache.get()) { CurrencyCode cur(el["coin"].get()); if (cur == currencyCode) { return ComputeWithdrawalFeesFromNetworkList(cur, el["networkList"]); } } - throw exception("Unable to find withdrawal fee for {}", currencyCode); + return {}; } MonetaryAmount BinancePublic::sanitizePrice(Market mk, MonetaryAmount pri) { diff --git a/src/api/exchanges/src/bithumbprivateapi.cpp b/src/api/exchanges/src/bithumbprivateapi.cpp index 6130681e..e0dd23b0 100644 --- a/src/api/exchanges/src/bithumbprivateapi.cpp +++ b/src/api/exchanges/src/bithumbprivateapi.cpp @@ -949,7 +949,7 @@ CurlPostData ComputeLaunchWithdrawCurlPostData(MonetaryAmount netEmittedAmount, InitiatedWithdrawInfo BithumbPrivate::launchWithdraw(MonetaryAmount grossAmount, Wallet&& destinationWallet) { const CurrencyCode currencyCode = grossAmount.currencyCode(); - MonetaryAmount withdrawFee = _exchangePublic.queryWithdrawalFee(currencyCode); + MonetaryAmount withdrawFee = _exchangePublic.queryWithdrawalFeeOrZero(currencyCode); MonetaryAmount netEmittedAmount = grossAmount - withdrawFee; // Unfortunately, Bithumb does not return any withdraw Id, diff --git a/src/api/exchanges/src/bithumbpublicapi.cpp b/src/api/exchanges/src/bithumbpublicapi.cpp index ae456a72..91c8ea9f 100644 --- a/src/api/exchanges/src/bithumbpublicapi.cpp +++ b/src/api/exchanges/src/bithumbpublicapi.cpp @@ -128,11 +128,11 @@ MarketSet BithumbPublic::queryTradableMarkets() { return markets; } -MonetaryAmount BithumbPublic::queryWithdrawalFee(CurrencyCode currencyCode) { +std::optional BithumbPublic::queryWithdrawalFee(CurrencyCode currencyCode) { const auto& map = _withdrawalFeesCache.get(); auto it = map.find(currencyCode); if (it == map.end()) { - throw exception("Unable to find {} in withdrawal fees", currencyCode); + return {}; } return *it; } @@ -147,7 +147,7 @@ MonetaryAmount BithumbPublic::queryLastPrice(Market mk) { return *avgPrice; } -WithdrawalFeesSet BithumbPublic::WithdrawalFeesFunc::operator()() { +MonetaryAmountByCurrencySet BithumbPublic::WithdrawalFeesFunc::operator()() { vector fees; // This is not a published API and only a "standard" html page. We will capture the text information in it. // Warning, it's not in json format so we will need manual parsing. @@ -189,7 +189,7 @@ WithdrawalFeesSet BithumbPublic::WithdrawalFeesFunc::operator()() { } else { log::info("Updated Bithumb withdrawal fees for {} coins", fees.size()); } - return WithdrawalFeesSet(std::move(fees)); + return MonetaryAmountByCurrencySet(std::move(fees)); } CurrencyExchangeFlatSet BithumbPublic::TradableCurrenciesFunc::operator()() { diff --git a/src/api/exchanges/src/huobiprivateapi.cpp b/src/api/exchanges/src/huobiprivateapi.cpp index 1d629afd..a8530693 100644 --- a/src/api/exchanges/src/huobiprivateapi.cpp +++ b/src/api/exchanges/src/huobiprivateapi.cpp @@ -41,7 +41,7 @@ #include "stringhelpers.hpp" #include "timedef.hpp" #include "timestring.hpp" -#include "toupperlower.hpp" +#include "toupperlower-string.hpp" #include "tradedamounts.hpp" #include "tradeinfo.hpp" #include "tradeside.hpp" @@ -587,9 +587,9 @@ InitiatedWithdrawInfo HuobiPrivate::launchWithdraw(MonetaryAmount grossAmount, W } withdrawPostData.append("address", destinationWallet.address()); - MonetaryAmount fee(_exchangePublic.queryWithdrawalFee(currencyCode)); + MonetaryAmount withdrawFee = _exchangePublic.queryWithdrawalFeeOrZero(currencyCode); HuobiPublic::WithdrawParams withdrawParams = huobiPublic.getWithdrawParams(currencyCode); - MonetaryAmount netEmittedAmount = grossAmount - fee; + MonetaryAmount netEmittedAmount = grossAmount - withdrawFee; if (!withdrawParams.minWithdrawAmt.isDefault() && netEmittedAmount < withdrawParams.minWithdrawAmt) { throw exception("Minimum withdraw amount for {} on Huobi is {}, cannot withdraw {}", currencyCode, withdrawParams.minWithdrawAmt, netEmittedAmount); @@ -608,7 +608,7 @@ InitiatedWithdrawInfo HuobiPrivate::launchWithdraw(MonetaryAmount grossAmount, W withdrawPostData.append("amount", netEmittedAmount.amountStr()); withdrawPostData.append("currency", lowerCaseCur); // Strange to have the fee as input parameter of a withdraw... - withdrawPostData.append("fee", fee.amountStr()); + withdrawPostData.append("fee", withdrawFee.amountStr()); json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kPost, "/v1/dw/withdraw/api/create", std::move(withdrawPostData)); diff --git a/src/api/exchanges/src/huobipublicapi.cpp b/src/api/exchanges/src/huobipublicapi.cpp index 227b9a38..eab08ee5 100644 --- a/src/api/exchanges/src/huobipublicapi.cpp +++ b/src/api/exchanges/src/huobipublicapi.cpp @@ -1,9 +1,11 @@ + #include "huobipublicapi.hpp" #include #include #include #include +#include #include #include #include @@ -33,7 +35,7 @@ #include "monetaryamount.hpp" #include "permanentcurloptions.hpp" #include "timedef.hpp" -#include "toupperlower.hpp" +#include "toupperlower-string.hpp" #include "tradeside.hpp" #include "volumeandpricenbdecimals.hpp" @@ -247,7 +249,7 @@ std::pair HuobiPublic::Marke return {std::move(markets), std::move(marketInfoMap)}; } -WithdrawalFeesSet HuobiPublic::queryWithdrawalFees() { +MonetaryAmountByCurrencySet HuobiPublic::queryWithdrawalFees() { vector fees; for (const json& curDetail : _tradableCurrenciesCache.get()) { std::string_view curStr = curDetail["currency"].get(); @@ -283,10 +285,10 @@ WithdrawalFeesSet HuobiPublic::queryWithdrawalFees() { } log::info("Retrieved {} withdrawal fees for {} coins", _name, fees.size()); - return WithdrawalFeesSet(std::move(fees)); + return MonetaryAmountByCurrencySet(std::move(fees)); } -MonetaryAmount HuobiPublic::queryWithdrawalFee(CurrencyCode currencyCode) { +std::optional HuobiPublic::queryWithdrawalFee(CurrencyCode currencyCode) { for (const json& curDetail : _tradableCurrenciesCache.get()) { std::string_view curStr = curDetail["currency"].get(); CurrencyCode cur(_coincenterInfo.standardizeCurrencyCode(curStr)); @@ -296,11 +298,11 @@ MonetaryAmount HuobiPublic::queryWithdrawalFee(CurrencyCode currencyCode) { for (const json& chainDetail : curDetail["chains"]) { std::string_view chainName = chainDetail["chain"].get(); if (chainName == cur) { - return {chainDetail["transactFeeWithdraw"].get(), cur}; + return MonetaryAmount(chainDetail["transactFeeWithdraw"].get(), cur); } } } - throw exception("Unable to find withdrawal fee for {}", currencyCode); + return {}; } MarketOrderBookMap HuobiPublic::AllOrderBooksFunc::operator()(int depth) { diff --git a/src/api/exchanges/src/krakenpublicapi.cpp b/src/api/exchanges/src/krakenpublicapi.cpp index 2ca57cb0..e357698d 100644 --- a/src/api/exchanges/src/krakenpublicapi.cpp +++ b/src/api/exchanges/src/krakenpublicapi.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -168,13 +169,11 @@ bool KrakenPublic::healthCheck() { return statusStr == "online"; } -MonetaryAmount KrakenPublic::queryWithdrawalFee(CurrencyCode currencyCode) { - const WithdrawalFeesSet& withdrawalFees = _withdrawalFeesCache.get().first; - MonetaryAmount emptyAmount(0, currencyCode); - auto foundIt = withdrawalFees.find(emptyAmount); +std::optional KrakenPublic::queryWithdrawalFee(CurrencyCode currencyCode) { + const MonetaryAmountByCurrencySet& withdrawalFees = _withdrawalFeesCache.get().first; + auto foundIt = withdrawalFees.find(currencyCode); if (foundIt == withdrawalFees.end()) { - log::warn("Unable to find {} withdrawal fee for {}, consider 0 instead", name(), currencyCode); - return emptyAmount; + return {}; } return *foundIt; } diff --git a/src/api/exchanges/src/kucoinprivateapi.cpp b/src/api/exchanges/src/kucoinprivateapi.cpp index a151a60c..116e5e1e 100644 --- a/src/api/exchanges/src/kucoinprivateapi.cpp +++ b/src/api/exchanges/src/kucoinprivateapi.cpp @@ -535,8 +535,9 @@ InitiatedWithdrawInfo KucoinPrivate::launchWithdraw(MonetaryAmount grossAmount, } const CurrencyCode currencyCode = grossAmount.currencyCode(); - MonetaryAmount fee(_exchangePublic.queryWithdrawalFee(grossAmount.currencyCode())); - MonetaryAmount netEmittedAmount = grossAmount - fee; + MonetaryAmount withdrawFee = _exchangePublic.queryWithdrawalFeeOrZero(currencyCode); + + MonetaryAmount netEmittedAmount = grossAmount - withdrawFee; CurlPostData opts{{"currency", currencyCode.str()}, {"address", destinationWallet.address()}, diff --git a/src/api/exchanges/src/kucoinpublicapi.cpp b/src/api/exchanges/src/kucoinpublicapi.cpp index 6fc11516..4c5ef3df 100644 --- a/src/api/exchanges/src/kucoinpublicapi.cpp +++ b/src/api/exchanges/src/kucoinpublicapi.cpp @@ -2,9 +2,9 @@ #include #include -#include #include #include +#include #include #include @@ -179,7 +179,7 @@ std::pair KucoinPublic::Mar return {std::move(markets), std::move(marketInfoMap)}; } -WithdrawalFeesSet KucoinPublic::queryWithdrawalFees() { +MonetaryAmountByCurrencySet KucoinPublic::queryWithdrawalFees() { vector fees; const auto& tradableCurrencies = _tradableCurrenciesCache.get(); fees.reserve(tradableCurrencies.size()); @@ -189,17 +189,16 @@ WithdrawalFeesSet KucoinPublic::queryWithdrawalFees() { } log::info("Retrieved {} withdrawal fees for {} coins", _name, fees.size()); - assert(!fees.empty()); - return WithdrawalFeesSet(std::move(fees)); + return MonetaryAmountByCurrencySet(std::move(fees)); } -MonetaryAmount KucoinPublic::queryWithdrawalFee(CurrencyCode currencyCode) { +std::optional KucoinPublic::queryWithdrawalFee(CurrencyCode currencyCode) { const auto& currencyInfoSet = _tradableCurrenciesCache.get(); - auto it = currencyInfoSet.find(TradableCurrenciesFunc::CurrencyInfo(currencyCode)); + auto it = currencyInfoSet.lower_bound(TradableCurrenciesFunc::CurrencyInfo(currencyCode)); if (it == currencyInfoSet.end()) { - throw exception("Unable to find withdrawal fee for {}", currencyCode); + return {}; } - return {it->withdrawalMinFee, it->currencyExchange.standardCode()}; + return MonetaryAmount(it->withdrawalMinFee, it->currencyExchange.standardCode()); } MarketOrderBookMap KucoinPublic::AllOrderBooksFunc::operator()(int depth) { diff --git a/src/api/exchanges/src/upbitprivateapi.cpp b/src/api/exchanges/src/upbitprivateapi.cpp index dc589945..c123ce1a 100644 --- a/src/api/exchanges/src/upbitprivateapi.cpp +++ b/src/api/exchanges/src/upbitprivateapi.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -583,16 +584,17 @@ OrderInfo UpbitPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext& return ParseOrderJson(orderRes, fromCurrencyCode, tradeContext.mk); } -MonetaryAmount UpbitPrivate::WithdrawFeesFunc::operator()(CurrencyCode currencyCode) { +std::optional UpbitPrivate::WithdrawFeesFunc::operator()(CurrencyCode currencyCode) { + auto curStr = currencyCode.str(); json result = PrivateQuery(_curlHandle, _apiKey, HttpRequestType::kGet, "/v1/withdraws/chance", - {{"currency", currencyCode.str()}}); + {{"currency", std::string_view(curStr)}, {"net_type", std::string_view(curStr)}}); std::string_view amountStr = result["currency"]["withdraw_fee"].get(); - return {amountStr, currencyCode}; + return MonetaryAmount(amountStr, currencyCode); } InitiatedWithdrawInfo UpbitPrivate::launchWithdraw(MonetaryAmount grossAmount, Wallet&& destinationWallet) { const CurrencyCode currencyCode = grossAmount.currencyCode(); - MonetaryAmount withdrawFee = _exchangePublic.queryWithdrawalFee(currencyCode); + MonetaryAmount withdrawFee = _exchangePublic.queryWithdrawalFeeOrZero(currencyCode); MonetaryAmount netEmittedAmount = grossAmount - withdrawFee; CurlPostData withdrawPostData{{"currency", currencyCode.str()}, {"amount", netEmittedAmount.amountStr()}, diff --git a/src/api/exchanges/src/upbitpublicapi.cpp b/src/api/exchanges/src/upbitpublicapi.cpp index 4205edcc..f31915db 100644 --- a/src/api/exchanges/src/upbitpublicapi.cpp +++ b/src/api/exchanges/src/upbitpublicapi.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -93,11 +94,11 @@ bool UpbitPublic::healthCheck() { return !result.empty() && result.is_array() && result.front().find("timestamp") != result.front().end(); } -MonetaryAmount UpbitPublic::queryWithdrawalFee(CurrencyCode currencyCode) { +std::optional UpbitPublic::queryWithdrawalFee(CurrencyCode currencyCode) { const auto& map = _withdrawalFeesCache.get(); auto it = map.find(currencyCode); if (it == map.end()) { - throw exception("Unable to find currency code in withdrawal fees"); + return {}; } return *it; } @@ -158,7 +159,7 @@ MarketSet UpbitPublic::MarketsFunc::operator()() { return ret; } -WithdrawalFeesSet UpbitPublic::WithdrawalFeesFunc::operator()() { +MonetaryAmountByCurrencySet UpbitPublic::WithdrawalFeesFunc::operator()() { vector fees; File withdrawFeesFile(_dataDir, File::Type::kStatic, "withdrawfees.json", File::IfError::kThrow); json jsonData = withdrawFeesFile.readAllJson(); @@ -169,7 +170,7 @@ WithdrawalFeesSet UpbitPublic::WithdrawalFeesFunc::operator()() { fees.push_back(ma); } log::info("Updated Upbit withdrawal fees for {} coins", fees.size()); - return WithdrawalFeesSet(std::move(fees)); + return MonetaryAmountByCurrencySet(std::move(fees)); } namespace { diff --git a/src/api/exchanges/test/commonapi_test.hpp b/src/api/exchanges/test/commonapi_test.hpp index 9daca097..f69c75ee 100644 --- a/src/api/exchanges/test/commonapi_test.hpp +++ b/src/api/exchanges/test/commonapi_test.hpp @@ -78,7 +78,7 @@ class TestAPI { // if (exchangePrivateOpt) { // json d; // for (const auto &c : currencies) { - // d[string(c.standardStr())] = exchangePrivateOpt->queryWithdrawalFee(c.standardCode()).amountStr(); + // d[string(c.standardStr())] = *exchangePrivateOpt->queryWithdrawalFee(c.standardCode()).amountStr(); // } // std::cout << d.dump(2) << '\n'; // } @@ -147,7 +147,7 @@ class TestAPI { sample = std::move(withdrawableCryptos); } - WithdrawalFeesSet withdrawalFees = + MonetaryAmountByCurrencySet withdrawalFees = exchangePrivateOpt ? exchangePrivateOpt->queryWithdrawalFees() : exchangePublic.queryWithdrawalFees(); for (const CurrencyExchange &curExchange : sample) { diff --git a/src/api/interface/include/exchange.hpp b/src/api/interface/include/exchange.hpp index eead8213..c5939398 100644 --- a/src/api/interface/include/exchange.hpp +++ b/src/api/interface/include/exchange.hpp @@ -1,12 +1,20 @@ #pragma once +#include #include +#include "cct_exception.hpp" +#include "currencycode.hpp" +#include "currencyexchange.hpp" +#include "currencyexchangeflatset.hpp" #include "exchangeinfo.hpp" #include "exchangename.hpp" #include "exchangeprivateapi.hpp" #include "exchangepublicapi.hpp" #include "exchangepublicapitypes.hpp" +#include "marketorderbook.hpp" +#include "monetaryamount.hpp" +#include "monetaryamountbycurrencyset.hpp" namespace cct { class Exchange { @@ -65,11 +73,11 @@ class Exchange { MarketPriceMap queryAllPrices() { return _exchangePublic.queryAllPrices(); } - WithdrawalFeesSet queryWithdrawalFees() { + MonetaryAmountByCurrencySet queryWithdrawalFees() { return hasPrivateAPI() ? _pExchangePrivate->queryWithdrawalFees() : _exchangePublic.queryWithdrawalFees(); } - MonetaryAmount queryWithdrawalFee(CurrencyCode currencyCode) { + std::optional queryWithdrawalFee(CurrencyCode currencyCode) { return hasPrivateAPI() ? _pExchangePrivate->queryWithdrawalFee(currencyCode) : _exchangePublic.queryWithdrawalFee(currencyCode); } diff --git a/src/api/interface/include/exchangeretrieverbase.hpp b/src/api/interface/include/exchangeretrieverbase.hpp index 57292c9c..35d16515 100644 --- a/src/api/interface/include/exchangeretrieverbase.hpp +++ b/src/api/interface/include/exchangeretrieverbase.hpp @@ -116,7 +116,7 @@ class ExchangeRetrieverBase { return select(order, exchangeNames, Matcher>()); } - /// Among all 'Exchange's, retrieve at most one 'Exchange' per public echange matching public exchange names. + /// Among all 'Exchange's, retrieve at most one 'Exchange' per public exchange matching public exchange names. /// Order of 'Exchange's will respect the same order as the 'exchangeNames' given in input. /// Examples /// {"kraken_user1", "kucoin_user1"} -> {"kraken_user1", "kucoin_user1"} diff --git a/src/engine/include/coincenter.hpp b/src/engine/include/coincenter.hpp index f4357d81..72d462c6 100644 --- a/src/engine/include/coincenter.hpp +++ b/src/engine/include/coincenter.hpp @@ -96,7 +96,7 @@ class Coincenter { ConversionPathPerExchange getConversionPaths(Market mk, ExchangeNameSpan exchangeNames); /// Get withdraw fees for all exchanges from given list (or all exchanges if list is empty) - MonetaryAmountPerExchange getWithdrawFees(CurrencyCode currencyCode, ExchangeNameSpan exchangeNames); + MonetaryAmountByCurrencySetPerExchange getWithdrawFees(CurrencyCode currencyCode, ExchangeNameSpan exchangeNames); /// Trade a specified amount of a given currency into another one, using the market defined in the given exchanges. /// If no exchange name is given, it will attempt to trade given amount on all exchanges with the sufficient balance. diff --git a/src/engine/include/coincenteroptions.hpp b/src/engine/include/coincenteroptions.hpp index 2c14e54c..d2fe2794 100644 --- a/src/engine/include/coincenteroptions.hpp +++ b/src/engine/include/coincenteroptions.hpp @@ -84,7 +84,7 @@ class CoincenterCmdLineOptions { std::string_view withdrawApply; std::string_view withdrawApplyAll; - std::string_view withdrawFee; + std::optional withdrawFees; Duration withdrawRefreshTime{WithdrawOptions().withdrawRefreshTime()}; std::string_view dustSweeper; diff --git a/src/engine/include/coincenteroptionsdef.hpp b/src/engine/include/coincenteroptionsdef.hpp index e619a2e5..9337f3bc 100644 --- a/src/engine/include/coincenteroptionsdef.hpp +++ b/src/engine/include/coincenteroptionsdef.hpp @@ -394,11 +394,11 @@ struct CoincenterAllowedOptions : private CoincenterCmdLineOptionsDefinitions { "Withdraw all available amount instead of a specified amount."}, &OptValueType::withdrawApplyAll}, {{{"Withdraw and deposit", 8000}, - "withdraw-fee", - "", - "Prints withdraw fees of given currency on all supported exchanges," - " or only for the list of specified ones if provided (comma separated)."}, - &OptValueType::withdrawFee}, + "withdraw-fees", + "<[cur][,exch1,...]>", + "Prints withdraw fees for matching currency and exchanges." + "Currency and exchanges are optional, if specified, output will be filtered to match them."}, + &OptValueType::withdrawFees}, {{{"Monitoring", 9000}, "--monitoring", "", diff --git a/src/engine/include/exchangesorchestrator.hpp b/src/engine/include/exchangesorchestrator.hpp index d49601fb..4b9efaaa 100644 --- a/src/engine/include/exchangesorchestrator.hpp +++ b/src/engine/include/exchangesorchestrator.hpp @@ -71,7 +71,7 @@ class ExchangesOrchestrator { const ExchangeName &toPrivateExchangeName, const WithdrawOptions &withdrawOptions); - MonetaryAmountPerExchange getWithdrawFees(CurrencyCode currencyCode, ExchangeNameSpan exchangeNames); + MonetaryAmountByCurrencySetPerExchange getWithdrawFees(CurrencyCode currencyCode, ExchangeNameSpan exchangeNames); MonetaryAmountPerExchange getLast24hTradedVolumePerExchange(Market mk, ExchangeNameSpan exchangeNames); diff --git a/src/engine/include/queryresultprinter.hpp b/src/engine/include/queryresultprinter.hpp index 4e64f5e8..88c63fac 100644 --- a/src/engine/include/queryresultprinter.hpp +++ b/src/engine/include/queryresultprinter.hpp @@ -77,7 +77,7 @@ class QueryResultPrinter { void printConversionPath(Market mk, const ConversionPathPerExchange &conversionPathsPerExchange) const; - void printWithdrawFees(const MonetaryAmountPerExchange &withdrawFeePerExchange, CurrencyCode cur) const; + void printWithdrawFees(const MonetaryAmountByCurrencySetPerExchange &withdrawFeesPerExchange, CurrencyCode cur) const; void printLast24hTradedVolume(Market mk, const MonetaryAmountPerExchange &tradedVolumePerExchange) const; diff --git a/src/engine/include/queryresulttypes.hpp b/src/engine/include/queryresulttypes.hpp index 5cd9263a..345fa070 100644 --- a/src/engine/include/queryresulttypes.hpp +++ b/src/engine/include/queryresulttypes.hpp @@ -15,6 +15,7 @@ #include "exchangepublicapitypes.hpp" #include "marketorderbook.hpp" #include "monetaryamount.hpp" +#include "monetaryamountbycurrencyset.hpp" #include "traderesult.hpp" #include "wallet.hpp" #include "withdrawinfo.hpp" @@ -33,6 +34,9 @@ using MarketsPerExchange = FixedCapacityVector, kNbSuppo using MonetaryAmountPerExchange = FixedCapacityVector, kNbSupportedExchanges>; +using MonetaryAmountByCurrencySetPerExchange = + FixedCapacityVector, kNbSupportedExchanges>; + using LastTradesPerExchange = FixedCapacityVector, kNbSupportedExchanges>; using TradeResultPerExchange = SmallVector, kTypicalNbPrivateAccounts>; diff --git a/src/engine/src/coincenter.cpp b/src/engine/src/coincenter.cpp index b12de533..3fbcfdad 100644 --- a/src/engine/src/coincenter.cpp +++ b/src/engine/src/coincenter.cpp @@ -125,7 +125,7 @@ TransferableCommandResultVector Coincenter::processCommand( _queryResultPrinter.printLast24hTradedVolume(cmd.market(), tradedVolumePerExchange); break; } - case CoincenterCommandType::kWithdrawFee: { + case CoincenterCommandType::kWithdrawFees: { const auto withdrawFeesPerExchange = getWithdrawFees(cmd.cur1(), cmd.exchangeNames()); _queryResultPrinter.printWithdrawFees(withdrawFeesPerExchange, cmd.cur1()); break; @@ -342,7 +342,8 @@ DeliveredWithdrawInfoWithExchanges Coincenter::withdraw(MonetaryAmount grossAmou toPrivateExchangeName, withdrawOptions); } -MonetaryAmountPerExchange Coincenter::getWithdrawFees(CurrencyCode currencyCode, ExchangeNameSpan exchangeNames) { +MonetaryAmountByCurrencySetPerExchange Coincenter::getWithdrawFees(CurrencyCode currencyCode, + ExchangeNameSpan exchangeNames) { return _exchangesOrchestrator.getWithdrawFees(currencyCode, exchangeNames); } diff --git a/src/engine/src/coincentercommand.cpp b/src/engine/src/coincentercommand.cpp index 6b3a9ac9..d117618f 100644 --- a/src/engine/src/coincentercommand.cpp +++ b/src/engine/src/coincentercommand.cpp @@ -35,7 +35,7 @@ bool CoincenterCommand::isPublic() const { [[fallthrough]]; case CoincenterCommandType::kLast24hTradedVolume: [[fallthrough]]; - case CoincenterCommandType::kWithdrawFee: + case CoincenterCommandType::kWithdrawFees: return true; default: return false; diff --git a/src/engine/src/coincentercommands.cpp b/src/engine/src/coincentercommands.cpp index 0f35294f..30983a15 100644 --- a/src/engine/src/coincentercommands.cpp +++ b/src/engine/src/coincentercommands.cpp @@ -152,10 +152,10 @@ void CoincenterCommands::addOption(const CoincenterCmdLineOptions &cmdLineOption .setExchangeNames(optionParser.parseExchanges()); } - if (!cmdLineOptions.withdrawFee.empty()) { - optionParser = StringOptionParser(cmdLineOptions.withdrawFee); - _commands.emplace_back(CoincenterCommandType::kWithdrawFee) - .setCur1(optionParser.parseCurrency()) + if (cmdLineOptions.withdrawFees) { + optionParser = StringOptionParser(*cmdLineOptions.withdrawFees); + _commands.emplace_back(CoincenterCommandType::kWithdrawFees) + .setCur1(optionParser.parseCurrency(StringOptionParser::FieldIs::kOptional)) .setExchangeNames(optionParser.parseExchanges()); } diff --git a/src/engine/src/exchangesorchestrator.cpp b/src/engine/src/exchangesorchestrator.cpp index f9db1f79..a821d1dc 100644 --- a/src/engine/src/exchangesorchestrator.cpp +++ b/src/engine/src/exchangesorchestrator.cpp @@ -339,6 +339,9 @@ UniquePublicSelectedExchanges ExchangesOrchestrator::getExchangesTradingCurrency _threadPool.parallelTransform( selectedExchanges.begin(), selectedExchanges.end(), isCurrencyTradablePerExchange.begin(), [currencyCode, shouldBeWithdrawable](Exchange *exchange) { + if (currencyCode.isNeutral()) { + return true; + } CurrencyExchangeFlatSet currencies = exchange->queryTradableCurrencies(); auto foundIt = currencies.find(currencyCode); return foundIt != currencies.end() && (!shouldBeWithdrawable || foundIt->canWithdraw()); @@ -799,17 +802,32 @@ DeliveredWithdrawInfoWithExchanges ExchangesOrchestrator::withdraw(MonetaryAmoun return ret; } -MonetaryAmountPerExchange ExchangesOrchestrator::getWithdrawFees(CurrencyCode currencyCode, - ExchangeNameSpan exchangeNames) { - log::info("{} withdraw fees for {}", currencyCode, ConstructAccumulatedExchangeNames(exchangeNames)); +MonetaryAmountByCurrencySetPerExchange ExchangesOrchestrator::getWithdrawFees(CurrencyCode currencyCode, + ExchangeNameSpan exchangeNames) { + if (currencyCode.isNeutral()) { + log::info("Withdraw fees for {}", ConstructAccumulatedExchangeNames(exchangeNames)); + } else { + log::info("{} withdraw fees for {}", currencyCode, ConstructAccumulatedExchangeNames(exchangeNames)); + } + UniquePublicSelectedExchanges selectedExchanges = getExchangesTradingCurrency(currencyCode, exchangeNames, true); - MonetaryAmountPerExchange withdrawFeePerExchange(selectedExchanges.size()); - _threadPool.parallelTransform(selectedExchanges.begin(), selectedExchanges.end(), withdrawFeePerExchange.begin(), + MonetaryAmountByCurrencySetPerExchange withdrawFeesPerExchange(selectedExchanges.size()); + _threadPool.parallelTransform(selectedExchanges.begin(), selectedExchanges.end(), withdrawFeesPerExchange.begin(), [currencyCode](Exchange *exchange) { - return std::make_pair(exchange, exchange->queryWithdrawalFee(currencyCode)); + MonetaryAmountByCurrencySet withdrawFees; + if (currencyCode.isNeutral()) { + withdrawFees = exchange->queryWithdrawalFees(); + } else { + std::optional optWithdrawFee = + exchange->queryWithdrawalFee(currencyCode); + if (optWithdrawFee) { + withdrawFees.insert(*optWithdrawFee); + } + } + return std::make_pair(exchange, std::move(withdrawFees)); }); - return withdrawFeePerExchange; + return withdrawFeesPerExchange; } MonetaryAmountPerExchange ExchangesOrchestrator::getLast24hTradedVolumePerExchange(Market mk, diff --git a/src/engine/src/queryresultprinter.cpp b/src/engine/src/queryresultprinter.cpp index beaaee11..8b7aa066 100644 --- a/src/engine/src/queryresultprinter.cpp +++ b/src/engine/src/queryresultprinter.cpp @@ -11,6 +11,7 @@ #include "apioutputtype.hpp" #include "balanceperexchangeportfolio.hpp" +#include "cct_const.hpp" #include "cct_json.hpp" #include "cct_log.hpp" #include "cct_string.hpp" @@ -508,18 +509,24 @@ json ConversionPathJson(Market mk, const ConversionPathPerExchange &conversionPa return ToJson(CoincenterCommandType::kConversionPath, std::move(in), std::move(out)); } -json WithdrawFeesJson(const MonetaryAmountPerExchange &withdrawFeePerExchange, CurrencyCode cur) { +json WithdrawFeesJson(const MonetaryAmountByCurrencySetPerExchange &withdrawFeePerExchange, CurrencyCode cur) { json in; - json inOpt; - inOpt.emplace("cur", cur.str()); + json inOpt = json::object(); + if (!cur.isNeutral()) { + inOpt.emplace("cur", cur.str()); + } in.emplace("opt", std::move(inOpt)); json out = json::object(); - for (const auto &[e, withdrawFee] : withdrawFeePerExchange) { - out.emplace(e->name(), withdrawFee.amountStr()); + for (const auto &[e, withdrawFees] : withdrawFeePerExchange) { + json amountsPerExchange = json::array(); + for (MonetaryAmount ma : withdrawFees) { + amountsPerExchange.emplace_back(ma.str()); + } + out.emplace(e->name(), std::move(amountsPerExchange)); } - return ToJson(CoincenterCommandType::kWithdrawFee, std::move(in), std::move(out)); + return ToJson(CoincenterCommandType::kWithdrawFees, std::move(in), std::move(out)); } json Last24hTradedVolumeJson(Market mk, const MonetaryAmountPerExchange &tradedVolumePerExchange) { @@ -640,6 +647,13 @@ json DustSweeperJson(const TradedAmountsVectorWithFinalAmountPerExchange &traded return ToJson(CoincenterCommandType::kDustSweeper, std::move(in), std::move(out)); } +template +void RemoveDuplicates(VecType &vec) { + std::ranges::sort(vec); + const auto [eraseIt1, eraseIt2] = std::ranges::unique(vec); + vec.erase(eraseIt1, eraseIt2); +} + } // namespace QueryResultPrinter::QueryResultPrinter(ApiOutputType apiOutputType, const LoggingInfo &loggingInfo) : _loggingInfo(loggingInfo), @@ -703,9 +717,8 @@ void QueryResultPrinter::printCurrencies(const CurrenciesPerExchange ¤cies for (const auto &[_, currencies] : currenciesPerExchange) { allCurrencyCodes.insert(allCurrencyCodes.end(), currencies.begin(), currencies.end()); } - std::ranges::sort(allCurrencyCodes); - const auto [eraseIt1, eraseIt2] = std::ranges::unique(allCurrencyCodes); - allCurrencyCodes.erase(eraseIt1, eraseIt2); + + RemoveDuplicates(allCurrencyCodes); simpleTable.reserve(1U + allCurrencyCodes.size()); @@ -1035,14 +1048,33 @@ void QueryResultPrinter::printConversionPath(Market mk, logActivity(CoincenterCommandType::kConversionPath, jsonData); } -void QueryResultPrinter::printWithdrawFees(const MonetaryAmountPerExchange &withdrawFeePerExchange, +void QueryResultPrinter::printWithdrawFees(const MonetaryAmountByCurrencySetPerExchange &withdrawFeesPerExchange, CurrencyCode cur) const { - json jsonData = WithdrawFeesJson(withdrawFeePerExchange, cur); + json jsonData = WithdrawFeesJson(withdrawFeesPerExchange, cur); switch (_apiOutputType) { case ApiOutputType::kFormattedTable: { - SimpleTable simpleTable("Exchange", "Withdraw fee"); - for (const auto &[e, withdrawFee] : withdrawFeePerExchange) { - simpleTable.emplace_back(e->name(), withdrawFee.str()); + SimpleTable::Row header("Withdraw fee currency"); + CurrencyCodeVector allCurrencyCodes; + for (const auto &[e, withdrawFees] : withdrawFeesPerExchange) { + header.emplace_back(e->name()); + for (MonetaryAmount ma : withdrawFees) { + allCurrencyCodes.push_back(ma.currencyCode()); + } + } + + RemoveDuplicates(allCurrencyCodes); + + SimpleTable simpleTable(std::move(header)); + for (CurrencyCode cur : allCurrencyCodes) { + auto &row = simpleTable.emplace_back(cur.str()); + for (const auto &[e, withdrawFees] : withdrawFeesPerExchange) { + auto it = withdrawFees.find(cur); + if (it == withdrawFees.end()) { + row.emplace_back(); + } else { + row.emplace_back(it->str()); + } + } } printTable(simpleTable); break; @@ -1053,7 +1085,7 @@ void QueryResultPrinter::printWithdrawFees(const MonetaryAmountPerExchange &with case ApiOutputType::kNoPrint: break; } - logActivity(CoincenterCommandType::kWithdrawFee, jsonData); + logActivity(CoincenterCommandType::kWithdrawFees, jsonData); } void QueryResultPrinter::printLast24hTradedVolume(Market mk, diff --git a/src/engine/test/queryresultprinter_public_test.cpp b/src/engine/test/queryresultprinter_public_test.cpp index c804b733..fdf06244 100644 --- a/src/engine/test/queryresultprinter_public_test.cpp +++ b/src/engine/test/queryresultprinter_public_test.cpp @@ -668,33 +668,33 @@ TEST_F(QueryResultPrinterConversionPathTest, NoPrint) { class QueryResultPrinterWithdrawFeeTest : public QueryResultPrinterTest { protected: - CurrencyCode curWithdrawFee{"ETH"}; - MonetaryAmountPerExchange withdrawFeePerExchange{{&exchange2, MonetaryAmount{"0.15", "ETH"}}, - {&exchange4, MonetaryAmount{"0.05", "ETH"}}}; + CurrencyCode curWithdrawFee; + MonetaryAmountByCurrencySetPerExchange withdrawFeesPerExchange{ + {&exchange2, MonetaryAmountByCurrencySet{MonetaryAmount{"0.15", "ETH"}}}, + {&exchange4, MonetaryAmountByCurrencySet{MonetaryAmount{"0.05", "ETH"}, MonetaryAmount{"0.001", "BTC"}}}}; }; TEST_F(QueryResultPrinterWithdrawFeeTest, FormattedTable) { - basicQueryResultPrinter(ApiOutputType::kFormattedTable).printWithdrawFees(withdrawFeePerExchange, curWithdrawFee); - static constexpr std::string_view kExpected = R"( -+----------+--------------+ -| Exchange | Withdraw fee | -+----------+--------------+ -| bithumb | 0.15 ETH | -| huobi | 0.05 ETH | -+----------+--------------+ + basicQueryResultPrinter(ApiOutputType::kFormattedTable).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); + static constexpr std::string_view kExpected = R"( ++-----------------------+----------+-----------+ +| Withdraw fee currency | bithumb | huobi | ++-----------------------+----------+-----------+ +| BTC | | 0.001 BTC | +| ETH | 0.15 ETH | 0.05 ETH | ++-----------------------+----------+-----------+ )"; expectStr(kExpected); } TEST_F(QueryResultPrinterWithdrawFeeTest, EmptyJson) { - basicQueryResultPrinter(ApiOutputType::kJson).printWithdrawFees(MonetaryAmountPerExchange{}, curWithdrawFee); + basicQueryResultPrinter(ApiOutputType::kJson) + .printWithdrawFees(MonetaryAmountByCurrencySetPerExchange{}, curWithdrawFee); static constexpr std::string_view kExpected = R"( { "in": { - "opt": { - "cur": "ETH" - }, - "req": "WithdrawFee" + "opt": {}, + "req": "WithdrawFees" }, "out": {} })"; @@ -702,25 +702,28 @@ TEST_F(QueryResultPrinterWithdrawFeeTest, EmptyJson) { } TEST_F(QueryResultPrinterWithdrawFeeTest, Json) { - basicQueryResultPrinter(ApiOutputType::kJson).printWithdrawFees(withdrawFeePerExchange, curWithdrawFee); + basicQueryResultPrinter(ApiOutputType::kJson).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); static constexpr std::string_view kExpected = R"( { "in": { - "opt": { - "cur": "ETH" - }, - "req": "WithdrawFee" + "opt": {}, + "req": "WithdrawFees" }, "out": { - "bithumb": "0.15", - "huobi": "0.05" + "bithumb": [ + "0.15 ETH" + ], + "huobi": [ + "0.001 BTC", + "0.05 ETH" + ] } })"; expectJson(kExpected); } TEST_F(QueryResultPrinterWithdrawFeeTest, NoPrint) { - basicQueryResultPrinter(ApiOutputType::kNoPrint).printWithdrawFees(withdrawFeePerExchange, curWithdrawFee); + basicQueryResultPrinter(ApiOutputType::kNoPrint).printWithdrawFees(withdrawFeesPerExchange, curWithdrawFee); expectNoStr(); } diff --git a/src/objects/include/coincentercommandtype.hpp b/src/objects/include/coincentercommandtype.hpp index c0d790ac..d7aeb6af 100644 --- a/src/objects/include/coincentercommandtype.hpp +++ b/src/objects/include/coincentercommandtype.hpp @@ -14,7 +14,7 @@ enum class CoincenterCommandType : int8_t { kOrderbook, kLastTrades, kLast24hTradedVolume, - kWithdrawFee, + kWithdrawFees, kBalance, kDepositInfo, diff --git a/src/objects/include/monetaryamountbycurrencyset.hpp b/src/objects/include/monetaryamountbycurrencyset.hpp index 2b203a5e..762f493e 100644 --- a/src/objects/include/monetaryamountbycurrencyset.hpp +++ b/src/objects/include/monetaryamountbycurrencyset.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include "cct_flatset.hpp" #include "cct_vector.hpp" #include "monetaryamount.hpp" @@ -25,6 +27,8 @@ class MonetaryAmountByCurrencySet { MonetaryAmountByCurrencySet() noexcept = default; + MonetaryAmountByCurrencySet(std::initializer_list init) : _set(init.begin(), init.end()) {} + explicit MonetaryAmountByCurrencySet(MonetaryAmountVector &&vec) noexcept : _set(std::move(vec)) {} const MonetaryAmount &front() const { return _set.front(); } diff --git a/src/objects/src/apioutputtype.cpp b/src/objects/src/apioutputtype.cpp index 30476576..de8e3be8 100644 --- a/src/objects/src/apioutputtype.cpp +++ b/src/objects/src/apioutputtype.cpp @@ -3,12 +3,11 @@ #include #include "cct_invalid_argument_exception.hpp" -#include "cct_string.hpp" -#include "toupperlower.hpp" +#include "toupperlower-string.hpp" namespace cct { ApiOutputType ApiOutputTypeFromString(std::string_view str) { - string lowerStr = ToLower(str); + auto lowerStr = ToLower(str); if (lowerStr == kApiOutputTypeNoPrintStr) { return ApiOutputType::kNoPrint; } diff --git a/src/objects/src/coincentercommandtype.cpp b/src/objects/src/coincentercommandtype.cpp index 830c25b7..1d2aea8e 100644 --- a/src/objects/src/coincentercommandtype.cpp +++ b/src/objects/src/coincentercommandtype.cpp @@ -25,8 +25,8 @@ std::string_view CoincenterCommandTypeToString(CoincenterCommandType type) { return "LastTrades"; case CoincenterCommandType::kLast24hTradedVolume: return "Last24hTradedVolume"; - case CoincenterCommandType::kWithdrawFee: - return "WithdrawFee"; + case CoincenterCommandType::kWithdrawFees: + return "WithdrawFees"; case CoincenterCommandType::kBalance: return "Balance"; @@ -83,8 +83,8 @@ CoincenterCommandType CoincenterCommandTypeFromString(std::string_view str) { if (str == "Last24hTradedVolume") { return CoincenterCommandType::kLast24hTradedVolume; } - if (str == "WithdrawFee") { - return CoincenterCommandType::kWithdrawFee; + if (str == "WithdrawFees") { + return CoincenterCommandType::kWithdrawFees; } if (str == "Balance") { diff --git a/src/objects/src/coincenterinfo.cpp b/src/objects/src/coincenterinfo.cpp index 67e5329d..6771aca4 100644 --- a/src/objects/src/coincenterinfo.cpp +++ b/src/objects/src/coincenterinfo.cpp @@ -19,8 +19,8 @@ #include "monitoringinfo.hpp" #include "reader.hpp" #include "runmodes.hpp" +#include "toupperlower-string.hpp" #include "toupperlower.hpp" - #ifdef CCT_ENABLE_PROMETHEUS #include "prometheusmetricgateway.hpp" #else @@ -34,6 +34,7 @@ CoincenterInfo::CurrencyEquivalentAcronymMap ComputeCurrencyEquivalentAcronymMap const Reader& currencyAcronymsTranslatorReader) { json jsonData = currencyAcronymsTranslatorReader.readAllJson(); CoincenterInfo::CurrencyEquivalentAcronymMap map; + map.reserve(jsonData.size()); for (const auto& [key, value] : jsonData.items()) { log::trace("Currency {} <=> {}", key, value.get()); map.insert_or_assign(CurrencyCode(key), value.get()); diff --git a/src/objects/src/exchangename.cpp b/src/objects/src/exchangename.cpp index 364a4164..edaa08bf 100644 --- a/src/objects/src/exchangename.cpp +++ b/src/objects/src/exchangename.cpp @@ -7,6 +7,7 @@ #include "cct_const.hpp" #include "cct_invalid_argument_exception.hpp" #include "cct_string.hpp" +#include "toupperlower-string.hpp" #include "toupperlower.hpp" namespace cct { diff --git a/src/tech/include/simpletable.hpp b/src/tech/include/simpletable.hpp index 7a4faac1..71c86ff1 100644 --- a/src/tech/include/simpletable.hpp +++ b/src/tech/include/simpletable.hpp @@ -44,7 +44,7 @@ class SimpleTable { using value_type = std::variant; using size_type = uint32_t; - explicit Cell(std::string_view v) : _data(v) {} + explicit Cell(std::string_view v = std::string_view()) : _data(v) {} explicit Cell(const char *v) : _data(std::string_view(v)) {} diff --git a/src/tech/include/toupperlower-string.hpp b/src/tech/include/toupperlower-string.hpp new file mode 100644 index 00000000..eb7a0e33 --- /dev/null +++ b/src/tech/include/toupperlower-string.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "cct_string.hpp" +#include "toupperlower.hpp" + +namespace cct { + +inline string ToUpper(std::string_view str) { + string ret(str); + std::ranges::transform(ret, ret.begin(), toupper); + return ret; +} + +inline string ToLower(std::string_view str) { + string ret(str); + std::ranges::transform(ret, ret.begin(), tolower); + return ret; +} + +} // namespace cct \ No newline at end of file diff --git a/src/tech/include/toupperlower.hpp b/src/tech/include/toupperlower.hpp index 842c9612..059be956 100644 --- a/src/tech/include/toupperlower.hpp +++ b/src/tech/include/toupperlower.hpp @@ -1,14 +1,9 @@ #pragma once -#include -#include - -#include "cct_string.hpp" - namespace cct { /// constexpr version of std::toupper with chars, as unfortunately for now (May 2021) std::toupper is not constexpr -constexpr char toupper(char c) noexcept { - switch (c) { +constexpr char toupper(char ch) noexcept { + switch (ch) { // clang-format off case 'a': return 'A'; case 'b': return 'B'; @@ -37,14 +32,14 @@ constexpr char toupper(char c) noexcept { case 'y': return 'Y'; case 'z': return 'Z'; - default: return c; + default: return ch; // clang-format on } } /// constexpr version of std::tolower with chars, as unfortunately for now (May 2021) std::tolower is not constexpr -constexpr char tolower(char c) noexcept { - switch (c) { +constexpr char tolower(char ch) noexcept { + switch (ch) { // clang-format off case 'A': return 'a'; case 'B': return 'b'; @@ -73,20 +68,9 @@ constexpr char tolower(char c) noexcept { case 'Y': return 'y'; case 'Z': return 'z'; - default: return c; + default: return ch; // clang-format on } } -inline string ToUpper(std::string_view str) { - string ret(str); - std::ranges::transform(ret, ret.begin(), toupper); - return ret; -} - -inline string ToLower(std::string_view str) { - string ret(str); - std::ranges::transform(ret, ret.begin(), tolower); - return ret; -} } // namespace cct \ No newline at end of file