Skip to content

Commit 1f7825d

Browse files
Merge pull request #508 from crypto-chassis/develop
Release
2 parents cc98436 + 2630790 commit 1f7825d

33 files changed

Lines changed: 257 additions & 2841 deletions

.github/workflows/test.yml

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -261,21 +261,6 @@ jobs:
261261
endif()
262262
endif()
263263
264-
execute_process(
265-
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake
266-
-S performance
267-
-B performance/build
268-
-D CMAKE_BUILD_TYPE=$ENV{CMAKE_BUILD_TYPE}
269-
-G Ninja
270-
-D CMAKE_MAKE_PROGRAM=ninja
271-
# -D CMAKE_C_COMPILER_LAUNCHER=ccache
272-
# -D CMAKE_CXX_COMPILER_LAUNCHER=ccache
273-
RESULT_VARIABLE result
274-
)
275-
if (NOT result EQUAL 0)
276-
message(FATAL_ERROR "Bad exit status")
277-
endif()
278-
279264
- name: Build 1
280265
shell: cmake -P {0}
281266
run: |
@@ -325,22 +310,6 @@ jobs:
325310
message(FATAL_ERROR "Bad exit status")
326311
endif()
327312
328-
execute_process(
329-
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build performance/build -j 2
330-
RESULT_VARIABLE result
331-
)
332-
if (NOT result EQUAL 0)
333-
message(FATAL_ERROR "Bad exit status")
334-
endif()
335-
336-
execute_process(
337-
COMMAND rm -rf performance/build
338-
RESULT_VARIABLE result
339-
)
340-
if (NOT result EQUAL 0)
341-
message(FATAL_ERROR "Bad exit status")
342-
endif()
343-
344313
execute_process(
345314
COMMAND ${{ steps.cmake_and_ninja.outputs.cmake_dir }}/cmake --build test/build -j 2
346315
RESULT_VARIABLE result

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,6 @@ session->setTimer(
988988
* Enable link time optimization (e.g. in CMakeLists.txt `set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)` before a target is created). Note that link time optimization is only applicable to static linking.
989989
* Shorten constant strings used as key names in the returned `Element` (e.g. in CmakeLists.txt `add_compile_definitions(CCAPI_BEST_BID_N_PRICE="b")`).
990990
* Only enable the services and exchanges that you need.
991-
* Use FIX API instead of REST API.
992991
* Handle events in ["batching" mode](#handle-events-in-immediate-vs-batching-mode) if your application (e.g. market data archiver) isn't latency sensitive.
993992
* Define macro `CCAPI_USE_SINGLE_THREAD`. It reduces locking overhead for single threaded applications.
994993

example/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,4 @@ add_subdirectory(src/fix_advanced)
8383
add_subdirectory(src/enable_library_logging)
8484
add_subdirectory(src/utility_set_timer)
8585
add_subdirectory(src/override_exchange_url_at_runtime)
86+
add_subdirectory(src/test_order_latency)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
set(NAME test_order_latency)
2+
project(${NAME})
3+
add_compile_definitions(CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT)
4+
add_compile_definitions(CCAPI_ENABLE_EXCHANGE_OKX)
5+
add_executable(${NAME} main.cpp)
6+
add_dependencies(${NAME} boost rapidjson)
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include <atomic>
2+
3+
#include "ccapi_cpp/ccapi_session.h"
4+
5+
namespace ccapi {
6+
Logger* Logger::logger = nullptr; // This line is needed.
7+
8+
class MyEventHandler : public EventHandler {
9+
public:
10+
MyEventHandler(const std::string& symbol, const std::string& side, const std::string& quantity, const std::string& price, int clientOrderIdLength,
11+
bool cancelByClientOrderId, int numOrders)
12+
: symbol(symbol),
13+
side(side),
14+
quantity(quantity),
15+
price(price),
16+
clientOrderIdLength(clientOrderIdLength),
17+
cancelByClientOrderId(cancelByClientOrderId),
18+
numOrders(numOrders) {}
19+
20+
bool processEvent(const Event& event, Session* sessionPtr) override {
21+
if (event.getType() == Event::Type::SUBSCRIPTION_STATUS) {
22+
const auto& message = event.getMessageList().at(0);
23+
if (message.getType() == Message::Type::SUBSCRIPTION_STARTED) {
24+
Request request(Request::Operation::GET_OPEN_ORDERS, "okx", this->symbol);
25+
sessionPtr->sendRequest(request);
26+
}
27+
} else if (event.getType() == Event::Type::RESPONSE) {
28+
const auto& message = event.getMessageList().at(0);
29+
if (message.getType() == Message::Type::GET_OPEN_ORDERS) {
30+
for (int i = 0; i < this->numOrders; ++i) {
31+
sessionPtr->setTimer(
32+
std::to_string(i), 100 * i,
33+
[](const boost::system::error_code&) {
34+
std::cout << std::string("Timer error handler is triggered at ") + UtilTime::getISOTimestamp(UtilTime::now()) << std::endl;
35+
},
36+
[this, sessionPtr]() {
37+
Request request(Request::Operation::CREATE_ORDER, "okx", this->symbol);
38+
const auto& clientOrderId = UtilString::generateRandomString(this->clientOrderIdLength);
39+
request.appendParam({
40+
{"SIDE", UtilString::toUpper(this->side)},
41+
{"LIMIT_PRICE", this->price},
42+
{"QUANTITY", this->quantity},
43+
{"CLIENT_ORDER_ID", clientOrderId},
44+
});
45+
this->orderCreateTimes.emplace(clientOrderId, UtilTime::now());
46+
sessionPtr->sendRequest(request);
47+
});
48+
}
49+
}
50+
} else if (event.getType() == Event::Type::SUBSCRIPTION_DATA) {
51+
const auto& message = event.getMessageList().at(0);
52+
if (message.getType() == Message::Type::EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE) {
53+
const auto& now = UtilTime::now();
54+
const auto& element = message.getElementList().front();
55+
const auto& orderId = element.getValue("ORDER_ID");
56+
const auto& clientOrderId = element.getValue("CLIENT_ORDER_ID");
57+
const auto& status = element.getValue("STATUS");
58+
if (status == "live") {
59+
this->orderCreateLatencies.push_back(now - this->orderCreateTimes.at(clientOrderId));
60+
this->orderCreateTimes.erase(clientOrderId);
61+
Request request(Request::Operation::CANCEL_ORDER, "okx", this->symbol);
62+
if (this->cancelByClientOrderId) {
63+
request.appendParam({
64+
{"CLIENT_ORDER_ID", clientOrderId},
65+
});
66+
} else {
67+
request.appendParam({
68+
{"ORDER_ID", orderId},
69+
});
70+
}
71+
this->orderCancelTimes.emplace(clientOrderId, now);
72+
sessionPtr->sendRequest(request);
73+
} else if (status == "canceled") {
74+
this->orderCancelLatencies.push_back(now - this->orderCancelTimes.at(clientOrderId));
75+
this->orderCancelTimes.erase(clientOrderId);
76+
++this->numCanceledOrders;
77+
if (this->numCanceledOrders == this->numOrders) {
78+
done = true;
79+
}
80+
}
81+
}
82+
}
83+
return true;
84+
}
85+
86+
std::string symbol;
87+
std::string side;
88+
std::string quantity;
89+
std::string price;
90+
int clientOrderIdLength{};
91+
bool cancelByClientOrderId{};
92+
int numOrders{};
93+
94+
std::map<std::string, TimePoint> orderCreateTimes;
95+
std::vector<std::chrono::nanoseconds> orderCreateLatencies;
96+
std::map<std::string, TimePoint> orderCancelTimes;
97+
std::vector<std::chrono::nanoseconds> orderCancelLatencies;
98+
99+
int numCanceledOrders{};
100+
std::atomic<bool> done{};
101+
};
102+
} /* namespace ccapi */
103+
104+
using ::ccapi::MyEventHandler;
105+
using ::ccapi::Request;
106+
using ::ccapi::Session;
107+
using ::ccapi::SessionConfigs;
108+
using ::ccapi::SessionOptions;
109+
using ::ccapi::Subscription;
110+
using ::ccapi::UtilSystem;
111+
112+
int main(int argc, char** argv) {
113+
if (UtilSystem::getEnvAsString("OKX_API_KEY").empty()) {
114+
std::cerr << "Please set environment variable OKX_API_KEY" << std::endl;
115+
return EXIT_FAILURE;
116+
}
117+
if (UtilSystem::getEnvAsString("OKX_API_SECRET").empty()) {
118+
std::cerr << "Please set environment variable OKX_API_SECRET" << std::endl;
119+
return EXIT_FAILURE;
120+
}
121+
if (UtilSystem::getEnvAsString("OKX_API_PASSPHRASE").empty()) {
122+
std::cerr << "Please set environment variable OKX_API_PASSPHRASE" << std::endl;
123+
return EXIT_FAILURE;
124+
}
125+
const auto& symbol = UtilSystem::getEnvAsString("SYMBOL");
126+
const auto& side = UtilSystem::getEnvAsString("SIDE");
127+
const auto& quantity = UtilSystem::getEnvAsString("QUANTITY");
128+
const auto& price = UtilSystem::getEnvAsString("PRICE");
129+
const auto& clientOrderIdLength = UtilSystem::getEnvAsInt("CLIENT_ORDER_ID_LENGTH", 4);
130+
const auto& cancelByClientOrderId = UtilSystem::getEnvAsBool("CANCEL_BY_CLIENT_ORDER_ID");
131+
const auto& numOrders = UtilSystem::getEnvAsInt("NUM_ORDERS", 10);
132+
SessionOptions sessionOptions;
133+
SessionConfigs sessionConfigs;
134+
MyEventHandler eventHandler(symbol, side, quantity, price, clientOrderIdLength, cancelByClientOrderId, numOrders);
135+
Session session(sessionOptions, sessionConfigs, &eventHandler);
136+
Subscription subscription("okx", symbol, "ORDER_UPDATE");
137+
session.subscribe(subscription);
138+
while (!eventHandler.done) {
139+
std::this_thread::sleep_for(std::chrono::seconds(1));
140+
}
141+
session.stop();
142+
double avgCreateLatencyMs =
143+
std::accumulate(eventHandler.orderCreateLatencies.begin(), eventHandler.orderCreateLatencies.end(), std::chrono::nanoseconds{0}).count() / 1e6 /
144+
eventHandler.orderCreateLatencies.size();
145+
std::cout << "avgCreateLatencyMs = " << avgCreateLatencyMs << " for " << eventHandler.orderCreateLatencies.size() << " orders" << std::endl;
146+
double avgCancelLatencyMs =
147+
std::accumulate(eventHandler.orderCancelLatencies.begin(), eventHandler.orderCancelLatencies.end(), std::chrono::nanoseconds{0}).count() / 1e6 /
148+
eventHandler.orderCancelLatencies.size();
149+
std::cout << "avgCancelLatencyMs = " << avgCancelLatencyMs << " for " << eventHandler.orderCancelLatencies.size() << " orders" << std::endl;
150+
return EXIT_SUCCESS;
151+
}

format_cpp.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
#!/usr/bin/env bash
2-
find . -type f -not -path "*/build/*" -not -name "ccapi_hmac.h" \( -name "*.h" -or -name "*.cpp" -or -name "*.hpp" \) -exec clang-format -i -style=file {} \+
2+
find . -type f -not -path "*/build/*" \( -name "*.h" -or -name "*.cpp" -or -name "*.hpp" \) -exec clang-format -i -style=file {} \+

include/ccapi_cpp/ccapi_decimal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace ccapi {
1010
* This class provides a numeric type for representing an arbitrary precision decimal number. It is minimalistic for the purpose of high performance.
1111
* Furthermore, unlike double, it is suitable for being used as the key of a map.
1212
*/
13-
class Decimal CCAPI_FINAL {
13+
class Decimal {
1414
public:
1515
Decimal() {}
1616

include/ccapi_cpp/ccapi_element.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace ccapi {
1010
* Element represents an item in a message. The value(s) in an Element can be queried in a number of ways. Use the getValue() functions to retrieve a single
1111
* value. Use the getNameValueMap() function (or getTagValueMap() function for FIX API) to retrieve all the values.
1212
*/
13-
class Element CCAPI_FINAL {
13+
class Element {
1414
public:
1515
explicit Element(bool isFix = false) : isFix(isFix) {}
1616

include/ccapi_cpp/ccapi_event.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace ccapi {
1212
*event. The event is the basic unit of work provided to applications. Each Event object consists of an Type attribute and zero or more Message objects.
1313
*/
1414

15-
class Event CCAPI_FINAL {
15+
class Event {
1616
public:
1717
enum class Type {
1818
UNKNOWN,

include/ccapi_cpp/ccapi_event_dispatcher.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace ccapi {
2020
* more internal threads for one or more sessions.
2121
*/
2222

23-
class EventDispatcher CCAPI_FINAL {
23+
class EventDispatcher {
2424
public:
2525
explicit EventDispatcher(const int numDispatcherThreads = 1) : numDispatcherThreads(numDispatcherThreads) {
2626
CCAPI_LOGGER_FUNCTION_ENTER;

0 commit comments

Comments
 (0)