Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve returned trade result information #472

Merged
merged 1 commit into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 11 additions & 16 deletions src/api-objects/include/tradedamounts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,24 @@
namespace cct {

struct TradedAmounts {
constexpr TradedAmounts() noexcept(std::is_nothrow_default_constructible_v<MonetaryAmount>) = default;
constexpr TradedAmounts() noexcept = default;

constexpr TradedAmounts(CurrencyCode fromCurrencyCode, CurrencyCode toCurrencyCode)
: tradedFrom(0, fromCurrencyCode), tradedTo(0, toCurrencyCode) {}
: from(0, fromCurrencyCode), to(0, toCurrencyCode) {}

constexpr TradedAmounts(MonetaryAmount fromAmount, MonetaryAmount toAmount)
: tradedFrom(fromAmount), tradedTo(toAmount) {}
constexpr TradedAmounts(MonetaryAmount fromAmount, MonetaryAmount toAmount) : from(fromAmount), to(toAmount) {}

TradedAmounts operator+(const TradedAmounts &o) const {
return TradedAmounts(tradedFrom + o.tradedFrom, tradedTo + o.tradedTo);
}
TradedAmounts &operator+=(const TradedAmounts &o) {
*this = *this + o;
return *this;
}
TradedAmounts operator+(const TradedAmounts &rhs) const { return {from + rhs.from, to + rhs.to}; }
TradedAmounts &operator+=(const TradedAmounts &rhs) { return (*this = *this + rhs); }

constexpr bool operator==(const TradedAmounts &) const = default;
constexpr bool operator==(const TradedAmounts &) const noexcept = default;

friend std::ostream &operator<<(std::ostream &os, const TradedAmounts &tradedAmounts);

string str() const;

MonetaryAmount tradedFrom; // In currency of 'from' amount
MonetaryAmount tradedTo; // In the opposite currency
MonetaryAmount from; // In currency of 'from' amount
MonetaryAmount to; // In the opposite currency
};

} // namespace cct
Expand All @@ -42,7 +36,8 @@ struct TradedAmounts {
template <>
struct fmt::formatter<cct::TradedAmounts> {
constexpr auto parse(format_parse_context &ctx) -> decltype(ctx.begin()) {
auto it = ctx.begin(), end = ctx.end();
const auto it = ctx.begin();
const auto end = ctx.end();
if (it != end && *it != '}') {
throw format_error("invalid format");
}
Expand All @@ -51,7 +46,7 @@ struct fmt::formatter<cct::TradedAmounts> {

template <typename FormatContext>
auto format(const cct::TradedAmounts &a, FormatContext &ctx) const -> decltype(ctx.out()) {
return fmt::format_to(ctx.out(), "{} -> {}", a.tradedFrom, a.tradedTo);
return fmt::format_to(ctx.out(), "{} -> {}", a.from, a.to);
}
};
#endif
7 changes: 3 additions & 4 deletions src/api-objects/src/tradedamounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@
namespace cct {

string TradedAmounts::str() const {
string ret = tradedFrom.str();
string ret = from.str();
ret.append(" -> ");
ret.append(tradedTo.str());
to.appendStrTo(ret);
return ret;
}

std::ostream &operator<<(std::ostream &os, const TradedAmounts &tradedAmounts) {
os << tradedAmounts.tradedFrom << " -> " << tradedAmounts.tradedTo;
return os;
return os << tradedAmounts.from << " -> " << tradedAmounts.to;
}

} // namespace cct
20 changes: 10 additions & 10 deletions src/api/common/src/exchangeprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ TradedAmounts ExchangePrivate::trade(MonetaryAmount from, CurrencyCode toCurrenc
Market mk = conversionPath[tradePos];
log::info("Step {}/{} - trade {} into {}", tradePos + 1, nbTrades, avAmount, mk.opposite(avAmount.currencyCode()));
TradedAmounts stepTradedAmounts = marketTrade(avAmount, options, mk);
avAmount = stepTradedAmounts.tradedTo;
avAmount = stepTradedAmounts.to;
if (avAmount == 0) {
break;
}
if (tradePos == 0) {
tradedAmounts.tradedFrom = stepTradedAmounts.tradedFrom;
tradedAmounts.from = stepTradedAmounts.from;
}
if (tradePos + 1 == nbTrades) {
tradedAmounts.tradedTo = stepTradedAmounts.tradedTo;
tradedAmounts.to = stepTradedAmounts.to;
}
}
return tradedAmounts;
Expand Down Expand Up @@ -220,7 +220,7 @@ TradedAmounts ExchangePrivate::marketTrade(MonetaryAmount from, const TradeOptio
log::debug("Cancel order {}", orderId);
OrderInfo cancelledOrderInfo = cancelOrder(orderId, tradeContext);
totalTradedAmounts += cancelledOrderInfo.tradedAmounts;
from -= cancelledOrderInfo.tradedAmounts.tradedFrom;
from -= cancelledOrderInfo.tradedAmounts.from;
if (from == 0) {
log::debug("Order {} matched with last traded amounts {} while cancelling", orderId,
cancelledOrderInfo.tradedAmounts);
Expand Down Expand Up @@ -380,7 +380,7 @@ std::pair<TradedAmounts, Market> ExchangePrivate::isSellingPossibleOneShotDustSw
for (Market mk : possibleMarkets) {
log::info("Dust sweeper - attempt to sell in one shot on {}", mk);
TradedAmounts tradedAmounts = marketTrade(amountBalance, tradeOptions, mk);
if (tradedAmounts.tradedTo != 0) {
if (tradedAmounts.to != 0) {
return {tradedAmounts, mk};
}
}
Expand Down Expand Up @@ -432,7 +432,7 @@ TradedAmounts ExchangePrivate::buySomeAmountToMakeFutureSellPossible(
log::info("Dust sweeper - attempt to buy some {} for future selling", currencyCode);
TradedAmounts tradedAmounts = marketTrade(fromAmount, tradeOptions, mk);

if (tradedAmounts.tradedTo != 0) {
if (tradedAmounts.to != 0) {
// Then we should have sufficient amount now on this market
return tradedAmounts;
}
Expand Down Expand Up @@ -500,7 +500,7 @@ TradedAmountsVectorWithFinalAmount ExchangePrivate::queryDustSweeper(CurrencyCod
TradedAmounts tradedAmounts;
std::tie(tradedAmounts, tradedMarket) =
isSellingPossibleOneShotDustSweeper(possibleMarkets, ret.finalAmount, tradeOptions);
if (tradedAmounts.tradedFrom != 0) {
if (tradedAmounts.from != 0) {
IncrementPenalty(tradedMarket, penaltyPerMarketMap);
ret.tradedAmountsVector.push_back(std::move(tradedAmounts));
continue;
Expand All @@ -510,7 +510,7 @@ TradedAmountsVectorWithFinalAmount ExchangePrivate::queryDustSweeper(CurrencyCod
// Selling has not worked - so we need to buy some amount on the requested currency first
tradedAmounts = buySomeAmountToMakeFutureSellPossible(possibleMarkets, marketPriceMap, dustThreshold, balance,
tradeOptions, dustThresholds);
if (tradedAmounts.tradedFrom == 0) {
if (tradedAmounts.from == 0) {
break;
}
ret.tradedAmountsVector.push_back(std::move(tradedAmounts));
Expand All @@ -532,7 +532,7 @@ PlaceOrderInfo ExchangePrivate::placeOrderProcess(MonetaryAmount &from, Monetary
price = isSell ? marketOrderbook.getHighestTheoreticalPrice() : marketOrderbook.getLowestTheoreticalPrice();
} else {
PlaceOrderInfo placeOrderInfo = computeSimulatedMatchedPlacedOrderInfo(volume, price, tradeInfo);
from -= placeOrderInfo.tradedAmounts().tradedFrom;
from -= placeOrderInfo.tradedAmounts().from;
return placeOrderInfo;
}
}
Expand All @@ -544,7 +544,7 @@ PlaceOrderInfo ExchangePrivate::placeOrderProcess(MonetaryAmount &from, Monetary
// (and remove the need to implement the matching amount computation with fees for each exchange)
placeOrderInfo = computeSimulatedMatchedPlacedOrderInfo(volume, price, tradeInfo);
}
from -= placeOrderInfo.tradedAmounts().tradedFrom;
from -= placeOrderInfo.tradedAmounts().from;
return placeOrderInfo;
}

Expand Down
3 changes: 2 additions & 1 deletion src/api/common/src/exchangepublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ MarketsPath ExchangePublic::findMarketsPath(CurrencyCode fromCurrency, CurrencyC
std::pop_heap(searchPaths.begin(), searchPaths.end(), comp);
CurrencyDirPath path = std::move(searchPaths.back());
searchPaths.pop_back();

CurrencyCode lastCurrencyCode = path.back().cur;
if (visitedCurrencies.contains(lastCurrencyCode)) {
continue;
Expand Down Expand Up @@ -159,7 +160,7 @@ MarketsPath ExchangePublic::findMarketsPath(CurrencyCode fromCurrency, CurrencyC
std::push_heap(searchPaths.begin(), searchPaths.end(), comp);
}
}
std::optional<CurrencyCode> optLastFiat =
const std::optional<CurrencyCode> optLastFiat =
considerStableCoinsAsFiats ? _coincenterInfo.fiatCurrencyIfStableCoin(lastCurrencyCode) : std::nullopt;
const bool isLastFiatLike = optLastFiat || fiats.contains(lastCurrencyCode);
if (isToFiatLike && isLastFiatLike) {
Expand Down
19 changes: 9 additions & 10 deletions src/api/common/test/exchangeprivateapi_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ inline bool operator==(const DeliveredWithdrawInfo &lhs, const DeliveredWithdraw

inline BalancePortfolio operator+(const BalancePortfolio &balancePortfolio, const TradedAmounts &tradedAmounts) {
BalancePortfolio ret = balancePortfolio;
ret.add(tradedAmounts.tradedTo);
ret.add(-tradedAmounts.tradedFrom);
ret.add(tradedAmounts.to);
ret.add(-tradedAmounts.from);
return ret;
}

Expand Down Expand Up @@ -684,7 +684,7 @@ TEST_F(ExchangePrivateDustSweeperTest, DustSweeperDirectSellingPossible) {
MonetaryAmount avBtcAmount{75, "BTC", 4};
EXPECT_CALL(exchangePrivate, queryAccountBalance(balanceOptions))
.WillOnce(testing::Return(BalancePortfolio{from, avBtcAmount}))
.WillOnce(testing::Return(BalancePortfolio{avBtcAmount + tradedAmounts.tradedTo}));
.WillOnce(testing::Return(BalancePortfolio{avBtcAmount + tradedAmounts.to}));

TradedAmountsVector tradedAmountsVector{tradedAmounts};
TradedAmountsVectorWithFinalAmount res{tradedAmountsVector, MonetaryAmount{0, dustCur}};
Expand All @@ -710,14 +710,13 @@ TEST_F(ExchangePrivateDustSweeperTest, DustSweeper2StepsSameMarket) {
MonetaryAmount xrpDustThreshold = dustThreshold(dustCur).value_or(MonetaryAmount{-1});
TradedAmounts tradedAmounts1 = expectTakerBuy(xrpDustThreshold, xrpbtcAskPri, xrpbtcBidPri, xrpbtcMarket);

TradedAmounts tradedAmounts2 = expectTakerSell(from + tradedAmounts1.tradedTo, pri);
TradedAmounts tradedAmounts2 = expectTakerSell(from + tradedAmounts1.to, pri);

MonetaryAmount avBtcAmount{75, "BTC", 4};
EXPECT_CALL(exchangePrivate, queryAccountBalance(balanceOptions))
.WillOnce(testing::Return(BalancePortfolio{from, avBtcAmount}))
.WillOnce(
testing::Return(BalancePortfolio{from + tradedAmounts1.tradedTo, avBtcAmount - tradedAmounts1.tradedFrom}))
.WillOnce(testing::Return(BalancePortfolio{avBtcAmount - tradedAmounts1.tradedFrom}));
.WillOnce(testing::Return(BalancePortfolio{from + tradedAmounts1.to, avBtcAmount - tradedAmounts1.from}))
.WillOnce(testing::Return(BalancePortfolio{avBtcAmount - tradedAmounts1.from}));

TradedAmountsVector tradedAmountsVector{tradedAmounts1, tradedAmounts2};
TradedAmountsVectorWithFinalAmount res{tradedAmountsVector, MonetaryAmount{0, dustCur}};
Expand Down Expand Up @@ -762,15 +761,15 @@ TEST_F(ExchangePrivateDustSweeperTest, DustSweeper5Steps) {

MonetaryAmount xrpDustThreshold = dustThreshold(dustCur).value_or(MonetaryAmount{-1});
TradedAmounts tradedAmounts1 = expectTakerBuy(xrpDustThreshold, xrpbtcAskPri, xrpbtcBidPri, xrpbtcMarket);
from += tradedAmounts1.tradedTo;
from += tradedAmounts1.to;

BalancePortfolio balance2 = balance1 + tradedAmounts1;

EXPECT_CALL(exchangePrivate, queryAccountBalance(balanceOptions)).WillOnce(testing::Return(balance2));

int percentXRPSoldSecondStep = 80;
TradedAmounts tradedAmounts2 = expectTakerSell(from, priBtc, percentXRPSoldSecondStep);
from -= tradedAmounts2.tradedFrom;
from -= tradedAmounts2.from;

BalancePortfolio balance3 = balance2 + tradedAmounts2;

Expand All @@ -784,7 +783,7 @@ TEST_F(ExchangePrivateDustSweeperTest, DustSweeper5Steps) {
expectTakerBuy(xrpDustThreshold, xrpbtcAskPri, xrpbtcBidPri, xrpbtcMarket, false);

TradedAmounts tradedAmounts3 = expectTakerBuy((3 * xrpDustThreshold) / 2, xrpeurAskPri, xrpeurBidPri, xrpeurMarket);
from += tradedAmounts3.tradedTo;
from += tradedAmounts3.to;

BalancePortfolio balance4 = balance3 + tradedAmounts3;
EXPECT_CALL(exchangePrivate, queryAccountBalance(balanceOptions)).WillOnce(testing::Return(balance4));
Expand Down
8 changes: 4 additions & 4 deletions src/api/exchanges/src/binanceprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,10 @@ TradedAmounts ParseTrades(Market mk, CurrencyCode fromCurrencyCode, const json&
MonetaryAmount fee(fillDetail["commission"].get<std::string_view>(),
fillDetail["commissionAsset"].get<std::string_view>());
log::debug("Gross {} has been matched at {} price, with a fee of {}", quantity, price, fee);
if (fee.currencyCode() == detailTradedInfo.tradedFrom.currencyCode()) {
detailTradedInfo.tradedFrom += fee;
} else if (fee.currencyCode() == detailTradedInfo.tradedTo.currencyCode()) {
detailTradedInfo.tradedTo -= fee;
if (fee.currencyCode() == detailTradedInfo.from.currencyCode()) {
detailTradedInfo.from += fee;
} else if (fee.currencyCode() == detailTradedInfo.to.currencyCode()) {
detailTradedInfo.to -= fee;
} else {
log::debug("Fee is deduced from {} which is outside {}, do not count it in this trade", fee.currencyStr(), mk);
}
Expand Down
8 changes: 4 additions & 4 deletions src/api/exchanges/src/bithumbprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -900,11 +900,11 @@ OrderInfo BithumbPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext
MonetaryAmount fee(contractDetail["fee"].get<std::string_view>(), feeCurrency);

if (fromCurrencyCode == mk.quote()) {
orderInfo.tradedAmounts.tradedFrom += tradedCost + fee;
orderInfo.tradedAmounts.tradedTo += tradedVol;
orderInfo.tradedAmounts.from += tradedCost + fee;
orderInfo.tradedAmounts.to += tradedVol;
} else {
orderInfo.tradedAmounts.tradedFrom += tradedVol;
orderInfo.tradedAmounts.tradedTo += tradedCost - fee;
orderInfo.tradedAmounts.from += tradedVol;
orderInfo.tradedAmounts.to += tradedCost - fee;
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/api/exchanges/src/krakenprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,11 +566,11 @@ OrderInfo KrakenPrivate::queryOrderInfo(OrderIdView orderId, const TradeContext&

if (fromCurrencyCode == mk.quote()) {
MonetaryAmount price(orderJson["price"].get<std::string_view>(), mk.base());
orderInfo.tradedAmounts.tradedFrom += tradedCost;
orderInfo.tradedAmounts.tradedTo += (tradedCost - fee).toNeutral() / price;
orderInfo.tradedAmounts.from += tradedCost;
orderInfo.tradedAmounts.to += (tradedCost - fee).toNeutral() / price;
} else {
orderInfo.tradedAmounts.tradedFrom += tradedVol;
orderInfo.tradedAmounts.tradedTo += tradedCost - fee;
orderInfo.tradedAmounts.from += tradedVol;
orderInfo.tradedAmounts.to += tradedCost - fee;
}
}

Expand Down
12 changes: 3 additions & 9 deletions src/api/exchanges/src/kucoinpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,9 @@ MarketOrderBook KucoinPublic::OrderBookFunc::operator()(Market mk, int depth) {
using OrderBookVec = vector<OrderBookLine>;
OrderBookVec orderBookLines;
orderBookLines.reserve(static_cast<OrderBookVec::size_type>(depth) * 2);
for (auto asksOrBids : {std::addressof(bids), std::addressof(asks)}) {
const bool isAsk = asksOrBids == std::addressof(asks);
if (isAsk) {
FillOrderBook(mk, depth, isAsk, asksOrBids->begin(), asksOrBids->end(), orderBookLines);
} else {
// Reverse iterate as they are received in descending order
FillOrderBook(mk, depth, isAsk, asksOrBids->rbegin(), asksOrBids->rend(), orderBookLines);
}
}
// Reverse iterate as bids are received in descending order
FillOrderBook(mk, depth, false, bids.rbegin(), bids.rend(), orderBookLines);
FillOrderBook(mk, depth, true, asks.begin(), asks.end(), orderBookLines);
return MarketOrderBook(mk, orderBookLines);
}

Expand Down
12 changes: 6 additions & 6 deletions src/api/exchanges/src/upbitprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,17 +470,17 @@ OrderInfo ParseOrderJson(const json& orderJson, CurrencyCode fromCurrencyCode, M
MonetaryAmount tradedCost(orderDetails["funds"].get<std::string_view>(), mk.quote());

if (fromCurrencyCode == mk.quote()) {
orderInfo.tradedAmounts.tradedFrom += tradedCost;
orderInfo.tradedAmounts.tradedTo += tradedVol;
orderInfo.tradedAmounts.from += tradedCost;
orderInfo.tradedAmounts.to += tradedVol;
} else {
orderInfo.tradedAmounts.tradedFrom += tradedVol;
orderInfo.tradedAmounts.tradedTo += tradedCost;
orderInfo.tradedAmounts.from += tradedVol;
orderInfo.tradedAmounts.to += tradedCost;
}
}
if (fromCurrencyCode == mk.quote()) {
orderInfo.tradedAmounts.tradedFrom += fee;
orderInfo.tradedAmounts.from += fee;
} else {
orderInfo.tradedAmounts.tradedTo -= fee;
orderInfo.tradedAmounts.to -= fee;
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/api/exchanges/test/commonapi_test.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,8 @@ class TestAPI {
TradeOptions tradeOptions(TradeMode::kSimulation);
MonetaryAmount smallFrom = smallAmountIt->amount() / 100;
MonetaryAmount bigFrom = bigAmountIt->amount().toNeutral() * bigAmountIt->price() * 100;
EXPECT_GT(exchangePrivateOpt->trade(smallFrom, mk.quote(), tradeOptions).tradedTo, 0);
EXPECT_NE(exchangePrivateOpt->trade(bigFrom, mk.base(), tradeOptions).tradedFrom, 0);
EXPECT_GT(exchangePrivateOpt->trade(smallFrom, mk.quote(), tradeOptions).to, 0);
EXPECT_NE(exchangePrivateOpt->trade(bigFrom, mk.base(), tradeOptions).from, 0);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/api/interface/include/exchange.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@ class Exchange {
const api::ExchangePublic &apiPublic() const { return _exchangePublic; }

api::ExchangePrivate &apiPrivate() {
if (_pExchangePrivate) {
if (hasPrivateAPI()) {
return *_pExchangePrivate;
}
throw exception("No private key associated to exchange {}", name());
}

const api::ExchangePrivate &apiPrivate() const {
if (_pExchangePrivate) {
if (hasPrivateAPI()) {
return *_pExchangePrivate;
}
throw exception("No private key associated to exchange {}", name());
}

const ExchangeInfo &exchangeInfo() const { return _exchangeInfo; }

bool hasPrivateAPI() const { return _pExchangePrivate; }
bool hasPrivateAPI() const { return _pExchangePrivate != nullptr; }

bool healthCheck() { return _exchangePublic.healthCheck(); }

Expand Down
14 changes: 7 additions & 7 deletions src/engine/include/coincenter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,15 @@ class Coincenter {
/// If no exchange name is given, it will attempt to trade given amount on all exchanges with the sufficient balance.
/// If exactly one private exchange is given, balance will not be queried and trade will be launched without balance
/// check.
TradedAmountsPerExchange trade(MonetaryAmount startAmount, bool isPercentageTrade, CurrencyCode toCurrency,
std::span<const ExchangeName> privateExchangeNames, const TradeOptions &tradeOptions);
TradeResultPerExchange trade(MonetaryAmount startAmount, bool isPercentageTrade, CurrencyCode toCurrency,
std::span<const ExchangeName> privateExchangeNames, const TradeOptions &tradeOptions);

TradedAmountsPerExchange smartBuy(MonetaryAmount endAmount, std::span<const ExchangeName> privateExchangeNames,
const TradeOptions &tradeOptions);
TradeResultPerExchange smartBuy(MonetaryAmount endAmount, std::span<const ExchangeName> privateExchangeNames,
const TradeOptions &tradeOptions);

TradedAmountsPerExchange smartSell(MonetaryAmount startAmount, bool isPercentageTrade,
std::span<const ExchangeName> privateExchangeNames,
const TradeOptions &tradeOptions);
TradeResultPerExchange smartSell(MonetaryAmount startAmount, bool isPercentageTrade,
std::span<const ExchangeName> privateExchangeNames,
const TradeOptions &tradeOptions);

/// Single withdraw of 'grossAmount' from 'fromExchangeName' to 'toExchangeName'
DeliveredWithdrawInfoWithExchanges withdraw(MonetaryAmount grossAmount, bool isPercentageWithdraw,
Expand Down
Loading
Loading