Skip to content

Commit ab1f0dd

Browse files
Merge pull request #513 from crypto-chassis/develop
Release
2 parents 1f7825d + a5f5968 commit ab1f0dd

43 files changed

Lines changed: 801 additions & 539 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "github-actions" # See documentation for possible values
9+
directory: "/" # Location of package manifests
10+
schedule:
11+
interval: "weekly"

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ jobs:
88
name: release
99
runs-on: ubuntu-latest
1010
steps:
11-
- uses: actions/checkout@v1
12-
- uses: actions/setup-node@v1
11+
- uses: actions/checkout@v4
12+
- uses: actions/setup-node@v4
1313
- run: 'echo ''{
1414
"name": "ccapi_cpp",
1515
"version": "1.0.0",

.github/workflows/test.yml

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ jobs:
2525
name: ${{ matrix.config.name }}
2626
runs-on: ${{ matrix.config.os }}
2727
strategy:
28-
max-parallel: 1
2928
fail-fast: false
3029
matrix:
3130
config:
@@ -34,11 +33,12 @@ jobs:
3433
os: ubuntu-latest,
3534
cc: "gcc", cxx: "g++"
3635
}
37-
# - {
38-
# name: "macOS Latest Clang",
39-
# os: macos-latest,
40-
# cc: "clang", cxx: "clang++"
41-
# }
36+
- {
37+
name: "macOS Latest Clang",
38+
os: macos-latest,
39+
cc: "clang", cxx: "clang++",
40+
arch: "arm64"
41+
}
4242
# - {
4343
# name: "Windows Latest MinGW",
4444
# os: windows-latest,
@@ -53,7 +53,7 @@ jobs:
5353
# }
5454

5555
steps:
56-
- uses: actions/checkout@v1
56+
- uses: actions/checkout@v4
5757

5858
- name: Download Ninja and CMake
5959
id: cmake_and_ninja
@@ -126,7 +126,7 @@ jobs:
126126
message(STATUS "Using host CMake version: ${cmake_version}")
127127
if ("${{ runner.os }}" STREQUAL "macOS")
128128
execute_process(
129-
COMMAND brew reinstall openssl@1.1
129+
COMMAND brew reinstall openssl@3
130130
)
131131
elseif ("${{ runner.os }}" STREQUAL "Windows")
132132
execute_process(
@@ -206,6 +206,7 @@ jobs:
206206
207207
execute_process(
208208
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake
209+
-DCMAKE_OSX_ARCHITECTURES=arm64
209210
-DBUILD_TEST_BUILD=OFF
210211
-DBUILD_TEST_UNIT=OFF
211212
-S test
@@ -223,6 +224,7 @@ jobs:
223224
224225
execute_process(
225226
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake
227+
-DCMAKE_OSX_ARCHITECTURES=arm64
226228
-S example
227229
-B example/build
228230
-D CMAKE_BUILD_TYPE=$ENV{CMAKE_BUILD_TYPE}
@@ -239,8 +241,9 @@ jobs:
239241
if ("${{ runner.os }}" STREQUAL "macOS" OR "${{ runner.os }}" STREQUAL "Linux")
240242
execute_process(
241243
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake
244+
-DCMAKE_OSX_ARCHITECTURES=arm64
242245
-DBUILD_PYTHON=ON
243-
-DBUILD_JAVA=ON
246+
# -DBUILD_JAVA=ON
244247
# -DBUILD_CSHARP=ON
245248
# -DBUILD_GO=ON
246249
# -DBUILD_JAVASCRIPT=ON
@@ -370,7 +373,8 @@ jobs:
370373
371374
execute_process(
372375
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake
373-
-DBUILD_TEST_BUILD=OFF
376+
-DCMAKE_OSX_ARCHITECTURES=arm64
377+
-DBUILD_TEST_BUILD=ON
374378
-DBUILD_TEST_UNIT=ON
375379
-S test
376380
-B test/build

README.md

Lines changed: 91 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,62 @@
11
# Some breaking changes introduced
2-
* Please update boost version to at least 1.87.0.
3-
* 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.
4-
* Removed the spot market making application and the single order execution application.
2+
* We made a change on how to "Send request by Websocket API".
53

64
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
7-
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
8-
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
9-
10-
- [ccapi](#ccapi)
11-
- [Branches](#branches)
12-
- [Build](#build)
13-
- [C++](#c)
14-
- [non-C++](#non-c)
15-
- [Constants](#constants)
16-
- [Examples](#examples)
17-
- [Documentations](#documentations)
18-
- [Simple Market Data](#simple-market-data)
19-
- [Advanced Market Data](#advanced-market-data)
20-
- [Complex request parameters](#complex-request-parameters)
21-
- [Specify subscription market depth](#specify-subscription-market-depth)
22-
- [Specify correlation id](#specify-correlation-id)
23-
- [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments)
24-
- [Receive subscription events at periodic intervals](#receive-subscription-events-at-periodic-intervals)
25-
- [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)
26-
- [Receive subscription market depth updates](#receive-subscription-market-depth-updates)
27-
- [Receive subscription trade events](#receive-subscription-trade-events)
28-
- [Receive subscription calculated-candlestick events at periodic intervals](#receive-subscription-calculated-candlestick-events-at-periodic-intervals)
29-
- [Receive subscription exchange-provided-candlestick events at periodic intervals](#receive-subscription-exchange-provided-candlestick-events-at-periodic-intervals)
30-
- [Send generic public requests](#send-generic-public-requests)
31-
- [Make generic public subscriptions](#make-generic-public-subscriptions)
32-
- [Send generic private requests](#send-generic-private-requests)
33-
- [Simple Execution Management](#simple-execution-management)
34-
- [Advanced Execution Management](#advanced-execution-management)
35-
- [Specify correlation id](#specify-correlation-id-1)
36-
- [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments-1)
37-
- [Multiple subscription fields](#multiple-subscription-fields)
38-
- [Make Session::sendRequest blocking](#make-sessionsendrequest-blocking)
39-
- [Provide API credentials for an exchange](#provide-api-credentials-for-an-exchange)
40-
- [Override exchange urls](#override-exchange-urls)
41-
- [Complex request parameters](#complex-request-parameters-1)
42-
- [Send request by Websocket API](#send-request-by-websocket-api)
43-
- [Specify instrument type](#specify-instrument-type)
44-
- [FIX API](#fix-api)
45-
- [More Advanced Topics](#more-advanced-topics)
46-
- [Handle events in "immediate" vs. "batching" mode](#handle-events-in-immediate-vs-batching-mode)
47-
- [Thread safety](#thread-safety)
48-
- [Enable library logging](#enable-library-logging)
49-
- [Set timer](#set-timer)
50-
- [Performance Tuning](#performance-tuning)
51-
- [Known Issues and Workarounds](#known-issues-and-workarounds)
52-
- [Contributing](#contributing)
5+
6+
**Table of Contents** *generated with [DocToc](https://github.com/ktechhub/doctoc)*
7+
8+
<!---toc start-->
9+
10+
* [Some breaking changes introduced](#some-breaking-changes-introduced)
11+
* [ccapi](#ccapi)
12+
* [Branches](#branches)
13+
* [Build](#build)
14+
* [C++](#c)
15+
* [non-C++](#non-c)
16+
* [Constants](#constants)
17+
* [Examples](#examples)
18+
* [Documentations](#documentations)
19+
* [Simple Market Data](#simple-market-data)
20+
* [Advanced Market Data](#advanced-market-data)
21+
* [Complex request parameters](#complex-request-parameters)
22+
* [Specify subscription market depth](#specify-subscription-market-depth)
23+
* [Specify correlation id](#specify-correlation-id)
24+
* [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments)
25+
* [Receive subscription events at periodic intervals](#receive-subscription-events-at-periodic-intervals)
26+
* [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)
27+
* [Receive subscription market depth updates](#receive-subscription-market-depth-updates)
28+
* [Receive subscription trade events](#receive-subscription-trade-events)
29+
* [Receive subscription calculated-candlestick events at periodic intervals](#receive-subscription-calculated-candlestick-events-at-periodic-intervals)
30+
* [Receive subscription exchange-provided-candlestick events at periodic intervals](#receive-subscription-exchange-provided-candlestick-events-at-periodic-intervals)
31+
* [Send generic public requests](#send-generic-public-requests)
32+
* [Make generic public subscriptions](#make-generic-public-subscriptions)
33+
* [Send generic private requests](#send-generic-private-requests)
34+
* [Simple Execution Management](#simple-execution-management)
35+
* [Advanced Execution Management](#advanced-execution-management)
36+
* [Specify correlation id](#specify-correlation-id-1)
37+
* [Multiple exchanges and/or instruments](#multiple-exchanges-andor-instruments-1)
38+
* [Multiple subscription fields](#multiple-subscription-fields)
39+
* [Make Session::sendRequest blocking](#make-sessionsendrequest-blocking)
40+
* [Provide API credentials for an exchange](#provide-api-credentials-for-an-exchange)
41+
* [Override exchange urls](#override-exchange-urls)
42+
* [Complex request parameters](#complex-request-parameters-1)
43+
* [Send request by Websocket API](#send-request-by-websocket-api)
44+
* [Specify instrument type](#specify-instrument-type)
45+
* [FIX API](#fix-api)
46+
* [More Advanced Topics](#more-advanced-topics)
47+
* [Handle events in "immediate" vs. "batching" mode](#handle-events-in-immediate-vs-batching-mode)
48+
* [Thread safety](#thread-safety)
49+
* [Enable library logging](#enable-library-logging)
50+
* [Set timer](#set-timer)
51+
* [Performance Tuning](#performance-tuning)
52+
* [Known Issues and Workarounds](#known-issues-and-workarounds)
53+
* [Contributing](#contributing)
54+
55+
<!---toc end-->
5356

5457
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
58+
59+
5560
# ccapi
5661
* 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).
5762
* Bindings for other languages such as Python, Java, C#, Go, and Javascript are provided.
@@ -220,7 +225,7 @@ Logger* Logger::logger = nullptr; // This line is needed.
220225
221226
class MyEventHandler : public EventHandler {
222227
public:
223-
bool processEvent(const Event& event, Session* session) override {
228+
bool processEvent(const Event& event, Session* sessionPtr) override {
224229
std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl;
225230
return true;
226231
}
@@ -297,7 +302,7 @@ Logger* Logger::logger = nullptr; // This line is needed.
297302
298303
class MyEventHandler : public EventHandler {
299304
public:
300-
bool processEvent(const Event& event, Session* session) override {
305+
bool processEvent(const Event& event, Session* sessionPtr) override {
301306
if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) {
302307
std::cout << "Received an event of type SUBSCRIPTION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl;
303308
} else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) {
@@ -386,13 +391,15 @@ Request request_1(Request::Operation::GET_RECENT_TRADES, "okx", "BTC-USDT", "coo
386391
request_1.appendParam(...);
387392
Request request_2(Request::Operation::GET_RECENT_TRADES, "binance", "ETH-USDT", "cool correlation id for ETH");
388393
request_2.appendParam(...);
389-
session.sendRequest({request_1, request_2});
394+
std::vector<ccapi::Request> requests = {request_1, request_2};
395+
session.sendRequest(requests);
390396
```
391397
Subscribe a `std::vector<Subscription>`.
392398
```
393399
Subscription subscription_1("okx", "BTC-USDT", "MARKET_DEPTH", "", "cool correlation id for okx BTC-USDT");
394400
Subscription subscription_2("binance", "ETH-USDT", "MARKET_DEPTH", "", "cool correlation id for binance ETH-USDT");
395-
session.subscribe({subscription_1, subscription_2});
401+
std::vector<ccapi::Subscription> subscriptions = {subscription_1, subscription_2};
402+
session.subscribe(subscriptions);
396403
```
397404

398405
#### Receive subscription events at periodic intervals
@@ -434,7 +441,7 @@ Subscription subscription("okx", "BTC-USDT", "TRADE", "CONFLATE_INTERVAL_MILLISE
434441

435442
Instantiate `Subscription` with field `CANDLESTICK` and option `CANDLESTICK_INTERVAL_SECONDS` set to be the desired interval.
436443
```
437-
Subscription subscription("okx", "BTC-USDTT", "CANDLESTICK", "CANDLESTICK_INTERVAL_SECONDS=60");
444+
Subscription subscription("okx", "BTC-USDT", "CANDLESTICK", "CANDLESTICK_INTERVAL_SECONDS=60");
438445
```
439446

440447
#### Send generic public requests
@@ -487,7 +494,7 @@ Logger* Logger::logger = nullptr; // This line is needed.
487494
488495
class MyEventHandler : public EventHandler {
489496
public:
490-
bool processEvent(const Event& event, Session* session) override {
497+
bool processEvent(const Event& event, Session* sessionPtr) override {
491498
std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl;
492499
return true;
493500
}
@@ -585,7 +592,7 @@ Logger* Logger::logger = nullptr; // This line is needed.
585592
586593
class MyEventHandler : public EventHandler {
587594
public:
588-
bool processEvent(const Event& event, Session* session) override {
595+
bool processEvent(const Event& event, Session* sessionPtr) override {
589596
if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) {
590597
std::cout << "Received an event of type SUBSCRIPTION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl;
591598
auto message = event.getMessageList().at(0);
@@ -597,7 +604,7 @@ class MyEventHandler : public EventHandler {
597604
{"QUANTITY", "0.001"},
598605
{"CLIENT_ORDER_ID", "6d4eb0fb"},
599606
});
600-
session->sendRequest(request);
607+
sessionPtr->sendRequest(request);
601608
}
602609
} else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) {
603610
std::cout << "Received an event of type SUBSCRIPTION_DATA:\n" + event.toStringPretty(2, 2) << std::endl;
@@ -712,7 +719,8 @@ Request request_1(Request::Operation::CREATE_ORDER, "okx", "BTC-USDT", "cool cor
712719
request_1.appendParam(...);
713720
Request request_2(Request::Operation::CREATE_ORDER, "okx", "ETH-USDT", "cool correlation id for ETH");
714721
request_2.appendParam(...);
715-
session.sendRequest({request_1, request_2});
722+
std::vector<ccapi::Request> requests = {request_1, request_2};
723+
session.sendRequest(requests);
716724
```
717725
Subscribe one `Subscription` per exchange with a comma separated string of instruments.
718726
```
@@ -774,23 +782,41 @@ request.appendParam({
774782
```
775783

776784
#### Send request by Websocket API
785+
For okx:
777786
```
778-
Subscription subscription("okx", "BTC-USDTT", "ORDER_UPDATE", "", "same correlation id for subscription and request");
787+
std::string websocketOrderEntrySubscriptionCorrelationId("any");
788+
Subscription subscription("okx", "", "ORDER_UPDATE", "", websocketOrderEntrySubscriptionCorrelationId);
779789
session.subscribe(subscription);
780790
...
781-
Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDTT", "same correlation id for subscription and request");
791+
Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDT");
792+
request.appendParam({
793+
{"SIDE", "BUY"},
794+
{"LIMIT_PRICE", "20000"},
795+
{"QUANTITY", "0.001"},
796+
});
797+
session.sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, request);
798+
```
799+
For bybit:
800+
```
801+
std::string websocketOrderEntrySubscriptionCorrelationId("any");
802+
Subscription subscription_1("bybit", "", "ORDER_UPDATE");
803+
Subscription subscription_2("bybit", "", "WEBSOCKET_ORDER_ENTRY", "", websocketOrderEntrySubscriptionCorrelationId);
804+
std::vector<ccapi::Subscription> subscriptions = {subscription_1, subscription_2};
805+
session.subscribe(subscriptions);
806+
...
807+
Request request(Request::Operation::CREATE_ORDER, "bybit", "BTCUSDT");
782808
request.appendParam({
783809
{"SIDE", "BUY"},
784810
{"LIMIT_PRICE", "20000"},
785811
{"QUANTITY", "0.001"},
786812
});
787-
session.sendRequestByWebsocket(request);
813+
session.sendRequestByWebsocket(websocketOrderEntrySubscriptionCorrelationId, request);
788814
```
789815

790816
#### Specify instrument type
791817
Some exchanges (i.e. bybit) might need instrument type for `Subscription`. Use `Subscription`'s `setInstrumentType` method.
792818
```
793-
Subscription subscription("bybit", "BTCUSDTT", "MARKET_DEPTH");
819+
Subscription subscription("bybit", "BTCUSDT", "MARKET_DEPTH");
794820
subscription.setInstrumentType("spot");
795821
session.subscribe(subscription);
796822
```
@@ -810,7 +836,7 @@ namespace ccapi {
810836
Logger* Logger::logger = nullptr; // This line is needed.
811837
class MyEventHandler : public EventHandler {
812838
public:
813-
bool processEvent(const Event& event, Session* session) override {
839+
bool processEvent(const Event& event, Session* sessionPtr) override {
814840
if (event.getType() == Event::Type::AUTHORIZATION_STATUS) {
815841
std::cout << "Received an event of type AUTHORIZATION_STATUS:\n" + event.toStringPretty(2, 2) << std::endl;
816842
auto message = event.getMessageList().at(0);
@@ -826,7 +852,7 @@ class MyEventHandler : public EventHandler {
826852
{40, "2"},
827853
{59, "1"},
828854
});
829-
session->sendRequestByFix(request);
855+
sessionPtr->sendRequestByFix(request);
830856
}
831857
} else if (event.getType() == Event::Type::FIX) {
832858
std::cout << "Received an event of type FIX:\n" + event.toStringPretty(2, 2) << std::endl;
@@ -975,7 +1001,7 @@ Logger* Logger::logger = &myLogger;
9751001

9761002
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.
9771003
```
978-
session->setTimer(
1004+
sessionPtr->setTimer(
9791005
"id", 1000,
9801006
[](const boost::system::error_code&) {
9811007
std::cout << std::string("Timer error handler is triggered at ") + UtilTime::getISOTimestamp(UtilTime::now()) << std::endl;

example/src/execution_management_advanced_request/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Logger* Logger::logger = nullptr; // This line is needed.
55

66
class MyEventHandler : public EventHandler {
77
public:
8-
bool processEvent(const Event& event, Session* session) override {
8+
bool processEvent(const Event& event, Session* sessionPtr) override {
99
std::cout << "Received an event:\n" + event.toStringPretty(2, 2) << std::endl;
1010
return true;
1111
}

0 commit comments

Comments
 (0)