From 61a0c7318edcaecd097188a11d340e13985f2b3d Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Fri, 29 Sep 2023 09:45:56 -0700 Subject: [PATCH 1/5] feat: add draft for rest query for trades, candlesticks, and market depth - binance --- README.md | 6 +- include/ccapi_cpp/ccapi_macro.h | 12 ++ include/ccapi_cpp/ccapi_message.h | 20 +++ include/ccapi_cpp/ccapi_request.h | 20 +++ .../service/ccapi_market_data_service.h | 131 ++++++++++++++++-- .../ccapi_market_data_service_binance.h | 5 + .../ccapi_market_data_service_binance_base.h | 112 ++++++++++++++- ...market_data_service_binance_coin_futures.h | 5 + ...et_data_service_binance_derivatives_base.h | 28 +++- .../ccapi_market_data_service_binance_us.h | 5 + ...market_data_service_binance_usds_futures.h | 5 + .../ccapi_market_data_service_bitfinex.h | 2 +- ...pi_market_data_service_bybit_derivatives.h | 2 +- .../ccapi_market_data_service_cryptocom.h | 2 +- .../ccapi_market_data_service_deribit.h | 2 +- .../ccapi_market_data_service_gateio_base.h | 2 +- .../service/ccapi_market_data_service_huobi.h | 2 +- .../ccapi_market_data_service_kraken.h | 2 +- include/ccapi_cpp/service/ccapi_service.h | 7 +- 19 files changed, 342 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 0a217111..5f0b4d88 100644 --- a/README.md +++ b/README.md @@ -279,8 +279,8 @@ Received an event: ] Bye ``` -* Request operation types: `GET_INSTRUMENT`, `GET_INSTRUMENTS`, `GET_RECENT_TRADES`, `GET_RECENT_AGG_TRADES`(only applicable to binance family: https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list). -* Request parameter names: `LIMIT`, `INSTRUMENT_TYPE`. Instead of these convenient names you can also choose to use arbitrary parameter names and they will be passed to the exchange's native API. See [this example](example/src/market_data_advanced_request/main.cpp). +* Request operation types: `GET_INSTRUMENT`, `GET_INSTRUMENTS`, `GET_RECENT_TRADES`, `GET_HISTORICAL_TRADES`, `GET_RECENT_CANDLESTICKS`, `GET_HISTORICAL_CANDLESTICKS`, `GET_RECENT_AGG_TRADES`, `GET_HISTORICAL_AGG_TRADES`(only applicable to binance family: https://binance-docs.github.io/apidocs/spot/en/#compressed-aggregate-trades-list), ``. +* Request parameter names: `LIMIT`, `INSTRUMENT_TYPE`, `CANDLESTICK_INTERVAL_SECONDS`, `START_TIME_SECONDS`, `END_TIME_SECONDS`, `START_TRADE_ID`, `END_TRADE_ID`, `START_AGG_TRADE_ID`, `END_AGG_TRADE_ID`. Instead of these convenient names you can also choose to use arbitrary parameter names and they will be passed to the exchange's native API. See [this example](example/src/market_data_advanced_request/main.cpp). * Message's `time` represents the exchange's reported timestamp. Its `timeReceived` represents the library's receiving timestamp. `time` can be retrieved by `getTime` method and `timeReceived` can be retrieved by `getTimeReceived` method. (For non-C++, please use `getTimeUnix` and `getTimeReceivedUnix` methods or `getTimeISO` and `getTimeReceivedISO` methods). **Objective 2:** @@ -338,7 +338,7 @@ Best bid and ask at 2020-07-27T23:56:51.884855000Z are: Best bid and ask at 2020-07-27T23:56:51.935993000Z are: ... ``` -* Subscription fields: `MARKET_DEPTH`, `TRADE`, `AGG_TRADE`(only applicable to binance family: https://binance-docs.github.io/apidocs/spot/en/#aggregate-trade-streams). +* Subscription fields: `MARKET_DEPTH`, `TRADE`, `CANDLESTICK`, `AGG_TRADE`(only applicable to binance family: https://binance-docs.github.io/apidocs/spot/en/#aggregate-trade-streams). ### Advanced Market Data diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index 81bdc7fd..3d7b3fff 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -229,6 +229,18 @@ #ifndef CCAPI_LIMIT #define CCAPI_LIMIT "LIMIT" #endif +#ifndef CCAPI_START_TRADE_ID +#define CCAPI_START_TRADE_ID "START_TRADE_ID" +#endif +#ifndef CCAPI_START_AGG_TRADE_ID +#define CCAPI_START_AGG_TRADE_ID "START_AGG_TRADE_ID" +#endif +#ifndef CCAPI_START_TIME_SECONDS +#define CCAPI_START_TIME_SECONDS "START_TIME_SECONDS" +#endif +#ifndef CCAPI_END_TIME_SECONDS +#define CCAPI_END_TIME_SECONDS "END_TIME_SECONDS" +#endif #ifndef CCAPI_BASE_ASSET #define CCAPI_BASE_ASSET "BASE_ASSET" #endif diff --git a/include/ccapi_cpp/ccapi_message.h b/include/ccapi_cpp/ccapi_message.h index eab02372..eb737a80 100644 --- a/include/ccapi_cpp/ccapi_message.h +++ b/include/ccapi_cpp/ccapi_message.h @@ -62,7 +62,12 @@ class Message CCAPI_FINAL { GET_ACCOUNT_BALANCES, GET_ACCOUNT_POSITIONS, GET_RECENT_TRADES, + GET_HISTORICAL_TRADES, GET_RECENT_AGG_TRADES, + GET_HISTORICAL_AGG_TRADES, + GET_RECENT_CANDLESTICKS, + GET_HISTORICAL_CANDLESTICKS, + GET_MARKET_DEPTH, GET_INSTRUMENT, GET_INSTRUMENTS, RESPONSE_ERROR, @@ -147,9 +152,24 @@ class Message CCAPI_FINAL { case Type::GET_RECENT_TRADES: output = "GET_RECENT_TRADES"; break; + case Type::GET_HISTORICAL_TRADES: + output = "GET_HISTORICAL_TRADES"; + break; case Type::GET_RECENT_AGG_TRADES: output = "GET_RECENT_AGG_TRADES"; break; + case Type::GET_HISTORICAL_AGG_TRADES: + output = "GET_HISTORICAL_AGG_TRADES"; + break; + case Type::GET_RECENT_CANDLESTICKS: + output = "GET_RECENT_CANDLESTICKS"; + break; + case Type::GET_HISTORICAL_CANDLESTICKS: + output = "GET_HISTORICAL_CANDLESTICKS"; + break; + case Type::GET_MARKET_DEPTH: + output = "GET_MARKET_DEPTH"; + break; case Type::GET_INSTRUMENT: output = "GET_INSTRUMENT"; break; diff --git a/include/ccapi_cpp/ccapi_request.h b/include/ccapi_cpp/ccapi_request.h index 4b02d4c4..28436597 100644 --- a/include/ccapi_cpp/ccapi_request.h +++ b/include/ccapi_cpp/ccapi_request.h @@ -31,7 +31,12 @@ class Request CCAPI_FINAL { GENERIC_PRIVATE_REQUEST = CCAPI_REQUEST_OPERATION_TYPE_GENERIC_PRIVATE_REQUEST, FIX = CCAPI_REQUEST_OPERATION_TYPE_FIX, GET_RECENT_TRADES = CCAPI_REQUEST_OPERATION_TYPE_MARKET_DATA, + GET_HISTORICAL_TRADES, GET_RECENT_AGG_TRADES, + GET_HISTORICAL_AGG_TRADES, + GET_RECENT_CANDLESTICKS, + GET_HISTORICAL_CANDLESTICKS, + GET_MARKET_DEPTH, GET_INSTRUMENT, GET_INSTRUMENTS, CREATE_ORDER = CCAPI_REQUEST_OPERATION_TYPE_EXECUTION_MANAGEMENT_ORDER, @@ -61,9 +66,24 @@ class Request CCAPI_FINAL { case Operation::GET_RECENT_TRADES: output = "GET_RECENT_TRADES"; break; + case Operation::GET_HISTORICAL_TRADES: + output = "GET_HISTORICAL_TRADES"; + break; case Operation::GET_RECENT_AGG_TRADES: output = "GET_RECENT_AGG_TRADES"; break; + case Operation::GET_HISTORICAL_AGG_TRADES: + output = "GET_HISTORICAL_AGG_TRADES"; + break; + case Operation::GET_RECENT_CANDLESTICKS: + output = "GET_RECENT_CANDLESTICKS"; + break; + case Operation::GET_HISTORICAL_CANDLESTICKS: + output = "GET_HISTORICAL_CANDLESTICKS"; + break; + case Operation::GET_MARKET_DEPTH: + output = "GET_MARKET_DEPTH"; + break; case Operation::GET_INSTRUMENT: output = "GET_INSTRUMENT"; break; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service.h b/include/ccapi_cpp/service/ccapi_market_data_service.h index 7c474d8b..06228ffb 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service.h @@ -22,7 +22,12 @@ class MarketDataService : public Service { CCAPI_LOGGER_FUNCTION_ENTER; this->requestOperationToMessageTypeMap = { {Request::Operation::GET_RECENT_TRADES, Message::Type::GET_RECENT_TRADES}, + {Request::Operation::GET_HISTORICAL_TRADES, Message::Type::GET_HISTORICAL_TRADES}, {Request::Operation::GET_RECENT_AGG_TRADES, Message::Type::GET_RECENT_AGG_TRADES}, + {Request::Operation::GET_HISTORICAL_AGG_TRADES, Message::Type::GET_HISTORICAL_AGG_TRADES}, + {Request::Operation::GET_RECENT_CANDLESTICKS, Message::Type::GET_RECENT_CANDLESTICKS}, + {Request::Operation::GET_HISTORICAL_CANDLESTICKS, Message::Type::GET_HISTORICAL_CANDLESTICKS}, + {Request::Operation::GET_MARKET_DEPTH, Message::Type::GET_MARKET_DEPTH}, {Request::Operation::GET_INSTRUMENT, Message::Type::GET_INSTRUMENT}, {Request::Operation::GET_INSTRUMENTS, Message::Type::GET_INSTRUMENTS}, }; @@ -778,6 +783,45 @@ class MarketDataService : public Service { } CCAPI_LOGGER_FUNCTION_EXIT; } + void updateElementListWithOrderBookSnapshot(const std::string& field, int maxMarketDepth, const std::map& snapshotBid, + const std::map& snapshotAsk, std::vector& elementList) { + CCAPI_LOGGER_FUNCTION_ENTER; + if (field == CCAPI_MARKET_DEPTH) { + int bidIndex = 0; + for (auto iter = snapshotBid.rbegin(); iter != snapshotBid.rend(); iter++) { + if (bidIndex < maxMarketDepth) { + Element element; + element.insert(CCAPI_BEST_BID_N_PRICE, iter->first.toString()); + element.insert(CCAPI_BEST_BID_N_SIZE, iter->second); + elementList.emplace_back(std::move(element)); + } + ++bidIndex; + } + if (snapshotBid.empty()) { + Element element; + element.insert(CCAPI_BEST_BID_N_PRICE, CCAPI_BEST_BID_N_PRICE_EMPTY); + element.insert(CCAPI_BEST_BID_N_SIZE, CCAPI_BEST_BID_N_SIZE_EMPTY); + elementList.emplace_back(std::move(element)); + } + int askIndex = 0; + for (auto iter = snapshotAsk.begin(); iter != snapshotAsk.end(); iter++) { + if (askIndex < maxMarketDepth) { + Element element; + element.insert(CCAPI_BEST_ASK_N_PRICE, iter->first.toString()); + element.insert(CCAPI_BEST_ASK_N_SIZE, iter->second); + elementList.emplace_back(std::move(element)); + } + ++askIndex; + } + if (snapshotAsk.empty()) { + Element element; + element.insert(CCAPI_BEST_ASK_N_PRICE, CCAPI_BEST_ASK_N_PRICE_EMPTY); + element.insert(CCAPI_BEST_ASK_N_SIZE, CCAPI_BEST_ASK_N_SIZE_EMPTY); + elementList.emplace_back(std::move(element)); + } + } + CCAPI_LOGGER_FUNCTION_EXIT; + } std::map calculateMarketDepthUpdate(bool isBid, const std::map& c1, const std::map& c2, int maxMarketDepth) { if (c1.empty()) { @@ -948,8 +992,8 @@ class MarketDataService : public Service { Element element; std::string k1(CCAPI_LAST_PRICE); std::string k2(CCAPI_LAST_SIZE); - element.emplace(k1, y.at(MarketDataMessage::DataFieldType::PRICE)); - element.emplace(k2, y.at(MarketDataMessage::DataFieldType::SIZE)); + element.emplace(k1, price); + element.emplace(k2, size); { auto it = y.find(MarketDataMessage::DataFieldType::TRADE_ID); if (it != y.end()) { @@ -1307,12 +1351,9 @@ class MarketDataService : public Service { const TimePoint& tp, const TimePoint& timeReceived, MarketDataMessage::TypeForData& input, const std::string& field, const std::map& optionMap, const std::vector& correlationIdList, bool isSolicited) { - CCAPI_LOGGER_TRACE("input = " + MarketDataMessage::dataToString(input)); - CCAPI_LOGGER_TRACE("optionMap = " + toString(optionMap)); std::vector messageList; std::vector elementList; this->updateElementListWithExchangeProvidedCandlestick(field, input, elementList); - CCAPI_LOGGER_TRACE("elementList = " + toString(elementList)); if (!elementList.empty()) { Message message; message.setTimeReceived(timeReceived); @@ -1327,6 +1368,24 @@ class MarketDataService : public Service { event.addMessages(messageList); } } + void processExchangeProvidedCandlestick(Event& event, const TimePoint& tp, const TimePoint& timeReceived, MarketDataMessage::TypeForData& input, + const std::vector& correlationIdList, Message::Type messageType) { + std::vector messageList; + std::vector elementList; + this->updateElementListWithExchangeProvidedCandlestick(CCAPI_CANDLESTICK, input, elementList); + if (!elementList.empty()) { + Message message; + message.setTimeReceived(timeReceived); + message.setType(Message::Type::MARKET_DATA_EVENTS_CANDLESTICK); + message.setTime(tp); + message.setElementList(elementList); + message.setCorrelationIdList(correlationIdList); + messageList.emplace_back(std::move(message)); + } + if (!messageList.empty()) { + event.addMessages(messageList); + } + } void updateCalculatedCandlestick(const WsConnection& wsConnection, const std::string& channelId, const std::string& symbolId, const std::string& field, const MarketDataMessage::TypeForData& input) { if (field == CCAPI_TRADE || field == CCAPI_AGG_TRADE) { @@ -1405,7 +1464,7 @@ class MarketDataService : public Service { } return true; } - int calculateMarketDepthSubscribedToExchange(int depthWanted, std::vector availableMarketDepth) { + int calculateMarketDepthAllowedByExchange(int depthWanted, std::vector availableMarketDepth) { int i = ceilSearch(availableMarketDepth, 0, availableMarketDepth.size(), depthWanted); if (i < 0) { i = availableMarketDepth.size() - 1; @@ -1552,13 +1611,24 @@ class MarketDataService : public Service { for (auto& marketDataMessage : marketDataMessageList) { if (marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_MARKET_DEPTH || marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_TRADE || - marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_AGG_TRADE) { + marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_AGG_TRADE || + marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_CANDLESTICK) { const std::vector& correlationIdList = {request.getCorrelationId()}; CCAPI_LOGGER_TRACE("correlationIdList = " + toString(correlationIdList)); - if (marketDataMessage.data.find(MarketDataMessage::DataType::TRADE) != marketDataMessage.data.end() || - marketDataMessage.data.find(MarketDataMessage::DataType::AGG_TRADE) != marketDataMessage.data.end()) { + if (marketDataMessage.data.find(MarketDataMessage::DataType::BID) != marketDataMessage.data.end() || + marketDataMessage.data.find(MarketDataMessage::DataType::ASK) != marketDataMessage.data.end()) { + auto messageType = this->requestOperationToMessageTypeMap.at(request.getOperation()); + const auto& param = request.getFirstParamWithDefault(); + const auto& maxMarketDepthStr = mapGetWithDefault(param, std::string(CCAPI_MARKET_DEPTH_MAX)); + int maxMarketDepth = maxMarketDepthStr.empty() ? INT_MAX : std::stoi(maxMarketDepthStr); + this->processOrderBookSnapshot(event, marketDataMessage.tp, timeReceived, marketDataMessage.data, correlationIdList, messageType, maxMarketDepth); + } else if (marketDataMessage.data.find(MarketDataMessage::DataType::TRADE) != marketDataMessage.data.end() || + marketDataMessage.data.find(MarketDataMessage::DataType::AGG_TRADE) != marketDataMessage.data.end()) { auto messageType = this->requestOperationToMessageTypeMap.at(request.getOperation()); this->processTrade(event, marketDataMessage.tp, timeReceived, marketDataMessage.data, correlationIdList, messageType); + } else if (marketDataMessage.data.find(MarketDataMessage::DataType::CANDLESTICK) != marketDataMessage.data.end()) { + auto messageType = this->requestOperationToMessageTypeMap.at(request.getOperation()); + this->processExchangeProvidedCandlestick(event, marketDataMessage.tp, timeReceived, marketDataMessage.data, correlationIdList, messageType); } } else { CCAPI_LOGGER_WARN("market data event type is unknown!"); @@ -1581,6 +1651,45 @@ class MarketDataService : public Service { messageList.emplace_back(std::move(message)); event.addMessages(messageList); } + void processOrderBookSnapshot(Event& event, const TimePoint& tp, const TimePoint& timeReceived, MarketDataMessage::TypeForData& input, + const std::vector& correlationIdList, Message::Type messageType, int maxMarketDepth) { + std::vector messageList; + std::vector elementList; + std::map snapshotBid, snapshotAsk; + for (auto& x : input) { + auto& type = x.first; + auto& detail = x.second; + if (type == MarketDataMessage::DataType::BID) { + for (auto& y : detail) { + auto& price = y.at(MarketDataMessage::DataFieldType::PRICE); + auto& size = y.at(MarketDataMessage::DataFieldType::SIZE); + Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum); + snapshotBid.emplace(std::move(decimalPrice), std::move(size)); + } + CCAPI_LOGGER_TRACE("lastNToString(snapshotBid, " + toString(maxMarketDepth) + ") = " + lastNToString(snapshotBid, maxMarketDepth)); + } else if (type == MarketDataMessage::DataType::ASK) { + for (auto& y : detail) { + auto& price = y.at(MarketDataMessage::DataFieldType::PRICE); + auto& size = y.at(MarketDataMessage::DataFieldType::SIZE); + Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum); + snapshotAsk.emplace(std::move(decimalPrice), std::move(size)); + } + CCAPI_LOGGER_TRACE("firstNToString(snapshotAsk, " + toString(maxMarketDepth) + ") = " + firstNToString(snapshotAsk, maxMarketDepth)); + } else { + CCAPI_LOGGER_WARN("extra type " + MarketDataMessage::dataTypeToString(type)); + } + } + this->updateElementListWithOrderBookSnapshot(CCAPI_MARKET_DEPTH, maxMarketDepth, snapshotBid, snapshotAsk, elementList); + CCAPI_LOGGER_TRACE("elementList = " + toString(elementList)); + Message message; + message.setTimeReceived(timeReceived); + message.setType(messageType); + message.setTime(tp); + message.setElementList(elementList); + message.setCorrelationIdList(correlationIdList); + messageList.emplace_back(std::move(message)); + event.addMessages(messageList); + } void convertRequestForRestGenericPublicRequest(http::request& req, const Request& request, const TimePoint& now, const std::string& symbolId, const std::map& credential) { const std::map param = request.getFirstParamWithDefault(); @@ -1879,6 +1988,10 @@ class MarketDataService : public Service { std::map>> lowByConnectionIdChannelIdSymbolIdMap; std::map>> closeByConnectionIdChannelIdSymbolIdMap; std::string getRecentTradesTarget; + std::string getHistoricalTradesTarget; + std::string getRecentCandlesticksTarget; + std::string getHistoricalCandlesticksTarget; + std::string getMarketDepthTarget; std::string getInstrumentTarget; std::string getInstrumentsTarget; std::map exchangeJsonPayloadIdByConnectionIdMap; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance.h index 06df7424..79afc94a 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance.h @@ -30,7 +30,12 @@ class MarketDataServiceBinance : public MarketDataServiceBinanceBase { this->apiKeyName = CCAPI_BINANCE_API_KEY; this->setupCredential({this->apiKeyName}); this->getRecentTradesTarget = "/api/v3/trades"; + this->getHistoricalTradesTarget = "/api/v3/historicalTrades"; this->getRecentAggTradesTarget = "/api/v3/aggTrades"; + this->getHistoricalAggTradesTarget = "/api/v3/aggTrades"; + this->getRecentCandlesticksTarget = "/api/v3/klines"; + this->getHistoricalCandlesticksTarget = "/api/v3/klines"; + this->getMarketDepthTarget = "/api/v3/depth"; this->getInstrumentTarget = "/api/v3/exchangeInfo"; this->getInstrumentsTarget = "/api/v3/exchangeInfo"; } diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_base.h index 088d25ed..9e429174 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_base.h @@ -42,7 +42,7 @@ class MarketDataServiceBinanceBase : public MarketDataService { channelId = CCAPI_WEBSOCKET_BINANCE_BASE_CHANNEL_BOOK_TICKER; } else { int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, std::vector({5, 10, 20})); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({5, 10, 20})); std::string updateSpeed; if (conflateIntervalMilliSeconds < 1000) { updateSpeed = "100ms"; @@ -269,6 +269,10 @@ class MarketDataServiceBinanceBase : public MarketDataService { req.set("X-MBX-APIKEY", apiKey); } } + std::string convertParamStartTimeEndTime(const std::string& input) { return std::to_string(std::stoll(input) * 1000); } + std::string convertParamInterval(const std::string& input) { + return this->convertCandlestickIntervalSecondsToInterval(std::stoi(input), "s", "m", "h", "d", "w"); + } void convertRequestForRest(http::request& req, const Request& request, const TimePoint& now, const std::string& symbolId, const std::map& credential) override { this->prepareReq(req, credential); @@ -288,14 +292,75 @@ class MarketDataServiceBinanceBase : public MarketDataService { this->appendSymbolId(queryString, symbolId, "symbol"); req.target(target + "?" + queryString); } break; - case Request::Operation::GET_RECENT_AGG_TRADES: { + case Request::Operation::GET_HISTORICAL_TRADES: { req.method(http::verb::get); - auto target = this->getRecentAggTradesTarget; + auto target = this->getHistoricalTradesTarget; std::string queryString; const std::map param = request.getFirstParamWithDefault(); this->appendParam(queryString, param, { {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TRADE_ID, "fromId"}, + }); + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; + case Request::Operation::GET_RECENT_AGG_TRADES: + case Request::Operation::GET_HISTORICAL_AGG_TRADES: { + req.method(http::verb::get); + auto target = this->getRecentAggTradesTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam( + queryString, param, + { + {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TIME_SECONDS, "startTime"}, + {CCAPI_END_TIME_SECONDS, "endTime"}, + {CCAPI_START_AGG_TRADE_ID, "fromId"}, + }, + { + {CCAPI_START_TIME_SECONDS, + [that = shared_from_base()](const std::string& input) { return that->convertParamStartTimeEndTime(input); }}, + {CCAPI_END_TIME_SECONDS, + [that = shared_from_base()](const std::string& input) { return that->convertParamStartTimeEndTime(input); }}, + }); + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + req.method(http::verb::get); + auto target = this->getRecentCandlesticksTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam( + queryString, param, + { + {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TIME_SECONDS, "startTime"}, + {CCAPI_END_TIME_SECONDS, "endTime"}, + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, "interval"}, + }, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, + [that = shared_from_base()](const std::string& input) { return that->convertParamInterval(input); }}, + {CCAPI_START_TIME_SECONDS, + [that = shared_from_base()](const std::string& input) { return that->convertParamStartTimeEndTime(input); }}, + {CCAPI_END_TIME_SECONDS, + [that = shared_from_base()](const std::string& input) { return that->convertParamStartTimeEndTime(input); }}, + }); + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; + case Request::Operation::GET_MARKET_DEPTH: { + req.method(http::verb::get); + auto target = this->getMarketDepthTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_MARKET_DEPTH_MAX, "limit"}, }); this->appendSymbolId(queryString, symbolId, "symbol"); req.target(target + "?" + queryString); @@ -337,7 +402,8 @@ class MarketDataServiceBinanceBase : public MarketDataService { rj::Document document; document.Parse(textMessage.c_str()); switch (request.getOperation()) { - case Request::Operation::GET_RECENT_TRADES: { + case Request::Operation::GET_RECENT_TRADES: + case Request::Operation::GET_HISTORICAL_TRADES: { for (const auto& x : document.GetArray()) { MarketDataMessage marketDataMessage; marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_TRADE; @@ -351,7 +417,8 @@ class MarketDataServiceBinanceBase : public MarketDataService { marketDataMessageList.emplace_back(std::move(marketDataMessage)); } } break; - case Request::Operation::GET_RECENT_AGG_TRADES: { + case Request::Operation::GET_RECENT_AGG_TRADES: + case Request::Operation::GET_HISTORICAL_AGG_TRADES: { for (const auto& x : document.GetArray()) { MarketDataMessage marketDataMessage; marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_AGG_TRADE; @@ -365,6 +432,40 @@ class MarketDataServiceBinanceBase : public MarketDataService { marketDataMessageList.emplace_back(std::move(marketDataMessage)); } } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + for (const auto& x : document.GetArray()) { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_CANDLESTICK; + marketDataMessage.tp = UtilTime::makeTimePointFromMilliseconds(std::stoll(x[0].GetString())); + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::OPEN_PRICE, x[1].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::HIGH_PRICE, x[2].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::LOW_PRICE, x[3].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::CLOSE_PRICE, x[4].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::VOLUME, x[5].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::QUOTE_VOLUME, x[7].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::CANDLESTICK].emplace_back(std::move(dataPoint)); + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } + } break; + case Request::Operation::GET_MARKET_DEPTH: { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_MARKET_DEPTH; + for (const auto& x : document["bids"].GetArray()) { + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint)); + } + for (const auto& x : document["asks"].GetArray()) { + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint)); + } + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } break; case Request::Operation::GET_INSTRUMENT: { Message message; message.setTimeReceived(timeReceived); @@ -400,6 +501,7 @@ class MarketDataServiceBinanceBase : public MarketDataService { } bool isDerivatives{}; std::string getRecentAggTradesTarget; + std::string getHistoricalAggTradesTarget; }; } /* namespace ccapi */ #endif diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance_coin_futures.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_coin_futures.h index 037de23d..a63db71d 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_coin_futures.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_coin_futures.h @@ -30,7 +30,12 @@ class MarketDataServiceBinanceCoinFutures : public MarketDataServiceBinanceDeriv this->apiKeyName = CCAPI_BINANCE_COIN_FUTURES_API_KEY; this->setupCredential({this->apiKeyName}); this->getRecentTradesTarget = "/dapi/v1/trades"; + this->getHistoricalTradesTarget = "/dapi/v1/historicalTrades"; this->getRecentAggTradesTarget = "/dapi/v1/aggTrades"; + this->getHistoricalAggTradesTarget = "/dapi/v1/aggTrades"; + this->getRecentCandlesticksTarget = "/dapi/v1/klines"; + this->getHistoricalCandlesticksTarget = "/dapi/v1/klines"; + this->getMarketDepthTarget = "/dapi/v1/depth"; this->getInstrumentTarget = "/dapi/v1/exchangeInfo"; this->getInstrumentsTarget = "/dapi/v1/exchangeInfo"; } diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance_derivatives_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_derivatives_base.h index 26154a45..619fe5ae 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_derivatives_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_derivatives_base.h @@ -22,7 +22,7 @@ class MarketDataServiceBinanceDerivativesBase : public MarketDataServiceBinanceB auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, std::vector({1, 5, 10, 20})); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({1, 5, 10, 20})); if (marketDepthSubscribedToExchange == 1) { channelId = CCAPI_WEBSOCKET_BINANCE_BASE_CHANNEL_BOOK_TICKER; } else { @@ -60,6 +60,32 @@ class MarketDataServiceBinanceDerivativesBase : public MarketDataServiceBinanceB } } } + void convertRequestForRest(http::request& req, const Request& request, const TimePoint& now, const std::string& symbolId, + const std::map& credential) override { + this->prepareReq(req, credential); + switch (request.getOperation()) { + case Request::Operation::GET_MARKET_DEPTH: { + req.method(http::verb::get); + auto target = this->getMarketDepthTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_MARKET_DEPTH_MAX, "limit"}, + }, + { + {CCAPI_MARKET_DEPTH_MAX, + [that = shared_from_base()](const std::string& input) { + return std::to_string(that->calculateMarketDepthAllowedByExchange(std::stoi(input), {5, 10, 20, 50, 100, 500, 1000})); + }}, + }); + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; + default: + MarketDataServiceBinanceBase::convertRequestForRest(req, request, now, symbolId, credential); + } + } 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_binance_us.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_us.h index 6df7d40f..ce814272 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_us.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_us.h @@ -30,7 +30,12 @@ class MarketDataServiceBinanceUs : public MarketDataServiceBinanceBase { this->apiKeyName = CCAPI_BINANCE_US_API_KEY; this->setupCredential({this->apiKeyName}); this->getRecentTradesTarget = "/api/v3/trades"; + this->getHistoricalTradesTarget = "/api/v3/historicalTrades"; this->getRecentAggTradesTarget = "/api/v3/aggTrades"; + this->getHistoricalAggTradesTarget = "/api/v3/aggTrades"; + this->getRecentCandlesticksTarget = "/api/v3/klines"; + this->getHistoricalCandlesticksTarget = "/api/v3/klines"; + this->getMarketDepthTarget = "/api/v3/depth"; this->getInstrumentTarget = "/api/v3/exchangeInfo"; this->getInstrumentsTarget = "/api/v3/exchangeInfo"; } diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance_usds_futures.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_usds_futures.h index 697be308..d5dabf99 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_usds_futures.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_usds_futures.h @@ -30,7 +30,12 @@ class MarketDataServiceBinanceUsdsFutures : public MarketDataServiceBinanceDeriv this->apiKeyName = CCAPI_BINANCE_USDS_FUTURES_API_KEY; this->setupCredential({this->apiKeyName}); this->getRecentTradesTarget = "/fapi/v1/trades"; + this->getHistoricalTradesTarget = "/fapi/v1/historicalTrades"; this->getRecentAggTradesTarget = "/fapi/v1/aggTrades"; + this->getHistoricalAggTradesTarget = "/fapi/v1/aggTrades"; + this->getRecentCandlesticksTarget = "/fapi/v1/klines"; + this->getHistoricalCandlesticksTarget = "/fapi/v1/klines"; + this->getMarketDepthTarget = "/fapi/v1/depth"; this->getInstrumentTarget = "/fapi/v1/exchangeInfo"; this->getInstrumentsTarget = "/fapi/v1/exchangeInfo"; } diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h b/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h index c8e324c5..dc4e54cc 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h @@ -175,7 +175,7 @@ class MarketDataServiceBitfinex : public MarketDataService { auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, std::vector({1, 25, 100, 250})); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({1, 25, 100, 250})); channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); this->marketDepthSubscribedToExchangeByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = marketDepthSubscribedToExchange; } else if (field == CCAPI_CANDLESTICK) { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bybit_derivatives.h b/include/ccapi_cpp/service/ccapi_market_data_service_bybit_derivatives.h index 7c7d6079..13d4c41e 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bybit_derivatives.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bybit_derivatives.h @@ -63,7 +63,7 @@ class MarketDataServiceBybitDerivatives : public MarketDataServiceBybitBase { depths = {1, 50, 200}; } int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, depths); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, depths); channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); this->marketDepthSubscribedToExchangeByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = marketDepthSubscribedToExchange; } else if (field == CCAPI_CANDLESTICK) { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_cryptocom.h b/include/ccapi_cpp/service/ccapi_market_data_service_cryptocom.h index 74576811..10f9ccc7 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_cryptocom.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_cryptocom.h @@ -41,7 +41,7 @@ class MarketDataServiceCryptocom : public MarketDataService { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); if (field == CCAPI_MARKET_DEPTH) { int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, std::vector({10, 150})); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({10, 150})); channelId = CCAPI_WEBSOCKET_CRYPTOCOM_CHANNEL_BOOK; this->marketDepthSubscribedToExchangeByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = marketDepthSubscribedToExchange; } diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_deribit.h b/include/ccapi_cpp/service/ccapi_market_data_service_deribit.h index 53adea16..b46c098b 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_deribit.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_deribit.h @@ -98,7 +98,7 @@ class MarketDataServiceDeribit : public MarketDataService { channelId = CCAPI_WEBSOCKET_DERIBIT_CHANNEL_QUOTE; } else if (marketDepthRequested <= 20) { int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, std::vector({10, 20})); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({10, 20})); channelId = CCAPI_WEBSOCKET_DERIBIT_CHANNEL_BOOK; this->marketDepthSubscribedToExchangeByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = marketDepthSubscribedToExchange; } else { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_gateio_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_gateio_base.h index e7b8768f..b0e7c359 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_gateio_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_gateio_base.h @@ -38,7 +38,7 @@ class MarketDataServiceGateioBase : public MarketDataService { channelId = this->websocketChannelBookTicker; } else { int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, std::vector({5, 10, 20})); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({5, 10, 20})); channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); std::string updateSpeed; if (this->isDerivatives) { 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 d4a41c4b..772cc17d 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h @@ -48,7 +48,7 @@ class MarketDataServiceHuobi : public MarketDataServiceHuobiBase { CCAPI_LOGGER_TRACE(""); channelId = CCAPI_WEBSOCKET_HUOBI_CHANNEL_MARKET_BY_PRICE_REFRESH_UPDATE; int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, std::vector({5, 10, 20})); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({5, 10, 20})); channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); this->marketDepthSubscribedToExchangeByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = marketDepthSubscribedToExchange; } diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h b/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h index a0b0814b..b70cde87 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h @@ -55,7 +55,7 @@ class MarketDataServiceKraken : public MarketDataService { auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { int marketDepthSubscribedToExchange = 1; - marketDepthSubscribedToExchange = this->calculateMarketDepthSubscribedToExchange(marketDepthRequested, std::vector({10, 25, 100, 500, 1000})); + marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({10, 25, 100, 500, 1000})); channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); this->marketDepthSubscribedToExchangeByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = marketDepthSubscribedToExchange; } else if (field == CCAPI_CANDLESTICK) { diff --git a/include/ccapi_cpp/service/ccapi_service.h b/include/ccapi_cpp/service/ccapi_service.h index c64c95ec..ba5ccf23 100644 --- a/include/ccapi_cpp/service/ccapi_service.h +++ b/include/ccapi_cpp/service/ccapi_service.h @@ -814,14 +814,15 @@ class Service : public std::enable_shared_from_this { } } } - void appendParam(std::string& queryString, const std::map& param, - const std::map standardizationMap = {}) { + void appendParam(std::string& queryString, const std::map& param, const std::map standardizationMap = {}, + const std::map> conversionMap = {}) { int i = 0; for (const auto& kv : param) { std::string key = standardizationMap.find(kv.first) != standardizationMap.end() ? standardizationMap.at(kv.first) : kv.first; queryString += key; queryString += "="; - queryString += Url::urlEncode(kv.second); + std::string value = conversionMap.find(kv.first) != conversionMap.end() ? conversionMap.at(kv.first)(kv.second) : kv.second; + queryString += Url::urlEncode(value); queryString += "&"; ++i; } From cfb7c91337892f82ee8870fa39741a06ad82dd48 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Fri, 29 Sep 2023 11:46:39 -0700 Subject: [PATCH 2/5] feat: add draft for rest query for trades, candlesticks, and market depth - okx --- README.md | 5 +- include/ccapi_cpp/ccapi_macro.h | 3 + include/ccapi_cpp/ccapi_session.h | 14 +- include/ccapi_cpp/ccapi_session_options.h | 36 +++--- ...xecution_management_service_binance_base.h | 8 +- ...pi_execution_management_service_bitstamp.h | 4 +- ...capi_execution_management_service_kraken.h | 4 +- ...execution_management_service_kucoin_base.h | 16 +-- .../ccapi_execution_management_service_mexc.h | 8 +- include/ccapi_cpp/service/ccapi_fix_service.h | 22 ++-- .../service/ccapi_fix_service_coinbase.h | 2 +- .../service/ccapi_fix_service_gemini.h | 2 +- .../service/ccapi_market_data_service.h | 56 ++++---- .../ccapi_market_data_service_binance_base.h | 68 +++++----- ...et_data_service_binance_derivatives_base.h | 6 +- .../ccapi_market_data_service_bitfinex.h | 2 +- .../ccapi_market_data_service_bitget_base.h | 4 +- .../ccapi_market_data_service_gateio_base.h | 4 +- .../ccapi_market_data_service_gemini.h | 2 +- .../service/ccapi_market_data_service_huobi.h | 6 +- ...rket_data_service_huobi_derivatives_base.h | 4 +- .../ccapi_market_data_service_kraken.h | 2 +- .../ccapi_market_data_service_kucoin_base.h | 20 +-- .../service/ccapi_market_data_service_okx.h | 117 ++++++++++++++++- include/ccapi_cpp/service/ccapi_service.h | 122 ++++++++++-------- 25 files changed, 328 insertions(+), 209 deletions(-) diff --git a/README.md b/README.md index 5f0b4d88..e5100f6a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -# Notification: we've added a new feature that allows our users to subscribe to exchange provided candlesticks. There is a small renaming: "OPEN" has been renamed to "OPEN_PRICE", "CLOSE" has been renamed to "CLOSE_PRICE", "HIGH" has been renamed to "HIGH_PRICE", "LOW" has been renamed to "LOW_PRICE". If you have any questions, feel free to directly ask us on Discord https://discord.gg/b5EKcp9s8T. - +# Notifications: +* New features: added REST endpoints for fetching historical public trades, historical/recent candlesticks, and market depth (i.e. order book snapshot). +* Small breaking change to correct an English typo: In `SessionOptions`, the substring "MilliSeconds" has been renamed to "Milliseconds". diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index 3d7b3fff..588a33a3 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -232,6 +232,9 @@ #ifndef CCAPI_START_TRADE_ID #define CCAPI_START_TRADE_ID "START_TRADE_ID" #endif +#ifndef CCAPI_END_TRADE_ID +#define CCAPI_END_TRADE_ID "END_TRADE_ID" +#endif #ifndef CCAPI_START_AGG_TRADE_ID #define CCAPI_START_AGG_TRADE_ID "START_AGG_TRADE_ID" #endif diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index e84228b6..653c8885 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -821,13 +821,13 @@ class Session { this->sendRequestByWebsocket(x); } } - virtual void sendRequest(Request& request, Queue* eventQueuePtr = nullptr, long delayMilliSeconds = 0) { + virtual void sendRequest(Request& request, Queue* eventQueuePtr = nullptr, long delayMilliseconds = 0) { CCAPI_LOGGER_FUNCTION_ENTER; std::vector requestList({request}); - this->sendRequest(requestList, eventQueuePtr, delayMilliSeconds); + this->sendRequest(requestList, eventQueuePtr, delayMilliseconds); CCAPI_LOGGER_FUNCTION_EXIT; } - virtual void sendRequest(std::vector& requestList, Queue* eventQueuePtr = nullptr, long delayMilliSeconds = 0) { + virtual void sendRequest(std::vector& requestList, Queue* eventQueuePtr = nullptr, long delayMilliseconds = 0) { CCAPI_LOGGER_FUNCTION_ENTER; std::vector > > futurePtrList; // std::set serviceNameExchangeSet; @@ -854,7 +854,7 @@ class Session { // serviceNameExchangeSet.insert(key); // } auto now = UtilTime::now(); - auto futurePtr = servicePtr->sendRequest(request, !!eventQueuePtr, now, delayMilliSeconds, eventQueuePtr); + auto futurePtr = servicePtr->sendRequest(request, !!eventQueuePtr, now, delayMilliseconds, eventQueuePtr); if (eventQueuePtr) { futurePtrList.push_back(futurePtr); } @@ -886,10 +886,10 @@ class Session { this->onEvent(event, eventQueuePtr); } #ifndef SWIG - virtual void setTimer(const std::string& id, long delayMilliSeconds, std::function errorHandler, + virtual void setTimer(const std::string& id, long delayMilliseconds, std::function errorHandler, std::function successHandler) { - boost::asio::post(*this->serviceContextPtr->ioContextPtr, [this, id, delayMilliSeconds, errorHandler, successHandler]() { - std::shared_ptr timerPtr(new steady_timer(*this->serviceContextPtr->ioContextPtr, boost::asio::chrono::milliseconds(delayMilliSeconds))); + boost::asio::post(*this->serviceContextPtr->ioContextPtr, [this, id, delayMilliseconds, errorHandler, successHandler]() { + std::shared_ptr timerPtr(new 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) { #ifdef CCAPI_USE_SINGLE_THREAD diff --git a/include/ccapi_cpp/ccapi_session_options.h b/include/ccapi_cpp/ccapi_session_options.h index e7b71eed..70e9975c 100644 --- a/include/ccapi_cpp/ccapi_session_options.h +++ b/include/ccapi_cpp/ccapi_session_options.h @@ -18,44 +18,44 @@ class SessionOptions CCAPI_FINAL { ", enableCheckPingPongWebsocketProtocolLevel = " + ccapi::toString(enableCheckPingPongWebsocketProtocolLevel) + ", enableCheckPingPongWebsocketApplicationLevel = " + ccapi::toString(enableCheckPingPongWebsocketApplicationLevel) + ", enableCheckHeartbeatFix = " + ccapi::toString(enableCheckHeartbeatFix) + - ", pingWebsocketProtocolLevelIntervalMilliSeconds = " + ccapi::toString(pingWebsocketProtocolLevelIntervalMilliSeconds) + - ", pongWebsocketProtocolLevelTimeoutMilliSeconds = " + ccapi::toString(pongWebsocketProtocolLevelTimeoutMilliSeconds) + - ", pingWebsocketApplicationLevelIntervalMilliSeconds = " + ccapi::toString(pingWebsocketApplicationLevelIntervalMilliSeconds) + - ", pongWebsocketApplicationLevelTimeoutMilliSeconds = " + ccapi::toString(pongWebsocketApplicationLevelTimeoutMilliSeconds) + - ", heartbeatFixIntervalMilliSeconds = " + ccapi::toString(heartbeatFixIntervalMilliSeconds) + - ", heartbeatFixTimeoutMilliSeconds = " + ccapi::toString(heartbeatFixTimeoutMilliSeconds) + + ", pingWebsocketProtocolLevelIntervalMilliseconds = " + ccapi::toString(pingWebsocketProtocolLevelIntervalMilliseconds) + + ", pongWebsocketProtocolLevelTimeoutMilliseconds = " + ccapi::toString(pongWebsocketProtocolLevelTimeoutMilliseconds) + + ", pingWebsocketApplicationLevelIntervalMilliseconds = " + ccapi::toString(pingWebsocketApplicationLevelIntervalMilliseconds) + + ", pongWebsocketApplicationLevelTimeoutMilliseconds = " + ccapi::toString(pongWebsocketApplicationLevelTimeoutMilliseconds) + + ", heartbeatFixIntervalMilliseconds = " + ccapi::toString(heartbeatFixIntervalMilliseconds) + + ", heartbeatFixTimeoutMilliseconds = " + ccapi::toString(heartbeatFixTimeoutMilliseconds) + ", maxEventQueueSize = " + ccapi::toString(maxEventQueueSize) + ", httpMaxNumRetry = " + ccapi::toString(httpMaxNumRetry) + ", httpMaxNumRedirect = " + ccapi::toString(httpMaxNumRedirect) + - ", httpRequestTimeoutMilliSeconds = " + ccapi::toString(httpRequestTimeoutMilliSeconds) + + ", httpRequestTimeoutMilliseconds = " + ccapi::toString(httpRequestTimeoutMilliseconds) + ", httpConnectionPoolMaxSize = " + ccapi::toString(httpConnectionPoolMaxSize) + - ", httpConnectionPoolIdleTimeoutMilliSeconds = " + ccapi::toString(httpConnectionPoolIdleTimeoutMilliSeconds) + + ", httpConnectionPoolIdleTimeoutMilliseconds = " + ccapi::toString(httpConnectionPoolIdleTimeoutMilliseconds) + ", enableOneHttpConnectionPerRequest = " + ccapi::toString(enableOneHttpConnectionPerRequest) + "]"; return output; } - // long warnLateEventMaxMilliSeconds{}; // used to print a warning log message if en event arrives late + // long warnLateEventMaxMilliseconds{}; // used to print a warning log message if en event arrives late bool enableCheckSequence{}; // used to check sequence number discontinuity bool enableCheckOrderBookChecksum{}; // used to check order book checksum bool enableCheckOrderBookCrossed{true}; // used to check order book cross, usually this should be set to true bool enableCheckPingPongWebsocketProtocolLevel{true}; // used to check ping-pong health for exchange connections on websocket protocol level bool enableCheckPingPongWebsocketApplicationLevel{true}; // used to check ping-pong health for exchange connections on websocket application level bool enableCheckHeartbeatFix{true}; // used to check heartbeat health for exchange connections on FIX - long pingWebsocketProtocolLevelIntervalMilliSeconds{60000}; - long pongWebsocketProtocolLevelTimeoutMilliSeconds{30000}; // should be less than pingWebsocketProtocolLevelIntervalMilliSeconds - long pingWebsocketApplicationLevelIntervalMilliSeconds{60000}; - long pongWebsocketApplicationLevelTimeoutMilliSeconds{30000}; // should be less than pingWebsocketApplicationLevelIntervalMilliSeconds - long heartbeatFixIntervalMilliSeconds{60000}; - long heartbeatFixTimeoutMilliSeconds{30000}; // should be less than heartbeatFixIntervalMilliSeconds + long pingWebsocketProtocolLevelIntervalMilliseconds{60000}; + long pongWebsocketProtocolLevelTimeoutMilliseconds{30000}; // should be less than pingWebsocketProtocolLevelIntervalMilliseconds + long pingWebsocketApplicationLevelIntervalMilliseconds{60000}; + long pongWebsocketApplicationLevelTimeoutMilliseconds{30000}; // should be less than pingWebsocketApplicationLevelIntervalMilliseconds + long heartbeatFixIntervalMilliseconds{60000}; + long heartbeatFixTimeoutMilliseconds{30000}; // should be less than heartbeatFixIntervalMilliseconds int maxEventQueueSize{0}; // if set to a positive integer, the event queue will throw an exception when overflown int httpMaxNumRetry{1}; int httpMaxNumRedirect{1}; - long httpRequestTimeoutMilliSeconds{10000}; + long httpRequestTimeoutMilliseconds{10000}; int httpConnectionPoolMaxSize{1}; // used to set the maximal number of http connections to be kept in the pool (connections in the pool are idle) - long httpConnectionPoolIdleTimeoutMilliSeconds{0}; // used to purge the http connection pool if all connections in the + long httpConnectionPoolIdleTimeoutMilliseconds{0}; // used to purge the http connection pool if all connections in the // pool have stayed idle for at least this amount of time bool enableOneHttpConnectionPerRequest{}; // create a new http connection for each request #ifdef CCAPI_LEGACY_USE_WEBSOCKETPP #else - long websocketConnectTimeoutMilliSeconds{10000}; + long websocketConnectTimeoutMilliseconds{10000}; #endif }; } /* namespace ccapi */ diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h index 1547050b..d4254938 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_binance_base.h @@ -74,7 +74,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService } that->onFail_(thisWsConnection); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } void onOpen(wspp::connection_hdl hdl) override { ExecutionManagementService::onOpen(hdl); @@ -138,7 +138,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService [wsConnection, that_2 = that->shared_from_base()](const http::response& res) { CCAPI_LOGGER_DEBUG("ping listen key success"); }, - that->sessionOptions.httpRequestTimeoutMilliSeconds); + that->sessionOptions.httpRequestTimeoutMilliseconds); }); } void onClose(wspp::connection_hdl hdl) override { @@ -201,7 +201,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService } that->onFail_(wsConnectionPtr); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } void onOpen(std::shared_ptr wsConnectionPtr) override { ExecutionManagementService::onOpen(wsConnectionPtr); @@ -265,7 +265,7 @@ class ExecutionManagementServiceBinanceBase : public ExecutionManagementService [wsConnectionPtr, that_2 = that->shared_from_base()](const http::response& res) { CCAPI_LOGGER_DEBUG("ping listen key success"); }, - that->sessionOptions.httpRequestTimeoutMilliSeconds); + that->sessionOptions.httpRequestTimeoutMilliseconds); }); this->pingListenKeyTimerMapByConnectionIdMap[wsConnectionPtr->id] = timerPtr; } diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bitstamp.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bitstamp.h index eecaeecc..2eb98e34 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_bitstamp.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bitstamp.h @@ -329,7 +329,7 @@ class ExecutionManagementServiceBitstamp : public ExecutionManagementService { } that->onFail_(thisWsConnection); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } #else void prepareConnect(std::shared_ptr wsConnectionPtr) override { @@ -381,7 +381,7 @@ class ExecutionManagementServiceBitstamp : public ExecutionManagementService { } that->onFail_(wsConnectionPtr); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } #endif std::vector createSendStringListFromSubscription(const WsConnection& wsConnection, const Subscription& subscription, const TimePoint& now, diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_kraken.h b/include/ccapi_cpp/service/ccapi_execution_management_service_kraken.h index 9e471a80..4780f11e 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_kraken.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_kraken.h @@ -324,7 +324,7 @@ class ExecutionManagementServiceKraken : public ExecutionManagementService { } that->onFail_(thisWsConnection); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } #else void prepareConnect(std::shared_ptr wsConnectionPtr) override { @@ -374,7 +374,7 @@ class ExecutionManagementServiceKraken : public ExecutionManagementService { } that->onFail_(wsConnectionPtr); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } #endif std::vector createSendStringListFromSubscription(const WsConnection& wsConnection, const Subscription& subscription, const TimePoint& now, 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 ae5e7010..34d39009 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 @@ -69,7 +69,7 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { } that->onFail_(thisWsConnection); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } #else void onOpen(std::shared_ptr wsConnectionPtr) override { wsConnectionPtr->status = WsConnection::Status::OPEN; } @@ -119,7 +119,7 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { } that->onFail_(wsConnectionPtr); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } #endif void signReqeustForRestGenericPrivateRequest(http::request& req, const Request& request, std::string& methodString, @@ -520,14 +520,14 @@ class ExecutionManagementServiceKucoinBase : public ExecutionManagementService { message.setElementList({element}); messageList.emplace_back(std::move(message)); } else if (type == "welcome") { - this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = + this->pingIntervalMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = std::stol(this->extraPropertyByConnectionIdMap.at(wsConnection.id).at("pingInterval")); - this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = + this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = std::stol(this->extraPropertyByConnectionIdMap.at(wsConnection.id).at("pingTimeout")); - if (this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] <= - this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL]) { - this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = - this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] - 1; + if (this->pingIntervalMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] <= + this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL]) { + this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = + this->pingIntervalMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] - 1; } #ifdef CCAPI_LEGACY_USE_WEBSOCKETPP ExecutionManagementService::onOpen(hdl); diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_mexc.h b/include/ccapi_cpp/service/ccapi_execution_management_service_mexc.h index 8b5b7a67..fabec045 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_mexc.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_mexc.h @@ -274,7 +274,7 @@ class ExecutionManagementServiceMexc : public ExecutionManagementService { } that->onFail_(thisWsConnection); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } void onOpen(wspp::connection_hdl hdl) override { ExecutionManagementService::onOpen(hdl); @@ -318,7 +318,7 @@ class ExecutionManagementServiceMexc : public ExecutionManagementService { [wsConnection, that_2 = that->shared_from_base()](const http::response& res) { CCAPI_LOGGER_DEBUG("ping listen key success"); }, - that->sessionOptions.httpRequestTimeoutMilliSeconds); + that->sessionOptions.httpRequestTimeoutMilliseconds); }); } void onClose(wspp::connection_hdl hdl) override { @@ -372,7 +372,7 @@ class ExecutionManagementServiceMexc : public ExecutionManagementService { } that->onFail_(wsConnectionPtr); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } void onOpen(std::shared_ptr wsConnectionPtr) override { ExecutionManagementService::onOpen(wsConnectionPtr); @@ -416,7 +416,7 @@ class ExecutionManagementServiceMexc : public ExecutionManagementService { [wsConnectionPtr, that_2 = that->shared_from_base()](const http::response& res) { CCAPI_LOGGER_DEBUG("ping listen key success"); }, - that->sessionOptions.httpRequestTimeoutMilliSeconds); + that->sessionOptions.httpRequestTimeoutMilliseconds); }); this->pingListenKeyTimerMapByConnectionIdMap[wsConnectionPtr->id] = timerPtr; } diff --git a/include/ccapi_cpp/service/ccapi_fix_service.h b/include/ccapi_cpp/service/ccapi_fix_service.h index 09624268..88d41bf1 100644 --- a/include/ccapi_cpp/service/ccapi_fix_service.h +++ b/include/ccapi_cpp/service/ccapi_fix_service.h @@ -454,11 +454,11 @@ class FixService : public Service { std::function>)> pingMethod, bool pingNow = false) { CCAPI_LOGGER_FUNCTION_ENTER; CCAPI_LOGGER_TRACE("method = " + pingPongMethodToString(method)); - auto pingIntervalMilliSeconds = this->pingIntervalMilliSecondsByMethodMap[method]; - auto pongTimeoutMilliSeconds = this->pongTimeoutMilliSecondsByMethodMap[method]; - CCAPI_LOGGER_TRACE("pingIntervalMilliSeconds = " + toString(pingIntervalMilliSeconds)); - CCAPI_LOGGER_TRACE("pongTimeoutMilliSeconds = " + toString(pongTimeoutMilliSeconds)); - if (pingIntervalMilliSeconds <= pongTimeoutMilliSeconds) { + auto pingIntervalMilliseconds = this->pingIntervalMillisecondsByMethodMap[method]; + auto pongTimeoutMilliseconds = this->pongTimeoutMillisecondsByMethodMap[method]; + CCAPI_LOGGER_TRACE("pingIntervalMilliseconds = " + toString(pingIntervalMilliseconds)); + CCAPI_LOGGER_TRACE("pongTimeoutMilliseconds = " + toString(pongTimeoutMilliseconds)); + if (pingIntervalMilliseconds <= pongTimeoutMilliseconds) { return; } if (fixConnectionPtr->status == FixConnection::Status::OPEN) { @@ -471,8 +471,8 @@ class FixService : public Service { this->pingTimerByMethodByConnectionIdMap.at(fixConnectionPtr->id).at(method)->cancel(); } TimerPtr timerPtr( - new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pingIntervalMilliSeconds - pongTimeoutMilliSeconds))); - timerPtr->async_wait([fixConnectionPtr, that = shared_from_base(), pingMethod, pongTimeoutMilliSeconds, method](ErrorCode const& ec) { + new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pingIntervalMilliseconds - pongTimeoutMilliseconds))); + timerPtr->async_wait([fixConnectionPtr, that = shared_from_base(), pingMethod, pongTimeoutMilliseconds, method](ErrorCode const& ec) { if (that->fixConnectionPtrByIdMap.find(fixConnectionPtr->id) != that->fixConnectionPtrByIdMap.end()) { if (ec) { CCAPI_LOGGER_ERROR("fixConnectionPtr = " + toString(*fixConnectionPtr) + ", ping timer error: " + ec.message()); @@ -484,7 +484,7 @@ class FixService : public Service { if (ec) { that->onError(Event::Type::FIX_STATUS, Message::Type::GENERIC_ERROR, ec, "ping"); } - if (pongTimeoutMilliSeconds <= 0) { + if (pongTimeoutMilliseconds <= 0) { return; } if (that->pongTimeOutTimerByMethodByConnectionIdMap.find(fixConnectionPtr->id) != that->pongTimeOutTimerByMethodByConnectionIdMap.end() && @@ -492,8 +492,8 @@ class FixService : public Service { that->pongTimeOutTimerByMethodByConnectionIdMap.at(fixConnectionPtr->id).end()) { that->pongTimeOutTimerByMethodByConnectionIdMap.at(fixConnectionPtr->id).at(method)->cancel(); } - TimerPtr timerPtr(new boost::asio::steady_timer(*that->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pongTimeoutMilliSeconds))); - timerPtr->async_wait([fixConnectionPtr, that, pingMethod, pongTimeoutMilliSeconds, method](ErrorCode const& ec) { + TimerPtr timerPtr(new boost::asio::steady_timer(*that->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pongTimeoutMilliseconds))); + timerPtr->async_wait([fixConnectionPtr, that, pingMethod, pongTimeoutMilliseconds, method](ErrorCode const& ec) { if (that->fixConnectionPtrByIdMap.find(fixConnectionPtr->id) != that->fixConnectionPtrByIdMap.end()) { if (ec) { CCAPI_LOGGER_ERROR("fixConnectionPtr = " + toString(*fixConnectionPtr) + ", pong timeout timer error: " + ec.message()); @@ -506,7 +506,7 @@ class FixService : public Service { that->lastPongTpByMethodByConnectionIdMap.at(fixConnectionPtr->id).end() && std::chrono::duration_cast(now - that->lastPongTpByMethodByConnectionIdMap.at(fixConnectionPtr->id).at(method)) - .count() >= pongTimeoutMilliSeconds) { + .count() >= pongTimeoutMilliseconds) { auto thisFixConnectionPtr = fixConnectionPtr; that->onFail(fixConnectionPtr, "pong timeout"); } else { diff --git a/include/ccapi_cpp/service/ccapi_fix_service_coinbase.h b/include/ccapi_cpp/service/ccapi_fix_service_coinbase.h index 8058b61d..31d1f9a3 100644 --- a/include/ccapi_cpp/service/ccapi_fix_service_coinbase.h +++ b/include/ccapi_cpp/service/ccapi_fix_service_coinbase.h @@ -44,7 +44,7 @@ class FixServiceCoinbase : public FixServicesessionOptions.heartbeatFixIntervalMilliSeconds / 1000)}); + param.push_back({hff::tag::HeartBtInt, std::to_string(this->sessionOptions.heartbeatFixIntervalMilliseconds / 1000)}); auto credential = this->credentialByConnectionIdMap[connectionId]; auto apiPassphrase = mapGetWithDefault(credential, this->apiPassphraseName); param.push_back({hff::tag::Password, apiPassphrase}); diff --git a/include/ccapi_cpp/service/ccapi_fix_service_gemini.h b/include/ccapi_cpp/service/ccapi_fix_service_gemini.h index a6692edc..6382a137 100644 --- a/include/ccapi_cpp/service/ccapi_fix_service_gemini.h +++ b/include/ccapi_cpp/service/ccapi_fix_service_gemini.h @@ -41,7 +41,7 @@ class FixServiceGemini : public FixService { param.push_back({hff::tag::MsgType, msgType}); param.push_back({hff::tag::ResetSeqNumFlag, "Y"}); param.push_back({hff::tag::EncryptMethod, "0"}); - param.push_back({hff::tag::HeartBtInt, std::to_string(this->sessionOptions.heartbeatFixIntervalMilliSeconds / 1000)}); + param.push_back({hff::tag::HeartBtInt, std::to_string(this->sessionOptions.heartbeatFixIntervalMilliseconds / 1000)}); for (const auto& x : logonOptionMap) { param.push_back({x.first, x.second}); } diff --git a/include/ccapi_cpp/service/ccapi_market_data_service.h b/include/ccapi_cpp/service/ccapi_market_data_service.h index 06228ffb..97f852d2 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service.h @@ -209,9 +209,9 @@ class MarketDataService : public Service { if (marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_MARKET_DEPTH || marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_TRADE || marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_AGG_TRADE) { - if (this->sessionOptions.warnLateEventMaxMilliSeconds > 0 && + if (this->sessionOptions.warnLateEventMaxMilliseconds > 0 && std::chrono::duration_cast(timeReceived - marketDataMessage.tp).count() > - this->sessionOptions.warnLateEventMaxMilliSeconds && + this->sessionOptions.warnLateEventMaxMilliseconds && marketDataMessage.recapType == MarketDataMessage::RecapType::NONE) { CCAPI_LOGGER_WARN("late websocket message: timeReceived = " + toString(timeReceived) + ", marketDataMessage.tp = " + toString(marketDataMessage.tp) + ", wsConnection = " + toString(wsConnection)); @@ -466,9 +466,9 @@ class MarketDataService : public Service { marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_TRADE || marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_AGG_TRADE || marketDataMessage.type == MarketDataMessage::Type::MARKET_DATA_EVENTS_CANDLESTICK) { - // if (this->sessionOptions.warnLateEventMaxMilliSeconds > 0 && + // if (this->sessionOptions.warnLateEventMaxMilliseconds > 0 && // std::chrono::duration_cast(timeReceived - marketDataMessage.tp).count() > - // this->sessionOptions.warnLateEventMaxMilliSeconds && + // this->sessionOptions.warnLateEventMaxMilliseconds && // marketDataMessage.recapType == MarketDataMessage::RecapType::NONE) { // CCAPI_LOGGER_WARN("late websocket message: timeReceived = " + toString(timeReceived) + ", marketDataMessage.tp = " + toString(marketDataMessage.tp) // + @@ -1722,43 +1722,43 @@ class MarketDataService : public Service { } } else { if (this->marketDataMessageDataBufferByConnectionIdExchangeSubscriptionIdVersionIdMap[wsConnection.id][exchangeSubscriptionId].empty()) { - int delayMilliSeconds = std::stoi(optionMap.at(CCAPI_FETCH_MARKET_DEPTH_INITIAL_SNAPSHOT_DELAY_MILLISECONDS)); - if (delayMilliSeconds > 0) { - TimerPtr timerPtr(new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(delayMilliSeconds))); - timerPtr->async_wait([wsConnection, exchangeSubscriptionId, delayMilliSeconds, that = this](ErrorCode const& ec) { + int delayMilliseconds = std::stoi(optionMap.at(CCAPI_FETCH_MARKET_DEPTH_INITIAL_SNAPSHOT_DELAY_MILLISECONDS)); + if (delayMilliseconds > 0) { + TimerPtr timerPtr(new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(delayMilliseconds))); + timerPtr->async_wait([wsConnection, exchangeSubscriptionId, delayMilliseconds, that = this](ErrorCode const& ec) { auto now = UtilTime::now(); if (ec) { that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { - that->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, delayMilliSeconds); + that->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, delayMilliseconds); } }); this->fetchMarketDepthInitialSnapshotTimerByConnectionIdExchangeSubscriptionIdMap[wsConnection.id][exchangeSubscriptionId] = timerPtr; } else { - this->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, delayMilliSeconds); + this->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, delayMilliseconds); } } this->marketDataMessageDataBufferByConnectionIdExchangeSubscriptionIdVersionIdMap[wsConnection.id][exchangeSubscriptionId][versionId] = marketDataMessage.data; } } - void buildOrderBookInitialOnFail(const WsConnection& wsConnection, const std::string& exchangeSubscriptionId, long delayMilliSeconds) { - auto thisDelayMilliSeconds = delayMilliSeconds * 2; - if (thisDelayMilliSeconds > 0) { - TimerPtr timerPtr(new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(thisDelayMilliSeconds))); - timerPtr->async_wait([wsConnection, exchangeSubscriptionId, thisDelayMilliSeconds, that = this](ErrorCode const& ec) { + void buildOrderBookInitialOnFail(const WsConnection& wsConnection, const std::string& exchangeSubscriptionId, long delayMilliseconds) { + auto thisDelayMilliseconds = delayMilliseconds * 2; + if (thisDelayMilliseconds > 0) { + TimerPtr timerPtr(new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(thisDelayMilliseconds))); + timerPtr->async_wait([wsConnection, exchangeSubscriptionId, thisDelayMilliseconds, that = this](ErrorCode const& ec) { if (ec) { that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { - that->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, thisDelayMilliSeconds); + that->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, thisDelayMilliseconds); } }); this->fetchMarketDepthInitialSnapshotTimerByConnectionIdExchangeSubscriptionIdMap[wsConnection.id][exchangeSubscriptionId] = timerPtr; } else { - this->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, thisDelayMilliSeconds); + this->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, thisDelayMilliseconds); } } - void buildOrderBookInitial(const WsConnection& wsConnection, const std::string& exchangeSubscriptionId, long delayMilliSeconds) { + void buildOrderBookInitial(const WsConnection& wsConnection, const std::string& exchangeSubscriptionId, long delayMilliseconds) { auto now = UtilTime::now(); http::request req; std::string symbolId = this->channelIdSymbolIdByConnectionIdExchangeSubscriptionIdMap[wsConnection.id][exchangeSubscriptionId][CCAPI_SYMBOL_ID]; @@ -1769,10 +1769,10 @@ class MarketDataService : public Service { this->createFetchOrderBookInitialReq(req, symbolId, now, credential); this->sendRequest( req, - [wsConnection, exchangeSubscriptionId, delayMilliSeconds, that = shared_from_base()](const beast::error_code& ec) { - that->buildOrderBookInitialOnFail(wsConnection, exchangeSubscriptionId, delayMilliSeconds); + [wsConnection, exchangeSubscriptionId, delayMilliseconds, that = shared_from_base()](const beast::error_code& ec) { + that->buildOrderBookInitialOnFail(wsConnection, exchangeSubscriptionId, delayMilliseconds); }, - [wsConnection, exchangeSubscriptionId, delayMilliSeconds, that = shared_from_base()](const http::response& res) { + [wsConnection, exchangeSubscriptionId, delayMilliseconds, that = shared_from_base()](const http::response& res) { auto timeReceived = UtilTime::now(); int statusCode = res.result_int(); std::string body = res.body(); @@ -1897,19 +1897,19 @@ class MarketDataService : public Service { that->eventHandler(event, nullptr); that->processedInitialSnapshotByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = true; } else { - that->buildOrderBookInitialOnFail(wsConnection, exchangeSubscriptionId, delayMilliSeconds); - // if (delayMilliSeconds > 0) { + that->buildOrderBookInitialOnFail(wsConnection, exchangeSubscriptionId, delayMilliseconds); + // if (delayMilliseconds > 0) { // that->fetchMarketDepthInitialSnapshotTimerByConnectionIdExchangeSubscriptionIdMap[wsConnection.id][exchangeSubscriptionId] = // that->serviceContextPtr->tlsClientPtr->set_timer( - // delayMilliSeconds, [wsConnection, exchangeSubscriptionId, delayMilliSeconds, that](ErrorCode const& ec) { + // delayMilliseconds, [wsConnection, exchangeSubscriptionId, delayMilliseconds, that](ErrorCode const& ec) { // if (ec) { // that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); // } else { - // that->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, delayMilliSeconds); + // that->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, delayMilliseconds); // } // }); // } else { - // that->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, delayMilliSeconds); + // that->buildOrderBookInitial(wsConnection, exchangeSubscriptionId, delayMilliseconds); // } } return; @@ -1917,11 +1917,11 @@ class MarketDataService : public Service { CCAPI_LOGGER_ERROR(std::string("e.what() = ") + e.what()); } } - that->buildOrderBookInitialOnFail(wsConnection, exchangeSubscriptionId, delayMilliSeconds); + that->buildOrderBookInitialOnFail(wsConnection, exchangeSubscriptionId, delayMilliseconds); // WsConnection thisWsConnection = wsConnection; // that->onFail_(thisWsConnection); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } std::string convertCandlestickIntervalSecondsToInterval(int intervalSeconds, const std::string& secondStr, const std::string& minuteStr, const std::string& hourStr, const std::string& dayStr, const std::string& weekStr) { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_base.h index 9e429174..30edaddc 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_base.h @@ -36,7 +36,7 @@ class MarketDataServiceBinanceBase : public MarketDataService { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { if (marketDepthRequested == 1) { channelId = CCAPI_WEBSOCKET_BINANCE_BASE_CHANNEL_BOOK_TICKER; @@ -44,7 +44,7 @@ class MarketDataServiceBinanceBase : public MarketDataService { int marketDepthSubscribedToExchange = 1; marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({5, 10, 20})); std::string updateSpeed; - if (conflateIntervalMilliSeconds < 1000) { + if (conflateIntervalMilliseconds < 1000) { updateSpeed = "100ms"; } channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); @@ -269,10 +269,6 @@ class MarketDataServiceBinanceBase : public MarketDataService { req.set("X-MBX-APIKEY", apiKey); } } - std::string convertParamStartTimeEndTime(const std::string& input) { return std::to_string(std::stoll(input) * 1000); } - std::string convertParamInterval(const std::string& input) { - return this->convertCandlestickIntervalSecondsToInterval(std::stoi(input), "s", "m", "h", "d", "w"); - } void convertRequestForRest(http::request& req, const Request& request, const TimePoint& now, const std::string& symbolId, const std::map& credential) override { this->prepareReq(req, credential); @@ -311,20 +307,19 @@ class MarketDataServiceBinanceBase : public MarketDataService { auto target = this->getRecentAggTradesTarget; std::string queryString; const std::map param = request.getFirstParamWithDefault(); - this->appendParam( - queryString, param, - { - {CCAPI_LIMIT, "limit"}, - {CCAPI_START_TIME_SECONDS, "startTime"}, - {CCAPI_END_TIME_SECONDS, "endTime"}, - {CCAPI_START_AGG_TRADE_ID, "fromId"}, - }, - { - {CCAPI_START_TIME_SECONDS, - [that = shared_from_base()](const std::string& input) { return that->convertParamStartTimeEndTime(input); }}, - {CCAPI_END_TIME_SECONDS, - [that = shared_from_base()](const std::string& input) { return that->convertParamStartTimeEndTime(input); }}, - }); + this->appendParam(queryString, param, + { + {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TIME_SECONDS, "startTime"}, + {CCAPI_END_TIME_SECONDS, "endTime"}, + {CCAPI_START_AGG_TRADE_ID, "fromId"}, + }, + { + {CCAPI_START_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + {CCAPI_END_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + }); this->appendSymbolId(queryString, symbolId, "symbol"); req.target(target + "?" + queryString); } break; @@ -334,22 +329,23 @@ class MarketDataServiceBinanceBase : public MarketDataService { auto target = this->getRecentCandlesticksTarget; std::string queryString; const std::map param = request.getFirstParamWithDefault(); - this->appendParam( - queryString, param, - { - {CCAPI_LIMIT, "limit"}, - {CCAPI_START_TIME_SECONDS, "startTime"}, - {CCAPI_END_TIME_SECONDS, "endTime"}, - {CCAPI_CANDLESTICK_INTERVAL_SECONDS, "interval"}, - }, - { - {CCAPI_CANDLESTICK_INTERVAL_SECONDS, - [that = shared_from_base()](const std::string& input) { return that->convertParamInterval(input); }}, - {CCAPI_START_TIME_SECONDS, - [that = shared_from_base()](const std::string& input) { return that->convertParamStartTimeEndTime(input); }}, - {CCAPI_END_TIME_SECONDS, - [that = shared_from_base()](const std::string& input) { return that->convertParamStartTimeEndTime(input); }}, - }); + this->appendParam(queryString, param, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, "interval"}, + {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TIME_SECONDS, "startTime"}, + {CCAPI_END_TIME_SECONDS, "endTime"}, + }, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, + [that = shared_from_base()](const std::string& input) { + return that->convertCandlestickIntervalSecondsToInterval(std::stoi(input), "s", "m", "h", "d", "w"); + }}, + {CCAPI_START_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + {CCAPI_END_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + }); this->appendSymbolId(queryString, symbolId, "symbol"); req.target(target + "?" + queryString); } break; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_binance_derivatives_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_binance_derivatives_base.h index 619fe5ae..bd9d5b0e 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_binance_derivatives_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_binance_derivatives_base.h @@ -19,7 +19,7 @@ class MarketDataServiceBinanceDerivativesBase : public MarketDataServiceBinanceB void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { int marketDepthSubscribedToExchange = 1; marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({1, 5, 10, 20})); @@ -27,9 +27,9 @@ class MarketDataServiceBinanceDerivativesBase : public MarketDataServiceBinanceB channelId = CCAPI_WEBSOCKET_BINANCE_BASE_CHANNEL_BOOK_TICKER; } else { std::string updateSpeed; - if (conflateIntervalMilliSeconds < 250) { + if (conflateIntervalMilliseconds < 250) { updateSpeed = "100ms"; - } else if (conflateIntervalMilliSeconds >= 500) { + } else if (conflateIntervalMilliseconds >= 500) { updateSpeed = "500ms"; } channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h b/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h index dc4e54cc..ed0bc0de 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bitfinex.h @@ -172,7 +172,7 @@ class MarketDataServiceBitfinex : public MarketDataService { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { int marketDepthSubscribedToExchange = 1; marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({1, 25, 100, 250})); diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bitget_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_bitget_base.h index 0f550512..aded1335 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bitget_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bitget_base.h @@ -20,10 +20,10 @@ class MarketDataServiceBitgetBase : public MarketDataService { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { if (this->isDerivatives) { - if (conflateIntervalMilliSeconds < 200) { + if (conflateIntervalMilliseconds < 200) { channelId = CCAPI_WEBSOCKET_BITGET_BASE_CHANNEL_BOOKS; } else { if (marketDepthRequested <= 1) { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_gateio_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_gateio_base.h index b0e7c359..732b2b63 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_gateio_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_gateio_base.h @@ -32,7 +32,7 @@ class MarketDataServiceGateioBase : public MarketDataService { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { if (marketDepthRequested == 1) { channelId = this->websocketChannelBookTicker; @@ -44,7 +44,7 @@ class MarketDataServiceGateioBase : public MarketDataService { if (this->isDerivatives) { updateSpeed = "0"; } else { - if (conflateIntervalMilliSeconds < 1000) { + if (conflateIntervalMilliseconds < 1000) { updateSpeed = "100ms"; } else { updateSpeed = "1000ms"; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h b/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h index 2e4ba552..63b8b4fe 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_gemini.h @@ -39,7 +39,7 @@ class MarketDataServiceGemini : public MarketDataService { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { if (marketDepthRequested == 1) { int marketDepthSubscribedToExchange = 1; 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 772cc17d..dd6386e0 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_huobi.h @@ -35,11 +35,11 @@ class MarketDataServiceHuobi : public MarketDataServiceHuobiBase { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); CCAPI_LOGGER_TRACE(""); if (field == CCAPI_MARKET_DEPTH) { CCAPI_LOGGER_TRACE(""); - if (conflateIntervalMilliSeconds < 100) { + if (conflateIntervalMilliseconds < 100) { CCAPI_LOGGER_TRACE(""); if (marketDepthRequested == 1) { CCAPI_LOGGER_TRACE(""); @@ -52,7 +52,7 @@ class MarketDataServiceHuobi : public MarketDataServiceHuobiBase { channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); this->marketDepthSubscribedToExchangeByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = marketDepthSubscribedToExchange; } - } else if (conflateIntervalMilliSeconds < 1000) { + } else if (conflateIntervalMilliseconds < 1000) { if (marketDepthRequested == 1) { channelId = CCAPI_WEBSOCKET_HUOBI_CHANNEL_MARKET_BBO; } else { 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 b6d5224b..2bef11e9 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 @@ -15,9 +15,9 @@ class MarketDataServiceHuobiDerivativesBase : public MarketDataServiceHuobiBase void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { - if (conflateIntervalMilliSeconds < 1000) { + if (conflateIntervalMilliseconds < 1000) { if (marketDepthRequested == 1) { channelId = CCAPI_WEBSOCKET_HUOBI_CHANNEL_MARKET_BBO; } else { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h b/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h index b70cde87..0ea7dbf0 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kraken.h @@ -52,7 +52,7 @@ class MarketDataServiceKraken : public MarketDataService { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { int marketDepthSubscribedToExchange = 1; marketDepthSubscribedToExchange = this->calculateMarketDepthAllowedByExchange(marketDepthRequested, std::vector({10, 25, 100, 500, 1000})); diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_base.h index 64eaa497..9421f84f 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_base.h @@ -18,7 +18,7 @@ class MarketDataServiceKucoinBase : public MarketDataService { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { if (this->isDerivatives) { if (marketDepthRequested == 1) { @@ -29,7 +29,7 @@ class MarketDataServiceKucoinBase : public MarketDataService { channelId = this->channelMarketLevel2Depth50; } } else { - // if (conflateIntervalMilliSeconds < 100) { + // if (conflateIntervalMilliseconds < 100) { // channelId = this->channelMarketLevel2; // }else{ if (marketDepthRequested == 1) { @@ -99,7 +99,7 @@ class MarketDataServiceKucoinBase : public MarketDataService { } that->onFail_(thisWsConnection); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } #else void pingOnApplicationLevel(std::shared_ptr wsConnectionPtr, ErrorCode& ec) override { @@ -145,7 +145,7 @@ class MarketDataServiceKucoinBase : public MarketDataService { } that->onFail_(wsConnectionPtr); }, - this->sessionOptions.httpRequestTimeoutMilliSeconds); + this->sessionOptions.httpRequestTimeoutMilliseconds); } #endif std::vector createSendStringList(const WsConnection& wsConnection) override { @@ -424,14 +424,14 @@ class MarketDataServiceKucoinBase : public MarketDataService { marketDataMessageList.emplace_back(std::move(marketDataMessage)); } } else if (type == "welcome") { - this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = + this->pingIntervalMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = std::stol(this->extraPropertyByConnectionIdMap.at(wsConnection.id).at("pingInterval")); - this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = + this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = std::stol(this->extraPropertyByConnectionIdMap.at(wsConnection.id).at("pingTimeout")); - if (this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] <= - this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL]) { - this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = - this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] - 1; + if (this->pingIntervalMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] <= + this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL]) { + this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = + this->pingIntervalMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] - 1; } #ifdef CCAPI_LEGACY_USE_WEBSOCKETPP Service::onOpen(hdl); diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_okx.h b/include/ccapi_cpp/service/ccapi_market_data_service_okx.h index d5fa12c3..00c3fbcb 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_okx.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_okx.h @@ -32,6 +32,11 @@ class MarketDataServiceOkx : public MarketDataService { this->apiPassphraseName = CCAPI_OKX_API_PASSPHRASE; this->setupCredential({this->apiKeyName, this->apiSecretName, this->apiPassphraseName}); this->getRecentTradesTarget = "/api/v5/market/trades"; + this->getHistoricalTradesTarget = "/api/v5/market/history-trades"; + this->getRecentCandlesticksTarget = "/api/v5/market/candles"; + this->getHistoricalCandlesticksTarget = "/api/v5/market/history-candles"; + this->getMarketDepthTarget = "/api/v5/market/books"; + this->getRecentTradesTarget = "/api/v5/market/trades"; this->getInstrumentTarget = "/api/v5/public/instruments"; this->getInstrumentsTarget = "/api/v5/public/instruments"; } @@ -52,9 +57,9 @@ class MarketDataServiceOkx : public MarketDataService { void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { auto marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); - auto conflateIntervalMilliSeconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); + auto conflateIntervalMilliseconds = std::stoi(optionMap.at(CCAPI_CONFLATE_INTERVAL_MILLISECONDS)); if (field == CCAPI_MARKET_DEPTH) { - if (conflateIntervalMilliSeconds < 100) { + if (conflateIntervalMilliseconds < 100) { if (marketDepthRequested == 1) { channelId = CCAPI_WEBSOCKET_OKX_CHANNEL_PUBLIC_DEPTH1_L2_TBT; } else if (marketDepthRequested <= 50) { @@ -302,6 +307,66 @@ class MarketDataServiceOkx : public MarketDataService { this->appendSymbolId(queryString, symbolId, "instId"); req.target(target + "?" + queryString); } break; + case Request::Operation::GET_HISTORICAL_TRADES: { + req.method(http::verb::get); + auto target = this->getHistoricalTradesTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TRADE_ID, "before"}, + {CCAPI_END_TRADE_ID, "after"}, + {CCAPI_START_TIME_SECONDS, "before"}, + {CCAPI_END_TIME_SECONDS, "after"}, + }, + { + {CCAPI_START_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + {CCAPI_END_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + }); + this->appendSymbolId(queryString, symbolId, "instId"); + req.target(target + "?" + queryString); + } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + req.method(http::verb::get); + auto target = this->getRecentCandlesticksTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, "bar"}, + {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TIME_SECONDS, "before"}, + {CCAPI_END_TIME_SECONDS, "after"}, + }, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, + [that = shared_from_base()](const std::string& input) { + return that->convertCandlestickIntervalSecondsToInterval(std::stoi(input), "s", "m", "H", "D", "W"); + }}, + {CCAPI_START_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + {CCAPI_END_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + }); + this->appendSymbolId(queryString, symbolId, "instId"); + req.target(target + "?" + queryString); + } break; + case Request::Operation::GET_MARKET_DEPTH: { + req.method(http::verb::get); + auto target = this->getMarketDepthTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_MARKET_DEPTH_MAX, "sz"}, + }); + this->appendSymbolId(queryString, symbolId, "instId"); + req.target(target + "?" + queryString); + } break; case Request::Operation::GET_INSTRUMENT: { req.method(http::verb::get); auto target = this->getInstrumentTarget; @@ -346,7 +411,8 @@ class MarketDataServiceOkx : public MarketDataService { rj::Document document; document.Parse(textMessage.c_str()); switch (request.getOperation()) { - case Request::Operation::GET_RECENT_TRADES: { + case Request::Operation::GET_RECENT_TRADES: + case Request::Operation::GET_HISTORICAL_TRADES: { for (const auto& datum : document["data"].GetArray()) { MarketDataMessage marketDataMessage; marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_TRADE; @@ -360,6 +426,51 @@ class MarketDataServiceOkx : public MarketDataService { marketDataMessageList.emplace_back(std::move(marketDataMessage)); } } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + for (const auto& x : document["data"].GetArray()) { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_CANDLESTICK; + marketDataMessage.tp = UtilTime::makeTimePointFromMilliseconds(std::stoll(x[0].GetString())); + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::OPEN_PRICE, x[1].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::HIGH_PRICE, x[2].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::LOW_PRICE, x[3].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::CLOSE_PRICE, x[4].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::VOLUME, x[5].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::QUOTE_VOLUME, x[7].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::CANDLESTICK].emplace_back(std::move(dataPoint)); + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } + } break; + case Request::Operation::GET_MARKET_DEPTH: { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_MARKET_DEPTH; + CCAPI_LOGGER_DEBUG(""); + const rj::Value& data = document["data"][0]; + CCAPI_LOGGER_DEBUG(""); + marketDataMessage.tp = UtilTime::makeTimePointFromMilliseconds(std::stoll(data["ts"].GetString())); + CCAPI_LOGGER_DEBUG(""); + for (const auto& x : data["bids"].GetArray()) { + CCAPI_LOGGER_DEBUG(""); + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + CCAPI_LOGGER_DEBUG(""); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + CCAPI_LOGGER_DEBUG(""); + marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint)); + } + for (const auto& x : data["asks"].GetArray()) { + CCAPI_LOGGER_DEBUG(""); + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + CCAPI_LOGGER_DEBUG(""); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + CCAPI_LOGGER_DEBUG(""); + marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint)); + } + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } break; case Request::Operation::GET_INSTRUMENT: { Message message; message.setTimeReceived(timeReceived); diff --git a/include/ccapi_cpp/service/ccapi_service.h b/include/ccapi_cpp/service/ccapi_service.h index ba5ccf23..b3196cf9 100644 --- a/include/ccapi_cpp/service/ccapi_service.h +++ b/include/ccapi_cpp/service/ccapi_service.h @@ -121,12 +121,12 @@ class Service : public std::enable_shared_from_this { httpConnectionPool(sessionOptions.httpConnectionPoolMaxSize) { this->enableCheckPingPongWebsocketProtocolLevel = this->sessionOptions.enableCheckPingPongWebsocketProtocolLevel; this->enableCheckPingPongWebsocketApplicationLevel = this->sessionOptions.enableCheckPingPongWebsocketApplicationLevel; - // this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_PROTOCOL_LEVEL] = sessionOptions.pingWebsocketProtocolLevelIntervalMilliSeconds; - // this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_PROTOCOL_LEVEL] = sessionOptions.pongWebsocketProtocolLevelTimeoutMilliSeconds; - this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = sessionOptions.pingWebsocketApplicationLevelIntervalMilliSeconds; - this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = sessionOptions.pongWebsocketApplicationLevelTimeoutMilliSeconds; - this->pingIntervalMilliSecondsByMethodMap[PingPongMethod::FIX_PROTOCOL_LEVEL] = sessionOptions.heartbeatFixIntervalMilliSeconds; - this->pongTimeoutMilliSecondsByMethodMap[PingPongMethod::FIX_PROTOCOL_LEVEL] = sessionOptions.heartbeatFixTimeoutMilliSeconds; + // this->pingIntervalMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_PROTOCOL_LEVEL] = sessionOptions.pingWebsocketProtocolLevelIntervalMilliseconds; + // this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_PROTOCOL_LEVEL] = sessionOptions.pongWebsocketProtocolLevelTimeoutMilliseconds; + this->pingIntervalMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = sessionOptions.pingWebsocketApplicationLevelIntervalMilliseconds; + this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::WEBSOCKET_APPLICATION_LEVEL] = sessionOptions.pongWebsocketApplicationLevelTimeoutMilliseconds; + this->pingIntervalMillisecondsByMethodMap[PingPongMethod::FIX_PROTOCOL_LEVEL] = sessionOptions.heartbeatFixIntervalMilliseconds; + this->pongTimeoutMillisecondsByMethodMap[PingPongMethod::FIX_PROTOCOL_LEVEL] = sessionOptions.heartbeatFixTimeoutMilliseconds; } virtual ~Service() { for (const auto& x : this->pingTimerByMethodByConnectionIdMap) { @@ -182,14 +182,14 @@ class Service : public std::enable_shared_from_this { const std::map& credential) {} virtual void processSuccessfulTextMessageRest(int statusCode, const Request& request, const std::string& textMessage, const TimePoint& timeReceived, Queue* eventQueuePtr) {} - std::shared_ptr> sendRequest(Request& request, const bool useFuture, const TimePoint& now, long delayMilliSeconds, + std::shared_ptr> sendRequest(Request& request, const bool useFuture, const TimePoint& now, long delayMilliseconds, Queue* eventQueuePtr) { CCAPI_LOGGER_FUNCTION_ENTER; CCAPI_LOGGER_DEBUG("request = " + toString(request)); CCAPI_LOGGER_DEBUG("useFuture = " + toString(useFuture)); TimePoint then; - if (delayMilliSeconds > 0) { - then = now + std::chrono::milliseconds(delayMilliSeconds); + if (delayMilliseconds > 0) { + then = now + std::chrono::milliseconds(delayMilliseconds); } else { then = now; } @@ -217,8 +217,8 @@ class Service : public std::enable_shared_from_this { } std::shared_ptr> promisePtr(promisePtrRaw); HttpRetry retry(0, 0, "", promisePtr); - if (delayMilliSeconds > 0) { - TimerPtr timerPtr(new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(delayMilliSeconds))); + if (delayMilliseconds > 0) { + TimerPtr timerPtr(new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(delayMilliseconds))); timerPtr->async_wait([that = shared_from_this(), request, req, retry, eventQueuePtr](ErrorCode const& ec) mutable { if (ec) { CCAPI_LOGGER_ERROR("request = " + toString(request) + ", sendRequest timer error: " + ec.message()); @@ -341,7 +341,7 @@ class Service : public std::enable_shared_from_this { return std::static_pointer_cast(shared_from_this()); } void sendRequest(const http::request& req, std::function errorHandler, - std::function&)> responseHandler, long timeoutMilliSeconds) { + std::function&)> responseHandler, long timeoutMilliseconds) { #if defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) std::ostringstream oss; oss << req; @@ -358,11 +358,11 @@ class Service : public std::enable_shared_from_this { } std::shared_ptr httpConnectionPtr(new HttpConnection(this->hostRest, this->portRest, streamPtr)); CCAPI_LOGGER_DEBUG("httpConnection = " + toString(*httpConnectionPtr)); - this->startConnect(httpConnectionPtr, req, errorHandler, responseHandler, timeoutMilliSeconds, this->tcpResolverResultsRest); + this->startConnect(httpConnectionPtr, req, errorHandler, responseHandler, timeoutMilliseconds, this->tcpResolverResultsRest); } void sendRequest(const std::string& host, const std::string& port, const http::request& req, std::function errorHandler, std::function&)> responseHandler, - long timeoutMilliSeconds) { + long timeoutMilliseconds) { #if defined(CCAPI_ENABLE_LOG_DEBUG) || defined(CCAPI_ENABLE_LOG_TRACE) std::ostringstream oss; oss << req; @@ -383,24 +383,24 @@ class Service : public std::enable_shared_from_this { CCAPI_LOGGER_TRACE("port = " + port); newResolverPtr->async_resolve(host, port, beast::bind_front_handler(&Service::onResolve, shared_from_this(), httpConnectionPtr, newResolverPtr, req, errorHandler, - responseHandler, timeoutMilliSeconds)); + responseHandler, timeoutMilliseconds)); } void onResolve(std::shared_ptr httpConnectionPtr, std::shared_ptr newResolverPtr, http::request req, std::function errorHandler, std::function&)> responseHandler, - long timeoutMilliSeconds, beast::error_code ec, tcp::resolver::results_type tcpNewResolverResults) { + long timeoutMilliseconds, beast::error_code ec, tcp::resolver::results_type tcpNewResolverResults) { if (ec) { CCAPI_LOGGER_TRACE("fail"); errorHandler(ec); return; } - this->startConnect(httpConnectionPtr, req, errorHandler, responseHandler, timeoutMilliSeconds, tcpNewResolverResults); + this->startConnect(httpConnectionPtr, req, errorHandler, responseHandler, timeoutMilliseconds, tcpNewResolverResults); } void startConnect(std::shared_ptr httpConnectionPtr, http::request req, std::function errorHandler, std::function&)> responseHandler, - long timeoutMilliSeconds, tcp::resolver::results_type tcpNewResolverResults) { + long timeoutMilliseconds, tcp::resolver::results_type tcpNewResolverResults) { beast::ssl_stream& stream = *httpConnectionPtr->streamPtr; - if (timeoutMilliSeconds > 0) { - beast::get_lowest_layer(stream).expires_after(std::chrono::milliseconds(timeoutMilliSeconds)); + if (timeoutMilliseconds > 0) { + beast::get_lowest_layer(stream).expires_after(std::chrono::milliseconds(timeoutMilliseconds)); } CCAPI_LOGGER_TRACE("before async_connect"); beast::get_lowest_layer(stream).async_connect( @@ -526,9 +526,9 @@ class Service : public std::enable_shared_from_this { CCAPI_LOGGER_DEBUG("httpConnection = " + toString(*httpConnectionPtr)); CCAPI_LOGGER_DEBUG("retry = " + toString(retry)); beast::ssl_stream& stream = *httpConnectionPtr->streamPtr; - CCAPI_LOGGER_DEBUG("this->sessionOptions.httpRequestTimeoutMilliSeconds = " + toString(this->sessionOptions.httpRequestTimeoutMilliSeconds)); - if (this->sessionOptions.httpRequestTimeoutMilliSeconds > 0) { - beast::get_lowest_layer(stream).expires_after(std::chrono::milliseconds(this->sessionOptions.httpRequestTimeoutMilliSeconds)); + CCAPI_LOGGER_DEBUG("this->sessionOptions.httpRequestTimeoutMilliseconds = " + toString(this->sessionOptions.httpRequestTimeoutMilliseconds)); + if (this->sessionOptions.httpRequestTimeoutMilliseconds > 0) { + beast::get_lowest_layer(stream).expires_after(std::chrono::milliseconds(this->sessionOptions.httpRequestTimeoutMilliseconds)); } CCAPI_LOGGER_TRACE("before async_connect"); beast::get_lowest_layer(stream).async_connect( @@ -569,8 +569,8 @@ class Service : public std::enable_shared_from_this { void startWrite_2(std::shared_ptr httpConnectionPtr, Request request, http::request req, HttpRetry retry, Queue* eventQueuePtr) { beast::ssl_stream& stream = *httpConnectionPtr->streamPtr; - if (this->sessionOptions.httpRequestTimeoutMilliSeconds > 0) { - beast::get_lowest_layer(stream).expires_after(std::chrono::milliseconds(this->sessionOptions.httpRequestTimeoutMilliSeconds)); + if (this->sessionOptions.httpRequestTimeoutMilliseconds > 0) { + beast::get_lowest_layer(stream).expires_after(std::chrono::milliseconds(this->sessionOptions.httpRequestTimeoutMilliseconds)); } std::shared_ptr> reqPtr(new http::request(std::move(req))); CCAPI_LOGGER_TRACE("before async_write"); @@ -610,7 +610,7 @@ class Service : public std::enable_shared_from_this { that->onError(Event::Type::SESSION_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { if (std::chrono::duration_cast(now - that->lastHttpConnectionPoolPushBackTp).count() > - that->sessionOptions.httpConnectionPoolIdleTimeoutMilliSeconds) { + that->sessionOptions.httpConnectionPoolIdleTimeoutMilliseconds) { that->httpConnectionPool.purge(); } that->setHttpConnectionPoolPurgeTimer(); @@ -637,7 +637,7 @@ class Service : public std::enable_shared_from_this { if (!this->sessionOptions.enableOneHttpConnectionPerRequest) { try { if (std::chrono::duration_cast(this->lastHttpConnectionPoolPushBackTp.time_since_epoch()).count() == 0 && - this->sessionOptions.httpConnectionPoolIdleTimeoutMilliSeconds > 0) { + this->sessionOptions.httpConnectionPoolIdleTimeoutMilliseconds > 0) { this->setHttpConnectionPoolPurgeTimer(); } this->httpConnectionPool.pushBack(std::move(httpConnectionPtr)); @@ -1114,11 +1114,11 @@ class Service : public std::enable_shared_from_this { std::function pingMethod) { CCAPI_LOGGER_FUNCTION_ENTER; CCAPI_LOGGER_TRACE("method = " + pingPongMethodToString(method)); - auto pingIntervalMilliSeconds = this->pingIntervalMilliSecondsByMethodMap[method]; - auto pongTimeoutMilliSeconds = this->pongTimeoutMilliSecondsByMethodMap[method]; - CCAPI_LOGGER_TRACE("pingIntervalMilliSeconds = " + toString(pingIntervalMilliSeconds)); - CCAPI_LOGGER_TRACE("pongTimeoutMilliSeconds = " + toString(pongTimeoutMilliSeconds)); - if (pingIntervalMilliSeconds <= pongTimeoutMilliSeconds) { + auto pingIntervalMilliseconds = this->pingIntervalMillisecondsByMethodMap[method]; + auto pongTimeoutMilliseconds = this->pongTimeoutMillisecondsByMethodMap[method]; + CCAPI_LOGGER_TRACE("pingIntervalMilliseconds = " + toString(pingIntervalMilliseconds)); + CCAPI_LOGGER_TRACE("pongTimeoutMilliseconds = " + toString(pongTimeoutMilliseconds)); + if (pingIntervalMilliseconds <= pongTimeoutMilliseconds) { return; } if (wsConnection.status == WsConnection::Status::OPEN) { @@ -1127,8 +1127,8 @@ class Service : public std::enable_shared_from_this { this->pingTimerByMethodByConnectionIdMap.at(wsConnection.id).at(method)->cancel(); } TimerPtr timerPtr( - new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pingIntervalMilliSeconds - pongTimeoutMilliSeconds))); - timerPtr->async_wait([wsConnection, that = shared_from_this(), hdl, pingMethod, pongTimeoutMilliSeconds, method](ErrorCode const& ec) { + new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pingIntervalMilliseconds - pongTimeoutMilliseconds))); + timerPtr->async_wait([wsConnection, that = shared_from_this(), hdl, pingMethod, pongTimeoutMilliseconds, method](ErrorCode const& ec) { if (that->wsConnectionByIdMap.find(wsConnection.id) != that->wsConnectionByIdMap.end()) { if (ec) { CCAPI_LOGGER_ERROR("wsConnection = " + toString(wsConnection) + ", ping timer error: " + ec.message()); @@ -1140,7 +1140,7 @@ class Service : public std::enable_shared_from_this { if (ec) { that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "ping"); } - if (pongTimeoutMilliSeconds <= 0) { + if (pongTimeoutMilliseconds <= 0) { return; } if (that->pongTimeOutTimerByMethodByConnectionIdMap.find(wsConnection.id) != that->pongTimeOutTimerByMethodByConnectionIdMap.end() && @@ -1148,8 +1148,8 @@ class Service : public std::enable_shared_from_this { that->pongTimeOutTimerByMethodByConnectionIdMap.at(wsConnection.id).end()) { that->pongTimeOutTimerByMethodByConnectionIdMap.at(wsConnection.id).at(method)->cancel(); } - TimerPtr timerPtr(new boost::asio::steady_timer(*that->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pongTimeoutMilliSeconds))); - timerPtr->async_wait([wsConnection, that, hdl, pingMethod, pongTimeoutMilliSeconds, method](ErrorCode const& ec) { + TimerPtr timerPtr(new boost::asio::steady_timer(*that->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pongTimeoutMilliseconds))); + timerPtr->async_wait([wsConnection, that, hdl, pingMethod, pongTimeoutMilliseconds, method](ErrorCode const& ec) { if (that->wsConnectionByIdMap.find(wsConnection.id) != that->wsConnectionByIdMap.end()) { if (ec) { CCAPI_LOGGER_ERROR("wsConnection = " + toString(wsConnection) + ", pong time out timer error: " + ec.message()); @@ -1161,7 +1161,7 @@ class Service : public std::enable_shared_from_this { that->lastPongTpByMethodByConnectionIdMap.at(wsConnection.id).find(method) != that->lastPongTpByMethodByConnectionIdMap.at(wsConnection.id).end() && std::chrono::duration_cast(now - that->lastPongTpByMethodByConnectionIdMap.at(wsConnection.id).at(method)) - .count() >= pongTimeoutMilliSeconds) { + .count() >= pongTimeoutMilliseconds) { auto thisWsConnection = wsConnection; ErrorCode ec; that->close(thisWsConnection, hdl, websocketpp::close::status::normal, "pong timeout", ec); @@ -1227,12 +1227,12 @@ class Service : public std::enable_shared_from_this { this->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::SUBSCRIPTION_FAILURE, ec, "dns resolve", wsConnectionPtr->correlationIdList); return; } - this->startConnectWs(wsConnectionPtr, this->sessionOptions.websocketConnectTimeoutMilliSeconds, tcpNewResolverResultsWs); + this->startConnectWs(wsConnectionPtr, this->sessionOptions.websocketConnectTimeoutMilliseconds, tcpNewResolverResultsWs); } - void startConnectWs(std::shared_ptr wsConnectionPtr, long timeoutMilliSeconds, tcp::resolver::results_type tcpResolverResults) { + void startConnectWs(std::shared_ptr wsConnectionPtr, long timeoutMilliseconds, tcp::resolver::results_type tcpResolverResults) { beast::websocket::stream>& stream = *wsConnectionPtr->streamPtr; - if (timeoutMilliSeconds > 0) { - beast::get_lowest_layer(stream).expires_after(std::chrono::milliseconds(timeoutMilliSeconds)); + if (timeoutMilliseconds > 0) { + beast::get_lowest_layer(stream).expires_after(std::chrono::milliseconds(timeoutMilliseconds)); } // Set SNI Hostname (many hosts need this to handshake successfully) CCAPI_LOGGER_TRACE("wsConnectionPtr->host = " + wsConnectionPtr->host) @@ -1274,8 +1274,8 @@ class Service : public std::enable_shared_from_this { CCAPI_LOGGER_TRACE("ssl handshaked"); beast::websocket::stream>& stream = *wsConnectionPtr->streamPtr; beast::get_lowest_layer(stream).expires_never(); - beast::websocket::stream_base::timeout opt{std::chrono::milliseconds(this->sessionOptions.websocketConnectTimeoutMilliSeconds), - std::chrono::milliseconds(this->sessionOptions.pongWebsocketProtocolLevelTimeoutMilliSeconds), true}; + beast::websocket::stream_base::timeout opt{std::chrono::milliseconds(this->sessionOptions.websocketConnectTimeoutMilliseconds), + std::chrono::milliseconds(this->sessionOptions.pongWebsocketProtocolLevelTimeoutMilliseconds), true}; stream.set_option(opt); stream.set_option(beast::websocket::stream_base::decorator([wsConnectionPtr](beast::websocket::request_type& req) { @@ -1642,11 +1642,11 @@ class Service : public std::enable_shared_from_this { void setPingPongTimer(PingPongMethod method, std::shared_ptr wsConnectionPtr, std::function pingMethod) { CCAPI_LOGGER_FUNCTION_ENTER; CCAPI_LOGGER_TRACE("method = " + pingPongMethodToString(method)); - auto pingIntervalMilliSeconds = this->pingIntervalMilliSecondsByMethodMap[method]; - auto pongTimeoutMilliSeconds = this->pongTimeoutMilliSecondsByMethodMap[method]; - CCAPI_LOGGER_TRACE("pingIntervalMilliSeconds = " + toString(pingIntervalMilliSeconds)); - CCAPI_LOGGER_TRACE("pongTimeoutMilliSeconds = " + toString(pongTimeoutMilliSeconds)); - if (pingIntervalMilliSeconds <= pongTimeoutMilliSeconds) { + auto pingIntervalMilliseconds = this->pingIntervalMillisecondsByMethodMap[method]; + auto pongTimeoutMilliseconds = this->pongTimeoutMillisecondsByMethodMap[method]; + CCAPI_LOGGER_TRACE("pingIntervalMilliseconds = " + toString(pingIntervalMilliseconds)); + CCAPI_LOGGER_TRACE("pongTimeoutMilliseconds = " + toString(pongTimeoutMilliseconds)); + if (pingIntervalMilliseconds <= pongTimeoutMilliseconds) { return; } WsConnection& wsConnection = *wsConnectionPtr; @@ -1656,8 +1656,8 @@ class Service : public std::enable_shared_from_this { this->pingTimerByMethodByConnectionIdMap.at(wsConnection.id).at(method)->cancel(); } TimerPtr timerPtr( - new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pingIntervalMilliSeconds - pongTimeoutMilliSeconds))); - timerPtr->async_wait([wsConnectionPtr, that = shared_from_this(), pingMethod, pongTimeoutMilliSeconds, method](ErrorCode const& ec) { + new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pingIntervalMilliseconds - pongTimeoutMilliseconds))); + timerPtr->async_wait([wsConnectionPtr, that = shared_from_this(), pingMethod, pongTimeoutMilliseconds, method](ErrorCode const& ec) { WsConnection& wsConnection = *wsConnectionPtr; if (that->wsConnectionByIdMap.find(wsConnection.id) != that->wsConnectionByIdMap.end()) { if (ec) { @@ -1670,7 +1670,7 @@ class Service : public std::enable_shared_from_this { if (ec) { that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "ping"); } - if (pongTimeoutMilliSeconds <= 0) { + if (pongTimeoutMilliseconds <= 0) { return; } if (that->pongTimeOutTimerByMethodByConnectionIdMap.find(wsConnection.id) != that->pongTimeOutTimerByMethodByConnectionIdMap.end() && @@ -1678,8 +1678,8 @@ class Service : public std::enable_shared_from_this { that->pongTimeOutTimerByMethodByConnectionIdMap.at(wsConnection.id).end()) { that->pongTimeOutTimerByMethodByConnectionIdMap.at(wsConnection.id).at(method)->cancel(); } - TimerPtr timerPtr(new boost::asio::steady_timer(*that->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pongTimeoutMilliSeconds))); - timerPtr->async_wait([wsConnectionPtr, that, pingMethod, pongTimeoutMilliSeconds, method](ErrorCode const& ec) { + TimerPtr timerPtr(new boost::asio::steady_timer(*that->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(pongTimeoutMilliseconds))); + timerPtr->async_wait([wsConnectionPtr, that, pingMethod, pongTimeoutMilliseconds, method](ErrorCode const& ec) { WsConnection& wsConnection = *wsConnectionPtr; if (that->wsConnectionByIdMap.find(wsConnection.id) != that->wsConnectionByIdMap.end()) { if (ec) { @@ -1692,7 +1692,7 @@ class Service : public std::enable_shared_from_this { that->lastPongTpByMethodByConnectionIdMap.at(wsConnection.id).find(method) != that->lastPongTpByMethodByConnectionIdMap.at(wsConnection.id).end() && std::chrono::duration_cast(now - that->lastPongTpByMethodByConnectionIdMap.at(wsConnection.id).at(method)) - .count() >= pongTimeoutMilliSeconds) { + .count() >= pongTimeoutMilliseconds) { auto thisWsConnectionPtr = wsConnectionPtr; ErrorCode ec; that->close(thisWsConnectionPtr, beast::websocket::close_code::normal, @@ -1718,6 +1718,14 @@ class Service : public std::enable_shared_from_this { } CCAPI_LOGGER_FUNCTION_EXIT; } + std::string convertParamTimeSecondsToTimeMilliseconds(const std::string& input) { + auto dotPosition = input.find('.'); + if (dotPosition == std::string::npos) { + return std::to_string(std::stoll(input) * 1000); + } else { + } + return std::to_string(std::stoll(input.substr(0, dotPosition)) * 1000 + std::stoll(UtilString::rightPadTo(input.substr(dotPosition + 1, 3), 3, '0'))); + } virtual void onTextMessage(std::shared_ptr wsConnectionPtr, boost::beast::string_view textMessage, const TimePoint& timeReceived) {} #endif bool hostHttpHeaderValueIgnorePort{}; @@ -1757,8 +1765,8 @@ class Service : public std::enable_shared_from_this { std::map> lastPongTpByMethodByConnectionIdMap; std::map> pingTimerByMethodByConnectionIdMap; std::map> pongTimeOutTimerByMethodByConnectionIdMap; - std::map pingIntervalMilliSecondsByMethodMap; - std::map pongTimeoutMilliSecondsByMethodMap; + std::map pingIntervalMillisecondsByMethodMap; + std::map pongTimeoutMillisecondsByMethodMap; std::atomic shouldContinue{true}; std::map> extraPropertyByConnectionIdMap; bool enableCheckPingPongWebsocketProtocolLevel{}; From a4c4d8ef568eaf6513698d9769781368f3c14525 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Tue, 3 Oct 2023 07:27:09 -0700 Subject: [PATCH 3/5] feat: add draft for rest query for trades, candlesticks, and market depth - kucoin --- example/src/fix_advanced/main.cpp | 4 +- .../ccapi_market_data_service_kucoin.h | 4 + .../ccapi_market_data_service_kucoin_base.h | 109 +++++++++++++++++- ...ccapi_market_data_service_kucoin_futures.h | 4 + 4 files changed, 117 insertions(+), 4 deletions(-) diff --git a/example/src/fix_advanced/main.cpp b/example/src/fix_advanced/main.cpp index 045623d4..f5655bc6 100644 --- a/example/src/fix_advanced/main.cpp +++ b/example/src/fix_advanced/main.cpp @@ -48,8 +48,8 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } SessionOptions sessionOptions; - sessionOptions.heartbeatFixIntervalMilliSeconds = 30000; // Note the unit is millisecond - sessionOptions.heartbeatFixTimeoutMilliSeconds = 5000; // Note the unit is millisecond, should be less than heartbeatFixIntervalMilliSeconds + sessionOptions.heartbeatFixIntervalMilliseconds = 30000; // Note the unit is millisecond + sessionOptions.heartbeatFixTimeoutMilliseconds = 5000; // Note the unit is millisecond, should be less than heartbeatFixIntervalMilliseconds SessionConfigs sessionConfigs; MyEventHandler eventHandler; Session session(sessionOptions, sessionConfigs, &eventHandler); 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 aea25e87..6f63c087 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin.h @@ -32,6 +32,10 @@ class MarketDataServiceKucoin : public MarketDataServiceKucoinBase { this->apiPassphraseName = CCAPI_KUCOIN_API_PASSPHRASE; this->setupCredential({this->apiKeyName, this->apiSecretName, this->apiPassphraseName}); this->getRecentTradesTarget = "/api/v1/market/histories"; + this->getHistoricalTradesTarget = "/api/v1/market/histories"; + this->getRecentCandlesticksTarget = "/api/v1/market/candles"; + this->getHistoricalCandlesticksTarget = "/api/v1/market/candles"; + this->getMarketDepthTarget = "/api/v1/market/orderbook/level2"; this->getInstrumentTarget = "/api/v1/symbols"; this->getInstrumentsTarget = "/api/v1/symbols"; this->channelMarketTicker = CCAPI_WEBSOCKET_KUCOIN_CHANNEL_MARKET_TICKER; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_base.h b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_base.h index 9421f84f..ca53f782 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_base.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_base.h @@ -502,7 +502,8 @@ class MarketDataServiceKucoinBase : public MarketDataService { case Request::Operation::GENERIC_PUBLIC_REQUEST: { MarketDataService::convertRequestForRestGenericPublicRequest(req, request, now, symbolId, credential); } break; - case Request::Operation::GET_RECENT_TRADES: { + case Request::Operation::GET_RECENT_TRADES: + case Request::Operation::GET_HISTORICAL_TRADES: { req.method(http::verb::get); auto target = this->getRecentTradesTarget; std::string queryString; @@ -510,6 +511,63 @@ class MarketDataServiceKucoinBase : public MarketDataService { this->appendSymbolId(queryString, symbolId, "symbol"); req.target(target + "?" + queryString); } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + req.method(http::verb::get); + auto target = this->getRecentCandlesticksTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + if (this->isDerivatives) { + this->appendParam(queryString, param, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, "granularity"}, + {CCAPI_START_TIME_SECONDS, "from"}, + {CCAPI_END_TIME_SECONDS, "to"}, + }, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, [that = shared_from_base()]( + const std::string& input) { return std::to_string(std::stoi(input) / 60); }}, + {CCAPI_START_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + {CCAPI_END_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + }); + } else { + this->appendParam(queryString, param, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, "type"}, + {CCAPI_START_TIME_SECONDS, "startAt"}, + {CCAPI_END_TIME_SECONDS, "endAt"}, + }, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, + [that = shared_from_base()](const std::string& input) { + return that->convertCandlestickIntervalSecondsToInterval(std::stoi(input), "", "min", "hour", "day", "week"); + }}, + }); + } + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; + case Request::Operation::GET_MARKET_DEPTH: { + req.method(http::verb::get); + auto target = this->getMarketDepthTarget; + ; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendSymbolId(queryString, symbolId, "symbol"); + std::string maxMarketDepthStr = mapGetWithDefault(param, std::string(CCAPI_MARKET_DEPTH_MAX)); + if (maxMarketDepthStr.empty()) { + if (this->isDerivatives) { + std::string toReplace = "depth"; + target.replace(target.find(toReplace), toReplace.length(), "snapshot"); + } + } else { + target = this->getMarketDepthTarget + (this->isDerivatives ? "" : "_") + + std::to_string(this->calculateMarketDepthAllowedByExchange(std::stoi(maxMarketDepthStr), std::vector({20, 100}))); + } + req.target(target + "?" + queryString); + } break; case Request::Operation::GET_INSTRUMENT: { req.method(http::verb::get); auto target = this->getInstrumentTarget; @@ -529,7 +587,8 @@ class MarketDataServiceKucoinBase : public MarketDataService { rj::Document document; document.Parse(textMessage.c_str()); switch (request.getOperation()) { - case Request::Operation::GET_RECENT_TRADES: { + case Request::Operation::GET_RECENT_TRADES: + case Request::Operation::GET_HISTORICAL_TRADES: { for (const auto& x : document["data"].GetArray()) { MarketDataMessage marketDataMessage; marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_TRADE; @@ -543,6 +602,52 @@ class MarketDataServiceKucoinBase : public MarketDataService { marketDataMessageList.emplace_back(std::move(marketDataMessage)); } } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + for (const auto& x : document["data"].GetArray()) { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_CANDLESTICK; + marketDataMessage.tp = this->isDerivatives ? TimePoint(std::chrono::milliseconds(std::stoll(x[0].GetString()))) + : TimePoint(std::chrono::seconds(std::stoll(x[0].GetString()))); + MarketDataMessage::TypeForDataPoint dataPoint; + if (this->isDerivatives) { + dataPoint.insert({MarketDataMessage::DataFieldType::OPEN_PRICE, std::string(x[1].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::HIGH_PRICE, std::string(x[2].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::LOW_PRICE, std::string(x[3].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::CLOSE_PRICE, std::string(x[4].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::VOLUME, std::string(x[5].GetString())}); + } else { + dataPoint.insert({MarketDataMessage::DataFieldType::OPEN_PRICE, std::string(x[1].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::HIGH_PRICE, std::string(x[3].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::LOW_PRICE, std::string(x[4].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::CLOSE_PRICE, std::string(x[2].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::VOLUME, std::string(x[5].GetString())}); + dataPoint.insert({MarketDataMessage::DataFieldType::QUOTE_VOLUME, std::string(x[6].GetString())}); + } + marketDataMessage.data[MarketDataMessage::DataType::CANDLESTICK].emplace_back(std::move(dataPoint)); + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } + } break; + case Request::Operation::GET_MARKET_DEPTH: { + const rj::Value& data = document["data"]; + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_MARKET_DEPTH; + marketDataMessage.tp = this->isDerivatives ? TimePoint(std::chrono::nanoseconds(std::stoll(data["ts"].GetString()))) + : TimePoint(std::chrono::milliseconds(std::stoll(data["time"].GetString()))); + for (const auto& x : data["bids"].GetArray()) { + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint)); + } + for (const auto& x : data["asks"].GetArray()) { + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint)); + } + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } break; case Request::Operation::GET_INSTRUMENT: { Message message; message.setTimeReceived(timeReceived); diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_futures.h b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_futures.h index 3a82feeb..29fc56be 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_futures.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_kucoin_futures.h @@ -28,6 +28,10 @@ class MarketDataServiceKucoinFutures : public MarketDataServiceKucoinBase { // } // #endif this->getRecentTradesTarget = "/api/v1/trade/history"; + this->getHistoricalTradesTarget = "/api/v1/trade/history"; + this->getRecentCandlesticksTarget = "/api/v1/kline/query"; + this->getHistoricalCandlesticksTarget = "/api/v1/kline/query"; + this->getMarketDepthTarget = "/api/v1/level2/depth"; this->getInstrumentTarget = "/api/v1/contracts/active"; this->getInstrumentsTarget = "/api/v1/contracts/active"; this->isDerivatives = true; From 8a6896992df247aa08193264b3cdea629e78ca53 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Fri, 6 Oct 2023 14:10:34 -0700 Subject: [PATCH 4/5] feat: add draft for rest query for trades, candlesticks, and market depth - bybit --- app/src/single_order_execution/main.cpp | 2 +- .../service/ccapi_market_data_service_bybit.h | 83 ++++++++++++- ...pi_market_data_service_bybit_derivatives.h | 113 ++++++++++++++++-- .../service/ccapi_market_data_service_okx.h | 9 -- 4 files changed, 185 insertions(+), 22 deletions(-) diff --git a/app/src/single_order_execution/main.cpp b/app/src/single_order_execution/main.cpp index cea1444c..928118f3 100644 --- a/app/src/single_order_execution/main.cpp +++ b/app/src/single_order_execution/main.cpp @@ -132,7 +132,7 @@ int main(int argc, char** argv) { eventHandler.promisePtr = promisePtr; #ifndef CCAPI_APP_IS_BACKTEST SessionOptions sessionOptions; - sessionOptions.httpConnectionPoolIdleTimeoutMilliSeconds = 1; + sessionOptions.httpConnectionPoolIdleTimeoutMilliseconds = 1; sessionOptions.httpMaxNumRetry = 0; sessionOptions.httpMaxNumRedirect = 0; SessionConfigs sessionConfigs; diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bybit.h b/include/ccapi_cpp/service/ccapi_market_data_service_bybit.h index 1db33737..7f678eaf 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bybit.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bybit.h @@ -28,6 +28,10 @@ class MarketDataServiceBybit : public MarketDataServiceBybitBase { } #endif this->getRecentTradesTarget = "/spot/v3/public/quote/trades"; + this->getHistoricalTradesTarget = "/spot/v3/public/quote/trades"; + this->getRecentCandlesticksTarget = "/spot/v3/public/quote/kline"; + this->getHistoricalCandlesticksTarget = "/spot/v3/public/quote/kline"; + this->getMarketDepthTarget = "/spot/v3/public/quote/depth"; this->getInstrumentsTarget = "/spot/v3/public/symbols"; } virtual ~MarketDataServiceBybit() {} @@ -232,7 +236,8 @@ class MarketDataServiceBybit : public MarketDataServiceBybitBase { case Request::Operation::GENERIC_PUBLIC_REQUEST: { MarketDataService::convertRequestForRestGenericPublicRequest(req, request, now, symbolId, credential); } break; - case Request::Operation::GET_RECENT_TRADES: { + case Request::Operation::GET_RECENT_TRADES: + case Request::Operation::GET_HISTORICAL_TRADES: { req.method(http::verb::get); auto target = this->getRecentTradesTarget; std::string queryString; @@ -244,6 +249,44 @@ class MarketDataServiceBybit : public MarketDataServiceBybitBase { this->appendSymbolId(queryString, symbolId, "symbol"); req.target(target + "?" + queryString); } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + req.method(http::verb::get); + auto target = this->getRecentCandlesticksTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, "interval"}, + {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TIME_SECONDS, "startTime"}, + {CCAPI_END_TIME_SECONDS, "endTime"}, + }, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, + [that = shared_from_base()](const std::string& input) { + return that->convertCandlestickIntervalSecondsToInterval(std::stoi(input), "", "m", "h", "d", "w"); + }}, + {CCAPI_START_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + {CCAPI_END_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + }); + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; + case Request::Operation::GET_MARKET_DEPTH: { + req.method(http::verb::get); + auto target = this->getMarketDepthTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_LIMIT, "limit"}, + }); + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; case Request::Operation::GET_INSTRUMENT: { req.method(http::verb::get); auto target = this->getInstrumentsTarget; @@ -272,7 +315,8 @@ class MarketDataServiceBybit : public MarketDataServiceBybitBase { rj::Document document; document.Parse(textMessage.c_str()); switch (request.getOperation()) { - case Request::Operation::GET_RECENT_TRADES: { + case Request::Operation::GET_RECENT_TRADES: + case Request::Operation::GET_HISTORICAL_TRADES: { for (const auto& x : document["result"]["list"].GetArray()) { MarketDataMessage marketDataMessage; marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_TRADE; @@ -285,6 +329,41 @@ class MarketDataServiceBybit : public MarketDataServiceBybitBase { marketDataMessageList.emplace_back(std::move(marketDataMessage)); } } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + for (const auto& x : document["result"]["list"].GetArray()) { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_CANDLESTICK; + marketDataMessage.tp = UtilTime::makeTimePointFromMilliseconds(std::stoll(x["t"].GetString())); + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::OPEN_PRICE, x["o"].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::HIGH_PRICE, x["h"].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::LOW_PRICE, x["l"].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::CLOSE_PRICE, x["c"].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::VOLUME, x["v"].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::CANDLESTICK].emplace_back(std::move(dataPoint)); + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } + } break; + case Request::Operation::GET_MARKET_DEPTH: { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_MARKET_DEPTH; + const rj::Value& result = document["result"]; + marketDataMessage.tp = UtilTime::makeTimePointFromMilliseconds(std::stoll(result["time"].GetString())); + for (const auto& x : result["bids"].GetArray()) { + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint)); + } + for (const auto& x : result["asks"].GetArray()) { + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint)); + } + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } break; case Request::Operation::GET_INSTRUMENT: { Message message; message.setTimeReceived(timeReceived); diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_bybit_derivatives.h b/include/ccapi_cpp/service/ccapi_market_data_service_bybit_derivatives.h index 13d4c41e..f59fba9a 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_bybit_derivatives.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_bybit_derivatives.h @@ -28,6 +28,10 @@ class MarketDataServiceBybitDerivatives : public MarketDataServiceBybitBase { } #endif this->getRecentTradesTarget = "/derivatives/v3/public/recent-trade"; + this->getHistoricalTradesTarget = "/derivatives/v3/public/recent-trade"; + this->getRecentCandlesticksTarget = "/derivatives/v3/public/kline"; + this->getHistoricalCandlesticksTarget = "/derivatives/v3/public/kline"; + this->getMarketDepthTarget = "/derivatives/v3/public/order-book/L2"; this->getInstrumentTarget = "/derivatives/v3/public/instruments-info"; this->getInstrumentsTarget = "/derivatives/v3/public/instruments-info"; } @@ -51,6 +55,17 @@ class MarketDataServiceBybitDerivatives : public MarketDataServiceBybitBase { url.replace(url.find(toReplace), toReplace.length(), instrumentTypeSubstitute); return url; } + std::string convertCandlestickIntervalSecondsToInterval(int intervalSeconds) { + std::string interval; + if (intervalSeconds < 86400) { + interval = std::to_string(intervalSeconds / 60); + } else if (intervalSeconds == 86400) { + interval = "D"; + } else { + interval = "W"; + } + return interval; + } void prepareSubscriptionDetail(std::string& channelId, std::string& symbolId, const std::string& field, const WsConnection& wsConnection, const Subscription& subscription, const std::map optionMap) override { const auto& marketDepthRequested = std::stoi(optionMap.at(CCAPI_MARKET_DEPTH_MAX)); @@ -67,15 +82,8 @@ class MarketDataServiceBybitDerivatives : public MarketDataServiceBybitBase { channelId += std::string("?") + CCAPI_MARKET_DEPTH_SUBSCRIBED_TO_EXCHANGE + "=" + std::to_string(marketDepthSubscribedToExchange); this->marketDepthSubscribedToExchangeByConnectionIdChannelIdSymbolIdMap[wsConnection.id][channelId][symbolId] = marketDepthSubscribedToExchange; } else if (field == CCAPI_CANDLESTICK) { - std::string interval; int intervalSeconds = std::stoi(optionMap.at(CCAPI_CANDLESTICK_INTERVAL_SECONDS)); - if (intervalSeconds < 86400) { - interval = std::to_string(intervalSeconds / 60); - } else if (intervalSeconds == 86400) { - interval = "D"; - } else { - interval = "W"; - } + std::string interval = this->convertCandlestickIntervalSecondsToInterval(intervalSeconds); std::string toReplace = "{interval}"; channelId.replace(channelId.find(toReplace), toReplace.length(), interval); } @@ -241,7 +249,8 @@ class MarketDataServiceBybitDerivatives : public MarketDataServiceBybitBase { case Request::Operation::GENERIC_PUBLIC_REQUEST: { MarketDataService::convertRequestForRestGenericPublicRequest(req, request, now, symbolId, credential); } break; - case Request::Operation::GET_RECENT_TRADES: { + case Request::Operation::GET_RECENT_TRADES: + case Request::Operation::GET_HISTORICAL_TRADES: { req.method(http::verb::get); auto target = this->getRecentTradesTarget; std::string queryString; @@ -253,6 +262,44 @@ class MarketDataServiceBybitDerivatives : public MarketDataServiceBybitBase { this->appendSymbolId(queryString, symbolId, "symbol"); req.target(target + "?" + queryString); } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + req.method(http::verb::get); + auto target = this->getRecentCandlesticksTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, "interval"}, + {CCAPI_LIMIT, "limit"}, + {CCAPI_START_TIME_SECONDS, "start"}, + {CCAPI_END_TIME_SECONDS, "end"}, + }, + { + {CCAPI_CANDLESTICK_INTERVAL_SECONDS, + [that = shared_from_base()](const std::string& input) { + return that->convertCandlestickIntervalSecondsToInterval(std::stoi(input)); + }}, + {CCAPI_START_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + {CCAPI_END_TIME_SECONDS, [that = shared_from_base()]( + const std::string& input) { return that->convertParamTimeSecondsToTimeMilliseconds(input); }}, + }); + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; + case Request::Operation::GET_MARKET_DEPTH: { + req.method(http::verb::get); + auto target = this->getMarketDepthTarget; + std::string queryString; + const std::map param = request.getFirstParamWithDefault(); + this->appendParam(queryString, param, + { + {CCAPI_LIMIT, "limit"}, + }); + this->appendSymbolId(queryString, symbolId, "symbol"); + req.target(target + "?" + queryString); + } break; case Request::Operation::GET_INSTRUMENT: { req.method(http::verb::get); auto target = this->getInstrumentTarget; @@ -299,7 +346,8 @@ class MarketDataServiceBybitDerivatives : public MarketDataServiceBybitBase { rj::Document document; document.Parse(textMessage.c_str()); switch (request.getOperation()) { - case Request::Operation::GET_RECENT_TRADES: { + case Request::Operation::GET_RECENT_TRADES: + case Request::Operation::GET_HISTORICAL_TRADES: { for (const auto& x : document["result"]["list"].GetArray()) { MarketDataMessage marketDataMessage; marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_TRADE; @@ -313,6 +361,51 @@ class MarketDataServiceBybitDerivatives : public MarketDataServiceBybitBase { marketDataMessageList.emplace_back(std::move(marketDataMessage)); } } break; + case Request::Operation::GET_RECENT_CANDLESTICKS: + case Request::Operation::GET_HISTORICAL_CANDLESTICKS: { + for (const auto& x : document["result"]["list"].GetArray()) { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_CANDLESTICK; + marketDataMessage.tp = UtilTime::makeTimePointFromMilliseconds(std::stoll(x[0].GetString())); + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::OPEN_PRICE, x[1].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::HIGH_PRICE, x[2].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::LOW_PRICE, x[3].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::CLOSE_PRICE, x[4].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::VOLUME, x[5].GetString()}); + dataPoint.insert({MarketDataMessage::DataFieldType::QUOTE_VOLUME, x[6].GetString()}); + marketDataMessage.data[MarketDataMessage::DataType::CANDLESTICK].emplace_back(std::move(dataPoint)); + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } + } break; + case Request::Operation::GET_MARKET_DEPTH: { + MarketDataMessage marketDataMessage; + marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_MARKET_DEPTH; + CCAPI_LOGGER_TRACE(""); + const rj::Value& result = document["result"]; + CCAPI_LOGGER_TRACE(""); + marketDataMessage.tp = UtilTime::makeTimePointFromMilliseconds(std::stoll(result["ts"].GetString())); + CCAPI_LOGGER_TRACE(""); + for (const auto& x : result["b"].GetArray()) { + CCAPI_LOGGER_TRACE(""); + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + CCAPI_LOGGER_TRACE(""); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + CCAPI_LOGGER_TRACE(""); + marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint)); + } + for (const auto& x : result["a"].GetArray()) { + CCAPI_LOGGER_TRACE(""); + MarketDataMessage::TypeForDataPoint dataPoint; + dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); + CCAPI_LOGGER_TRACE(""); + dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); + CCAPI_LOGGER_TRACE(""); + marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint)); + } + marketDataMessageList.emplace_back(std::move(marketDataMessage)); + } break; case Request::Operation::GET_INSTRUMENT: { Message message; message.setTimeReceived(timeReceived); diff --git a/include/ccapi_cpp/service/ccapi_market_data_service_okx.h b/include/ccapi_cpp/service/ccapi_market_data_service_okx.h index 00c3fbcb..6c816677 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service_okx.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service_okx.h @@ -446,27 +446,18 @@ class MarketDataServiceOkx : public MarketDataService { case Request::Operation::GET_MARKET_DEPTH: { MarketDataMessage marketDataMessage; marketDataMessage.type = MarketDataMessage::Type::MARKET_DATA_EVENTS_MARKET_DEPTH; - CCAPI_LOGGER_DEBUG(""); const rj::Value& data = document["data"][0]; - CCAPI_LOGGER_DEBUG(""); marketDataMessage.tp = UtilTime::makeTimePointFromMilliseconds(std::stoll(data["ts"].GetString())); - CCAPI_LOGGER_DEBUG(""); for (const auto& x : data["bids"].GetArray()) { - CCAPI_LOGGER_DEBUG(""); MarketDataMessage::TypeForDataPoint dataPoint; dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); - CCAPI_LOGGER_DEBUG(""); dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); - CCAPI_LOGGER_DEBUG(""); marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint)); } for (const auto& x : data["asks"].GetArray()) { - CCAPI_LOGGER_DEBUG(""); MarketDataMessage::TypeForDataPoint dataPoint; dataPoint.insert({MarketDataMessage::DataFieldType::PRICE, x[0].GetString()}); - CCAPI_LOGGER_DEBUG(""); dataPoint.insert({MarketDataMessage::DataFieldType::SIZE, x[1].GetString()}); - CCAPI_LOGGER_DEBUG(""); marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint)); } marketDataMessageList.emplace_back(std::move(marketDataMessage)); From 5c240db24d30b52c7132114fd71020c43e73b4e1 Mon Sep 17 00:00:00 2001 From: Crypto Chassis Date: Fri, 6 Oct 2023 14:31:05 -0700 Subject: [PATCH 5/5] ci: correct typo --- app/src/spot_market_making/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/spot_market_making/main.cpp b/app/src/spot_market_making/main.cpp index 6f556444..7f79f08a 100644 --- a/app/src/spot_market_making/main.cpp +++ b/app/src/spot_market_making/main.cpp @@ -168,7 +168,7 @@ int main(int argc, char** argv) { eventHandler.promisePtr = promisePtr; #ifndef CCAPI_APP_IS_BACKTEST SessionOptions sessionOptions; - sessionOptions.httpConnectionPoolIdleTimeoutMilliSeconds = 1 + eventHandler.accountBalanceRefreshWaitSeconds; + sessionOptions.httpConnectionPoolIdleTimeoutMilliseconds = 1 + eventHandler.accountBalanceRefreshWaitSeconds; sessionOptions.httpMaxNumRetry = 0; sessionOptions.httpMaxNumRedirect = 0; SessionConfigs sessionConfigs;