Skip to content
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
24 changes: 24 additions & 0 deletions include/ccapi_cpp/ccapi_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,30 @@ class Element {
}
}

// Template insert: accept any string-like value
template <typename S>
void insert_or_assign(std::string_view name, S&& value) {
// Construct std::string only if necessary
if constexpr (std::is_same_v<std::decay_t<S>, std::string>) {
// If value is std::string, move it in to avoid copy
nameValueMap.insert_or_assign(name, std::forward<S>(value));
} else {
// Otherwise, construct std::string from value (string_view, const char*)
nameValueMap.insert_or_assign(name, std::string(std::forward<S>(value)));
}
}

template <typename S>
void insert_or_assign(int tag, S&& value) {
if constexpr (std::is_same_v<std::decay_t<S>, std::string>) {
// If already std::string, move to avoid copy
tagValueMap.insert_or_assign(tag, std::forward<S>(value));
} else {
// Otherwise, construct std::string from value (string_view, literal, etc.)
tagValueMap.insert_or_assign(tag, std::string(std::forward<S>(value)));
}
}

// void emplace(std::string& name, std::string& value) { this->nameValueMap.emplace(std::move(name), std::move(value)); }

// void emplace(int tag, std::string& value) { this->tagValueMap.emplace(std::move(tag), std::move(value)); }
Expand Down
11 changes: 0 additions & 11 deletions include/ccapi_cpp/ccapi_http_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,12 @@ class HttpConnection {

void clearBuffer() { this->buffer.consume(this->buffer.size()); }

void resetResponseParser() {
this->resParserOpt.emplace();
this->resParserOpt->body_limit(CCAPI_HTTP_RESPONSE_PARSER_BODY_LIMIT);
}

void prepareReadNextResponse() {
this->clearBuffer();
this->resetResponseParser();
}

std::string host;
std::string port;
std::shared_ptr<beast::ssl_stream<beast::tcp_stream>> streamPtr;
TimePoint lastReceiveDataTp{std::chrono::seconds{0}};

boost::beast::flat_buffer buffer;
std::optional<boost::beast::http::response_parser<boost::beast::http::string_body>> resParserOpt;
};

} /* namespace ccapi */
Expand Down
2 changes: 1 addition & 1 deletion include/ccapi_cpp/ccapi_http_retry.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class HttpRetry {
std::ostringstream oss;
oss << promisePtr;
std::string output =
"HttpConnection [numRetry = " + ccapi::toString(numRetry) + ", numRedirect = " + ccapi::toString(numRedirect) + ", promisePtr = " + oss.str() + "]";
"HttpRetry [numRetry = " + ccapi::toString(numRetry) + ", numRedirect = " + ccapi::toString(numRedirect) + ", promisePtr = " + oss.str() + "]";
return output;
}

Expand Down
16 changes: 12 additions & 4 deletions include/ccapi_cpp/ccapi_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ namespace ccapi {
class Request {
public:
enum class Operation {
UNKNOWN = 0,
CUSTOM = CCAPI_REQUEST_OPERATION_TYPE_CUSTOM,
GENERIC_PUBLIC_REQUEST = CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PUBLIC_REQUEST,
GENERIC_PRIVATE_REQUEST = CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PRIVATE_REQUEST,
Expand Down Expand Up @@ -60,6 +61,9 @@ class Request {
case Operation::CUSTOM:
output = "CUSTOM";
break;
case Operation::UNKNOWN:
output = "UNKNOWN";
break;
case Operation::GENERIC_PUBLIC_REQUEST:
output = "GENERIC_PUBLIC_REQUEST";
break;
Expand Down Expand Up @@ -130,15 +134,15 @@ class Request {
output = "GET_ACCOUNT_POSITIONS";
break;
default:
CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE);
CCAPI_LOGGER_FATAL(std::string(CCAPI_UNSUPPORTED_VALUE) + " " + std::to_string(static_cast<int>(operation)));
}
return output;
}

Request() {}

Request(Operation operation, const std::string& exchange, const std::string& instrument = "", const std::string& correlationId = "",
const std::map<std::string, std::string>& credential = {})
explicit Request(Operation operation, const std::string& exchange = "", const std::string& instrument = "", const std::string& correlationId = "",
const std::map<std::string, std::string>& credential = {})
: operation(operation), exchange(exchange), instrument(instrument), correlationId(correlationId), credential(credential) {
if (operation == Operation::CUSTOM) {
this->serviceName = CCAPI_UNKNOWN;
Expand Down Expand Up @@ -228,6 +232,10 @@ class Request {

const std::string& getPort() const { return port; }

void setExchange(const std::string& exchange) { this->exchange = exchange; }

void setInstrument(const std::string& instrument) { this->instrument = instrument; }

void setIndex(int index) { this->index = index; }

void setCredential(const std::map<std::string, std::string>& credential) { this->credential = credential; }
Expand Down Expand Up @@ -263,7 +271,7 @@ class Request {

private:
#endif
Operation operation;
Operation operation{Operation::UNKNOWN};
std::string exchange;
std::string marginType;
std::string instrument;
Expand Down
22 changes: 15 additions & 7 deletions include/ccapi_cpp/ccapi_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ class Session {

virtual ~Session() {
CCAPI_LOGGER_FUNCTION_ENTER;
this->delayTimerByIdMap.clear();
this->serviceByServiceNameExchangeMap.clear();
if (this->useInternalServiceContextPtr) {
delete this->serviceContextPtr;
}
Expand Down Expand Up @@ -597,6 +599,9 @@ class Session {

virtual void stop() {
boost::asio::post(*this->serviceContextPtr->ioContextPtr, [this]() {
for (const auto& [_, delayTimer] : this->delayTimerByIdMap) {
delayTimer->cancel();
}
for (const auto& x : this->serviceByServiceNameExchangeMap) {
for (const auto& y : x.second) {
y.second->stop();
Expand Down Expand Up @@ -655,7 +660,7 @@ class Session {
auto subscriptionList = x.second;
if (this->serviceByServiceNameExchangeMap.find(serviceName) == this->serviceByServiceNameExchangeMap.end()) {
this->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::SUBSCRIPTION_FAILURE,
"please enable service: " + serviceName + ", and the exchanges that you want");
"please enable service: " + serviceName + ", and the exchanges that you want for subscriptionList " + toString(subscriptionList));
return;
}
if (serviceName == CCAPI_MARKET_DATA) {
Expand Down Expand Up @@ -722,7 +727,8 @@ class Session {
auto serviceName = subscription.getServiceName();
CCAPI_LOGGER_DEBUG("serviceName = " + serviceName);
if (this->serviceByServiceNameExchangeMap.find(serviceName) == this->serviceByServiceNameExchangeMap.end()) {
this->onError(Event::Type::FIX_STATUS, Message::Type::FIX_FAILURE, "please enable service: " + serviceName + ", and the exchanges that you want");
this->onError(Event::Type::FIX_STATUS, Message::Type::FIX_FAILURE,
"please enable service: " + serviceName + ", and the exchanges that you want for subscription " + toString(subscription));
return;
}
auto exchange = subscription.getExchange();
Expand Down Expand Up @@ -776,7 +782,8 @@ class Session {
auto serviceName = request.getServiceName();
CCAPI_LOGGER_DEBUG("serviceName = " + serviceName);
if (this->serviceByServiceNameExchangeMap.find(serviceName) == this->serviceByServiceNameExchangeMap.end()) {
this->onError(Event::Type::FIX_STATUS, Message::Type::FIX_FAILURE, "please enable service: " + serviceName + ", and the exchanges that you want");
this->onError(Event::Type::FIX_STATUS, Message::Type::FIX_FAILURE,
"please enable service: " + serviceName + ", and the exchanges that you want for request " + toString(request));
return;
}
std::map<std::string, std::shared_ptr<Service>>& serviceByExchangeMap = this->serviceByServiceNameExchangeMap.at(serviceName);
Expand All @@ -802,7 +809,9 @@ class Session {
const auto& serviceName = request.getServiceName();
CCAPI_LOGGER_DEBUG("serviceName = " + serviceName);
if (this->serviceByServiceNameExchangeMap.find(serviceName) == this->serviceByServiceNameExchangeMap.end()) {
this->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, "please enable service: " + serviceName + ", and the exchanges that you want");
this->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE,
"please enable service: " + serviceName + ", and the exchanges that you want for websocketOrderEntrySubscriptionCorrelationId " +
toString(websocketOrderEntrySubscriptionCorrelationId) + ", request = " + toString(request));
return;
}
const std::map<std::string, std::shared_ptr<Service>>& serviceByExchangeMap = this->serviceByServiceNameExchangeMap.at(serviceName);
Expand Down Expand Up @@ -841,7 +850,7 @@ class Session {
CCAPI_LOGGER_DEBUG("serviceName = " + serviceName);
if (this->serviceByServiceNameExchangeMap.find(serviceName) == this->serviceByServiceNameExchangeMap.end()) {
this->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE,
"please enable service: " + serviceName + ", and the exchanges that you want", eventQueuePtr);
"please enable service: " + serviceName + ", and the exchanges that you want for request " + toString(request), eventQueuePtr);
return;
}
std::map<std::string, std::shared_ptr<Service>>& serviceByExchangeMap = this->serviceByServiceNameExchangeMap.at(serviceName);
Expand Down Expand Up @@ -902,8 +911,7 @@ class Session {
virtual void setTimer(const std::string& id, long delayMilliseconds, std::function<void(const boost::system::error_code&)> errorHandler,
std::function<void()> successHandler) {
boost::asio::post(*this->serviceContextPtr->ioContextPtr, [this, id, delayMilliseconds, errorHandler, successHandler]() {
std::shared_ptr<boost::asio::steady_timer> timerPtr(
new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, boost::asio::chrono::milliseconds(delayMilliseconds)));
auto timerPtr = std::make_shared<boost::asio::steady_timer>(*this->serviceContextPtr->ioContextPtr, boost::asio::chrono::milliseconds(delayMilliseconds));
timerPtr->async_wait([this, id, errorHandler, successHandler](const boost::system::error_code& ec) {
if (this->eventHandler) {
if (!this->eventDispatcher) {
Expand Down
2 changes: 1 addition & 1 deletion include/ccapi_cpp/ccapi_subscription.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class Subscription {
output = "UNSUBSCRIBED";
break;
default:
CCAPI_LOGGER_FATAL(CCAPI_UNSUPPORTED_VALUE);
CCAPI_LOGGER_FATAL(std::string(CCAPI_UNSUPPORTED_VALUE) + " " + std::to_string(static_cast<int>(status)));
}
return output;
}
Expand Down
20 changes: 15 additions & 5 deletions include/ccapi_cpp/ccapi_util_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -1142,18 +1142,21 @@ class Decimal {
return *this;
}

#ifndef CCAPI_EXPOSE_INTERNAL

private:
#endif
Decimal negate() const {
Decimal o;
o.sign = !this->sign;
o.before = this->before;
o.frac = this->frac;
o.sign = !this->sign;
return o;
}

Decimal abs() const {
if (!this->sign) { // if the input is negative
return -*this; // negate it
}
return *this; // already positive
}

Decimal add(const Decimal& x) const {
/* ---------------- Same-sign fast path ---------------- */
if (this->sign && x.sign) {
Expand Down Expand Up @@ -1337,7 +1340,10 @@ class Decimal {

return result;
}
#ifndef CCAPI_EXPOSE_INTERNAL

private:
#endif
// false means negative sign needed
bool sign{true};
// {-}bbbb.aaaa
Expand Down Expand Up @@ -1381,6 +1387,10 @@ inline std::string ConvertDecimalToString(const Decimal& input, bool normalize =
return input.toString();
}

inline Decimal ConvertDecimalToAbs(const Decimal& input) { return input.abs(); }

inline double ConvertDecimalToDouble(const Decimal& input) { return input.toDouble(); }

inline std::string size_tToString(const size_t& t) {
std::stringstream ss;
ss << t;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,14 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService
element.insert(CCAPI_EM_ORDER_SIDE, std::string_view(data["S"].GetString()) == "BUY" ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL);
element.insert(CCAPI_IS_MAKER, data["m"].GetBool() ? "1" : "0");
element.insert(CCAPI_EM_ORDER_ID, data["i"].GetString());
element.insert(CCAPI_EM_CLIENT_ORDER_ID, data["c"].GetString());
{
auto it = data.FindMember("C");
if (it != data.MemberEnd() && !it->value.IsNull() && it->value.GetStringLength()) {
element.insert(CCAPI_EM_CLIENT_ORDER_ID, std::string(it->value.GetString()));
} else {
element.insert(CCAPI_EM_CLIENT_ORDER_ID, data["c"].GetString());
}
}
element.insert(CCAPI_EM_ORDER_INSTRUMENT, instrument);
{
auto it = data.FindMember("n");
Expand All @@ -555,7 +562,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService
message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE);
const std::map<std::string_view, std::pair<std::string_view, JsonDataType>>& extractionFieldNameMap = {
{CCAPI_EM_ORDER_ID, std::make_pair("i", JsonDataType::INTEGER)},
{CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("c", JsonDataType::STRING)},
{CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("C", JsonDataType::STRING)},
{CCAPI_EM_ORDER_SIDE, std::make_pair("S", JsonDataType::STRING)},
{CCAPI_EM_ORDER_LIMIT_PRICE, std::make_pair("p", JsonDataType::STRING)},
{CCAPI_EM_ORDER_QUANTITY, std::make_pair("q", JsonDataType::STRING)},
Expand All @@ -566,10 +573,10 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService
};
Element info;
this->extractOrderInfo(info, data, extractionFieldNameMap);
{
auto it = data.FindMember("C");
if (info.getValue(CCAPI_EM_CLIENT_ORDER_ID).empty()) {
auto it = data.FindMember("c");
if (it != data.MemberEnd() && !it->value.IsNull() && it->value.GetStringLength()) {
info.insert(CCAPI_EM_ORIGINAL_CLIENT_ORDER_ID, std::string(it->value.GetString()));
info.insert_or_assign(CCAPI_EM_CLIENT_ORDER_ID, std::string(it->value.GetString()));
}
}
{
Expand Down Expand Up @@ -723,7 +730,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService
{CCAPI_EM_ORDER_STATUS, std::make_pair("status", JsonDataType::STRING)},
{CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("symbol", JsonDataType::STRING)},
{CCAPI_LAST_UPDATED_TIME_SECONDS, std::make_pair(this->isDerivatives ? "updateTime" : "transactTime", JsonDataType::STRING)},
{CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("clientOrderId", JsonDataType::STRING)},
{CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("origClientOrderId", JsonDataType::STRING)},
};

Element element;
Expand Down
Loading
Loading