Skip to content

Commit

Permalink
Kraken Public - Migrate to glaze
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Dec 17, 2024
1 parent 1d09f82 commit 3d27837
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 158 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ if(NOT glaze)

FetchContent_Declare(
glaze
URL https://github.com/stephenberry/glaze/archive/refs/tags/v4.0.2.tar.gz
URL_HASH SHA256=65f01a479c786a21141dc1a77cbb9d4af63beed70fbd6bf42bba4c7c3c62943c
URL https://github.com/stephenberry/glaze/archive/refs/tags/v4.2.0.tar.gz
URL_HASH SHA256=96037265d138a0d778d2b8672c976bc2739b3f753aefabc3fcf55ada3ead1869
)

list(APPEND fetchContentPackagesToMakeAvailable glaze)
Expand Down
20 changes: 9 additions & 11 deletions src/api/common/src/binance-common-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,15 @@ BinanceGlobalInfos::BinanceGlobalInfosFunc::BinanceGlobalInfosFunc(AbstractMetri
schema::binance::NetworkCoinDataVector BinanceGlobalInfos::BinanceGlobalInfosFunc::operator()() {
RequestRetry requestRetry(_curlHandle, CurlOptions(HttpRequestType::kGet));

schema::binance::NetworkCoinAll ret =
requestRetry.query<schema::binance::NetworkCoinAll,
json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
"/bapi/capital/v1/public/capital/getNetworkCoinAll", [](const auto& response) {
static constexpr std::string_view kExpectedCode = "000000";
if (response.code != kExpectedCode) {
log::warn("Binance error ({})", response.code);
return RequestRetry::Status::kResponseError;
}
return RequestRetry::Status::kResponseOK;
});
schema::binance::NetworkCoinAll ret = requestRetry.query<schema::binance::NetworkCoinAll>(
"/bapi/capital/v1/public/capital/getNetworkCoinAll", [](const auto& response) {
static constexpr std::string_view kExpectedCode = "000000";
if (response.code != kExpectedCode) {
log::warn("Binance error ({})", response.code);
return RequestRetry::Status::kResponseError;
}
return RequestRetry::Status::kResponseOK;
});

const auto [endIt, oldEndIt] =
std::ranges::remove_if(ret.data, [](const auto& el) { return el.coin.size() > CurrencyCode::kMaxLen; });
Expand Down
4 changes: 2 additions & 2 deletions src/api/exchanges/include/huobi-schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ struct V1AccountAccountsBalance {
// https://huobiapi.github.io/docs/spot/v1/en/#query-deposit-address

struct V2AccountDepositAddress {
string status;
int code;

struct Item {
string address;
Expand Down Expand Up @@ -355,7 +355,7 @@ struct V1OrderOrdersDetail {
// https://huobiapi.github.io/docs/spot/v1/en/#query-withdraw-address

struct V1QueryWithdrawAddress {
string status;
int code;

struct Item {
string address;
Expand Down
106 changes: 106 additions & 0 deletions src/api/exchanges/include/kraken-schema.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#pragma once

#include <array>
#include <cstdint>
#include <unordered_map>
#include <variant>

#include "cct_string.hpp"
#include "cct_type_traits.hpp"
#include "cct_vector.hpp"
#include "monetaryamount.hpp"

namespace cct::schema::kraken {

template <class T>
using has_error_t = decltype(std::declval<T>().error);

// PUBLIC

// https://docs.kraken.com/api/docs/rest-api/get-system-status

struct PublicSystemStatus {
vector<string> error;

struct Result {
string status;
};

Result result;
};

// https://docs.kraken.com/api/docs/rest-api/get-asset-info

struct PublicAssets {
vector<string> error;

struct Result {
string altname;
};

std::unordered_map<string, Result> result;
};

// https://docs.kraken.com/api/docs/rest-api/get-tradable-asset-pairs

struct PublicAssetPairs {
vector<string> error;

struct Result {
string base;
string quote;
MonetaryAmount ordermin;
int8_t lot_decimals;
int8_t pair_decimals;
};

std::unordered_map<string, Result> result;
};

// https://docs.kraken.com/api/docs/rest-api/get-ticker-information

struct PublicTicker {
vector<string> error;

struct Result {
using AskOrBid = std::array<MonetaryAmount, 3>;

AskOrBid a;
AskOrBid b;
std::array<MonetaryAmount, 2> c;
std::array<MonetaryAmount, 2> v;
};

std::unordered_map<string, Result> result;
};

// https://docs.kraken.com/api/docs/rest-api/get-order-book

struct PublicDepth {
vector<string> error;

struct Result {
using Item = std::variant<int64_t, string>;

using Data = std::array<Item, 3>;

vector<Data> asks;
vector<Data> bids;
};

std::unordered_map<string, Result> result;
};

// https://docs.kraken.com/api/docs/rest-api/get-recent-trades

struct PublicTrades {
vector<string> error;

using Item = std::variant<double, string>;

using Data = vector<std::array<Item, 7>>;

std::unordered_map<string, std::variant<Data, string>> result;
};

} // namespace cct::schema::kraken
2 changes: 1 addition & 1 deletion src/api/exchanges/src/binanceprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ T PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType req
SetNonceAndSignature(apiKey, opts.mutablePostData(), queryDelay);

auto resStr = curlHandle.query(endpoint, opts);

// NOLINTNEXTLINE(readability-implicit-bool-conversion)
auto ec = ReadJson<json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
resStr, "binance private", ret);
if (ec) {
Expand Down
24 changes: 11 additions & 13 deletions src/api/exchanges/src/binancepublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,18 @@ T PublicQuery(CurlHandle& curlHandle, std::string_view method, const CurlPostDat
endpoint.append(curlPostData.str());
}
RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet));
return requestRetry.query<T>(endpoint, [](const T& response) {
if constexpr (amc::is_detected<schema::binance::has_code_t, T>::value &&
amc::is_detected<schema::binance::has_msg_t, T>::value) {
if (response.code && response.msg) {
const int statusCode = *response.code; // "1100" for instance
log::warn("Binance error ({}), msg: '{}'", statusCode, *response.msg);
return RequestRetry::Status::kResponseError;
}
}

return requestRetry.query<T, json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
endpoint, [](const T& response) {
if constexpr (amc::is_detected<schema::binance::has_code_t, T>::value &&
amc::is_detected<schema::binance::has_msg_t, T>::value) {
if (response.code && response.msg) {
const int statusCode = *response.code; // "1100" for instance
log::warn("Binance error ({}), msg: '{}'", statusCode, *response.msg);
return RequestRetry::Status::kResponseError;
}
}

return RequestRetry::Status::kResponseOK;
});
return RequestRetry::Status::kResponseOK;
});
}

const auto& RetrieveMarketData(const auto& exchangeInfoData, Market mk) {
Expand Down
3 changes: 1 addition & 2 deletions src/api/exchanges/src/bithumbprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,7 @@ template <class T>
T PrivateQueryProcessWithRetries(CurlHandle& curlHandle, const APIKey& apiKey, std::string_view endpoint,
CurlOptions&& opts) {
RequestRetry requestRetry(curlHandle, std::move(opts));

return requestRetry.query<T, json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
return requestRetry.query<T>(
endpoint,
[endpoint](T& jsonResponse) {
auto statusCode = StringToIntegral<int64_t>(jsonResponse.status);
Expand Down
24 changes: 12 additions & 12 deletions src/api/exchanges/src/bithumbpublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,19 @@ T PublicQuery(CurlHandle& curlHandle, std::string_view method, CurrencyCode base
std::string_view urlOpts = "") {
RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet));

return requestRetry.query<T, json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
ComputeMethodUrl(method, base, quote, urlOpts), [](const T& response) {
if constexpr (amc::is_detected<schema::bithumb::has_status_t, T>::value) {
if (!response.status.empty()) {
auto statusCode = StringToIntegral<int64_t>(response.status);
if (statusCode != BithumbPublic::kStatusOK) {
log::warn("Bithumb error ({})", statusCode);
return RequestRetry::Status::kResponseError;
}
}
return requestRetry.query<T>(ComputeMethodUrl(method, base, quote, urlOpts), [](const T& response) {
if constexpr (amc::is_detected<schema::bithumb::has_status_t, T>::value) {
if (!response.status.empty()) {
auto statusCode = StringToIntegral<int64_t>(response.status);
if (statusCode != BithumbPublic::kStatusOK) {
log::warn("Bithumb error ({})", statusCode);
return RequestRetry::Status::kResponseError;
}
}
}

return RequestRetry::Status::kResponseOK;
});
return RequestRetry::Status::kResponseOK;
});
}

} // namespace
Expand All @@ -119,6 +118,7 @@ BithumbPublic::BithumbPublic(const CoincenterInfo& config, FiatConverter& fiatCo
bool BithumbPublic::healthCheck() {
auto networkInfoStr = _curlHandle.query("/public/network-info", CurlOptions(HttpRequestType::kGet));
schema::bithumb::V1NetworkInfo networkInfo;
// NOLINTNEXTLINE(readability-implicit-bool-conversion)
auto ec = ReadJson<json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
networkInfoStr, "Bithumb network info", networkInfo);
if (ec) {
Expand Down
26 changes: 21 additions & 5 deletions src/api/exchanges/src/huobiprivateapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,28 @@ T PrivateQuery(CurlHandle& curlHandle, const APIKey& apiKey, HttpRequestType req

RequestRetry requestRetry(curlHandle, CurlOptions(requestType, std::move(postData), postDataFormat),
QueryRetryPolicy{.initialRetryDelay = seconds{1}, .nbMaxRetries = 3});

return requestRetry.query<T, json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
return requestRetry.query<T>(
method,
[](const T& response) {
if (response.status != "ok") {
log::warn("Huobi status error: {}", response.status);
return RequestRetry::Status::kResponseError;
if constexpr (amc::is_detected<schema::huobi::has_code_t, T>::value) {
if (response.code != 200) {
log::warn("Huobi error code: {}", response.code);
return RequestRetry::Status::kResponseError;
}
} else if constexpr (amc::is_detected<schema::huobi::has_status_t, T>::value) {
if (response.status != "ok") {
if (response.status.empty()) {
log::warn("Huobi status is empty - is it supposed to be returned by this endpoint?");
} else {
log::warn("Huobi status error: {}", response.status);
return RequestRetry::Status::kResponseError;
}
}
} else {
// TODO: can be replaced by static_assert(false) in C++23
static_assert(amc::is_detected<schema::huobi::has_code_t, T>::value ||
amc::is_detected<schema::huobi::has_status_t, T>::value,
"T should have a code or status member");
}
return RequestRetry::Status::kResponseOK;
},
Expand Down Expand Up @@ -159,6 +174,7 @@ HuobiPrivate::HuobiPrivate(const CoincenterInfo& coincenterInfo, HuobiPublic& hu
bool HuobiPrivate::validateApiKey() {
const auto result = PrivateQuery<schema::huobi::V1AccountAccounts>(_curlHandle, _apiKey, HttpRequestType::kGet,
"/v1/account/accounts", CurlPostData());

return result.status == "ok" && !result.data.empty();
}

Expand Down
36 changes: 20 additions & 16 deletions src/api/exchanges/src/huobipublicapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,26 @@ T PublicQuery(CurlHandle& curlHandle, std::string_view endpoint, const CurlPostD
}

RequestRetry requestRetry(curlHandle, CurlOptions(HttpRequestType::kGet));
return requestRetry.query<T>(method, [](const T& response) {
if constexpr (amc::is_detected<schema::huobi::has_code_t, T>::value) {
if (response.code != 200) {
log::warn("Huobi error code: {}", response.code);
return RequestRetry::Status::kResponseError;
}
} else if constexpr (amc::is_detected<schema::huobi::has_status_t, T>::value) {
if (response.status != "ok") {
log::warn("Huobi status error: {}", response.status);
return RequestRetry::Status::kResponseError;
}
} else {
// TODO: can be replaced by static_assert(false) in C++23
static_assert(amc::is_detected<schema::huobi::has_code_t, T>::value ||
amc::is_detected<schema::huobi::has_status_t, T>::value,
"T should have a code or status member");
}

return requestRetry.query<T, json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
method, [](const T& response) {
if constexpr (amc::is_detected<schema::huobi::has_code_t, T>::value) {
if (response.code != 200) {
log::warn("Huobi error code: {}", response.code);
return RequestRetry::Status::kResponseError;
}
} else if constexpr (amc::is_detected<schema::huobi::has_status_t, T>::value) {
if (response.status != "ok") {
log::warn("Huobi status error: {}", response.status);
return RequestRetry::Status::kResponseError;
}
}

return RequestRetry::Status::kResponseOK;
});
return RequestRetry::Status::kResponseOK;
});
}

} // namespace
Expand Down Expand Up @@ -113,6 +116,7 @@ HuobiPublic::HuobiPublic(const CoincenterInfo& config, FiatConverter& fiatConver
bool HuobiPublic::healthCheck() {
auto strData = _healthCheckCurlHandle.query("/api/v2/summary.json", CurlOptions(HttpRequestType::kGet));
schema::huobi::V2SystemStatus networkInfo;
// NOLINTNEXTLINE(readability-implicit-bool-conversion)
auto ec = ReadJson<json::opts{.error_on_unknown_keys = false, .minified = true, .raw_string = true}>(
strData, "Huobi system status", networkInfo);
if (ec) {
Expand Down
Loading

0 comments on commit 3d27837

Please sign in to comment.