From 8ee825e74ecc3b66930a3192ea873eb6aa13db76 Mon Sep 17 00:00:00 2001 From: ubuntu <> Date: Tue, 27 May 2025 17:16:20 +0000 Subject: [PATCH 01/17] fix: fix ServiceContext --- include/ccapi_cpp/ccapi_session.h | 171 +++++++++--------- include/ccapi_cpp/ccapi_session_options.h | 1 - .../ccapi_cpp/service/ccapi_service_context.h | 34 +++- 3 files changed, 107 insertions(+), 99 deletions(-) diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 4c38fa46..37f501c4 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -275,6 +275,7 @@ class Session { { if (!this->serviceContextPtr) { this->serviceContextPtr = new ServiceContext(); + this->useInternalServiceContextPtr = true; } CCAPI_LOGGER_FUNCTION_ENTER; #ifndef CCAPI_USE_SINGLE_THREAD @@ -300,312 +301,303 @@ class Session { delete this->eventDispatcher; } #endif - delete this->serviceContextPtr; + if (this->useInternalServiceContextPtr) { + delete this->serviceContextPtr; + } CCAPI_LOGGER_FUNCTION_EXIT; } virtual void start() { CCAPI_LOGGER_FUNCTION_ENTER; - std::thread t([this]() { - if (this->sessionOptions.cpuCoreIdOpt) { -#ifdef __linux__ - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - CPU_SET(*this->sessionOptions.cpuCoreIdOpt, &cpuset); - if (pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset) != 0) { - CCAPI_LOGGER_ERROR("pthread_setaffinity_np"); - } -#endif - } + if (this->useInternalServiceContextPtr) { this->serviceContextPtr->start(); - }); - this->t = std::move(t); - this->internalEventHandler = std::bind(&Session::onEvent, this, std::placeholders::_1, std::placeholders::_2); + } + this->onEventFunc = std::bind(&Session::onEvent, this, std::placeholders::_1, std::placeholders::_2); #ifdef CCAPI_ENABLE_SERVICE_MARKET_DATA #ifdef CCAPI_ENABLE_EXCHANGE_COINBASE this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_COINBASE] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_GEMINI this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_GEMINI] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_KRAKEN this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_KRAKEN] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_KRAKEN_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_KRAKEN_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITSTAMP this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITSTAMP] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITFINEX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITFINEX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITMEX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITMEX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BINANCE_US] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BINANCE] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_USDS_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BINANCE_USDS_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_COIN_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BINANCE_COIN_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_HUOBI this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_HUOBI] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_HUOBI_USDT_SWAP this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_HUOBI_USDT_SWAP] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_HUOBI_COIN_SWAP this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_HUOBI_COIN_SWAP] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_OKX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_OKX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_ERISX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_ERISX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_KUCOIN this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_KUCOIN] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_KUCOIN_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_KUCOIN_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_FTX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_FTX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_FTX_US this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_FTX_US] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_DERIBIT this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_DERIBIT] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_GATEIO this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_GATEIO] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_GATEIO_PERPETUAL_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_GATEIO_PERPETUAL_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_CRYPTOCOM this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_CRYPTOCOM] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BYBIT this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BYBIT] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_ASCENDEX this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_ASCENDEX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITGET this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITGET] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITGET_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITGET_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITMART this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_BITMART] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_MEXC this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_MEXC] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_MEXC_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_MEXC_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_WHITEBIT this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_WHITEBIT] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #endif #ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT #ifdef CCAPI_ENABLE_EXCHANGE_COINBASE this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_COINBASE] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_GEMINI this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_GEMINI] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_KRAKEN this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_KRAKEN] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_KRAKEN_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_KRAKEN_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITSTAMP this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BITSTAMP] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITFINEX this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BITFINEX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITMEX this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BITMEX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_US this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_US] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif // #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_MARGIN // this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_MARGIN] = -// std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +// std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); // #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_USDS_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_USDS_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BINANCE_COIN_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BINANCE_COIN_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_HUOBI this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_HUOBI] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_HUOBI_USDT_SWAP this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_HUOBI_USDT_SWAP] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_HUOBI_COIN_SWAP this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_HUOBI_COIN_SWAP] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_OKX this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_OKX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_ERISX this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_ERISX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_KUCOIN this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_KUCOIN] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_KUCOIN_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_KUCOIN_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_FTX this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_FTX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_FTX_US this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_FTX_US] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_DERIBIT this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_DERIBIT] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_GATEIO this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_GATEIO] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_GATEIO_PERPETUAL_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_GATEIO_PERPETUAL_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_CRYPTOCOM this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_CRYPTOCOM] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BYBIT this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BYBIT] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_ASCENDEX this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_ASCENDEX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITGET this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BITGET] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITGET_FUTURES this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BITGET_FUTURES] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_BITMART this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_BITMART] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_MEXC this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_MEXC] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif // #ifdef CCAPI_ENABLE_EXCHANGE_MEXC_FUTURES // this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_MEXC_FUTURES] = -// std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +// std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); // #endif // #ifdef CCAPI_ENABLE_EXCHANGE_WHITEBIT // this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_WHITEBIT] = -// std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +// std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); // #endif #endif #ifdef CCAPI_ENABLE_SERVICE_FIX #ifdef CCAPI_ENABLE_EXCHANGE_COINBASE this->serviceByServiceNameExchangeMap[CCAPI_FIX][CCAPI_EXCHANGE_NAME_COINBASE] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif // #ifdef CCAPI_ENABLE_EXCHANGE_GEMINI // this->serviceByServiceNameExchangeMap[CCAPI_FIX][CCAPI_EXCHANGE_NAME_GEMINI] = -// std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +// std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); // #endif #ifdef CCAPI_ENABLE_EXCHANGE_FTX this->serviceByServiceNameExchangeMap[CCAPI_FIX][CCAPI_EXCHANGE_NAME_FTX] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif #ifdef CCAPI_ENABLE_EXCHANGE_FTX_US this->serviceByServiceNameExchangeMap[CCAPI_FIX][CCAPI_EXCHANGE_NAME_FTX_US] = - std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); + std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); #endif // #ifdef CCAPI_ENABLE_EXCHANGE_DERIBIT // this->serviceByServiceNameExchangeMap[CCAPI_FIX][CCAPI_EXCHANGE_NAME_DERIBIT] = -// std::make_shared(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr); +// std::make_shared(this->onEventFunc, sessionOptions, sessionConfigs, this->serviceContextPtr); // #endif #endif for (const auto& x : this->serviceByServiceNameExchangeMap) { @@ -629,8 +621,9 @@ class Session { y.second->stop(); } } - this->serviceContextPtr->stop(); - this->t.join(); + if (this->useInternalServiceContextPtr) { + this->serviceContextPtr->stop(); + } } virtual void subscribe(Subscription& subscription) { @@ -1008,10 +1001,10 @@ class Session { bool useInternalEventDispatcher{}; #endif std::map>> serviceByServiceNameExchangeMap; - std::thread t; Queue eventQueue; ServiceContext* serviceContextPtr{nullptr}; - std::function* eventQueue)> internalEventHandler; + bool useInternalServiceContextPtr{}; + std::function* eventQueue)> onEventFunc; std::map> delayTimerByIdMap; }; } /* namespace ccapi */ diff --git a/include/ccapi_cpp/ccapi_session_options.h b/include/ccapi_cpp/ccapi_session_options.h index 830e7dff..5d9051ab 100644 --- a/include/ccapi_cpp/ccapi_session_options.h +++ b/include/ccapi_cpp/ccapi_session_options.h @@ -57,7 +57,6 @@ class SessionOptions { 10}; // used to remove a http connection from the http connection pool if it has stayed idle for at least this amount of time bool enableOneHttpConnectionPerRequest{}; // create a new http connection for each request long websocketConnectTimeoutMilliseconds{10000}; - std::optional cpuCoreIdOpt; // used to set cpu affinity }; } /* namespace ccapi */ #endif // INCLUDE_CCAPI_CPP_CCAPI_SESSION_OPTIONS_H_ diff --git a/include/ccapi_cpp/service/ccapi_service_context.h b/include/ccapi_cpp/service/ccapi_service_context.h index 7ba8da50..c70da7f6 100644 --- a/include/ccapi_cpp/service/ccapi_service_context.h +++ b/include/ccapi_cpp/service/ccapi_service_context.h @@ -19,8 +19,10 @@ class ServiceContext { ServiceContext() { this->ioContextPtr = new boost::asio::io_context(); + this->useInternalIoContextPtr = true; this->executorWorkGuardPtr = new ExecutorWorkGuard(this->ioContextPtr->get_executor()); this->sslContextPtr = new SslContext(SslContext::tls_client); + this->useInternalSslContextPtr = true; // this->sslContextPtr->set_options(SslContext::default_workarounds | SslContext::no_sslv2 | SslContext::no_sslv3 | SslContext::single_dh_use); this->sslContextPtr->set_verify_mode(boost::asio::ssl::verify_none); // TODO(cryptochassis): verify ssl certificate to strengthen security @@ -31,11 +33,13 @@ class ServiceContext { this->ioContextPtr = ioContextPtr; this->executorWorkGuardPtr = new ExecutorWorkGuard(this->ioContextPtr->get_executor()); this->sslContextPtr = new SslContext(SslContext::tls_client); + this->useInternalSslContextPtr = true; this->sslContextPtr->set_verify_mode(boost::asio::ssl::verify_none); } ServiceContext(SslContextPtr sslContextPtr) { this->ioContextPtr = new boost::asio::io_context(); + this->useInternalIoContextPtr = true; this->executorWorkGuardPtr = new ExecutorWorkGuard(this->ioContextPtr->get_executor()); this->sslContextPtr = sslContextPtr; this->sslContextPtr->set_verify_mode(boost::asio::ssl::verify_none); @@ -53,27 +57,39 @@ class ServiceContext { virtual ~ServiceContext() { delete this->executorWorkGuardPtr; - delete this->ioContextPtr; - delete this->sslContextPtr; + if (this->useInternalIoContextPtr) { + delete this->ioContextPtr; + } + if (this->useInternalSslContextPtr) { + delete this->sslContextPtr; + } } void start() { - CCAPI_LOGGER_INFO("about to start client asio io_context run loop"); - this->ioContextPtr->run(); - CCAPI_LOGGER_INFO("just exited client asio io_context run loop"); + if (this->useInternalIoContextPtr) { + std::thread thread([this]() { + CCAPI_LOGGER_INFO("about to start asio io_context run loop"); + this->ioContextPtr->run(); + CCAPI_LOGGER_INFO("just exited asio io_context run loop"); + }); + this->thread = std::move(thread); + } } void stop() { this->executorWorkGuardPtr->reset(); - this->ioContextPtr->stop(); + if (this->useInternalIoContextPtr) { + this->ioContextPtr->stop(); + this->thread.join(); + } } IoContextPtr ioContextPtr{nullptr}; + bool useInternalIoContextPtr{}; ExecutorWorkGuardPtr executorWorkGuardPtr{nullptr}; SslContextPtr sslContextPtr{nullptr}; - // IoContextPtr ioContextPtr{new IoContext()}; - // ExecutorWorkGuardPtr executorWorkGuardPtr{new ExecutorWorkGuard(ioContextPtr->get_executor())}; - // SslContextPtr sslContextPtr{new SslContext(SslContext::tls_client)}; + bool useInternalSslContextPtr{}; + std::thread thread; }; } /* namespace ccapi */ From f77ac954e5d0ecf2e302f4bb4b685930f3cedda9 Mon Sep 17 00:00:00 2001 From: ubuntu <> Date: Tue, 27 May 2025 17:44:45 +0000 Subject: [PATCH 02/17] fix: remove spurious errors associated with intended timer cancel --- include/ccapi_cpp/service/ccapi_fix_service.h | 6 +++--- include/ccapi_cpp/service/ccapi_market_data_service.h | 2 +- include/ccapi_cpp/service/ccapi_service.h | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/ccapi_cpp/service/ccapi_fix_service.h b/include/ccapi_cpp/service/ccapi_fix_service.h index fde47f1f..dbf51bef 100644 --- a/include/ccapi_cpp/service/ccapi_fix_service.h +++ b/include/ccapi_cpp/service/ccapi_fix_service.h @@ -102,7 +102,7 @@ class FixService : public Service { TimerPtr timerPtr(new boost::asio::steady_timer(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(seconds * 1000))); timerPtr->async_wait([fixConnectionPtr, that = shared_from_base(), urlBase](ErrorCode const& ec) { if (that->fixConnectionPtrByIdMap.find(fixConnectionPtr->id) == that->fixConnectionPtrByIdMap.end()) { - if (ec) { + if (ec && ec != boost::asio::error::operation_aborted) { CCAPI_LOGGER_ERROR("fixConnectionPtr = " + toString(*fixConnectionPtr) + ", connect retry on fail timer error: " + ec.message()); that->onError(Event::Type::FIX_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { @@ -498,7 +498,7 @@ class FixService : public Service { 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) { + if (ec && ec != boost::asio::error::operation_aborted) { CCAPI_LOGGER_ERROR("fixConnectionPtr = " + toString(*fixConnectionPtr) + ", ping timer error: " + ec.message()); that->onError(Event::Type::FIX_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { @@ -519,7 +519,7 @@ class FixService : public Service { 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) { + if (ec && ec != boost::asio::error::operation_aborted) { CCAPI_LOGGER_ERROR("fixConnectionPtr = " + toString(*fixConnectionPtr) + ", pong timeout timer error: " + ec.message()); that->onError(Event::Type::FIX_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { diff --git a/include/ccapi_cpp/service/ccapi_market_data_service.h b/include/ccapi_cpp/service/ccapi_market_data_service.h index 4102f1c5..d114b718 100644 --- a/include/ccapi_cpp/service/ccapi_market_data_service.h +++ b/include/ccapi_cpp/service/ccapi_market_data_service.h @@ -1245,7 +1245,7 @@ class MarketDataService : public Service { timerPtr->async_wait( [wsConnection, channelId, symbolId, field, optionMap, correlationIdList, previousConflateTp, interval, gracePeriod, this](ErrorCode const& ec) { if (this->wsConnectionByIdMap.find(wsConnection.id) != this->wsConnectionByIdMap.end()) { - if (ec) { + if (ec && ec != boost::asio::error::operation_aborted) { CCAPI_LOGGER_ERROR("wsConnection = " + toString(wsConnection) + ", conflate timer error: " + ec.message()); this->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { diff --git a/include/ccapi_cpp/service/ccapi_service.h b/include/ccapi_cpp/service/ccapi_service.h index 5522f6e9..aa5c860d 100644 --- a/include/ccapi_cpp/service/ccapi_service.h +++ b/include/ccapi_cpp/service/ccapi_service.h @@ -211,7 +211,7 @@ class Service : public std::enable_shared_from_this { if (delayMilliseconds > 0) { TimerPtr timerPtr(new net::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) { + if (ec && ec != boost::asio::error::operation_aborted) { CCAPI_LOGGER_ERROR("request = " + toString(request) + ", sendRequest timer error: " + ec.message()); that->onError(Event::Type::REQUEST_STATUS, Message::Type::GENERIC_ERROR, ec, "timer", {request.getCorrelationId()}, eventQueuePtr); } else { @@ -580,7 +580,7 @@ class Service : public std::enable_shared_from_this { timerPtr = std::make_shared(*this->serviceContextPtr->ioContextPtr, std::chrono::milliseconds(this->sessionOptions.httpRequestTimeoutMilliseconds)); timerPtr->async_wait([httpConnectionPtr](ErrorCode const& ec) { - if (ec) { + if (ec && ec != boost::asio::error::operation_aborted) { if (ec != net::error::make_error_code(net::error::basic_errors::operation_aborted)) { CCAPI_LOGGER_ERROR("httpConnectionPtr = " + toString(*httpConnectionPtr) + ", connect timeout timer error: " + ec.message()); } @@ -1225,7 +1225,7 @@ class Service : public std::enable_shared_from_this { timerPtr->async_wait([wsConnectionPtr, that = shared_from_this(), urlBase](ErrorCode const& ec) { WsConnection& thisWsConnection = *wsConnectionPtr; if (that->wsConnectionByIdMap.find(thisWsConnection.id) == that->wsConnectionByIdMap.end()) { - if (ec) { + if (ec && ec != boost::asio::error::operation_aborted) { CCAPI_LOGGER_ERROR("wsConnection = " + toString(thisWsConnection) + ", connect retry on fail timer error: " + ec.message()); that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { @@ -1451,7 +1451,7 @@ class Service : public std::enable_shared_from_this { 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) { + if (ec && ec != boost::asio::error::operation_aborted) { CCAPI_LOGGER_ERROR("wsConnection = " + toString(wsConnection) + ", ping timer error: " + ec.message()); that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { @@ -1473,7 +1473,7 @@ class Service : public std::enable_shared_from_this { 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) { + if (ec && ec != boost::asio::error::operation_aborted) { CCAPI_LOGGER_ERROR("wsConnection = " + toString(wsConnection) + ", pong time out timer error: " + ec.message()); that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::GENERIC_ERROR, ec, "timer"); } else { From fc32ba5898b9e508fbcdc7bfdcb885b441db2af1 Mon Sep 17 00:00:00 2001 From: ubuntu <> Date: Tue, 27 May 2025 20:18:39 +0000 Subject: [PATCH 03/17] feat: change how to do order entry via websocket --- README.md | 109 +++++++++--------- .../main.cpp | 15 ++- include/ccapi_cpp/ccapi_macro.h | 3 + include/ccapi_cpp/ccapi_message.h | 13 +-- include/ccapi_cpp/ccapi_request.h | 11 +- include/ccapi_cpp/ccapi_session.h | 34 +++--- include/ccapi_cpp/ccapi_subscription.h | 4 +- .../ccapi_execution_management_service.h | 85 +++++++------- .../ccapi_execution_management_service_okx.h | 18 ++- include/ccapi_cpp/service/ccapi_service.h | 2 +- 10 files changed, 145 insertions(+), 149 deletions(-) diff --git a/README.md b/README.md index 0fcb81ce..80ab88a4 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,61 @@ # Some breaking changes introduced -* Please update boost version to at least 1.87.0. -* When a subscription fails due to the underlying websocket connection fails to open, the emitted message type is SUBSCRIPTION_FAILURE_DUE_TO_CONNECTION_FAILURE instead of SUBSCRIPTION_FAILURE. -* Removed the spot market making application and the single order execution application. +* We made a change on how to "Send request by Websocket API". - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [ccapi](#ccapi) - - [Branches](#branches) - - [Build](#build) - - [C++](#c) - - [non-C++](#non-c) - - [Constants](#constants) - - [Examples](#examples) - - [Documentations](#documentations) - - [Simple Market Data](#simple-market-data) - - [Advanced Market Data](#advanced-market-data) - - [Complex request parameters](#complex-request-parameters) - - [Specify subscription market depth](#specify-subscription-market-depth) - - [Specify correlation id](#specify-correlation-id) - - [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments) - - [Receive subscription events at periodic intervals](#receive-subscription-events-at-periodic-intervals) - - [Receive subscription events at periodic intervals including when the market depth snapshot hasn't changed](#receive-subscription-events-at-periodic-intervals-including-when-the-market-depth-snapshot-hasnt-changed) - - [Receive subscription market depth updates](#receive-subscription-market-depth-updates) - - [Receive subscription trade events](#receive-subscription-trade-events) - - [Receive subscription calculated-candlestick events at periodic intervals](#receive-subscription-calculated-candlestick-events-at-periodic-intervals) - - [Receive subscription exchange-provided-candlestick events at periodic intervals](#receive-subscription-exchange-provided-candlestick-events-at-periodic-intervals) - - [Send generic public requests](#send-generic-public-requests) - - [Make generic public subscriptions](#make-generic-public-subscriptions) - - [Send generic private requests](#send-generic-private-requests) - - [Simple Execution Management](#simple-execution-management) - - [Advanced Execution Management](#advanced-execution-management) - - [Specify correlation id](#specify-correlation-id-1) - - [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments-1) - - [Multiple subscription fields](#multiple-subscription-fields) - - [Make Session::sendRequest blocking](#make-sessionsendrequest-blocking) - - [Provide API credentials for an exchange](#provide-api-credentials-for-an-exchange) - - [Override exchange urls](#override-exchange-urls) - - [Complex request parameters](#complex-request-parameters-1) - - [Send request by Websocket API](#send-request-by-websocket-api) - - [Specify instrument type](#specify-instrument-type) - - [FIX API](#fix-api) - - [More Advanced Topics](#more-advanced-topics) - - [Handle events in "immediate" vs. "batching" mode](#handle-events-in-immediate-vs-batching-mode) - - [Thread safety](#thread-safety) - - [Enable library logging](#enable-library-logging) - - [Set timer](#set-timer) - - [Performance Tuning](#performance-tuning) - - [Known Issues and Workarounds](#known-issues-and-workarounds) - - [Contributing](#contributing) + +**Table of Contents** *generated with [DocToc](https://github.com/ktechhub/doctoc)* + + + +* [Some breaking changes introduced](#some-breaking-changes-introduced) +* [ccapi](#ccapi) + * [Branches](#branches) + * [Build](#build) + * [C++](#c) + * [non-C++](#non-c) + * [Constants](#constants) + * [Examples](#examples) + * [Documentations](#documentations) + * [Simple Market Data](#simple-market-data) + * [Advanced Market Data](#advanced-market-data) + * [Complex request parameters](#complex-request-parameters) + * [Specify subscription market depth](#specify-subscription-market-depth) + * [Specify correlation id](#specify-correlation-id) + * [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments) + * [Receive subscription events at periodic intervals](#receive-subscription-events-at-periodic-intervals) + * [Receive subscription events at periodic intervals including when the market depth snapshot hasn't changed](#receive-subscription-events-at-periodic-intervals-including-when-the-market-depth-snapshot-hasnt-changed) + * [Receive subscription market depth updates](#receive-subscription-market-depth-updates) + * [Receive subscription trade events](#receive-subscription-trade-events) + * [Receive subscription calculated-candlestick events at periodic intervals](#receive-subscription-calculated-candlestick-events-at-periodic-intervals) + * [Receive subscription exchange-provided-candlestick events at periodic intervals](#receive-subscription-exchange-provided-candlestick-events-at-periodic-intervals) + * [Send generic public requests](#send-generic-public-requests) + * [Make generic public subscriptions](#make-generic-public-subscriptions) + * [Send generic private requests](#send-generic-private-requests) + * [Simple Execution Management](#simple-execution-management) + * [Advanced Execution Management](#advanced-execution-management) + * [Specify correlation id](#specify-correlation-id-1) + * [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments-1) + * [Multiple subscription fields](#multiple-subscription-fields) + * [Make Session::sendRequest blocking](#make-sessionsendrequest-blocking) + * [Provide API credentials for an exchange](#provide-api-credentials-for-an-exchange) + * [Override exchange urls](#override-exchange-urls) + * [Complex request parameters](#complex-request-parameters-1) + * [Send request by Websocket API](#send-request-by-websocket-api) + * [Specify instrument type](#specify-instrument-type) + * [FIX API](#fix-api) + * [More Advanced Topics](#more-advanced-topics) + * [Handle events in "immediate" vs. "batching" mode](#handle-events-in-immediate-vs-batching-mode) + * [Thread safety](#thread-safety) + * [Enable library logging](#enable-library-logging) + * [Set timer](#set-timer) + * [Performance Tuning](#performance-tuning) + * [Known Issues and Workarounds](#known-issues-and-workarounds) + * [Contributing](#contributing) + + + # ccapi * A header-only C++ library for streaming market data and executing trades directly from cryptocurrency exchanges (i.e. the connections are between your server and the exchange server without anything in-between). * Bindings for other languages such as Python, Java, C#, Go, and Javascript are provided. @@ -775,16 +779,17 @@ request.appendParam({ #### Send request by Websocket API ``` -Subscription subscription("okx", "BTC-USDTT", "ORDER_UPDATE", "", "same correlation id for subscription and request"); +std::string websocketOrderEntrySubscriptionCorrelationId("any"); +Subscription subscription("okx", "BTC-USDTT", "ORDER_UPDATE", "", websocketOrderEntrySubscriptionCorrelationId); session.subscribe(subscription); ... -Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDTT", "same correlation id for subscription and request"); +Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDTT"); request.appendParam({ {"SIDE", "BUY"}, {"LIMIT_PRICE", "20000"}, {"QUANTITY", "0.001"}, }); -session.sendRequestByWebsocket(request); +session.sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, request); ``` #### Specify instrument type diff --git a/example/src/execution_management_advanced_subscription/main.cpp b/example/src/execution_management_advanced_subscription/main.cpp index db849c8e..c8ecc25b 100644 --- a/example/src/execution_management_advanced_subscription/main.cpp +++ b/example/src/execution_management_advanced_subscription/main.cpp @@ -5,18 +5,21 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: + MyEventHandler(const std::string& websocketOrderEntrySubscriptionCorrelationId) + : websocketOrderEntrySubscriptionCorrelationId(websocketOrderEntrySubscriptionCorrelationId) {} + bool processEvent(const Event& event, Session* session) override { if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) { std::cout << "Received an event of type SUBSCRIPTION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; auto message = event.getMessageList().at(0); if (message.getType() == Message::Type::SUBSCRIPTION_STARTED) { - Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDT", "same correlation id for subscription and request"); + Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDT"); request.appendParam({ {"SIDE", "BUY"}, {"LIMIT_PRICE", "20000"}, {"QUANTITY", "0.001"}, }); - session->sendRequestByWebsocket(request); + session->sendRequestByWebsocket(this->websocketOrderEntrySubscriptionCorrelationId, request); } } else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) { std::cout << "Received an event of type SUBSCRIPTION_DATA:\n" + event.toStringPretty(2, 2) << std::endl; @@ -25,6 +28,9 @@ class MyEventHandler : public EventHandler { } return true; } + + private: + std::string websocketOrderEntrySubscriptionCorrelationId; }; } /* namespace ccapi */ @@ -51,9 +57,10 @@ int main(int argc, char** argv) { } SessionOptions sessionOptions; SessionConfigs sessionConfigs; - MyEventHandler eventHandler; + std::string websocketOrderEntrySubscriptionCorrelationId("any"); + MyEventHandler eventHandler(websocketOrderEntrySubscriptionCorrelationId); Session session(sessionOptions, sessionConfigs, &eventHandler); - Subscription subscription("okx", "BTC-USDT", "ORDER_UPDATE", "", "same correlation id for subscription and request"); + Subscription subscription("okx", "BTC-USDT", "ORDER_UPDATE", "", websocketOrderEntrySubscriptionCorrelationId); session.subscribe(subscription); std::this_thread::sleep_for(std::chrono::seconds(10)); session.stop(); diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index 816048b4..09ff08b1 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -414,6 +414,9 @@ #ifndef CCAPI_EM_POSITION_UPDATE #define CCAPI_EM_POSITION_UPDATE "POSITION_UPDATE" #endif +#ifndef CCAPI_EM_WEBSOCKET_ORDER_ENTRY +#define CCAPI_EM_WEBSOCKET_ORDER_ENTRY "WEBSOCKET_ORDER_ENTRY" +#endif #ifndef CCAPI_EM_ORDER_SIDE #define CCAPI_EM_ORDER_SIDE "SIDE" #endif diff --git a/include/ccapi_cpp/ccapi_message.h b/include/ccapi_cpp/ccapi_message.h index 52e71a32..6c0c6282 100644 --- a/include/ccapi_cpp/ccapi_message.h +++ b/include/ccapi_cpp/ccapi_message.h @@ -239,8 +239,7 @@ class Message { std::string toString() const { std::string output = "Message [type = " + typeToString(type) + ", recapType = " + recapTypeToString(recapType) + ", time = " + UtilTime::getISOTimestamp(time) + ", timeReceived = " + UtilTime::getISOTimestamp(timeReceived) + - ", elementList = " + ccapi::firstNToString(elementList, 10) + ", correlationIdList = " + ccapi::toString(correlationIdList) + - ", secondaryCorrelationIdMap = " + ccapi::toString(secondaryCorrelationIdMap) + "]"; + ", elementList = " + ccapi::firstNToString(elementList, 10) + ", correlationIdList = " + ccapi::toString(correlationIdList) + "]"; return output; } @@ -251,8 +250,7 @@ class Message { "recapType = " + recapTypeToString(recapType) + ",\n" + ss + "time = " + UtilTime::getISOTimestamp(time) + ",\n" + ss + "timeReceived = " + UtilTime::getISOTimestamp(timeReceived) + ",\n" + ss + "elementList = " + ccapi::firstNToStringPretty(elementList, 10, space, space + leftToIndent, false) + ",\n" + ss + - "correlationIdList = " + ccapi::toString(correlationIdList) + ",\n" + ss + - "secondaryCorrelationIdMap = " + ccapi::toString(secondaryCorrelationIdMap) + "\n" + sl + "]"; + "correlationIdList = " + ccapi::toString(correlationIdList) + ",\n" + sl + "]"; return output; } @@ -264,14 +262,8 @@ class Message { const std::vector& getCorrelationIdList() const { return correlationIdList; } - const std::map& getSecondaryCorrelationIdMap() const { return secondaryCorrelationIdMap; } - void setCorrelationIdList(const std::vector& correlationIdList) { this->correlationIdList = correlationIdList; } - void setSecondaryCorrelationIdMap(const std::map& secondaryCorrelationIdMap) { - this->secondaryCorrelationIdMap = secondaryCorrelationIdMap; - } - // 'getTime' only works in C++. For other languages, please use 'getTimeISO'. TimePoint getTime() const { return time; } @@ -309,7 +301,6 @@ class Message { TimePoint timeReceived{std::chrono::seconds{0}}; std::vector elementList; std::vector correlationIdList; - std::map secondaryCorrelationIdMap; Type type{Type::UNKNOWN}; RecapType recapType{RecapType::UNKNOWN}; }; diff --git a/include/ccapi_cpp/ccapi_request.h b/include/ccapi_cpp/ccapi_request.h index c5e024c8..87145755 100644 --- a/include/ccapi_cpp/ccapi_request.h +++ b/include/ccapi_cpp/ccapi_request.h @@ -132,8 +132,8 @@ class Request { Request() {} - Request(Operation operation, std::string exchange, std::string instrument = "", std::string correlationId = "", - std::map credential = {}) + Request(Operation operation, const std::string& exchange, const std::string& instrument = "", const std::string& correlationId = "", + const std::map& credential = {}) : operation(operation), exchange(exchange), instrument(instrument), correlationId(correlationId), credential(credential) { if (operation == Operation::CUSTOM) { this->serviceName = CCAPI_UNKNOWN; @@ -158,7 +158,7 @@ class Request { } std::string output = "Request [exchange = " + exchange + ", marginType = " + marginType + ", instrument = " + instrument + ", serviceName = " + serviceName + - ", correlationId = " + correlationId + ", secondaryCorrelationId = " + secondaryCorrelationId + + ", correlationId = " + correlationId + (this->serviceName == CCAPI_FIX ? ", paramListFix = " + ccapi::toString(paramListFix) : ", paramList = " + ccapi::toString(paramList)) + ", credential = " + ccapi::toString(shortCredential) + ", operation = " + operationToString(operation) + ", timeSent = " + UtilTime::getISOTimestamp(timeSent) + ", index = " + ccapi::toString(index) + ", localIpAddress = " + localIpAddress + @@ -168,8 +168,6 @@ class Request { const std::string& getCorrelationId() const { return correlationId; } - const std::string& getSecondaryCorrelationId() const { return secondaryCorrelationId; } - const std::string& getExchange() const { return exchange; } const std::string& getMarginType() const { return marginType; } @@ -231,8 +229,6 @@ class Request { void setCorrelationId(const std::string& correlationId) { this->correlationId = correlationId; } - void setSecondaryCorrelationId(const std::string& secondaryCorrelationId) { this->secondaryCorrelationId = secondaryCorrelationId; } - void setMarginType(const std::string& marginType) { this->marginType = marginType; } void setLocalIpAddress(const std::string& localIpAddress) { this->localIpAddress = localIpAddress; } @@ -268,7 +264,6 @@ class Request { std::string instrument; std::string serviceName; std::string correlationId; - std::string secondaryCorrelationId; std::vector> paramList; std::map credential; std::vector>> paramListFix; diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index 37f501c4..a9a7026e 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -807,7 +807,7 @@ class Session { this->onError(Event::Type::FIX_STATUS, Message::Type::FIX_FAILURE, "please enable exchange: " + exchange); return; } - std::shared_ptr& servicePtr = serviceByExchangeMap.at(exchange); + std::shared_ptr servicePtr = serviceByExchangeMap.at(exchange); auto now = UtilTime::now(); servicePtr->sendRequestByFix(request, now); CCAPI_LOGGER_FUNCTION_EXIT; @@ -819,29 +819,29 @@ class Session { } } - virtual void sendRequestByWebsocket(Request& request) { + virtual void sendRequestByWebsocket(const std::string& websocketOrderEntrySubscriptionCorrelationId, Request& request) { CCAPI_LOGGER_FUNCTION_ENTER; - auto serviceName = request.getServiceName(); + const auto& serviceName = request.getServiceName(); CCAPI_LOGGER_DEBUG("serviceName = " + serviceName); if (this->serviceByServiceNameExchangeMap.find(serviceName) == this->serviceByServiceNameExchangeMap.end()) { this->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, "please enable service: " + serviceName + ", and the exchanges that you want"); return; } - std::map>& serviceByExchangeMap = this->serviceByServiceNameExchangeMap.at(serviceName); - auto exchange = request.getExchange(); + const std::map>& serviceByExchangeMap = this->serviceByServiceNameExchangeMap.at(serviceName); + const auto& exchange = request.getExchange(); if (serviceByExchangeMap.find(exchange) == serviceByExchangeMap.end()) { this->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, "please enable exchange: " + exchange); return; } - std::shared_ptr& servicePtr = serviceByExchangeMap.at(exchange); - auto now = UtilTime::now(); - servicePtr->sendRequestByWebsocket(request, now); + std::shared_ptr servicePtr = serviceByExchangeMap.at(exchange); + const auto& now = UtilTime::now(); + servicePtr->sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, request, now); CCAPI_LOGGER_FUNCTION_EXIT; } - virtual void sendRequestByWebsocket(std::vector& requestList) { + virtual void sendRequestByWebsocket(const std::string& websocketOrderEntrySubscriptionCorrelationId, std::vector& requestList) { for (auto& x : requestList) { - this->sendRequestByWebsocket(x); + this->sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, x); } } @@ -859,7 +859,7 @@ class Session { int i = 0; for (auto& request : requestList) { request.setIndex(i); - auto serviceName = request.getServiceName(); + const auto& serviceName = request.getServiceName(); CCAPI_LOGGER_DEBUG("serviceName = " + serviceName); if (this->serviceByServiceNameExchangeMap.find(serviceName) == this->serviceByServiceNameExchangeMap.end()) { this->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, @@ -867,18 +867,14 @@ class Session { return; } std::map>& serviceByExchangeMap = this->serviceByServiceNameExchangeMap.at(serviceName); - auto exchange = request.getExchange(); + const auto& exchange = request.getExchange(); if (serviceByExchangeMap.find(exchange) == serviceByExchangeMap.end()) { this->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, "please enable exchange: " + exchange, eventQueuePtr); return; } - std::shared_ptr& servicePtr = serviceByExchangeMap.at(exchange); - std::string key = serviceName + exchange; - // if (eventQueuePtr && serviceNameExchangeSet.find(key) == serviceNameExchangeSet.end()) { - // // servicePtr->setEventHandler(std::bind(&Session::onEvent, this, std::placeholders::_1, eventQueuePtr)); - // serviceNameExchangeSet.insert(key); - // } - auto now = UtilTime::now(); + std::shared_ptr servicePtr = serviceByExchangeMap.at(exchange); + const std::string& key = serviceName + exchange; + const auto& now = UtilTime::now(); auto futurePtr = servicePtr->sendRequest(request, !!eventQueuePtr, now, delayMilliseconds, eventQueuePtr); if (eventQueuePtr) { futurePtrList.push_back(futurePtr); diff --git a/include/ccapi_cpp/ccapi_subscription.h b/include/ccapi_cpp/ccapi_subscription.h index 973b8f13..79a67e49 100644 --- a/include/ccapi_cpp/ccapi_subscription.h +++ b/include/ccapi_cpp/ccapi_subscription.h @@ -16,8 +16,8 @@ class Subscription { public: Subscription() {} - Subscription(std::string exchange, std::string instrument, std::string field, std::string options = "", std::string correlationId = "", - std::map credential = {}) + Subscription(const std::string& exchange, const std::string& instrument, const std::string& field, const std::string& options = "", + const std::string& correlationId = "", const std::map& credential = {}) : exchange(exchange), instrument(instrument), field(field), correlationId(correlationId), credential(credential) { auto originalInstrumentSet = UtilString::splitToSet(instrument, ","); std::copy_if(originalInstrumentSet.begin(), originalInstrumentSet.end(), std::inserter(this->instrumentSet, this->instrumentSet.end()), diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index 54767e14..a0d5680b 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -282,50 +282,51 @@ class ExecutionManagementService : public Service { return nonce; } - void sendRequestByWebsocket(Request& request, const TimePoint& now) override { + void sendRequestByWebsocket(const std::string& websocketOrderEntrySubscriptionCorrelationId, Request& request, const TimePoint& now) override { CCAPI_LOGGER_FUNCTION_ENTER; CCAPI_LOGGER_TRACE("now = " + toString(now)); - boost::asio::post(*this->serviceContextPtr->ioContextPtr, [that = shared_from_base(), request]() mutable { - auto now = UtilTime::now(); - CCAPI_LOGGER_DEBUG("request = " + toString(request)); - CCAPI_LOGGER_TRACE("now = " + toString(now)); - request.setTimeSent(now); - auto nowFixTimeStr = UtilTime::convertTimePointToFIXTime(now); - auto& correlationId = request.getCorrelationId(); - auto it = that->wsConnectionByCorrelationIdMap.find(correlationId); - if (it == that->wsConnectionByCorrelationIdMap.end()) { - that->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, "Websocket connection was not found", {correlationId}); - return; - } - - auto wsConnectionPtr = it->second; - auto& wsConnection = *wsConnectionPtr; - - CCAPI_LOGGER_TRACE("wsConnection = " + toString(wsConnection)); - auto instrument = request.getInstrument(); - auto symbolId = instrument; - CCAPI_LOGGER_TRACE("symbolId = " + symbolId); - ErrorCode ec; - rj::Document document; - rj::Document::AllocatorType& allocator = document.GetAllocator(); - auto credential = request.getCredential(); - if (credential.empty()) { - credential = that->credentialDefault; - } - that->convertRequestForWebsocket(document, allocator, wsConnection, request, ++that->wsRequestIdByConnectionIdMap[wsConnection.id], now, symbolId, - credential); - rj::StringBuffer stringBuffer; - rj::Writer writer(stringBuffer); - document.Accept(writer); - std::string sendString = stringBuffer.GetString(); - CCAPI_LOGGER_TRACE("sendString = " + sendString); - - that->send(wsConnectionPtr, sendString, ec); - - if (ec) { - that->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, ec, "request"); - } - }); + boost::asio::post(*this->serviceContextPtr->ioContextPtr, + [that = shared_from_base(), websocketOrderEntrySubscriptionCorrelationId, request]() mutable { + auto now = UtilTime::now(); + CCAPI_LOGGER_DEBUG("websocketOrderEntrySubscriptionCorrelationId = " + toString(websocketOrderEntrySubscriptionCorrelationId)); + CCAPI_LOGGER_DEBUG("request = " + toString(request)); + CCAPI_LOGGER_TRACE("now = " + toString(now)); + request.setTimeSent(now); + auto it = that->wsConnectionByCorrelationIdMap.find(websocketOrderEntrySubscriptionCorrelationId); + if (it == that->wsConnectionByCorrelationIdMap.end()) { + that->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, "Websocket connection was not found", + {websocketOrderEntrySubscriptionCorrelationId}); + return; + } + + auto wsConnectionPtr = it->second; + auto& wsConnection = *wsConnectionPtr; + + CCAPI_LOGGER_TRACE("wsConnection = " + toString(wsConnection)); + const auto& instrument = request.getInstrument(); + const auto& symbolId = instrument; + CCAPI_LOGGER_TRACE("symbolId = " + symbolId); + ErrorCode ec; + rj::Document document; + rj::Document::AllocatorType& allocator = document.GetAllocator(); + auto credential = request.getCredential(); + if (credential.empty()) { + credential = that->credentialDefault; + } + that->convertRequestForWebsocket(document, allocator, wsConnection, request, ++that->wsRequestIdByConnectionIdMap[wsConnection.id], now, + symbolId, credential); + rj::StringBuffer stringBuffer; + rj::Writer writer(stringBuffer); + document.Accept(writer); + std::string sendString = stringBuffer.GetString(); + CCAPI_LOGGER_TRACE("sendString = " + sendString); + + that->send(wsConnectionPtr, sendString, ec); + + if (ec) { + that->onError(Event::Type::REQUEST_STATUS, Message::Type::REQUEST_FAILURE, ec, "request"); + } + }); CCAPI_LOGGER_FUNCTION_EXIT; } diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h b/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h index ed4608a9..2ee57a81 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h @@ -228,9 +228,7 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { int wsRequestId, const TimePoint& now, const std::string& symbolId, const std::map& credential) override { document.SetObject(); - const auto& secondaryCorrelationId = request.getSecondaryCorrelationId(); - document.AddMember("id", rj::Value((secondaryCorrelationId.empty() ? std::to_string(wsRequestId) : secondaryCorrelationId).c_str(), allocator).Move(), - allocator); + document.AddMember("id", rj::Value(request.getCorrelationId().c_str(), allocator).Move(), allocator); Request::Operation operation = request.getOperation(); switch (operation) { case Request::Operation::CREATE_ORDER: { @@ -469,7 +467,6 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { Message message; message.setTimeReceived(timeReceived); const auto& correlationId = subscription.getCorrelationId(); - message.setCorrelationIdList({correlationId}); const auto& fieldSet = subscription.getFieldSet(); if (eventStr.empty()) { auto it = document.FindMember("op"); @@ -482,9 +479,8 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { Element element; element.insert(CCAPI_ERROR_MESSAGE, textMessage); message.setElementList({element}); - message.setSecondaryCorrelationIdMap({ - {correlationId, document["id"].GetString()}, - }); + std::string id = document["id"].GetString(); + message.setCorrelationIdList({id}); messageList.emplace_back(std::move(message)); } else { std::vector elementList; @@ -495,12 +491,12 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { } this->extractOrderInfoFromRequest(elementList, document); message.setElementList(elementList); - message.setSecondaryCorrelationIdMap({ - {correlationId, document["id"].GetString()}, - }); + std::string id = document["id"].GetString(); + message.setCorrelationIdList({id}); messageList.emplace_back(std::move(message)); } } else { + message.setCorrelationIdList({correlationId}); const rj::Value& arg = document["arg"]; const rj::Value& data = document["data"]; std::string channel = std::string(arg["channel"].GetString()); @@ -627,6 +623,7 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { } else if (eventStr == "subscribe") { event.setType(Event::Type::SUBSCRIPTION_STATUS); message.setType(Message::Type::SUBSCRIPTION_STARTED); + message.setCorrelationIdList({correlationId}); Element element; element.insert(CCAPI_INFO_MESSAGE, textMessage); message.setElementList({element}); @@ -634,6 +631,7 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { } else if (eventStr == "error") { event.setType(Event::Type::SUBSCRIPTION_STATUS); message.setType(Message::Type::SUBSCRIPTION_FAILURE); + message.setCorrelationIdList({correlationId}); Element element; element.insert(CCAPI_ERROR_MESSAGE, textMessage); message.setElementList({element}); diff --git a/include/ccapi_cpp/service/ccapi_service.h b/include/ccapi_cpp/service/ccapi_service.h index aa5c860d..399ecc87 100644 --- a/include/ccapi_cpp/service/ccapi_service.h +++ b/include/ccapi_cpp/service/ccapi_service.h @@ -235,7 +235,7 @@ class Service : public std::enable_shared_from_this { return futurePtr; } - virtual void sendRequestByWebsocket(Request& request, const TimePoint& now) {} + virtual void sendRequestByWebsocket(const std::string& websocketOrderEntrySubscriptionCorrelationId, Request& request, const TimePoint& now) {} virtual void sendRequestByFix(Request& request, const TimePoint& now) {} From 02bdc14392c4a1c13ff240213d3a8d6cf8ad069f Mon Sep 17 00:00:00 2001 From: ubuntu <> Date: Wed, 28 May 2025 21:03:15 +0000 Subject: [PATCH 04/17] fix compile issues --- README.md | 51 ++- .../main.cpp | 2 +- .../main.cpp | 22 +- .../main.cpp | 2 +- .../main.cpp | 4 +- example/src/fix_advanced/main.cpp | 4 +- example/src/fix_simple/main.cpp | 4 +- example/src/generic_private_request/main.cpp | 2 +- example/src/generic_public_request/main.cpp | 2 +- .../src/market_data_advanced_request/main.cpp | 2 +- .../main.cpp | 2 +- .../src/market_data_simple_request/main.cpp | 2 +- .../market_data_simple_subscription/main.cpp | 2 +- .../override_exchange_url_at_runtime/main.cpp | 2 +- example/src/test_order_latency/main.cpp | 28 +- example/src/utility_set_timer/main.cpp | 10 +- include/ccapi_cpp/ccapi_macro.h | 6 + include/ccapi_cpp/ccapi_session.h | 12 +- include/ccapi_cpp/ccapi_session_configs.h | 7 + include/ccapi_cpp/ccapi_subscription.h | 4 +- .../ccapi_execution_management_service.h | 22 +- ...pi_execution_management_service_ascendex.h | 2 +- ...pi_execution_management_service_bitfinex.h | 4 +- ...capi_execution_management_service_bitget.h | 2 +- ...capi_execution_management_service_bitmex.h | 2 +- ...ccapi_execution_management_service_bybit.h | 390 ++++++++++++------ ...i_execution_management_service_cryptocom.h | 2 +- .../ccapi_execution_management_service_okx.h | 54 ++- include/ccapi_cpp/service/ccapi_service.h | 9 + 29 files changed, 435 insertions(+), 222 deletions(-) diff --git a/README.md b/README.md index 80ab88a4..bf887d7d 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ + # ccapi * A header-only C++ library for streaming market data and executing trades directly from cryptocurrency exchanges (i.e. the connections are between your server and the exchange server without anything in-between). * Bindings for other languages such as Python, Java, C#, Go, and Javascript are provided. @@ -224,7 +225,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } @@ -301,7 +302,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) { std::cout << "Received an event of type SUBSCRIPTION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; } else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) { @@ -390,13 +391,15 @@ Request request_1(Request::Operation::GET_RECENT_TRADES, "okx", "BTC-USDT", "coo request_1.appendParam(...); Request request_2(Request::Operation::GET_RECENT_TRADES, "binance", "ETH-USDT", "cool correlation id for ETH"); request_2.appendParam(...); -session.sendRequest({request_1, request_2}); +std::vector requests = {request_1, request_2}; +session.sendRequest(requests); ``` Subscribe a `std::vector`. ``` Subscription subscription_1("okx", "BTC-USDT", "MARKET_DEPTH", "", "cool correlation id for okx BTC-USDT"); Subscription subscription_2("binance", "ETH-USDT", "MARKET_DEPTH", "", "cool correlation id for binance ETH-USDT"); -session.subscribe({subscription_1, subscription_2}); +std::vector subscriptions = {subscription_1, subscription_2}; +session.subscribe(subscriptions); ``` #### Receive subscription events at periodic intervals @@ -438,7 +441,7 @@ Subscription subscription("okx", "BTC-USDT", "TRADE", "CONFLATE_INTERVAL_MILLISE Instantiate `Subscription` with field `CANDLESTICK` and option `CANDLESTICK_INTERVAL_SECONDS` set to be the desired interval. ``` -Subscription subscription("okx", "BTC-USDTT", "CANDLESTICK", "CANDLESTICK_INTERVAL_SECONDS=60"); +Subscription subscription("okx", "BTC-USDT", "CANDLESTICK", "CANDLESTICK_INTERVAL_SECONDS=60"); ``` #### Send generic public requests @@ -491,7 +494,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } @@ -589,7 +592,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) { std::cout << "Received an event of type SUBSCRIPTION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; auto message = event.getMessageList().at(0); @@ -601,7 +604,7 @@ class MyEventHandler : public EventHandler { {"QUANTITY", "0.001"}, {"CLIENT_ORDER_ID", "6d4eb0fb"}, }); - session->sendRequest(request); + sessionPtr->sendRequest(request); } } else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) { std::cout << "Received an event of type SUBSCRIPTION_DATA:\n" + event.toStringPretty(2, 2) << std::endl; @@ -716,7 +719,8 @@ Request request_1(Request::Operation::CREATE_ORDER, "okx", "BTC-USDT", "cool cor request_1.appendParam(...); Request request_2(Request::Operation::CREATE_ORDER, "okx", "ETH-USDT", "cool correlation id for ETH"); request_2.appendParam(...); -session.sendRequest({request_1, request_2}); +std::vector requests = {request_1, request_2}; +session.sendRequest(requests); ``` Subscribe one `Subscription` per exchange with a comma separated string of instruments. ``` @@ -778,12 +782,29 @@ request.appendParam({ ``` #### Send request by Websocket API +For okx: ``` std::string websocketOrderEntrySubscriptionCorrelationId("any"); -Subscription subscription("okx", "BTC-USDTT", "ORDER_UPDATE", "", websocketOrderEntrySubscriptionCorrelationId); +Subscription subscription("okx", "", "ORDER_UPDATE", "", websocketOrderEntrySubscriptionCorrelationId); session.subscribe(subscription); ... -Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDTT"); +Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDT"); +request.appendParam({ + {"SIDE", "BUY"}, + {"LIMIT_PRICE", "20000"}, + {"QUANTITY", "0.001"}, +}); +session.sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, request); +``` +For bybit: +``` +std::string websocketOrderEntrySubscriptionCorrelationId("any"); +Subscription subscription_1("bybit", "", "ORDER_UPDATE"); +Subscription subscription_2("bybit", "", "WEBSOCKET_ORDER_ENTRY", "", websocketOrderEntrySubscriptionCorrelationId); +std::vector subscriptions = {subscription_1, subscription_2}; +session.subscribe(subscriptions); +... +Request request(Request::Operation::CREATE_ORDER, "bybit", "BTCUSDT"); request.appendParam({ {"SIDE", "BUY"}, {"LIMIT_PRICE", "20000"}, @@ -795,7 +816,7 @@ session.sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, req #### Specify instrument type Some exchanges (i.e. bybit) might need instrument type for `Subscription`. Use `Subscription`'s `setInstrumentType` method. ``` -Subscription subscription("bybit", "BTCUSDTT", "MARKET_DEPTH"); +Subscription subscription("bybit", "BTCUSDT", "MARKET_DEPTH"); subscription.setInstrumentType("spot"); session.subscribe(subscription); ``` @@ -815,7 +836,7 @@ namespace ccapi { Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::AUTHORIZATION_STATUS) { std::cout << "Received an event of type AUTHORIZATION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; auto message = event.getMessageList().at(0); @@ -831,7 +852,7 @@ class MyEventHandler : public EventHandler { {40, "2"}, {59, "1"}, }); - session->sendRequestByFix(request); + sessionPtr->sendRequestByFix(request); } } else if (event.getType() == Event::Type::FIX) { std::cout << "Received an event of type FIX:\n" + event.toStringPretty(2, 2) << std::endl; @@ -980,7 +1001,7 @@ Logger* Logger::logger = &myLogger; To perform an asynchronous wait, use the utility method `setTimer` in class `Session`. The handlers are invoked in the same threads as the `processEvent` method in the `EventHandler` class. The `id` of the timer should be unique. `delayMilliseconds` can be 0. ``` -session->setTimer( +sessionPtr->setTimer( "id", 1000, [](const boost::system::error_code&) { std::cout << std::string("Timer error handler is triggered at ") + UtilTime::getISOTimestamp(UtilTime::now()) << std::endl; diff --git a/example/src/execution_management_advanced_request/main.cpp b/example/src/execution_management_advanced_request/main.cpp index 8e16da07..44ec037f 100644 --- a/example/src/execution_management_advanced_request/main.cpp +++ b/example/src/execution_management_advanced_request/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } diff --git a/example/src/execution_management_advanced_subscription/main.cpp b/example/src/execution_management_advanced_subscription/main.cpp index c8ecc25b..432db05a 100644 --- a/example/src/execution_management_advanced_subscription/main.cpp +++ b/example/src/execution_management_advanced_subscription/main.cpp @@ -8,29 +8,27 @@ class MyEventHandler : public EventHandler { MyEventHandler(const std::string& websocketOrderEntrySubscriptionCorrelationId) : websocketOrderEntrySubscriptionCorrelationId(websocketOrderEntrySubscriptionCorrelationId) {} - bool processEvent(const Event& event, Session* session) override { - if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) { - std::cout << "Received an event of type SUBSCRIPTION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; - auto message = event.getMessageList().at(0); - if (message.getType() == Message::Type::SUBSCRIPTION_STARTED) { + bool processEvent(const Event& event, Session* sessionPtr) override { + std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; + if (!willSendRequest) { + sessionPtr->setTimer("id", 1000, nullptr, [this, sessionPtr]() { Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDT"); request.appendParam({ {"SIDE", "BUY"}, {"LIMIT_PRICE", "20000"}, {"QUANTITY", "0.001"}, }); - session->sendRequestByWebsocket(this->websocketOrderEntrySubscriptionCorrelationId, request); - } - } else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) { - std::cout << "Received an event of type SUBSCRIPTION_DATA:\n" + event.toStringPretty(2, 2) << std::endl; - } else if (event.getType() == Event::Type::RESPONSE) { - std::cout << "Received an event of type RESPONSE:\n" + event.toStringPretty(2, 2) << std::endl; + std::cout << "About to send a request:\n" + request.toString() << std::endl; + sessionPtr->sendRequestByWebsocket(this->websocketOrderEntrySubscriptionCorrelationId, request); + }); + willSendRequest = true; } return true; } private: std::string websocketOrderEntrySubscriptionCorrelationId; + bool willSendRequest{}; }; } /* namespace ccapi */ @@ -60,7 +58,7 @@ int main(int argc, char** argv) { std::string websocketOrderEntrySubscriptionCorrelationId("any"); MyEventHandler eventHandler(websocketOrderEntrySubscriptionCorrelationId); Session session(sessionOptions, sessionConfigs, &eventHandler); - Subscription subscription("okx", "BTC-USDT", "ORDER_UPDATE", "", websocketOrderEntrySubscriptionCorrelationId); + Subscription subscription("okx", "", "ORDER_UPDATE", "", websocketOrderEntrySubscriptionCorrelationId); session.subscribe(subscription); std::this_thread::sleep_for(std::chrono::seconds(10)); session.stop(); diff --git a/example/src/execution_management_simple_request/main.cpp b/example/src/execution_management_simple_request/main.cpp index 38bdfc11..380f9c10 100644 --- a/example/src/execution_management_simple_request/main.cpp +++ b/example/src/execution_management_simple_request/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } diff --git a/example/src/execution_management_simple_subscription/main.cpp b/example/src/execution_management_simple_subscription/main.cpp index 263220b6..7dffbafd 100644 --- a/example/src/execution_management_simple_subscription/main.cpp +++ b/example/src/execution_management_simple_subscription/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) { std::cout << "Received an event of type SUBSCRIPTION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; auto message = event.getMessageList().at(0); @@ -17,7 +17,7 @@ class MyEventHandler : public EventHandler { {"QUANTITY", "0.001"}, {"CLIENT_ORDER_ID", "6d4eb0fb"}, }); - session->sendRequest(request); + sessionPtr->sendRequest(request); } } else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) { std::cout << "Received an event of type SUBSCRIPTION_DATA:\n" + event.toStringPretty(2, 2) << std::endl; diff --git a/example/src/fix_advanced/main.cpp b/example/src/fix_advanced/main.cpp index 782e7841..ab6c5dde 100644 --- a/example/src/fix_advanced/main.cpp +++ b/example/src/fix_advanced/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::AUTHORIZATION_STATUS) { std::cout << "Received an event of type AUTHORIZATION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; auto message = event.getMessageList().at(0); @@ -21,7 +21,7 @@ class MyEventHandler : public EventHandler { {40, "2"}, {59, "1"}, }); - session->sendRequestByFix(request); + sessionPtr->sendRequestByFix(request); } } else if (event.getType() == Event::Type::FIX) { std::cout << "Received an event of type FIX:\n" + event.toStringPretty(2, 2) << std::endl; diff --git a/example/src/fix_simple/main.cpp b/example/src/fix_simple/main.cpp index 1487659b..2f1f32af 100644 --- a/example/src/fix_simple/main.cpp +++ b/example/src/fix_simple/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::AUTHORIZATION_STATUS) { std::cout << "Received an event of type AUTHORIZATION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; auto message = event.getMessageList().at(0); @@ -21,7 +21,7 @@ class MyEventHandler : public EventHandler { {40, "2"}, {59, "1"}, }); - session->sendRequestByFix(request); + sessionPtr->sendRequestByFix(request); } } else if (event.getType() == Event::Type::FIX) { std::cout << "Received an event of type FIX:\n" + event.toStringPretty(2, 2) << std::endl; diff --git a/example/src/generic_private_request/main.cpp b/example/src/generic_private_request/main.cpp index c630fe98..28fe4630 100644 --- a/example/src/generic_private_request/main.cpp +++ b/example/src/generic_private_request/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } diff --git a/example/src/generic_public_request/main.cpp b/example/src/generic_public_request/main.cpp index f728a73f..91caf86e 100644 --- a/example/src/generic_public_request/main.cpp +++ b/example/src/generic_public_request/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } diff --git a/example/src/market_data_advanced_request/main.cpp b/example/src/market_data_advanced_request/main.cpp index aff47473..56559020 100644 --- a/example/src/market_data_advanced_request/main.cpp +++ b/example/src/market_data_advanced_request/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } diff --git a/example/src/market_data_advanced_subscription/main.cpp b/example/src/market_data_advanced_subscription/main.cpp index def876dd..ee39135f 100644 --- a/example/src/market_data_advanced_subscription/main.cpp +++ b/example/src/market_data_advanced_subscription/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << toString(event) + "\n" << std::endl; return true; } diff --git a/example/src/market_data_simple_request/main.cpp b/example/src/market_data_simple_request/main.cpp index 4f4823a5..9d8d8418 100644 --- a/example/src/market_data_simple_request/main.cpp +++ b/example/src/market_data_simple_request/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl; return true; } diff --git a/example/src/market_data_simple_subscription/main.cpp b/example/src/market_data_simple_subscription/main.cpp index 52c1c3f6..a0e2318e 100644 --- a/example/src/market_data_simple_subscription/main.cpp +++ b/example/src/market_data_simple_subscription/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) { std::cout << "Received an event of type SUBSCRIPTION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl; } else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) { diff --git a/example/src/override_exchange_url_at_runtime/main.cpp b/example/src/override_exchange_url_at_runtime/main.cpp index 8e1db301..d728c4c6 100644 --- a/example/src/override_exchange_url_at_runtime/main.cpp +++ b/example/src/override_exchange_url_at_runtime/main.cpp @@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::SESSION_STATUS) { for (const auto& message : event.getMessageList()) { if (message.getType() == Message::Type::SESSION_CONNECTION_UP) { diff --git a/example/src/test_order_latency/main.cpp b/example/src/test_order_latency/main.cpp index c017f1db..b8f92a1c 100644 --- a/example/src/test_order_latency/main.cpp +++ b/example/src/test_order_latency/main.cpp @@ -8,14 +8,16 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: MyEventHandler(const std::string& symbol, const std::string& side, const std::string& quantity, const std::string& price, int clientOrderIdLength, - bool cancelByClientOrderId, int numOrders) + bool cancelByClientOrderId, int numOrders, bool byWebsocket, const std::string& websocketOrderEntrySubscriptionCorrelationId) : symbol(symbol), side(side), quantity(quantity), price(price), clientOrderIdLength(clientOrderIdLength), cancelByClientOrderId(cancelByClientOrderId), - numOrders(numOrders) {} + numOrders(numOrders), + byWebsocket(byWebsocket), + websocketOrderEntrySubscriptionCorrelationId(websocketOrderEntrySubscriptionCorrelationId) {} bool processEvent(const Event& event, Session* sessionPtr) override { if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) { @@ -43,7 +45,11 @@ class MyEventHandler : public EventHandler { {"CLIENT_ORDER_ID", clientOrderId}, }); this->orderCreateTimes.emplace(clientOrderId, UtilTime::now()); - sessionPtr->sendRequest(request); + if (this->byWebsocket) { + sessionPtr->sendRequestByWebsocket(this->websocketOrderEntrySubscriptionCorrelationId, request); + } else { + sessionPtr->sendRequest(request); + } }); } } @@ -69,7 +75,11 @@ class MyEventHandler : public EventHandler { }); } this->orderCancelTimes.emplace(clientOrderId, now); - sessionPtr->sendRequest(request); + if (this->byWebsocket) { + sessionPtr->sendRequestByWebsocket(this->websocketOrderEntrySubscriptionCorrelationId, request); + } else { + sessionPtr->sendRequest(request); + } } else if (status == "canceled") { this->orderCancelLatencies.push_back(now - this->orderCancelTimes.at(clientOrderId)); this->orderCancelTimes.erase(clientOrderId); @@ -90,6 +100,9 @@ class MyEventHandler : public EventHandler { int clientOrderIdLength{}; bool cancelByClientOrderId{}; int numOrders{}; + bool byWebsocket{}; + + std::string websocketOrderEntrySubscriptionCorrelationId; std::map orderCreateTimes; std::vector orderCreateLatencies; @@ -129,11 +142,14 @@ int main(int argc, char** argv) { const auto& clientOrderIdLength = UtilSystem::getEnvAsInt("CLIENT_ORDER_ID_LENGTH", 4); const auto& cancelByClientOrderId = UtilSystem::getEnvAsBool("CANCEL_BY_CLIENT_ORDER_ID"); const auto& numOrders = UtilSystem::getEnvAsInt("NUM_ORDERS", 10); + const auto& byWebsocket = UtilSystem::getEnvAsBool("BY_WEBSOCKET"); SessionOptions sessionOptions; SessionConfigs sessionConfigs; - MyEventHandler eventHandler(symbol, side, quantity, price, clientOrderIdLength, cancelByClientOrderId, numOrders); + std::string websocketOrderEntrySubscriptionCorrelationId("any"); + MyEventHandler eventHandler(symbol, side, quantity, price, clientOrderIdLength, cancelByClientOrderId, numOrders, byWebsocket, + websocketOrderEntrySubscriptionCorrelationId); Session session(sessionOptions, sessionConfigs, &eventHandler); - Subscription subscription("okx", symbol, "ORDER_UPDATE"); + Subscription subscription("okx", symbol, "ORDER_UPDATE", "", websocketOrderEntrySubscriptionCorrelationId); session.subscribe(subscription); while (!eventHandler.done) { std::this_thread::sleep_for(std::chrono::seconds(1)); diff --git a/example/src/utility_set_timer/main.cpp b/example/src/utility_set_timer/main.cpp index 31d6dd8d..1a86e628 100644 --- a/example/src/utility_set_timer/main.cpp +++ b/example/src/utility_set_timer/main.cpp @@ -5,15 +5,13 @@ Logger* Logger::logger = nullptr; // This line is needed. class MyEventHandler : public EventHandler { public: - bool processEvent(const Event& event, Session* session) override { + bool processEvent(const Event& event, Session* sessionPtr) override { if (numEvent == 0) { std::cout << std::string("Timer is set at ") + UtilTime::getISOTimestamp(UtilTime::now()) << std::endl; - session->setTimer( + sessionPtr->setTimer( "id", 1000, - [](const boost::system::error_code&) { - std::cout << std::string("Timer error handler is triggered at ") + UtilTime::getISOTimestamp(UtilTime::now()) << std::endl; - }, - []() { std::cout << std::string("Timer success handler is triggered at ") + UtilTime::getISOTimestamp(UtilTime::now()) << std::endl; }); + [](const boost::system::error_code&) { std::cout << std::string("Timer is canceled at ") + UtilTime::getISOTimestamp(UtilTime::now()) << std::endl; }, + []() { std::cout << std::string("Timer is triggered at ") + UtilTime::getISOTimestamp(UtilTime::now()) << std::endl; }); } ++numEvent; return true; diff --git a/include/ccapi_cpp/ccapi_macro.h b/include/ccapi_cpp/ccapi_macro.h index 09ff08b1..d2591384 100644 --- a/include/ccapi_cpp/ccapi_macro.h +++ b/include/ccapi_cpp/ccapi_macro.h @@ -891,6 +891,12 @@ #ifndef CCAPI_BYBIT_URL_WS_BASE #define CCAPI_BYBIT_URL_WS_BASE "wss://stream.bybit.com" #endif +#ifndef CCAPI_BYBIT_URL_WS_ORDER_ENTRY_BASE +#define CCAPI_BYBIT_URL_WS_ORDER_ENTRY_BASE "wss://stream.bybit.com" +#endif +#ifndef CCAPI_BYBIT_WS_ORDER_ENTRY_PATH +#define CCAPI_BYBIT_WS_ORDER_ENTRY_PATH "/v5/trade" +#endif #ifndef CCAPI_ASCENDEX_URL_WS_BASE #define CCAPI_ASCENDEX_URL_WS_BASE "wss://ascendex.com" #endif diff --git a/include/ccapi_cpp/ccapi_session.h b/include/ccapi_cpp/ccapi_session.h index a9a7026e..b669bead 100644 --- a/include/ccapi_cpp/ccapi_session.h +++ b/include/ccapi_cpp/ccapi_session.h @@ -932,16 +932,20 @@ class Session { if (this->eventHandler) { #ifdef CCAPI_USE_SINGLE_THREAD if (ec) { - errorHandler(ec); + if (errorHandler) { + errorHandler(ec); + } } else { - successHandler(); + if (successHandler) { + successHandler(); + } } #else this->eventDispatcher->dispatch([ec, errorHandler, successHandler] { if (ec) { - errorHandler(ec); + if (errorHandler){errorHandler(ec);} } else { - successHandler(); + if (successHandler) {successHandler();} } }); #endif diff --git a/include/ccapi_cpp/ccapi_session_configs.h b/include/ccapi_cpp/ccapi_session_configs.h index 6307fa71..a8bb0baf 100644 --- a/include/ccapi_cpp/ccapi_session_configs.h +++ b/include/ccapi_cpp/ccapi_session_configs.h @@ -28,6 +28,8 @@ class SessionConfigs { const std::map& getUrlWebsocketBase() const { return urlWebsocketBase; } + const std::map& getUrlWebsocketOrderEntryBase() const { return urlWebsocketOrderEntryBase; } + const std::map& getUrlRestBase() const { return urlRestBase; } const std::map& getUrlFixBase() const { return urlFixBase; } @@ -363,6 +365,10 @@ class SessionConfigs { {CCAPI_EXCHANGE_NAME_MEXC_FUTURES, CCAPI_MEXC_FUTURES_URL_WS_BASE}, {CCAPI_EXCHANGE_NAME_WHITEBIT, CCAPI_WHITEBIT_URL_WS_BASE}, }; + this->urlWebsocketOrderEntryBase = { + {CCAPI_EXCHANGE_NAME_OKX, CCAPI_OKX_URL_WS_BASE}, + {CCAPI_EXCHANGE_NAME_BYBIT, CCAPI_BYBIT_URL_WS_ORDER_ENTRY_BASE}, + }; this->initialSequenceByExchangeMap = {{CCAPI_EXCHANGE_NAME_GEMINI, 0}, {CCAPI_EXCHANGE_NAME_BITFINEX, 1}}; } @@ -416,6 +422,7 @@ class SessionConfigs { std::map> exchangeFieldMap; std::map> exchangeFieldWebsocketChannelMap; std::map urlWebsocketBase; + std::map urlWebsocketOrderEntryBase; std::map urlRestBase; std::map urlFixBase; std::map initialSequenceByExchangeMap; diff --git a/include/ccapi_cpp/ccapi_subscription.h b/include/ccapi_cpp/ccapi_subscription.h index 79a67e49..2b96cb27 100644 --- a/include/ccapi_cpp/ccapi_subscription.h +++ b/include/ccapi_cpp/ccapi_subscription.h @@ -43,9 +43,9 @@ class Subscription { this->optionMap[optionKeyValue.at(0)] = optionKeyValue.at(1); } } - std::set executionManagementSubscriptionFieldSet = {std::string(CCAPI_EM_ORDER_UPDATE), std::string(CCAPI_EM_PRIVATE_TRADE), + std::set executionManagementSubscriptionFieldSet = {std::string(CCAPI_EM_ORDER_UPDATE), std::string(CCAPI_EM_PRIVATE_TRADE), std::string(CCAPI_EM_PRIVATE_TRADE_LITE), std::string(CCAPI_EM_BALANCE_UPDATE), - std::string(CCAPI_EM_POSITION_UPDATE)}; + std::string(CCAPI_EM_POSITION_UPDATE), std::string(CCAPI_EM_WEBSOCKET_ORDER_ENTRY)}; if (field == CCAPI_GENERIC_PUBLIC_SUBSCRIPTION) { this->serviceName = CCAPI_MARKET_DATA; } else if (field == CCAPI_FIX || field == CCAPI_FIX_MARKET_DATA || field == CCAPI_FIX_EXECUTION_MANAGEMENT) { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service.h b/include/ccapi_cpp/service/ccapi_execution_management_service.h index a0d5680b..9ec6ae2d 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service.h @@ -68,9 +68,16 @@ class ExecutionManagementService : public Service { that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::SUBSCRIPTION_FAILURE, ec, "create stream", {subscription.getCorrelationId()}); return; } - std::shared_ptr wsConnectionPtr(new WsConnection(that->baseUrlWs, "", {subscription}, credential, streamPtr)); - CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr)); - that->prepareConnect(wsConnectionPtr); + const auto& fieldSet = subscription.getFieldSet(); + if (fieldSet.find(CCAPI_EM_WEBSOCKET_ORDER_ENTRY) != fieldSet.end()) { + std::shared_ptr wsConnectionPtr(new WsConnection(that->baseUrlWsOrderEntry, "", {subscription}, credential, streamPtr)); + CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr)); + that->prepareConnect(wsConnectionPtr); + } else { + std::shared_ptr wsConnectionPtr(new WsConnection(that->baseUrlWs, "", {subscription}, credential, streamPtr)); + CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr)); + that->prepareConnect(wsConnectionPtr); + } }); } } @@ -190,7 +197,7 @@ class ExecutionManagementService : public Service { } virtual void convertRequestForWebsocketCustom(rj::Document& document, rj::Document::AllocatorType& allocator, const WsConnection& wsConnection, - const Request& request, int wsRequestId, const TimePoint& now, const std::string& symbolId, + const Request& request, unsigned long wsRequestId, const TimePoint& now, const std::string& symbolId, const std::map& credential) { auto errorMessage = "Websocket unimplemented operation " + Request::operationToString(request.getOperation()) + " for exchange " + request.getExchange(); throw std::runtime_error(errorMessage); @@ -200,6 +207,7 @@ class ExecutionManagementService : public Service { CCAPI_LOGGER_INFO("about to logon to exchange"); CCAPI_LOGGER_INFO("exchange is " + this->exchangeName); WsConnection& wsConnection = *wsConnectionPtr; + CCAPI_LOGGER_FINE("wsConnection = " + toString(wsConnection)); auto subscription = wsConnection.subscriptionList.at(0); std::vector sendStringList = this->createSendStringListFromSubscription(wsConnection, subscription, now, credential); for (const auto& sendString : sendStringList) { @@ -238,6 +246,7 @@ class ExecutionManagementService : public Service { this->correlationIdByConnectionIdMap.erase(wsConnection.id); } this->wsRequestIdByConnectionIdMap.erase(wsConnection.id); + this->requestCorrelationIdByWsRequestIdByConnectionIdMap.erase(wsConnection.id); Service::onClose(wsConnectionPtr, ec); } @@ -334,7 +343,7 @@ class ExecutionManagementService : public Service { const std::string& symbolId, const std::map& credential) {} virtual void convertRequestForWebsocket(rj::Document& document, rj::Document::AllocatorType& allocator, const WsConnection& wsConnection, - const Request& request, int wsRequestId, const TimePoint& now, const std::string& symbolId, + const Request& request, unsigned long wsRequestId, const TimePoint& now, const std::string& symbolId, const std::map& credential) {} virtual void extractOrderInfoFromRequest(std::vector& elementList, const Request& request, const Request::Operation operation, @@ -365,7 +374,8 @@ class ExecutionManagementService : public Service { std::map> wsConnectionByCorrelationIdMap; // TODO(cryptochassis): for consistency, to be renamed to wsConnectionPtrByCorrelationIdMap - std::map wsRequestIdByConnectionIdMap; + std::map wsRequestIdByConnectionIdMap; + std::map> requestCorrelationIdByWsRequestIdByConnectionIdMap; }; } /* namespace ccapi */ #endif diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_ascendex.h b/include/ccapi_cpp/service/ccapi_execution_management_service_ascendex.h index 0ce62324..17e3f990 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_ascendex.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_ascendex.h @@ -232,7 +232,7 @@ class ExecutionManagementServiceAscendex : public ExecutionManagementService { } void convertRequestForWebsocket(rj::Document& document, rj::Document::AllocatorType& allocator, const WsConnection& wsConnection, const Request& request, - int wsRequestId, const TimePoint& now, const std::string& symbolId, + unsigned long wsRequestId, const TimePoint& now, const std::string& symbolId, const std::map& credential) override { document.SetObject(); document.AddMember("id", rj::Value(std::to_string(wsRequestId).c_str(), allocator).Move(), allocator); diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bitfinex.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bitfinex.h index 1174748b..3d1e2da5 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_bitfinex.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bitfinex.h @@ -196,7 +196,7 @@ class ExecutionManagementServiceBitfinex : public ExecutionManagementService { } void convertRequestForWebsocket(rj::Document& document, rj::Document::AllocatorType& allocator, const WsConnection& wsConnection, const Request& request, - int wsRequestId, const TimePoint& now, const std::string& symbolId, + unsigned long wsRequestId, const TimePoint& now, const std::string& symbolId, const std::map& credential) override { switch (request.getOperation()) { case Request::Operation::CREATE_ORDER: { @@ -475,7 +475,7 @@ class ExecutionManagementServiceBitfinex : public ExecutionManagementService { event.setMessageList(messageList); return event; } -}; // namespace ccapi +}; } /* namespace ccapi */ #endif #endif diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bitget.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bitget.h index b119a9de..07779ed4 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_bitget.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bitget.h @@ -431,7 +431,7 @@ class ExecutionManagementServiceBitget : public ExecutionManagementServiceBitget event.setMessageList(messageList); return event; } -}; // namespace ccapi +}; } /* namespace ccapi */ #endif #endif diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h index e8854e96..8d74e788 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bitmex.h @@ -465,7 +465,7 @@ class ExecutionManagementServiceBitmex : public ExecutionManagementService { event.setMessageList(messageList); return event; } -}; // namespace ccapi +}; } /* namespace ccapi */ #endif #endif diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_bybit.h b/include/ccapi_cpp/service/ccapi_execution_management_service_bybit.h index 03c20275..81ae7205 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_bybit.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_bybit.h @@ -12,9 +12,11 @@ class ExecutionManagementServiceBybit : public ExecutionManagementService { : ExecutionManagementService(eventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->exchangeName = CCAPI_EXCHANGE_NAME_BYBIT; this->baseUrlWs = sessionConfigs.getUrlWebsocketBase().at(this->exchangeName) + "/v5/private"; + this->baseUrlWsOrderEntry = sessionConfigs.getUrlWebsocketOrderEntryBase().at(this->exchangeName) + CCAPI_BYBIT_WS_ORDER_ENTRY_PATH; this->baseUrlRest = sessionConfigs.getUrlRestBase().at(this->exchangeName); this->setHostRestFromUrlRest(this->baseUrlRest); this->setHostWsFromUrlWs(this->baseUrlWs); + this->setHostWsFromUrlWsOrderEntry(this->baseUrlWsOrderEntry); this->apiKeyName = CCAPI_BYBIT_API_KEY; this->apiSecretName = CCAPI_BYBIT_API_SECRET; this->setupCredential({this->apiKeyName, this->apiSecretName}); @@ -279,6 +281,25 @@ class ExecutionManagementServiceBybit : public ExecutionManagementService { } } + void extractOrderInfoFromRequest(std::vector& elementList, const rj::Document& document) { + const std::map>& extractionFieldNameMap = { + {CCAPI_EM_ORDER_ID, std::make_pair("orderId", JsonDataType::STRING)}, + {CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("orderLinkId", JsonDataType::STRING)}, + }; + const rj::Value& data = document["data"]; + if (data.IsObject()) { + Element element; + this->extractOrderInfo(element, data, extractionFieldNameMap); + elementList.emplace_back(std::move(element)); + } else { + for (const auto& x : data.GetArray()) { + Element element; + this->extractOrderInfo(element, x, extractionFieldNameMap); + elementList.emplace_back(std::move(element)); + } + } + } + void extractOrderInfoFromRequest(std::vector& elementList, const Request& request, const Request::Operation operation, const rj::Document& document) override { std::map> extractionFieldNameMap = { @@ -340,164 +361,269 @@ class ExecutionManagementServiceBybit : public ExecutionManagementService { std::vector messageList; Message message; message.setTimeReceived(timeReceived); - message.setCorrelationIdList({subscription.getCorrelationId()}); - const auto& fieldSet = subscription.getFieldSet(); - const auto& instrumentSet = subscription.getInstrumentSet(); - if (document.HasMember("topic")) { - std::string topic = document["topic"].GetString(); - if (topic.rfind("order", 0) == 0) { - event.setType(Event::Type::SUBSCRIPTION_DATA); - const rj::Value& data = document["data"]; - for (const auto& x : data.GetArray()) { - std::string instrument = x["symbol"].GetString(); - if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) { - auto time = TimePoint(std::chrono::milliseconds(std::stoll(x["updatedTime"].GetString()))); + if (wsConnectionPtr->path == CCAPI_BYBIT_WS_ORDER_ENTRY_PATH) { + if (document.HasMember("op")) { + std::string op = document["op"].GetString(); + if (op == "auth") { + std::string retCode = document["retCode"].GetString(); + if (retCode == "0") { + event.setType(Event::Type::AUTHORIZATION_STATUS); Message message; - message.setTimeReceived(timeReceived); - message.setCorrelationIdList({subscription.getCorrelationId()}); - message.setTime(time); - message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE); - const std::map>& extractionFieldNameMap = { - {CCAPI_EM_ORDER_ID, std::make_pair("orderId", JsonDataType::STRING)}, - {CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("orderLinkId", JsonDataType::STRING)}, - {CCAPI_EM_ORDER_SIDE, std::make_pair("side", JsonDataType::STRING)}, - {CCAPI_EM_ORDER_LIMIT_PRICE, std::make_pair("price", JsonDataType::STRING)}, - {CCAPI_EM_ORDER_QUANTITY, std::make_pair("qty", JsonDataType::STRING)}, - {CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, std::make_pair("cumExecQty", JsonDataType::STRING)}, - {CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::make_pair("cumExecValue", JsonDataType::STRING)}, - {CCAPI_EM_ORDER_STATUS, std::make_pair("orderStatus", JsonDataType::STRING)}, - {CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("symbol", JsonDataType::STRING)}, - }; - Element info; - this->extractOrderInfo(info, x, extractionFieldNameMap); - std::vector elementList; - elementList.emplace_back(std::move(info)); - message.setElementList(elementList); + message.setType(Message::Type::AUTHORIZATION_SUCCESS); + Element element; + element.insert(CCAPI_INFO_MESSAGE, textMessage); + message.setElementList({element}); messageList.emplace_back(std::move(message)); } - } - } else if (topic.rfind("execution", 0) == 0) { - event.setType(Event::Type::SUBSCRIPTION_DATA); - const rj::Value& data = document["data"]; - for (const auto& x : data.GetArray()) { - std::string instrument = x["symbol"].GetString(); - if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) { - auto time = TimePoint(std::chrono::milliseconds(std::stoll(x["execTime"].GetString()))); - Message message; - message.setTimeReceived(timeReceived); - message.setCorrelationIdList({subscription.getCorrelationId()}); - message.setTime(time); - message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_PRIVATE_TRADE); - std::vector elementList; + } else if (op == "order.create" || op == "order.cancel") { + unsigned long wsRequestId = std::stoul(document["reqId"].GetString()); + const auto& requestCorrelationId = this->requestCorrelationIdByWsRequestIdByConnectionIdMap.at(wsConnectionPtr->id).at(wsRequestId); + event.setType(Event::Type::RESPONSE); + std::string retCode = document["retCode"].GetString(); + if (retCode != "0") { + message.setType(Message::Type::RESPONSE_ERROR); Element element; - element.insert(CCAPI_TRADE_ID, x["execId"].GetString()); - element.insert(CCAPI_EM_ORDER_LAST_EXECUTED_PRICE, std::string(x["execPrice"].GetString())); - element.insert(CCAPI_EM_ORDER_LAST_EXECUTED_SIZE, std::string(x["execQty"].GetString())); - element.insert(CCAPI_EM_ORDER_SIDE, std::string(x["side"].GetString()) == "Buy" ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL); - element.insert(CCAPI_IS_MAKER, x["isMaker"].GetBool() ? "1" : "0"); - element.insert(CCAPI_EM_ORDER_ID, std::string(x["orderId"].GetString())); - element.insert(CCAPI_EM_CLIENT_ORDER_ID, std::string(x["orderLinkId"].GetString())); - element.insert(CCAPI_EM_ORDER_INSTRUMENT, instrument); - { - auto it = x.FindMember("execFee"); - if (it != x.MemberEnd() && !it->value.IsNull()) { - element.insert(CCAPI_EM_ORDER_FEE_QUANTITY, std::string(it->value.GetString())); - } + element.insert(CCAPI_ERROR_MESSAGE, textMessage); + message.setElementList({element}); + message.setCorrelationIdList({requestCorrelationId}); + messageList.emplace_back(std::move(message)); + } else { + std::vector elementList; + std::string op = document["op"].GetString(); + if (op == "order.create") { + message.setType(Message::Type::CREATE_ORDER); + } else if (op == "order.cancel") { + message.setType(Message::Type::CANCEL_ORDER); } - elementList.emplace_back(std::move(element)); + this->extractOrderInfoFromRequest(elementList, document); message.setElementList(elementList); + message.setCorrelationIdList({requestCorrelationId}); messageList.emplace_back(std::move(message)); } } - } else if (topic == "wallet") { - event.setType(Event::Type::SUBSCRIPTION_DATA); - const rj::Value& data = document["data"]; - for (const auto& x : data[0]["coin"].GetArray()) { - Message message; - message.setTimeReceived(timeReceived); - message.setCorrelationIdList({subscription.getCorrelationId()}); - message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_BALANCE_UPDATE); - std::vector elementList; - Element element; - element.insert(CCAPI_EM_ASSET, x["coin"].GetString()); - element.insert(CCAPI_EM_QUANTITY_TOTAL, x["walletBalance"].GetString()); - element.insert(CCAPI_EM_QUANTITY_AVAILABLE_FOR_TRADING, x["equity"].GetString()); - elementList.emplace_back(std::move(element)); - message.setElementList(elementList); - messageList.emplace_back(std::move(message)); - } - } else if (topic.rfind("position", 0) == 0) { - event.setType(Event::Type::SUBSCRIPTION_DATA); - const rj::Value& data = document["data"]; - for (const auto& x : data.GetArray()) { - std::string instrument = x["symbol"].GetString(); - if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) { - auto time = TimePoint(std::chrono::milliseconds(std::stoll(x["updatedTime"].GetString()))); + } + } else { + message.setCorrelationIdList({subscription.getCorrelationId()}); + const auto& fieldSet = subscription.getFieldSet(); + const auto& instrumentSet = subscription.getInstrumentSet(); + if (document.HasMember("topic")) { + std::string topic = document["topic"].GetString(); + if (topic.rfind("order", 0) == 0) { + event.setType(Event::Type::SUBSCRIPTION_DATA); + const rj::Value& data = document["data"]; + for (const auto& x : data.GetArray()) { + std::string instrument = x["symbol"].GetString(); + if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) { + auto time = TimePoint(std::chrono::milliseconds(std::stoll(x["updatedTime"].GetString()))); + Message message; + message.setTimeReceived(timeReceived); + message.setCorrelationIdList({subscription.getCorrelationId()}); + message.setTime(time); + message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE); + const std::map>& extractionFieldNameMap = { + {CCAPI_EM_ORDER_ID, std::make_pair("orderId", JsonDataType::STRING)}, + {CCAPI_EM_CLIENT_ORDER_ID, std::make_pair("orderLinkId", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_SIDE, std::make_pair("side", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_LIMIT_PRICE, std::make_pair("price", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_QUANTITY, std::make_pair("qty", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, std::make_pair("cumExecQty", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY, std::make_pair("cumExecValue", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_STATUS, std::make_pair("orderStatus", JsonDataType::STRING)}, + {CCAPI_EM_ORDER_INSTRUMENT, std::make_pair("symbol", JsonDataType::STRING)}, + }; + Element info; + this->extractOrderInfo(info, x, extractionFieldNameMap); + std::vector elementList; + elementList.emplace_back(std::move(info)); + message.setElementList(elementList); + messageList.emplace_back(std::move(message)); + } + } + } else if (topic.rfind("execution", 0) == 0) { + event.setType(Event::Type::SUBSCRIPTION_DATA); + const rj::Value& data = document["data"]; + for (const auto& x : data.GetArray()) { + std::string instrument = x["symbol"].GetString(); + if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) { + auto time = TimePoint(std::chrono::milliseconds(std::stoll(x["execTime"].GetString()))); + Message message; + message.setTimeReceived(timeReceived); + message.setCorrelationIdList({subscription.getCorrelationId()}); + message.setTime(time); + message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_PRIVATE_TRADE); + std::vector elementList; + Element element; + element.insert(CCAPI_TRADE_ID, x["execId"].GetString()); + element.insert(CCAPI_EM_ORDER_LAST_EXECUTED_PRICE, std::string(x["execPrice"].GetString())); + element.insert(CCAPI_EM_ORDER_LAST_EXECUTED_SIZE, std::string(x["execQty"].GetString())); + element.insert(CCAPI_EM_ORDER_SIDE, std::string(x["side"].GetString()) == "Buy" ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL); + element.insert(CCAPI_IS_MAKER, x["isMaker"].GetBool() ? "1" : "0"); + element.insert(CCAPI_EM_ORDER_ID, std::string(x["orderId"].GetString())); + element.insert(CCAPI_EM_CLIENT_ORDER_ID, std::string(x["orderLinkId"].GetString())); + element.insert(CCAPI_EM_ORDER_INSTRUMENT, instrument); + { + auto it = x.FindMember("execFee"); + if (it != x.MemberEnd() && !it->value.IsNull()) { + element.insert(CCAPI_EM_ORDER_FEE_QUANTITY, std::string(it->value.GetString())); + } + } + elementList.emplace_back(std::move(element)); + message.setElementList(elementList); + messageList.emplace_back(std::move(message)); + } + } + } else if (topic == "wallet") { + event.setType(Event::Type::SUBSCRIPTION_DATA); + const rj::Value& data = document["data"]; + for (const auto& x : data[0]["coin"].GetArray()) { Message message; message.setTimeReceived(timeReceived); message.setCorrelationIdList({subscription.getCorrelationId()}); - message.setTime(time); - message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_POSITION_UPDATE); + message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_BALANCE_UPDATE); std::vector elementList; Element element; - element.insert(CCAPI_INSTRUMENT, x["symbol"].GetString()); - element.insert(CCAPI_EM_POSITION_SIDE, x["side"].GetString()); - element.insert(CCAPI_EM_POSITION_QUANTITY, x["size"].GetString()); - element.insert(CCAPI_EM_POSITION_ENTRY_PRICE, x["entryPrice"].GetString()); - element.insert(CCAPI_EM_POSITION_LEVERAGE, x["leverage"].GetString()); + element.insert(CCAPI_EM_ASSET, x["coin"].GetString()); + element.insert(CCAPI_EM_QUANTITY_TOTAL, x["walletBalance"].GetString()); + element.insert(CCAPI_EM_QUANTITY_AVAILABLE_FOR_TRADING, x["equity"].GetString()); elementList.emplace_back(std::move(element)); message.setElementList(elementList); messageList.emplace_back(std::move(message)); } - } - } - } else if (document.HasMember("op")) { - std::string op = document["op"].GetString(); - if (op == "auth") { - bool success = document["success"].GetBool(); - if (success) { - rj::Document document; - document.SetObject(); - rj::Document::AllocatorType& allocator = document.GetAllocator(); - document.AddMember("op", rj::Value("subscribe").Move(), allocator); - rj::Value args(rj::kArrayType); - if (fieldSet.find(CCAPI_EM_ORDER_UPDATE) != fieldSet.end()) { - args.PushBack(rj::Value(("order." + subscription.getInstrumentType()).c_str(), allocator).Move(), allocator); - } - if (fieldSet.find(CCAPI_EM_PRIVATE_TRADE) != fieldSet.end()) { - args.PushBack(rj::Value(("execution." + subscription.getInstrumentType()).c_str(), allocator).Move(), allocator); - } - if (fieldSet.find(CCAPI_EM_POSITION_UPDATE) != fieldSet.end() && subscription.getInstrumentType() != "spot") { - args.PushBack(rj::Value(("position." + subscription.getInstrumentType()).c_str(), allocator).Move(), allocator); - } - if (fieldSet.find(CCAPI_EM_BALANCE_UPDATE) != fieldSet.end()) { - args.PushBack(rj::Value("wallet").Move(), allocator); + } else if (topic.rfind("position", 0) == 0) { + event.setType(Event::Type::SUBSCRIPTION_DATA); + const rj::Value& data = document["data"]; + for (const auto& x : data.GetArray()) { + std::string instrument = x["symbol"].GetString(); + if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) { + auto time = TimePoint(std::chrono::milliseconds(std::stoll(x["updatedTime"].GetString()))); + Message message; + message.setTimeReceived(timeReceived); + message.setCorrelationIdList({subscription.getCorrelationId()}); + message.setTime(time); + message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_POSITION_UPDATE); + std::vector elementList; + Element element; + element.insert(CCAPI_INSTRUMENT, x["symbol"].GetString()); + element.insert(CCAPI_EM_POSITION_SIDE, x["side"].GetString()); + element.insert(CCAPI_EM_POSITION_QUANTITY, x["size"].GetString()); + element.insert(CCAPI_EM_POSITION_ENTRY_PRICE, x["entryPrice"].GetString()); + element.insert(CCAPI_EM_POSITION_LEVERAGE, x["leverage"].GetString()); + elementList.emplace_back(std::move(element)); + message.setElementList(elementList); + messageList.emplace_back(std::move(message)); + } } - document.AddMember("args", args, allocator); - rj::StringBuffer stringBuffer; - rj::Writer writer(stringBuffer); - document.Accept(writer); - std::string sendString = stringBuffer.GetString(); - ErrorCode ec; - this->send(wsConnectionPtr, sendString, ec); - if (ec) { - this->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::SUBSCRIPTION_FAILURE, ec, "subscribe"); + } + } else if (document.HasMember("op")) { + std::string op = document["op"].GetString(); + if (op == "auth") { + bool success = document["success"].GetBool(); + if (success) { + event.setType(Event::Type::AUTHORIZATION_STATUS); + Message message; + message.setType(Message::Type::AUTHORIZATION_SUCCESS); + Element element; + element.insert(CCAPI_INFO_MESSAGE, textMessage); + message.setElementList({element}); + messageList.emplace_back(std::move(message)); + + rj::Document document; + document.SetObject(); + rj::Document::AllocatorType& allocator = document.GetAllocator(); + document.AddMember("op", rj::Value("subscribe").Move(), allocator); + rj::Value args(rj::kArrayType); + const auto& instrumentType = subscription.getInstrumentType(); + if (fieldSet.find(CCAPI_EM_ORDER_UPDATE) != fieldSet.end()) { + args.PushBack(rj::Value((instrumentType.empty() ? "order" : "order." + instrumentType).c_str(), allocator).Move(), allocator); + } + if (fieldSet.find(CCAPI_EM_PRIVATE_TRADE) != fieldSet.end()) { + args.PushBack(rj::Value((instrumentType.empty() ? "execution" : "execution." + instrumentType).c_str(), allocator).Move(), allocator); + } + if (fieldSet.find(CCAPI_EM_POSITION_UPDATE) != fieldSet.end() && subscription.getInstrumentType() != "spot") { + args.PushBack(rj::Value((instrumentType.empty() ? "position" : "position." + instrumentType).c_str(), allocator).Move(), allocator); + } + if (fieldSet.find(CCAPI_EM_BALANCE_UPDATE) != fieldSet.end()) { + args.PushBack(rj::Value("wallet").Move(), allocator); + } + document.AddMember("args", args, allocator); + rj::StringBuffer stringBuffer; + rj::Writer writer(stringBuffer); + document.Accept(writer); + std::string sendString = stringBuffer.GetString(); + ErrorCode ec; + this->send(wsConnectionPtr, sendString, ec); + if (ec) { + this->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::SUBSCRIPTION_FAILURE, ec, "subscribe"); + } } + } else if (op == "subscribe") { + bool success = document["success"].GetBool(); + event.setType(Event::Type::SUBSCRIPTION_STATUS); + message.setType(success ? Message::Type::SUBSCRIPTION_STARTED : Message::Type::SUBSCRIPTION_FAILURE); + Element element; + element.insert(success ? CCAPI_INFO_MESSAGE : CCAPI_ERROR_MESSAGE, textMessage); + message.setElementList({element}); + messageList.emplace_back(std::move(message)); } - } else if (op == "subscribe") { - bool success = document["success"].GetBool(); - event.setType(Event::Type::SUBSCRIPTION_STATUS); - message.setType(success ? Message::Type::SUBSCRIPTION_STARTED : Message::Type::SUBSCRIPTION_FAILURE); - Element element; - element.insert(success ? CCAPI_INFO_MESSAGE : CCAPI_ERROR_MESSAGE, textMessage); - message.setElementList({element}); - messageList.emplace_back(std::move(message)); } } event.setMessageList(messageList); return event; } -}; // namespace ccapi + + void convertRequestForWebsocket(rj::Document& document, rj::Document::AllocatorType& allocator, const WsConnection& wsConnection, const Request& request, + unsigned long wsRequestId, const TimePoint& now, const std::string& symbolId, + const std::map& credential) override { + document.SetObject(); + document.AddMember("reqId", rj::Value(std::to_string(wsRequestId).c_str(), allocator).Move(), allocator); + this->requestCorrelationIdByWsRequestIdByConnectionIdMap[wsConnection.id][wsRequestId] = request.getCorrelationId(); + rj::Value header(rj::kObjectType); + header.AddMember("X-BAPI-TIMESTAMP", + rj::Value(std::to_string(std::chrono::duration_cast(now.time_since_epoch()).count()).c_str(), allocator).Move(), + allocator); + header.AddMember("X-BAPI-RECV-WINDOW", rj::Value(std::to_string(CCAPI_BYBIT_BASE_API_RECEIVE_WINDOW_MILLISECONDS).c_str(), allocator).Move(), allocator); + header.AddMember("Referer", rj::Value(CCAPI_BYBIT_API_BROKER_ID, allocator), allocator); + document.AddMember("header", header, allocator); + Request::Operation operation = request.getOperation(); + switch (operation) { + case Request::Operation::CREATE_ORDER: { + document.AddMember("op", rj::Value("order.create").Move(), allocator); + rj::Value args(rj::kArrayType); + const std::map param = request.getFirstParamWithDefault(); + rj::Value arg(rj::kObjectType); + this->appendParam(arg, allocator, param); + if (param.find("category") == param.end()) { + arg.AddMember("category", rj::Value("spot").Move(), allocator); + } + if (param.find("orderType") == param.end()) { + arg.AddMember("orderType", rj::Value("Limit").Move(), allocator); + } + if (!symbolId.empty()) { + this->appendSymbolId(arg, allocator, symbolId, "symbol"); + } + args.PushBack(arg, allocator); + document.AddMember("args", args, allocator); + } break; + case Request::Operation::CANCEL_ORDER: { + document.AddMember("op", rj::Value("order.cancel").Move(), allocator); + rj::Value args(rj::kArrayType); + const std::map param = request.getFirstParamWithDefault(); + rj::Value arg(rj::kObjectType); + this->appendParam(arg, allocator, param); + if (param.find("category") == param.end()) { + arg.AddMember("category", rj::Value("spot").Move(), allocator); + } + if (!symbolId.empty()) { + this->appendSymbolId(arg, allocator, symbolId, "symbol"); + } + args.PushBack(arg, allocator); + document.AddMember("args", args, allocator); + } break; + default: + this->convertRequestForWebsocketCustom(document, allocator, wsConnection, request, wsRequestId, now, symbolId, credential); + } + } +}; } /* namespace ccapi */ #endif #endif diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_cryptocom.h b/include/ccapi_cpp/service/ccapi_execution_management_service_cryptocom.h index 927257fd..54b995d7 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_cryptocom.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_cryptocom.h @@ -204,7 +204,7 @@ class ExecutionManagementServiceCryptocom : public ExecutionManagementService { } void convertRequestForWebsocket(rj::Document& document, rj::Document::AllocatorType& allocator, const WsConnection& wsConnection, const Request& request, - int wsRequestId, const TimePoint& now, const std::string& symbolId, + unsigned long wsRequestId, const TimePoint& now, const std::string& symbolId, const std::map& credential) override { switch (request.getOperation()) { case Request::Operation::CREATE_ORDER: { diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h b/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h index 2ee57a81..b9b69c00 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h @@ -12,9 +12,11 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { : ExecutionManagementService(eventHandler, sessionOptions, sessionConfigs, serviceContextPtr) { this->exchangeName = CCAPI_EXCHANGE_NAME_OKX; this->baseUrlWs = sessionConfigs.getUrlWebsocketBase().at(this->exchangeName) + CCAPI_OKX_PRIVATE_WS_PATH; + this->baseUrlWsOrderEntry = sessionConfigs.getUrlWebsocketOrderEntryBase().at(this->exchangeName) + CCAPI_OKX_PRIVATE_WS_PATH; this->baseUrlRest = sessionConfigs.getUrlRestBase().at(this->exchangeName); this->setHostRestFromUrlRest(this->baseUrlRest); this->setHostWsFromUrlWs(this->baseUrlWs); + this->setHostWsFromUrlWsOrderEntry(this->baseUrlWsOrderEntry); this->apiKeyName = CCAPI_OKX_API_KEY; this->apiSecretName = CCAPI_OKX_API_SECRET; this->apiPassphraseName = CCAPI_OKX_API_PASSPHRASE; @@ -225,10 +227,11 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { } void convertRequestForWebsocket(rj::Document& document, rj::Document::AllocatorType& allocator, const WsConnection& wsConnection, const Request& request, - int wsRequestId, const TimePoint& now, const std::string& symbolId, + unsigned long wsRequestId, const TimePoint& now, const std::string& symbolId, const std::map& credential) override { document.SetObject(); - document.AddMember("id", rj::Value(request.getCorrelationId().c_str(), allocator).Move(), allocator); + document.AddMember("id", rj::Value(std::to_string(wsRequestId).c_str(), allocator).Move(), allocator); + this->requestCorrelationIdByWsRequestIdByConnectionIdMap[wsConnection.id][wsRequestId] = request.getCorrelationId(); Request::Operation operation = request.getOperation(); switch (operation) { case Request::Operation::CREATE_ORDER: { @@ -385,6 +388,18 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { auto it = document.FindMember("event"); std::string eventStr = it != document.MemberEnd() ? it->value.GetString() : ""; if (eventStr == "login") { + Event event; + event.setType(Event::Type::AUTHORIZATION_STATUS); + Message message; + message.setType(Message::Type::AUTHORIZATION_SUCCESS); + Element element; + element.insert(CCAPI_INFO_MESSAGE, textMessage); + message.setElementList({element}); + std::vector messageList; + messageList.emplace_back(std::move(message)); + event.setMessageList(messageList); + this->eventHandler(event, nullptr); + rj::Document document; document.SetObject(); auto& allocator = document.GetAllocator(); @@ -439,20 +454,22 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { arg.AddMember("channel", rj::Value("balance_and_position").Move(), allocator); args.PushBack(arg, allocator); } - document.AddMember("args", args, allocator); - rj::StringBuffer stringBufferSubscribe; - rj::Writer writerSubscribe(stringBufferSubscribe); - document.Accept(writerSubscribe); - std::string sendString = stringBufferSubscribe.GetString(); - ErrorCode ec; + if (!args.Empty()) { + document.AddMember("args", args, allocator); + rj::StringBuffer stringBufferSubscribe; + rj::Writer writerSubscribe(stringBufferSubscribe); + document.Accept(writerSubscribe); + std::string sendString = stringBufferSubscribe.GetString(); + ErrorCode ec; - this->send(wsConnectionPtr, sendString, ec); + this->send(wsConnectionPtr, sendString, ec); - if (ec) { - this->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::SUBSCRIPTION_FAILURE, ec, "subscribe"); + if (ec) { + this->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::SUBSCRIPTION_FAILURE, ec, "subscribe"); + } } } else { - Event event = this->createEvent(subscription, textMessage, document, eventStr, timeReceived); + Event event = this->createEvent(wsConnectionPtr, subscription, textMessage, document, eventStr, timeReceived); if (!event.getMessageList().empty()) { this->eventHandler(event, nullptr); } @@ -460,8 +477,8 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { } } - Event createEvent(const Subscription& subscription, const std::string& textMessage, const rj::Document& document, const std::string& eventStr, - const TimePoint& timeReceived) { + Event createEvent(const std::shared_ptr wsConnectionPtr, const Subscription& subscription, const std::string& textMessage, + const rj::Document& document, const std::string& eventStr, const TimePoint& timeReceived) { Event event; std::vector messageList; Message message; @@ -472,6 +489,8 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { auto it = document.FindMember("op"); std::string op = it != document.MemberEnd() ? it->value.GetString() : ""; if (op == "order" || op == "cancel-order") { + unsigned long wsRequestId = std::stoul(document["id"].GetString()); + const auto& requestCorrelationId = this->requestCorrelationIdByWsRequestIdByConnectionIdMap.at(wsConnectionPtr->id).at(wsRequestId); event.setType(Event::Type::RESPONSE); std::string code = document["code"].GetString(); if (code != "0") { @@ -479,8 +498,7 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { Element element; element.insert(CCAPI_ERROR_MESSAGE, textMessage); message.setElementList({element}); - std::string id = document["id"].GetString(); - message.setCorrelationIdList({id}); + message.setCorrelationIdList({requestCorrelationId}); messageList.emplace_back(std::move(message)); } else { std::vector elementList; @@ -491,10 +509,10 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { } this->extractOrderInfoFromRequest(elementList, document); message.setElementList(elementList); - std::string id = document["id"].GetString(); - message.setCorrelationIdList({id}); + message.setCorrelationIdList({requestCorrelationId}); messageList.emplace_back(std::move(message)); } + this->requestCorrelationIdByWsRequestIdByConnectionIdMap.at(wsConnectionPtr->id).erase(wsRequestId); } else { message.setCorrelationIdList({correlationId}); const rj::Value& arg = document["arg"]; diff --git a/include/ccapi_cpp/service/ccapi_service.h b/include/ccapi_cpp/service/ccapi_service.h index 399ecc87..f6ed34aa 100644 --- a/include/ccapi_cpp/service/ccapi_service.h +++ b/include/ccapi_cpp/service/ccapi_service.h @@ -306,6 +306,12 @@ class Service : public std::enable_shared_from_this { this->portWs = hostPort.second; } + void setHostWsFromUrlWsOrderEntry(std::string baseUrlWsOrderEntry) { + auto hostPort = this->extractHostFromUrl(baseUrlWs); + this->hostWsOrderEntry = hostPort.first; + this->portWsOrderEntry = hostPort.second; + } + std::pair extractHostFromUrl(std::string baseUrl) { std::string host; std::string port; @@ -1526,6 +1532,7 @@ class Service : public std::enable_shared_from_this { std::string apiSecretName; std::string exchangeName; std::string baseUrlWs; + std::string baseUrlWsOrderEntry; std::string baseUrlRest; std::function* eventQueue)> eventHandler; SessionOptions sessionOptions; @@ -1536,6 +1543,8 @@ class Service : public std::enable_shared_from_this { std::string portRest; std::string hostWs; std::string portWs; + std::string hostWsOrderEntry; + std::string portWsOrderEntry; // tcp::resolver::results_type tcpResolverResultsRest, tcpResolverResultsWs; std::map>>> httpConnectionPool; std::map credentialDefault; From 13cc800393ace28ebdfc4ee4e32c9560bfdc01c1 Mon Sep 17 00:00:00 2001 From: ubuntu <> Date: Wed, 28 May 2025 22:00:53 +0000 Subject: [PATCH 05/17] fix compile issues --- .github/workflows/test.yml | 16 +-- format.sh | 8 +- .../ccapi_execution_management_service_okx.h | 10 +- test/test_build/CMakeLists.txt | 97 ++++++++++++------- test/test_unit/CMakeLists.txt | 20 ++-- .../src/execution_management/okx/test.cpp | 18 ++-- 6 files changed, 99 insertions(+), 70 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f3c6887d..1e04105b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,11 +34,11 @@ jobs: os: ubuntu-latest, cc: "gcc", cxx: "g++" } - # - { - # name: "macOS Latest Clang", - # os: macos-latest, - # cc: "clang", cxx: "clang++" - # } + - { + name: "macOS Latest Clang", + os: macos-latest, + cc: "clang", cxx: "clang++" + } # - { # name: "Windows Latest MinGW", # os: windows-latest, @@ -126,7 +126,7 @@ jobs: message(STATUS "Using host CMake version: ${cmake_version}") if ("${{ runner.os }}" STREQUAL "macOS") execute_process( - COMMAND brew reinstall openssl@1.1 + COMMAND brew reinstall openssl@3 ) elseif ("${{ runner.os }}" STREQUAL "Windows") execute_process( @@ -240,7 +240,7 @@ jobs: execute_process( COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake -DBUILD_PYTHON=ON - -DBUILD_JAVA=ON + # -DBUILD_JAVA=ON # -DBUILD_CSHARP=ON # -DBUILD_GO=ON # -DBUILD_JAVASCRIPT=ON @@ -370,7 +370,7 @@ jobs: execute_process( COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake - -DBUILD_TEST_BUILD=OFF + -DBUILD_TEST_BUILD=ON -DBUILD_TEST_UNIT=ON -S test -B test/build diff --git a/format.sh b/format.sh index 8c56cc90..5038896c 100755 --- a/format.sh +++ b/format.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash ./format_cpp.sh -./format_csharp.sh -./format_go.sh -./format_java.sh -./format_javascript.sh +# ./format_csharp.sh +# ./format_go.sh +# ./format_java.sh +# ./format_javascript.sh ./format_python.sh diff --git a/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h b/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h index b9b69c00..e1c1a108 100644 --- a/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h +++ b/include/ccapi_cpp/service/ccapi_execution_management_service_okx.h @@ -469,7 +469,7 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { } } } else { - Event event = this->createEvent(wsConnectionPtr, subscription, textMessage, document, eventStr, timeReceived); + Event event = this->createEvent(*wsConnectionPtr, subscription, textMessage, document, eventStr, timeReceived); if (!event.getMessageList().empty()) { this->eventHandler(event, nullptr); } @@ -477,8 +477,8 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { } } - Event createEvent(const std::shared_ptr wsConnectionPtr, const Subscription& subscription, const std::string& textMessage, - const rj::Document& document, const std::string& eventStr, const TimePoint& timeReceived) { + Event createEvent(const WsConnection& wsConnection, const Subscription& subscription, const std::string& textMessage, const rj::Document& document, + const std::string& eventStr, const TimePoint& timeReceived) { Event event; std::vector messageList; Message message; @@ -490,7 +490,7 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { std::string op = it != document.MemberEnd() ? it->value.GetString() : ""; if (op == "order" || op == "cancel-order") { unsigned long wsRequestId = std::stoul(document["id"].GetString()); - const auto& requestCorrelationId = this->requestCorrelationIdByWsRequestIdByConnectionIdMap.at(wsConnectionPtr->id).at(wsRequestId); + const auto& requestCorrelationId = this->requestCorrelationIdByWsRequestIdByConnectionIdMap.at(wsConnection.id).at(wsRequestId); event.setType(Event::Type::RESPONSE); std::string code = document["code"].GetString(); if (code != "0") { @@ -512,7 +512,7 @@ class ExecutionManagementServiceOkx : public ExecutionManagementService { message.setCorrelationIdList({requestCorrelationId}); messageList.emplace_back(std::move(message)); } - this->requestCorrelationIdByWsRequestIdByConnectionIdMap.at(wsConnectionPtr->id).erase(wsRequestId); + this->requestCorrelationIdByWsRequestIdByConnectionIdMap.at(wsConnection.id).erase(wsRequestId); } else { message.setCorrelationIdList({correlationId}); const rj::Value& arg = document["arg"]; diff --git a/test/test_build/CMakeLists.txt b/test/test_build/CMakeLists.txt index f58a1aab..977f14e9 100644 --- a/test/test_build/CMakeLists.txt +++ b/test/test_build/CMakeLists.txt @@ -1,70 +1,79 @@ set(NAME build_test) project(${NAME}) + add_compile_definitions(CCAPI_ENABLE_LOG_TRACE) + set(SERVICE_LIST "MARKET_DATA" "EXECUTION_MANAGEMENT" "FIX") + set(MARKET_DATA_EXCHANGE_LIST "COINBASE" - "GEMINI" - "KRAKEN" - "KRAKEN_FUTURES" - "BITSTAMP" - "BITFINEX" - "BITMEX" - "BINANCE_US" + # "GEMINI" + # "KRAKEN" + # "KRAKEN_FUTURES" + # "BITSTAMP" + # "BITFINEX" + # "BITMEX" + # "BINANCE_US" "BINANCE" "BINANCE_USDS_FUTURES" "BINANCE_COIN_FUTURES" - "HUOBI" - "HUOBI_USDT_SWAP" - "HUOBI_COIN_SWAP" + # "HUOBI" + # "HUOBI_USDT_SWAP" + # "HUOBI_COIN_SWAP" "OKX" - "ERISX" - "KUCOIN" - "KUCOIN_FUTURES" - "DERIBIT" + # "ERISX" + # "KUCOIN" + # "KUCOIN_FUTURES" + # "DERIBIT" "GATEIO" "GATEIO_PERPETUAL_FUTURES" "CRYPTOCOM" - "ASCENDEX" + # "ASCENDEX" "BYBIT" "BITGET" "BITGET_FUTURES" - "BITMART" - "MEXC" - "MEXC_FUTURES" - "WHITEBIT") + # "BITMART" + # "MEXC" + # "MEXC_FUTURES" + # "WHITEBIT" + ) + set(EXECUTION_MANAGEMENT_EXCHANGE_LIST "COINBASE" - "GEMINI" - "KRAKEN" - "KRAKEN_FUTURES" - "BITSTAMP" - "BITFINEX" - "BITMEX" - "BINANCE_US" + # "GEMINI" + # "KRAKEN" + # "KRAKEN_FUTURES" + # "BITSTAMP" + # "BITFINEX" + # "BITMEX" + # "BINANCE_US" "BINANCE" "BINANCE_USDS_FUTURES" "BINANCE_COIN_FUTURES" - "HUOBI" - "HUOBI_USDT_SWAP" - "HUOBI_COIN_SWAP" + # "HUOBI" + # "HUOBI_USDT_SWAP" + # "HUOBI_COIN_SWAP" "OKX" - "ERISX" - "KUCOIN" - "KUCOIN_FUTURES" - "DERIBIT" + # "ERISX" + # "KUCOIN" + # "KUCOIN_FUTURES" + # "DERIBIT" "GATEIO" "GATEIO_PERPETUAL_FUTURES" "CRYPTOCOM" - "ASCENDEX" + # "ASCENDEX" "BYBIT" "BITGET" "BITGET_FUTURES" - "BITMART" - "MEXC" - "WHITEBIT") + # "BITMART" + # "MEXC" + # "WHITEBIT" + ) + set(FIX_EXCHANGE_LIST "COINBASE" "GEMINI") + set(HFFIX_INCLUDE_DIR ${CCAPI_PROJECT_DIR}/dependency/hffix/include) + foreach(SERVICE IN LISTS SERVICE_LIST) message(STATUS "SERVICE=${SERVICE}") if("${SERVICE}" STREQUAL "MARKET_DATA") @@ -74,21 +83,26 @@ foreach(SERVICE IN LISTS SERVICE_LIST) elseif("${SERVICE}" STREQUAL "FIX") set(EXCHANGE_LIST ${FIX_EXCHANGE_LIST}) endif() + foreach(EXCHANGE IN LISTS EXCHANGE_LIST) message(STATUS "EXCHANGE=${EXCHANGE}") set(CCAPI_CPP_TARGET_NAME "${SERVICE}__${EXCHANGE}") add_executable("${CCAPI_CPP_TARGET_NAME}" ${SOURCE_LOGGER} test.cpp) + if(NOT CCAPI_LEGACY_USE_WEBSOCKETPP) add_dependencies("${CCAPI_CPP_TARGET_NAME}" boost rapidjson hffix) endif() + target_compile_definitions( "${CCAPI_CPP_TARGET_NAME}" PRIVATE "CCAPI_ENABLE_SERVICE_${SERVICE}" "CCAPI_ENABLE_EXCHANGE_${EXCHANGE}") + if("${SERVICE}" STREQUAL "FIX") message(STATUS "need hffix") target_include_directories("${CCAPI_CPP_TARGET_NAME}" PRIVATE ${HFFIX_INCLUDE_DIR}) endif() + if("${EXCHANGE}" MATCHES "^HUOBI" OR "${EXCHANGE}" MATCHES "^OKX" OR "${EXCHANGE}" MATCHES "^BITMART") @@ -96,5 +110,14 @@ foreach(SERVICE IN LISTS SERVICE_LIST) find_package(ZLIB REQUIRED) target_link_libraries("${CCAPI_CPP_TARGET_NAME}" PRIVATE ZLIB::ZLIB) endif() + + # Add post-build deletion of the target binary + add_custom_command( + TARGET "${CCAPI_CPP_TARGET_NAME}" + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo + "Deleting built target: $" + COMMAND ${CMAKE_COMMAND} -E rm -f $) + endforeach() endforeach() diff --git a/test/test_unit/CMakeLists.txt b/test/test_unit/CMakeLists.txt index a8266729..3dd6983f 100644 --- a/test/test_unit/CMakeLists.txt +++ b/test/test_unit/CMakeLists.txt @@ -43,16 +43,16 @@ add_compile_definitions(CCAPI_EXPOSE_INTERNAL) add_subdirectory(src/common) add_subdirectory(src/market_data/generic) add_subdirectory(src/execution_management/binance_usds_futures) -add_subdirectory(src/execution_management/binance_us) -add_subdirectory(src/execution_management/bitmex) +# add_subdirectory(src/execution_management/binance_us) +# add_subdirectory(src/execution_management/bitmex) add_subdirectory(src/execution_management/coinbase) -add_subdirectory(src/execution_management/erisx) +# add_subdirectory(src/execution_management/erisx) add_subdirectory(src/execution_management/gateio) -add_subdirectory(src/execution_management/gemini) -add_subdirectory(src/execution_management/huobi) -add_subdirectory(src/execution_management/huobi_usdt_swap) -add_subdirectory(src/execution_management/huobi_coin_swap) -add_subdirectory(src/execution_management/kucoin) -add_subdirectory(src/execution_management/kraken) -add_subdirectory(src/execution_management/kraken_futures) +# add_subdirectory(src/execution_management/gemini) +# add_subdirectory(src/execution_management/huobi) +# add_subdirectory(src/execution_management/huobi_usdt_swap) +# add_subdirectory(src/execution_management/huobi_coin_swap) +# add_subdirectory(src/execution_management/kucoin) +# add_subdirectory(src/execution_management/kraken) +# add_subdirectory(src/execution_management/kraken_futures) add_subdirectory(src/execution_management/okx) diff --git a/test/test_unit/src/execution_management/okx/test.cpp b/test/test_unit/src/execution_management/okx/test.cpp index 105bcddc..72fe44ef 100644 --- a/test/test_unit/src/execution_management/okx/test.cpp +++ b/test/test_unit/src/execution_management/okx/test.cpp @@ -581,7 +581,7 @@ TEST_F(ExecutionManagementServiceOkxTest, createEventFilled) { )"; rj::Document document; document.Parse(textMessage.c_str()); - auto messageList = this->service->createEvent(subscription, textMessage, document, "", this->now).getMessageList(); + auto messageList = this->service->createEvent(WsConnection(), subscription, textMessage, document, "", this->now).getMessageList(); EXPECT_EQ(messageList.size(), 1); verifyCorrelationId(messageList, subscription.getCorrelationId()); auto message = messageList.at(0); @@ -658,7 +658,7 @@ TEST_F(ExecutionManagementServiceOkxTest, createEventLive) { )"; rj::Document document; document.Parse(textMessage.c_str()); - auto messageList = this->service->createEvent(subscription, textMessage, document, "", this->now).getMessageList(); + auto messageList = this->service->createEvent(WsConnection(), subscription, textMessage, document, "", this->now).getMessageList(); EXPECT_EQ(messageList.size(), 1); verifyCorrelationId(messageList, subscription.getCorrelationId()); auto message = messageList.at(0); @@ -696,9 +696,12 @@ TEST_F(ExecutionManagementServiceOkxTest, createEventWebsocketTradePlaceOrder) { )"; rj::Document document; document.Parse(textMessage.c_str()); - auto messageList = this->service->createEvent(subscription, textMessage, document, "", this->now).getMessageList(); + WsConnection wsConnection; + std::string requestCorrelationId("123"); + this->service->requestCorrelationIdByWsRequestIdByConnectionIdMap[wsConnection.id][1512] = requestCorrelationId; + auto messageList = this->service->createEvent(wsConnection, subscription, textMessage, document, "", this->now).getMessageList(); EXPECT_EQ(messageList.size(), 1); - verifyCorrelationId(messageList, subscription.getCorrelationId()); + verifyCorrelationId(messageList, requestCorrelationId); auto message = messageList.at(0); EXPECT_EQ(message.getType(), Message::Type::CREATE_ORDER); auto elementList = message.getElementList(); @@ -727,9 +730,12 @@ TEST_F(ExecutionManagementServiceOkxTest, createEventWebsocketTradeCancelOrder) )"; rj::Document document; document.Parse(textMessage.c_str()); - auto messageList = this->service->createEvent(subscription, textMessage, document, "", this->now).getMessageList(); + WsConnection wsConnection; + std::string requestCorrelationId("123"); + this->service->requestCorrelationIdByWsRequestIdByConnectionIdMap[wsConnection.id][1] = requestCorrelationId; + auto messageList = this->service->createEvent(wsConnection, subscription, textMessage, document, "", this->now).getMessageList(); EXPECT_EQ(messageList.size(), 1); - verifyCorrelationId(messageList, subscription.getCorrelationId()); + verifyCorrelationId(messageList, requestCorrelationId); auto message = messageList.at(0); EXPECT_EQ(message.getType(), Message::Type::CANCEL_ORDER); auto elementList = message.getElementList(); From 8fba0343fbce96bd1a1568e7d9efb80a0f477e2a Mon Sep 17 00:00:00 2001 From: macos <> Date: Wed, 28 May 2025 15:37:47 -0700 Subject: [PATCH 06/17] fix compile issue on mac --- include/ccapi_cpp/ccapi_hmac.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/ccapi_cpp/ccapi_hmac.h b/include/ccapi_cpp/ccapi_hmac.h index 4457dcef..f58c3e36 100644 --- a/include/ccapi_cpp/ccapi_hmac.h +++ b/include/ccapi_cpp/ccapi_hmac.h @@ -4,6 +4,7 @@ #include #include #include +#include #include From 836dc74745e7d1c9dd46c5cc3c39a84af9024c56 Mon Sep 17 00:00:00 2001 From: macos <> Date: Wed, 28 May 2025 16:27:16 -0700 Subject: [PATCH 07/17] update test.yml --- .github/workflows/test.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1e04105b..7a7b45a9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,8 +15,8 @@ on: - '**.example' env: - CMAKE_VERSION: 3.17.5 - NINJA_VERSION: 1.9.0 + CMAKE_VERSION: 4.0.2 + NINJA_VERSION: 1.12.0 # BUILD_TYPE: Release # CCACHE_VERSION: 3.7.7 @@ -25,7 +25,6 @@ jobs: name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} strategy: - max-parallel: 1 fail-fast: false matrix: config: @@ -35,8 +34,9 @@ jobs: cc: "gcc", cxx: "g++" } - { - name: "macOS Latest Clang", - os: macos-latest, + name: "macOS 14 ARM64 Clang", + os: macos-14, + arch: "arm64", cc: "clang", cxx: "clang++" } # - { From 29616de5df2d37fc86b1766fbb5f324e37ee560c Mon Sep 17 00:00:00 2001 From: cryptochassis <57077778+cryptochassis@users.noreply.github.com> Date: Wed, 28 May 2025 16:29:52 -0700 Subject: [PATCH 08/17] Create dependabot.yml --- .github/dependabot.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..0d08e261 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" From 7cf2119c3468be5be9cab90f6b47ecf111fa1a18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 23:30:28 +0000 Subject: [PATCH 09/17] build(deps): bump actions/setup-node from 1 to 4 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 1 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v1...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8cd058ed..8fc05fa1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v4 - run: 'echo ''{ "name": "ccapi_cpp", "version": "1.0.0", From aa932559c30231d9f37e2d06c0c4848efde050fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 23:30:30 +0000 Subject: [PATCH 10/17] build(deps): bump actions/checkout from 1 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 1 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v1...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8cd058ed..f9a934f9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,7 @@ jobs: name: release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - uses: actions/setup-node@v1 - run: 'echo ''{ "name": "ccapi_cpp", diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f3c6887d..1bb820ad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -53,7 +53,7 @@ jobs: # } steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 - name: Download Ninja and CMake id: cmake_and_ninja From f9d1bdd2a5b49a362443c794736da8386a57fd5e Mon Sep 17 00:00:00 2001 From: macos <> Date: Wed, 28 May 2025 16:37:43 -0700 Subject: [PATCH 11/17] update test.yml --- .github/workflows/test.yml | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7a7b45a9..59ae30a7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ on: env: CMAKE_VERSION: 4.0.2 - NINJA_VERSION: 1.12.0 + NINJA_VERSION: 1.12.1 # BUILD_TYPE: Release # CCACHE_VERSION: 3.7.7 @@ -78,13 +78,22 @@ jobs: set(cmake_dir "cmake-${cmake_version}-Darwin-x86_64/CMake.app/Contents/bin") endif() - set(ninja_url "https://github.com/ninja-build/ninja/releases/download/v${ninja_version}/ninja-${ninja_suffix}") - file(DOWNLOAD "${ninja_url}" ./ninja.zip SHOW_PROGRESS) - execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./ninja.zip) + set(ninja_url "https://github.com/ninja-build/ninja/releases/download/v${ninja_version}/ninja-${ninja_version}.zip") + file(DOWNLOAD "${ninja_url}" "${CMAKE_BINARY_DIR}/ninja.zip" SHOW_PROGRESS) + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf "${CMAKE_BINARY_DIR}/ninja.zip" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") + # Construct URL and download path set(cmake_url "https://github.com/Kitware/CMake/releases/download/v${cmake_version}/cmake-${cmake_version}-${cmake_suffix}") - file(DOWNLOAD "${cmake_url}" ./cmake.zip SHOW_PROGRESS) - execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./cmake.zip) + set(cmake_archive "${CMAKE_BINARY_DIR}/cmake-${cmake_version}-${cmake_suffix}") + + # Download the archive to the build directory + file(DOWNLOAD "${cmake_url}" "${cmake_archive}" SHOW_PROGRESS) + + # Extract the archive + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar xvf "${cmake_archive}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + ) # Save the path for other steps file(TO_CMAKE_PATH "$ENV{GITHUB_WORKSPACE}/${cmake_dir}" cmake_dir) From 81f68ca3ee462fc8b2c37e39b89319d7292021cb Mon Sep 17 00:00:00 2001 From: macos <> Date: Wed, 28 May 2025 16:43:38 -0700 Subject: [PATCH 12/17] update test.yml --- .github/workflows/test.yml | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 59ae30a7..1e04105b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,8 +15,8 @@ on: - '**.example' env: - CMAKE_VERSION: 4.0.2 - NINJA_VERSION: 1.12.1 + CMAKE_VERSION: 3.17.5 + NINJA_VERSION: 1.9.0 # BUILD_TYPE: Release # CCACHE_VERSION: 3.7.7 @@ -25,6 +25,7 @@ jobs: name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} strategy: + max-parallel: 1 fail-fast: false matrix: config: @@ -34,9 +35,8 @@ jobs: cc: "gcc", cxx: "g++" } - { - name: "macOS 14 ARM64 Clang", - os: macos-14, - arch: "arm64", + name: "macOS Latest Clang", + os: macos-latest, cc: "clang", cxx: "clang++" } # - { @@ -78,22 +78,13 @@ jobs: set(cmake_dir "cmake-${cmake_version}-Darwin-x86_64/CMake.app/Contents/bin") endif() - set(ninja_url "https://github.com/ninja-build/ninja/releases/download/v${ninja_version}/ninja-${ninja_version}.zip") - file(DOWNLOAD "${ninja_url}" "${CMAKE_BINARY_DIR}/ninja.zip" SHOW_PROGRESS) - execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf "${CMAKE_BINARY_DIR}/ninja.zip" WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") + set(ninja_url "https://github.com/ninja-build/ninja/releases/download/v${ninja_version}/ninja-${ninja_suffix}") + file(DOWNLOAD "${ninja_url}" ./ninja.zip SHOW_PROGRESS) + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./ninja.zip) - # Construct URL and download path set(cmake_url "https://github.com/Kitware/CMake/releases/download/v${cmake_version}/cmake-${cmake_version}-${cmake_suffix}") - set(cmake_archive "${CMAKE_BINARY_DIR}/cmake-${cmake_version}-${cmake_suffix}") - - # Download the archive to the build directory - file(DOWNLOAD "${cmake_url}" "${cmake_archive}" SHOW_PROGRESS) - - # Extract the archive - execute_process( - COMMAND ${CMAKE_COMMAND} -E tar xvf "${cmake_archive}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - ) + file(DOWNLOAD "${cmake_url}" ./cmake.zip SHOW_PROGRESS) + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./cmake.zip) # Save the path for other steps file(TO_CMAKE_PATH "$ENV{GITHUB_WORKSPACE}/${cmake_dir}" cmake_dir) From b36f9a380754418fc2d35e7950ffff9a1bd60a9f Mon Sep 17 00:00:00 2001 From: macos <> Date: Wed, 28 May 2025 16:46:12 -0700 Subject: [PATCH 13/17] arm64 --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1e04105b..95fcf937 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,6 @@ jobs: name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} strategy: - max-parallel: 1 fail-fast: false matrix: config: @@ -37,7 +36,8 @@ jobs: - { name: "macOS Latest Clang", os: macos-latest, - cc: "clang", cxx: "clang++" + cc: "clang", cxx: "clang++", + arch: "arm64" } # - { # name: "Windows Latest MinGW", From d7fe3800adc20d276cc21755cfade2f99d95db76 Mon Sep 17 00:00:00 2001 From: macos <> Date: Wed, 28 May 2025 16:47:02 -0700 Subject: [PATCH 14/17] CMAKE_VERSION: 4.0.2 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 95fcf937..657434e0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ on: - '**.example' env: - CMAKE_VERSION: 3.17.5 + CMAKE_VERSION: 4.0.2 NINJA_VERSION: 1.9.0 # BUILD_TYPE: Release # CCACHE_VERSION: 3.7.7 From 42643e7ae64c9d844c0bb45d4818290a662624b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 02:05:45 +0000 Subject: [PATCH 15/17] build(deps): bump actions/setup-node from 1 to 4 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 1 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v1...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f9a934f9..90284e1e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v4 - run: 'echo ''{ "name": "ccapi_cpp", "version": "1.0.0", From d0019edd572202a13a9a200d5b19d6aa83c451c9 Mon Sep 17 00:00:00 2001 From: macos <> Date: Wed, 28 May 2025 19:10:57 -0700 Subject: [PATCH 16/17] fix ci --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f0b5f99a..dd042078 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ on: - '**.example' env: - CMAKE_VERSION: 4.0.2 + CMAKE_VERSION: 3.17.5 NINJA_VERSION: 1.9.0 # BUILD_TYPE: Release # CCACHE_VERSION: 3.7.7 From fe565c2bcb8c5c4decb39f760041efe0221e22db Mon Sep 17 00:00:00 2001 From: macos <> Date: Wed, 28 May 2025 19:15:34 -0700 Subject: [PATCH 17/17] add -DCMAKE_OSX_ARCHITECTURES=arm64 --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dd042078..c78ca23f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -206,6 +206,7 @@ jobs: execute_process( COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake + -DCMAKE_OSX_ARCHITECTURES=arm64 -DBUILD_TEST_BUILD=OFF -DBUILD_TEST_UNIT=OFF -S test @@ -223,6 +224,7 @@ jobs: execute_process( COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake + -DCMAKE_OSX_ARCHITECTURES=arm64 -S example -B example/build -D CMAKE_BUILD_TYPE=$ENV{CMAKE_BUILD_TYPE} @@ -239,6 +241,7 @@ jobs: if ("${{ runner.os }}" STREQUAL "macOS" OR "${{ runner.os }}" STREQUAL "Linux") execute_process( COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake + -DCMAKE_OSX_ARCHITECTURES=arm64 -DBUILD_PYTHON=ON # -DBUILD_JAVA=ON # -DBUILD_CSHARP=ON @@ -370,6 +373,7 @@ jobs: execute_process( COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake + -DCMAKE_OSX_ARCHITECTURES=arm64 -DBUILD_TEST_BUILD=ON -DBUILD_TEST_UNIT=ON -S test