diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h index 0b9ecfbb..932a5b16 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi.h @@ -192,6 +192,10 @@ class ExecutionManagementServiceHuobi : public ExecutionManagementServiceHuobiBa } else if (data.IsObject()) { Element element; this->extractOrderInfo(element, data, extractionFieldNameMap); + if (operation == Request::Operation::GET_ORDER) { + element.insert(CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, std::string(data["field-amount"].GetString())); + element.insert(CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::string(data["field-cash-amount"].GetString())); + } elementList.emplace_back(std::move(element)); } else { for (const auto& x : data.GetArray()) { @@ -286,9 +290,9 @@ class ExecutionManagementServiceHuobi : public ExecutionManagementServiceHuobiBa auto& allocator = document.GetAllocator(); document.AddMember("action", rj::Value("sub").Move(), allocator); std::string ch; - if (fieldSet.find(CCAPI_EM_ORDER_UPDATE) != fieldSet.end()) { + if (field == CCAPI_EM_ORDER_UPDATE) { ch = "orders#" + symbol; - } else if (fieldSet.find(CCAPI_EM_PRIVATE_TRADE) != fieldSet.end()) { + } else if (field == CCAPI_EM_PRIVATE_TRADE) { ch = "trade.clearing#" + symbol; } document.AddMember("ch", rj::Value(ch.c_str(), allocator).Move(), allocator); @@ -370,6 +374,11 @@ class ExecutionManagementServiceHuobi : public ExecutionManagementServiceHuobiBa std::string dataEventType = data["eventType"].GetString(); if (dataEventType == "trigger" || dataEventType == "deletion") { info.insert(CCAPI_EM_ORDER_SIDE, std::string(data["orderSide"].GetString()) == "buy" ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL); + } else if (dataEventType == "trade") { + info.insert(CCAPI_TRADE_ID, std::string(data["tradeId"].GetString())); + info.insert(CCAPI_EM_ORDER_LAST_EXECUTED_PRICE, data["tradePrice"].GetString()); + info.insert(CCAPI_EM_ORDER_LAST_EXECUTED_SIZE, data["tradeVolume"].GetString()); + info.insert(CCAPI_IS_MAKER, data["aggressor"].GetBool() ? "0" : "1"); } std::vector elementList; elementList.emplace_back(std::move(info)); diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_base.h index 2ee2764c..b0bd0a4f 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_base.h @@ -14,10 +14,6 @@ class ExecutionManagementServiceHuobiBase : public ExecutionManagementService { protected: #endif - void pingOnApplicationLevel(wspp::connection_hdl hdl, ErrorCode& ec) override { - auto now = UtilTime::now(); - this->send(hdl, "{\"ping\":" + std::to_string(UtilTime::getUnixTimestamp(now)) + "}", wspp::frame::opcode::text, ec); - } void createSignature(std::string& signature, std::string& queryString, const std::string& reqMethod, const std::string& host, const std::string& path, const std::map& queryParamMap, const std::map& credential) { std::string preSignedText; @@ -51,6 +47,12 @@ class ExecutionManagementServiceHuobiBase : public ExecutionManagementService { queryParamMap.insert(std::make_pair(y.at(0), y.at(1))); } } + auto apiKey = mapGetWithDefault(credential, this->apiKeyName); + queryParamMap.insert(std::make_pair("AccessKeyId", apiKey)); + queryParamMap.insert(std::make_pair("SignatureMethod", "HmacSHA256")); + queryParamMap.insert(std::make_pair("SignatureVersion", "2")); + std::string timestamp = UtilTime::getISOTimestamp(now, "%FT%T"); + queryParamMap.insert(std::make_pair("Timestamp", Url::urlEncode(timestamp))); std::string signature; this->createSignature(signature, queryString, methodString, this->hostRest, path, queryParamMap, credential); if (!queryString.empty()) { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_derivatives_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_derivatives_base.h index f139224b..ef411a99 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_derivatives_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_huobi_derivatives_base.h @@ -256,9 +256,9 @@ class ExecutionManagementServiceHuobiDerivativesBase : public ExecutionManagemen auto& allocator = document.GetAllocator(); document.AddMember("op", rj::Value("sub").Move(), allocator); std::string topic; - if (fieldSet.find(CCAPI_EM_ORDER_UPDATE) != fieldSet.end()) { + if (field == CCAPI_EM_ORDER_UPDATE) { topic = this->orderDataTopic + "." + instrument; - } else if (fieldSet.find(CCAPI_EM_PRIVATE_TRADE) != fieldSet.end()) { + } else if (field == CCAPI_EM_PRIVATE_TRADE) { topic = this->matchOrderDataTopic + "." + instrument; } document.AddMember("topic", rj::Value(topic.c_str(), allocator).Move(), allocator); @@ -335,6 +335,12 @@ class ExecutionManagementServiceHuobiDerivativesBase : public ExecutionManagemen std::to_string(std::stod(it1->value.GetString()) * std::stod(it2->value.GetString()))); } } + for (const auto& x : document["trade"].GetArray()) { + info.insert(CCAPI_TRADE_ID, std::string(x["trade_id"].GetString())); + info.insert(CCAPI_EM_ORDER_LAST_EXECUTED_PRICE, x["trade_price"].GetString()); + info.insert(CCAPI_EM_ORDER_LAST_EXECUTED_SIZE, x["trade_volume"].GetString()); + info.insert(CCAPI_IS_MAKER, std::string(x["role"].GetString()) == "maker" ? "1" : "0"); + } std::vector elementList; elementList.emplace_back(std::move(info)); message.setElementList(elementList); diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin.h b/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin.h index d76adb7c..87e34935 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin.h @@ -32,11 +32,13 @@ class ExecutionManagementServiceKucoin : public ExecutionManagementServiceKucoin this->createOrderTarget = "/api/v1/orders"; this->cancelOrderTarget = "/api/v1/orders/"; this->getOrderTarget = "/api/v1/orders/"; + this->getOrderByClientOrderIdTarget = "/api/v1/order/client-order/"; this->getOpenOrdersTarget = "/api/v1/orders"; this->cancelOpenOrdersTarget = "/api/v1/orders"; this->getAccountsTarget = "/api/v1/accounts"; this->getAccountBalancesTarget = "/api/v1/accounts/"; this->topicTradeOrders = "/spotMarket/tradeOrders"; + this->createOrderMarginTarget = "/api/v1/margin/order"; } virtual ~ExecutionManagementServiceKucoin() {} #ifndef CCAPI_EXPOSE_INTERNAL diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin_base.h index 4bcc55e3..0ea6c905 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin_base.h @@ -166,7 +166,9 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { case Request::Operation::CREATE_ORDER: { req.method(http::verb::post); const std::map param = request.getFirstParamWithDefault(); - req.target(this->createOrderTarget); + req.target(request.getMarginType() == CCAPI_EM_MARGIN_TYPE_CROSS_MARGIN || request.getMarginType() == CCAPI_EM_MARGIN_TYPE_ISOLATED_MARGIN + ? this->createOrderMarginTarget + : this->createOrderTarget); rj::Document document; document.SetObject(); rj::Document::AllocatorType& allocator = document.GetAllocator(); @@ -196,10 +198,10 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { const std::map param = request.getFirstParamWithDefault(); bool useOrderId = param.find(CCAPI_EM_ORDER_ID) != param.end(); std::string id = useOrderId ? param.at(CCAPI_EM_ORDER_ID) - : param.find(CCAPI_EM_CLIENT_ORDER_ID) != param.end() ? "client-order/" + param.at(CCAPI_EM_CLIENT_ORDER_ID) + : param.find(CCAPI_EM_CLIENT_ORDER_ID) != param.end() ? param.at(CCAPI_EM_CLIENT_ORDER_ID) : ""; auto target = - useOrderId ? std::regex_replace(this->getOrderTarget, std::regex(""), id) : std::regex_replace("/api/v1/order/", std::regex(""), id); + std::regex_replace(useOrderId ? this->getOrderTarget : this->getOrderByClientOrderIdTarget, std::regex(""), Url::urlEncode(id)); req.target(target); this->signRequest(req, "", credential); } break; @@ -207,6 +209,10 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { req.method(http::verb::get); auto target = this->getOpenOrdersTarget; target += "?status=active"; + target += std::string("&tradeType=") + + (request.getMarginType() == CCAPI_EM_MARGIN_TYPE_CROSS_MARGIN ? "MARGIN_TRADE" + : request.getMarginType() == CCAPI_EM_MARGIN_TYPE_ISOLATED_MARGIN ? "MARGIN_ISOLATED_TRADE" + : "TRADE"); if (!symbolId.empty()) { target += "&symbol="; target += symbolId; @@ -217,8 +223,12 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { case Request::Operation::CANCEL_OPEN_ORDERS: { req.method(http::verb::delete_); auto target = this->cancelOpenOrdersTarget; + target += std::string("?tradeType=") + + (request.getMarginType() == CCAPI_EM_MARGIN_TYPE_CROSS_MARGIN ? "MARGIN_TRADE" + : request.getMarginType() == CCAPI_EM_MARGIN_TYPE_ISOLATED_MARGIN ? "MARGIN_ISOLATED_TRADE" + : "TRADE"); if (!symbolId.empty()) { - target += "?symbol="; + target += "&symbol="; target += symbolId; } req.target(target); @@ -280,6 +290,8 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { {CCAPI_EM_ORDER_SIDE, std::make_pair("side", JsonDataType::STRING)}, {CCAPI_EM_ORDER_QUANTITY, std::make_pair("size", JsonDataType::STRING)}, {CCAPI_EM_ORDER_LIMIT_PRICE, std::make_pair("price", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, std::make_pair("dealSize", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::make_pair("dealFunds", JsonDataType::STRING)}, {CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("symbol", JsonDataType::STRING)}}; const rj::Value& data = document["data"]; if (operation == Request::Operation::CANCEL_ORDER || operation == Request::Operation::CANCEL_OPEN_ORDERS) { @@ -450,6 +462,8 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { std::string apiPassphraseName; bool isDerivatives{}; std::string topicTradeOrders; + std::string createOrderMarginTarget; + std::string getOrderByClientOrderIdTarget; }; } /* namespace ccapi */ #endif diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin_futures.h b/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin_futures.h index 6d1bb4b5..5f9bde58 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin_futures.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_kucoin_futures.h @@ -32,6 +32,7 @@ class ExecutionManagementServiceKucoinFutures : public ExecutionManagementServic this->createOrderTarget = "/api/v1/orders"; this->cancelOrderTarget = "/api/v1/orders/"; this->getOrderTarget = "/api/v1/orders/"; + this->getOrderByClientOrderIdTarget = "/api/v1/orders/byClientOid?clientOid="; this->getOpenOrdersTarget = "/api/v1/orders"; this->cancelOpenOrdersTarget = "/api/v1/orders"; this->getAccountBalancesTarget = "/api/v1/account-overview"; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h b/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h index 54dc4f28..8e33a9ac 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h @@ -81,23 +81,6 @@ class MarketDataServiceHuobi : public MarketDataServiceHuobiBase { MarketDataServiceHuobiBase::convertRequestForRest(req, request, now, symbolId, credential); } } - void extractInstrumentInfo(Element& element, const rj::Value& x) { - element.insert(CCAPI_INSTRUMENT, x["symbol"].GetString()); - element.insert(CCAPI_BASE_ASSET, x["base-currency"].GetString()); - element.insert(CCAPI_QUOTE_ASSET, x["quote-currency"].GetString()); - int pricePrecision = std::stoi(x["price-precision"].GetString()); - if (pricePrecision > 0) { - element.insert(CCAPI_ORDER_PRICE_INCREMENT, "0." + std::string(pricePrecision - 1, '0') + "1"); - } else { - element.insert(CCAPI_ORDER_PRICE_INCREMENT, "1"); - } - int amountPrecision = std::stoi(x["amount-precision"].GetString()); - if (amountPrecision > 0) { - element.insert(CCAPI_ORDER_QUANTITY_INCREMENT, "0." + std::string(amountPrecision - 1, '0') + "1"); - } else { - element.insert(CCAPI_ORDER_QUANTITY_INCREMENT, "1"); - } - } void convertTextMessageToMarketDataMessage(const Request& request, const std::string& textMessage, const TimePoint& timeReceived, Event& event, std::vector& marketDataMessageList) override { switch (request.getOperation()) { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_huobi_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_huobi_base.h index 59184e3f..b57417d6 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_huobi_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_huobi_base.h @@ -327,6 +327,7 @@ class MarketDataServiceHuobiBase : public MarketDataService { } } void extractInstrumentInfo(Element& element, const rj::Value& x) { + element.insert(CCAPI_INSTRUMENT, x["symbol"].GetString()); element.insert(CCAPI_BASE_ASSET, x["base-currency"].GetString()); element.insert(CCAPI_QUOTE_ASSET, x["quote-currency"].GetString()); int pricePrecision = std::stoi(x["price-precision"].GetString()); diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_huobi_derivatives_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_huobi_derivatives_base.h index e3723dcf..b6d5224b 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_huobi_derivatives_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_huobi_derivatives_base.h @@ -51,7 +51,7 @@ class MarketDataServiceHuobiDerivativesBase : public MarketDataServiceHuobiBase void extractInstrumentInfo(Element& element, const rj::Value& x) { element.insert(CCAPI_INSTRUMENT, x["symbol"].GetString()); element.insert(CCAPI_ORDER_PRICE_INCREMENT, UtilString::normalizeDecimalString(x["price_tick"].GetString())); - element.insert(CCAPI_ORDER_QUANTITY_INCREMENT, UtilString::normalizeDecimalString(x["contract_size"].GetString())); + element.insert(CCAPI_CONTRACT_SIZE, UtilString::normalizeDecimalString(x["contract_size"].GetString())); } void convertTextMessageToMarketDataMessage(const Request& request, const std::string& textMessage, const TimePoint& timeReceived, Event& event, std::vector& marketDataMessageList) override { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin.h b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin.h index 0fdde550..731118c1 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin.h @@ -57,6 +57,7 @@ class MarketDataServiceKucoin : public MarketDataServiceKucoinBase { element.insert(CCAPI_ORDER_PRICE_INCREMENT, x["priceIncrement"].GetString()); element.insert(CCAPI_ORDER_QUANTITY_INCREMENT, x["baseIncrement"].GetString()); element.insert(CCAPI_ORDER_QUANTITY_MIN, x["baseMinSize"].GetString()); + element.insert(CCAPI_ORDER_PRICE_TIMES_QUANTITY_MIN, x["quoteMinSize"].GetString()); } }; } /* namespace ccapi */ diff --git a/test/test_unit/src/execution_management/huobi/test.cpp b/test/test_unit/src/execution_management/huobi/test.cpp index 01e56a7b..4aa3adf5 100644 --- a/test/test_unit/src/execution_management/huobi/test.cpp +++ b/test/test_unit/src/execution_management/huobi/test.cpp @@ -215,9 +215,9 @@ TEST_F(ExecutionManagementServiceHuobiTest, convertTextMessageToMessageRestGetOr "price": "100.1000000000", "created-at": 1494901162595, "type": "buy-limit", - "filled-amount": "10.1000000000", - "filled-cash-amount": "1011.0100000000", - "filled-fees": "0.0202000000", + "field-amount": "10.1000000000", + "field-cash-amount": "1011.0100000000", + "field-fees": "0.0202000000", "finished-at": 1494901400468, "user-id": 1000, "source": "api",