Skip to content

Commit

Permalink
Strong typing for market order book lines, minor code clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Feb 11, 2024
1 parent a8c2d1f commit d46f596
Show file tree
Hide file tree
Showing 22 changed files with 112 additions and 165 deletions.
2 changes: 1 addition & 1 deletion src/api-objects/include/order.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Order {
Market market() const { return Market(_matchedVolume.currencyCode(), _price.currencyCode()); }

/// default ordering by place time first, then matched volume, etc
auto operator<=>(const Order &) const = default;
std::strong_ordering operator<=>(const Order &) const noexcept = default;

using trivially_relocatable = is_trivially_relocatable<OrderId>::type;

Expand Down
2 changes: 1 addition & 1 deletion src/api-objects/include/publictrade.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class PublicTrade {

/// 3 way operator - make compiler generate all 6 operators (including == and !=)
/// we order by time first, then amount, price, etc. Do not change the fields order!
std::strong_ordering operator<=>(const PublicTrade &) const = default;
std::strong_ordering operator<=>(const PublicTrade&) const noexcept = default;

private:
TimePoint _time;
Expand Down
2 changes: 2 additions & 0 deletions src/api-objects/src/publictrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@
#include "timestring.hpp"

namespace cct {

string PublicTrade::timeStr() const { return ToString(_time); }

} // namespace cct
4 changes: 2 additions & 2 deletions src/api/exchanges/src/binancepublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,12 +495,12 @@ MarketOrderBook BinancePublic::OrderBookFunc::operator()(Market mk, int depth) {
if (asksIt != asksAndBids.end() && bidsIt != asksAndBids.end()) {
orderBookLines.reserve(static_cast<OrderBookVec::size_type>(asksIt->size() + bidsIt->size()));
for (const auto& asksOrBids : {asksIt, bidsIt}) {
const bool isAsk = asksOrBids == asksIt;
const auto type = asksOrBids == asksIt ? OrderBookLine::Type::kAsk : OrderBookLine::Type::kBid;
for (const auto& priceQuantityPair : *asksOrBids) {
MonetaryAmount amount(priceQuantityPair.back().get<std::string_view>(), mk.base());
MonetaryAmount price(priceQuantityPair.front().get<std::string_view>(), mk.quote());

orderBookLines.emplace_back(amount, price, isAsk);
orderBookLines.emplace_back(amount, price, type);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/api/exchanges/src/bithumbpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,12 @@ MarketOrderBookMap GetOrderbooks(CurlHandle& curlHandle, const CoincenterInfo& c
OrderBookVec orderBookLines;
orderBookLines.reserve(static_cast<OrderBookVec::size_type>(asksBids[0]->size() + asksBids[1]->size()));
for (const json* asksOrBids : asksBids) {
const bool isAsk = asksOrBids == asksBids[0];
const auto type = asksOrBids == asksBids[0] ? OrderBookLine::Type::kAsk : OrderBookLine::Type::kBid;
for (const json& priceQuantityPair : *asksOrBids) {
MonetaryAmount amount(priceQuantityPair["quantity"].get<std::string_view>(), baseCurrencyCode);
MonetaryAmount price(priceQuantityPair["price"].get<std::string_view>(), quoteCurrencyCode);

orderBookLines.emplace_back(amount, price, isAsk);
orderBookLines.emplace_back(amount, price, type);
}
}
Market market(baseCurrencyCode, quoteCurrencyCode);
Expand Down
7 changes: 4 additions & 3 deletions src/api/exchanges/src/huobipublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,15 +389,16 @@ MarketOrderBook HuobiPublic::OrderBookFunc::operator()(Market mk, int depth) {
orderBookLines.reserve(bidsIt->size() + asksIt->size());
for (const auto& asksOrBids : {bidsIt, asksIt}) {
int currentDepth = 0;
bool isBid = asksOrBids == bidsIt;
const auto type = asksOrBids == asksIt ? OrderBookLine::Type::kAsk : OrderBookLine::Type::kBid;
for (const auto& priceQuantityPair : *asksOrBids) {
MonetaryAmount amount(priceQuantityPair.back().get<double>(), mk.base());
MonetaryAmount price(priceQuantityPair.front().get<double>(), mk.quote());

orderBookLines.emplace_back(amount, price, !isBid);
orderBookLines.emplace_back(amount, price, type);
if (++currentDepth == depth) {
if (depth < static_cast<int>(asksOrBids->size())) {
log::debug("Truncate number of {} prices in order book to {}", isBid ? "bid" : "ask", depth);
log::debug("Truncate number of {} prices in order book to {}",
type == OrderBookLine::Type::kAsk ? "ask" : "bid", depth);
}
break;
}
Expand Down
4 changes: 2 additions & 2 deletions src/api/exchanges/src/krakenpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,15 +309,15 @@ MarketOrderBook KrakenPublic::OrderBookFunc::operator()(Market mk, int count) {

orderBookLines.reserve(static_cast<OrderBookVec::size_type>(asksIt->size() + bidsIt->size()));
for (const auto& asksOrBids : {asksIt, bidsIt}) {
const bool isAsk = asksOrBids == asksIt;
const auto type = asksOrBids == asksIt ? OrderBookLine::Type::kAsk : OrderBookLine::Type::kBid;
for (const auto& priceQuantityTuple : *asksOrBids) {
std::string_view priceStr = priceQuantityTuple[0].get<std::string_view>();
std::string_view amountStr = priceQuantityTuple[1].get<std::string_view>();

MonetaryAmount amount(amountStr, mk.base());
MonetaryAmount price(priceStr, mk.quote());

orderBookLines.emplace_back(amount, price, isAsk);
orderBookLines.emplace_back(amount, price, type);
}
}
}
Expand Down
12 changes: 7 additions & 5 deletions src/api/exchanges/src/kucoinpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,16 +261,18 @@ MarketOrderBookMap KucoinPublic::AllOrderBooksFunc::operator()(int depth) {

namespace {
template <class InputIt>
void FillOrderBook(Market mk, int depth, bool isAsk, InputIt beg, InputIt end, vector<OrderBookLine>& orderBookLines) {
void FillOrderBook(Market mk, int depth, OrderBookLine::Type type, InputIt beg, InputIt end,
vector<OrderBookLine>& orderBookLines) {
int currentDepth = 0;
for (auto it = beg; it != end; ++it) {
MonetaryAmount price((*it)[0].template get<std::string_view>(), mk.quote());
MonetaryAmount amount((*it)[1].template get<std::string_view>(), mk.base());

orderBookLines.emplace_back(amount, price, isAsk);
orderBookLines.emplace_back(amount, price, type);
if (++currentDepth == depth) {
if (++it != end) {
log::debug("Truncate number of {} prices in order book to {}", isAsk ? "ask" : "bid", depth);
log::debug("Truncate number of {} prices in order book to {}",
type == OrderBookLine::Type::kAsk ? "ask" : "bid", depth);
}
break;
}
Expand Down Expand Up @@ -299,8 +301,8 @@ MarketOrderBook KucoinPublic::OrderBookFunc::operator()(Market mk, int depth) {
if (asksIt != asksAndBids.end() && bidsIt != asksAndBids.end()) {
orderBookLines.reserve(asksIt->size() + bidsIt->size());
// Reverse iterate as bids are received in descending order
FillOrderBook(mk, depth, false, bidsIt->rbegin(), bidsIt->rend(), orderBookLines);
FillOrderBook(mk, depth, true, asksIt->begin(), asksIt->end(), orderBookLines);
FillOrderBook(mk, depth, OrderBookLine::Type::kBid, bidsIt->rbegin(), bidsIt->rend(), orderBookLines);
FillOrderBook(mk, depth, OrderBookLine::Type::kAsk, asksIt->begin(), asksIt->end(), orderBookLines);
}

return MarketOrderBook(Clock::now(), mk, orderBookLines);
Expand Down
4 changes: 2 additions & 2 deletions src/api/exchanges/src/upbitpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ MarketOrderBookMap ParseOrderBooks(const json& result, int depth) {
MonetaryAmount askVol(orderbookDetails["ask_size"].get<double>(), base);
MonetaryAmount bidVol(orderbookDetails["bid_size"].get<double>(), base);

orderBookLines.emplace_back(askVol, askPri, true /* isAsk */);
orderBookLines.emplace_back(bidVol, bidPri, false /* isAsk */);
orderBookLines.emplace_back(askVol, askPri, OrderBookLine::Type::kAsk);
orderBookLines.emplace_back(bidVol, bidPri, OrderBookLine::Type::kBid);

if (static_cast<int>(orderBookLines.size() / 2) == depth) {
// Upbit does not have a depth parameter, the only thing we can do is to truncate it manually
Expand Down
2 changes: 0 additions & 2 deletions src/monitoring/include/prometheusmetricgateway.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@

#include <memory>
#include <mutex>
#include <string_view>
#include <unordered_map>
#include <utility>

#include "abstractmetricgateway.hpp"
#include "timedef.hpp"
Expand Down
4 changes: 2 additions & 2 deletions src/monitoring/include/voidmetricgateway.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#pragma once

#include <string_view>

#include "abstractmetricgateway.hpp"
#include "metric.hpp"
#include "monitoringinfo.hpp"

namespace cct {
class VoidMetricGateway : public AbstractMetricGateway {
Expand Down
2 changes: 2 additions & 0 deletions src/objects/include/coincentercommandtype.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ enum class CoincenterCommandType : int8_t {
kSell,
kWithdrawApply,
kDustSweeper,

kLast
};

std::string_view CoincenterCommandTypeToString(CoincenterCommandType type);
Expand Down
4 changes: 2 additions & 2 deletions src/objects/include/generalconfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class GeneralConfig {

static json LoadFile(std::string_view dataDir);

GeneralConfig() : _loggingInfo(LoggingInfo::WithLoggersCreation::kYes) {}
GeneralConfig() = default;

GeneralConfig(LoggingInfo &&loggingInfo, RequestsConfig &&requestsConfig, Duration fiatConversionQueryRate,
ApiOutputType apiOutputType);
Expand All @@ -30,7 +30,7 @@ class GeneralConfig {
Duration fiatConversionQueryRate() const { return _fiatConversionQueryRate; }

private:
LoggingInfo _loggingInfo;
LoggingInfo _loggingInfo{LoggingInfo::WithLoggersCreation::kYes};
RequestsConfig _requestsConfig;
Duration _fiatConversionQueryRate = std::chrono::hours(8);
ApiOutputType _apiOutputType = ApiOutputType::kFormattedTable;
Expand Down
2 changes: 1 addition & 1 deletion src/objects/include/market.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,4 @@ struct hash<cct::Market> {
return cct::HashCombine(hash<cct::CurrencyCode>()(mk.base()), hash<cct::CurrencyCode>()(mk.quote()));
}
};
} // namespace std
} // namespace std
15 changes: 10 additions & 5 deletions src/objects/include/marketorderbook.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#pragma once

#include <cstdint>
#include <optional>
#include <span>
#include <string_view>
#include <utility>

#include "cct_smallvector.hpp"
#include "market.hpp"
Expand All @@ -18,10 +20,11 @@ class PriceOptions;
/// Represents an entry in an order book, an amount at a given price.
class OrderBookLine {
public:
enum class Type : int8_t { kAsk, kBid };

/// Constructs a new OrderBookLine.
/// @param isAsk true if it represents a 'ask' price, false if it is a 'bid' price.
OrderBookLine(MonetaryAmount amount, MonetaryAmount price, bool isAsk)
: _amount(isAsk ? -amount : amount), _price(price) {}
OrderBookLine(MonetaryAmount amount, MonetaryAmount price, Type type)
: _amount(type == Type::kAsk ? -amount : amount), _price(price) {}

private:
friend class MarketOrderBook;
Expand Down Expand Up @@ -142,6 +145,8 @@ class MarketOrderBook {

std::optional<MonetaryAmount> computeAvgPrice(MonetaryAmount from, const PriceOptions& priceOptions) const;

VolAndPriNbDecimals volAndPriNbDecimals() const noexcept { return _volAndPriNbDecimals; }

/// Print the market order book in a SimpleTable and returns it.
/// @param conversionPriceRate prices will be multiplied to given amount to display an additional column of equivalent
/// currency
Expand All @@ -153,7 +158,7 @@ class MarketOrderBook {
struct AmountPrice {
using AmountType = MonetaryAmount::AmountType;

bool operator==(const AmountPrice& o) const noexcept = default;
bool operator==(const AmountPrice&) const noexcept = default;

AmountType amount = 0;
AmountType price = 0;
Expand All @@ -165,7 +170,7 @@ class MarketOrderBook {
public:
using trivially_relocatable = is_trivially_relocatable<AmountPriceVector>::type;

bool operator==(const MarketOrderBook&) const = default;
bool operator==(const MarketOrderBook&) const noexcept = default;

private:
/// Represents a total amount of waiting orders at a given price.
Expand Down
Loading

0 comments on commit d46f596

Please sign in to comment.