Skip to content

Commit c381f82

Browse files
committed
Refactor REST API tests and enhance WebSocket tests
- Updated REST API tests to improve order handling and logging. - Introduced a new `order_` member variable to store order details for reuse. - Enhanced error logging for order creation, modification, and cancellation. - Adjusted order quantities for better precision in tests. - Refactored WebSocket tests to include connection and disconnection tracking. - Added a new test for repeated connect/disconnect scenarios to validate stability. - Improved logging for market data and user data events.
1 parent 520cdd8 commit c381f82

6 files changed

Lines changed: 599 additions & 298 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,27 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [unreleased] -
8+
## [0.1.1] - 2026-02-01
99

1010
### Added
1111
- DataHandler class to process Coinbase market and user data
1212
- Unit test for UserThreadWebsocketCallbacks multiple client support
1313
- IsMarketDataConnected and IsUserDataConnected methods
14+
- WebSocket connection lifecycle callbacks for market/user data
15+
- WebSocketClient stop method for explicit shutdown
16+
- WebSocket test for repeated connect/disconnect cycles
1417

1518
### Changed
1619
- Try to find dependent slick components using `find_package` before falling back to `FetchContent`
1720
- Changed header files from .h to .hpp
1821
- Decoupled UserThreadWebsocketCallbacks from WebSocketeClient to support multiple WebSocketClient
1922
- Create market data and user data websocket when url is set
2023
- UserThreadWebsocketCallbacks now drains multiple queued messages per tick for higher throughput
24+
- Updated slick-net to v1.2.3 and report version when found
25+
- Added stricter warning and release optimization flags for MSVC and non-MSVC builds
26+
- WebSocketCallbacks now receive WebSocketClient pointers on all events, and error callbacks take rvalue strings
27+
- WebSocketClient now initializes sockets on subscribe and dispatches connect/disconnect events through the data queue
28+
- UserThreadWebsocketCallbacks now track per-client sequence numbers and active client sets
2129

2230
### Fixed
2331
- Various WebSocket unit tests not waiting for snapshot
@@ -30,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3038
- PriceBookResponse parsing when pricebook is missing
3139
- Order status string typo and size_ratio field name
3240
- Missing default return in FCM trading session state parsing
41+
- WebSocket teardown now waits briefly for disconnect callbacks and clears per-client sequence state
42+
- REST API tests now clean up created orders on failures and log API errors for debugging
3343

3444
## [0.1.0] - 2026-01-13
3545

CMakeLists.txt

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.30)
33
set(CMAKE_CXX_STANDARD 20)
44

55
project(coinbase-advanced-cpp
6-
VERSION 0.1.0
6+
VERSION 0.1.1
77
LANGUAGES CXX)
88

99
if (CMAKE_BUILD_TYPE MATCHES Debug)
@@ -19,7 +19,6 @@ find_package(OpenSSL CONFIG REQUIRED)
1919
find_package(jwt-cpp CONFIG REQUIRED)
2020

2121
find_package(slick-net 1.2.2 CONFIG QUIET)
22-
2322
if (NOT slick-net_FOUND)
2423
message(STATUS "fetching slick-net...")
2524
include(FetchContent)
@@ -28,9 +27,11 @@ if (NOT slick-net_FOUND)
2827
FetchContent_Declare(
2928
slick-net
3029
GIT_REPOSITORY https://github.com/SlickQuant/slick-net.git
31-
GIT_TAG v1.2.2
30+
GIT_TAG v1.2.3
3231
)
3332
FetchContent_MakeAvailable(slick-net)
33+
else()
34+
message(STATUS "slick-net: ${slick-net_VERSION}")
3435
endif()
3536

3637
add_library(coinbase-advanced-cpp INTERFACE)
@@ -51,11 +52,24 @@ if (MSVC)
5152
add_definitions(-D_WIN32_WINNT=0x0A00)
5253
set(CMAKE_SUPPRESS_REGENERATION true) # supress zero_check
5354
set_target_properties(coinbase-advanced-cpp PROPERTIES LINK_INCREMENTAL ON)
54-
target_compile_options(coinbase-advanced-cpp INTERFACE "/MP" "/FS" "/bigobj" "/wd4101")
55+
target_compile_options(coinbase-advanced-cpp INTERFACE
56+
/MP
57+
/FS
58+
/bigobj
59+
/wd4101
60+
/W4
61+
$<$<CONFIG:Release>:/O2>
62+
$<$<CONFIG:Release>:/GL> # Whole program optimization
63+
)
5564
# Faster linking
5665
add_link_options(/DEBUG:FASTLINK)
5766
else()
58-
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
67+
add_compile_options(
68+
-Wall -Wextra -Wpedantic
69+
$<$<CONFIG:Release>:-O3>
70+
$<$<CONFIG:Release>:-march=native>
71+
$<$<CONFIG:Release>:-flto>
72+
)
5973
endif()
6074

6175
option(BUILD_COINBASE_ADVANCED_TESTS "Build tests" ON)
@@ -102,4 +116,4 @@ install(FILES
102116
DESTINATION lib/cmake/coinbase-advanced-cpp
103117
)
104118

105-
message(STATUS "coinbase-advance-cpp: ${PROJECT_VERSION}")
119+
message(STATUS "${PROJECT_NAME}: ${PROJECT_VERSION}")

README.md

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ A modern C++ SDK for interacting with the Coinbase Advanced API, providing both
1212

1313
- **REST API Support**: Complete implementation of Coinbase Advanced API endpoints for accounts, orders, products, trades, and more
1414
- **WebSocket Support**: Real-time market data streaming with level2, ticker, market trades, and user data channels
15+
- Connection lifecycle callbacks for connect/disconnect events
16+
- Per-client sequence number tracking for multiple concurrent connections
17+
- Explicit shutdown control with `stop()` method
1518
- **Comprehensive Order Types**: Support for market, limit, stop limit, bracket, and TWAP orders
1619
- **Type Safety**: Full C++ type definitions for all API responses with JSON serialization/deserialization
1720
- **Modern C++**: Uses C++20 features, RAII, smart pointers, and modern C++ best practices
1821
- **Async/Await Support**: Built-in async support using C++ coroutines
19-
- **Thread-Safe**: Designed for multi-threaded applications
22+
- **Thread-Safe**: Designed for multi-threaded applications with lock-free data structures
2023

2124
## Architecture
2225

@@ -111,23 +114,61 @@ auto cancel_response = client.cancel_orders({"order_id_123"});
111114
112115
#### WebSocket Client
113116
117+
The SDK provides two callback mechanisms for handling WebSocket data:
118+
119+
1. **`WebsocketCallbacks`**: Callbacks are invoked directly on the WebSocket thread. Use this for simple applications or when you want immediate processing.
120+
121+
2. **`UserThreadWebsocketCallbacks`**: Callbacks are invoked on your own thread. The WebSocket data is queued in a lock-free queue, and you control when to process it by calling `processData()`. Use this for better control over threading and to avoid blocking the WebSocket thread.
122+
123+
##### Using WebsocketCallbacks (WebSocket Thread)
124+
114125
```cpp
115126
#include <coinbase/websocket.h>
116127
117128
class MyCallbacks : public coinbase::WebsocketCallbacks {
118129
public:
119-
void onLevel2Snapshot(uin64_t seq_num, const coinbase::Level2UpdateBatch& snapshot) override {
130+
// Connection lifecycle callbacks
131+
void onMarketDataConnected(coinbase::WebSocketClient* client) override {
132+
// Handle market data connection established
133+
}
134+
135+
void onMarketDataDisconnected(coinbase::WebSocketClient* client) override {
136+
// Handle market data disconnection
137+
}
138+
139+
void onUserDataConnected(coinbase::WebSocketClient* client) override {
140+
// Handle user data connection established
141+
}
142+
143+
void onUserDataDisconnected(coinbase::WebSocketClient* client) override {
144+
// Handle user data disconnection
145+
}
146+
147+
// Data callbacks
148+
void onLevel2Snapshot(coinbase::WebSocketClient* client, uint64_t seq_num,
149+
const coinbase::Level2UpdateBatch& snapshot) override {
120150
// Handle level2 snapshot
121151
}
122-
123-
void onLevel2Updates(uin64_t seq_num, const coinbase::Level2UpdateBatch& updates) override {
152+
153+
void onLevel2Updates(coinbase::WebSocketClient* client, uint64_t seq_num,
154+
const coinbase::Level2UpdateBatch& updates) override {
124155
// Handle level2 updates
125156
}
126-
127-
void onMarketTrades(uin64_t seq_num, const std::vector<coinbase::MarketTrade>& trades) override {
157+
158+
void onMarketTrades(coinbase::WebSocketClient* client, uint64_t seq_num,
159+
const std::vector<coinbase::MarketTrade>& trades) override {
128160
// Handle market trades
129161
}
130-
162+
163+
// Error callbacks
164+
void onMarketDataError(coinbase::WebSocketClient* client, std::string&& err) override {
165+
// Handle market data errors
166+
}
167+
168+
void onUserDataError(coinbase::WebSocketClient* client, std::string&& err) override {
169+
// Handle user data errors
170+
}
171+
131172
// ... other callback methods
132173
};
133174
@@ -142,8 +183,57 @@ std::vector<coinbase::WebSocketChannel> channels = {
142183
coinbase::WebSocketChannel::TICKER
143184
};
144185
client.subscribe(product_ids, channels);
186+
187+
// Explicitly stop WebSocket connections when done
188+
client.stop();
145189
```
146190

191+
##### Using UserThreadWebsocketCallbacks (User Thread)
192+
193+
```cpp
194+
#include <coinbase/websocket.h>
195+
196+
class MyCallbacks : public coinbase::UserThreadWebsocketCallbacks {
197+
public:
198+
// Same callback signatures as WebsocketCallbacks
199+
void onMarketDataConnected(coinbase::WebSocketClient* client) override {
200+
// Handle market data connection established
201+
}
202+
203+
void onLevel2Snapshot(coinbase::WebSocketClient* client, uint64_t seq_num,
204+
const coinbase::Level2UpdateBatch& snapshot) override {
205+
// Handle level2 snapshot
206+
}
207+
208+
// ... other callback methods
209+
};
210+
211+
// Create callbacks and WebSocket client
212+
MyCallbacks callbacks;
213+
coinbase::WebSocketClient client(&callbacks);
214+
215+
// Subscribe to channels
216+
client.subscribe({"BTC-USD", "ETH-USD"}, {
217+
coinbase::WebSocketChannel::LEVEL2,
218+
coinbase::WebSocketChannel::TICKER
219+
});
220+
221+
// In your main loop or dedicated thread, process queued data
222+
while (running) {
223+
// Process up to 100 queued messages per call
224+
callbacks.processData(100);
225+
226+
// Your other application logic here
227+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
228+
}
229+
230+
client.stop();
231+
```
232+
233+
**Key Differences:**
234+
- **`WebsocketCallbacks`**: Immediate processing on WebSocket I/O thread. Simple but can block WebSocket operations if callbacks are slow.
235+
- **`UserThreadWebsocketCallbacks`**: Deferred processing on your thread. Better performance and control, but requires calling `processData()` regularly. Uses lock-free queues for efficient data transfer between threads.
236+
147237
## API Endpoints
148238
149239
### REST API

0 commit comments

Comments
 (0)