Skip to content

Commit 85402e7

Browse files
Merge pull request #547 from crypto-chassis/proxy
add subscription proxyUrl
2 parents b85da3e + 6667d2c commit 85402e7

12 files changed

Lines changed: 90 additions & 59 deletions

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
- [Multiple subscription fields](#multiple-subscription-fields)
3333
- [Make Session::sendRequest blocking](#make-sessionsendrequest-blocking)
3434
- [Provide API credentials for an exchange](#provide-api-credentials-for-an-exchange)
35-
- [Override exchange urls](#override-exchange-urls)
3635
- [Complex request parameters](#complex-request-parameters-1)
3736
- [Send request by Websocket API](#send-request-by-websocket-api)
3837
- [Specify instrument type](#specify-instrument-type)
@@ -44,6 +43,8 @@
4443
- [Set timer](#set-timer)
4544
- [Heartbeat](#heartbeat)
4645
- [Use multiple sessions](#use-multiple-sessions)
46+
- [Override exchange urls](#override-exchange-urls)
47+
- [Connect to a proxy](#connect-to-a-proxy)
4748
- [Performance Tuning](#performance-tuning)
4849
- [Known Issues and Workarounds](#known-issues-and-workarounds)
4950

@@ -701,11 +702,11 @@ Bye
701702

702703
#### Specify correlation id
703704

704-
Instantiate `Request` with the desired correlationId. The `correlationId` should be unique.
705+
Instantiate `Request` with the desired `correlationId`. The `correlationId` should be unique.
705706
```
706707
Request request(Request::Operation::CREATE_ORDER, "okx", "BTC-USDT", "cool correlation id");
707708
```
708-
Instantiate `Subscription` with the desired correlationId.
709+
Instantiate `Subscription` with the desired `correlationId`.
709710
```
710711
Subscription subscription("okx", "BTC-USDT", "ORDER_UPDATE", "", "cool correlation id");
711712
```
@@ -768,9 +769,6 @@ Subscription subscription("okx", "BTC-USDT", "ORDER_UPDATE", "", "", {
768769
});
769770
```
770771

771-
#### Override exchange urls
772-
You can override exchange urls at compile time by using macros. See section "exchange REST urls", "exchange WS urls", and "exchange FIX urls" in [`include/ccapi_cpp/ccapi_macro.h`](include/ccapi_cpp/ccapi_macro.h). You can also override exchange urls at runtime. See [this example](example/src/override_exchange_url_at_runtime/main.cpp). These can be useful if you need to connect to test accounts (e.g. https://www.okx.com/docs-v5/en/#overview-demo-trading-services) or connect to an IP address (e.g. ws://172.30.0.146:9000).
773-
774772
#### Complex request parameters
775773
Please follow the exchange's API documentations: e.g. https://www.okx.com/docs-v5/en/#order-book-trading-trade-post-place-order.
776774
```
@@ -1074,6 +1072,14 @@ Subscription subscription("", "", "HEARTBEAT", "HEARTBEAT_INTERVAL_MILLISECONDS=
10741072
session.subscribe(subscription);
10751073
```
10761074

1075+
#### Override exchange urls
1076+
You can override exchange urls at compile time by using macros. See section "exchange REST urls", "exchange WS urls", and "exchange FIX urls" in [`include/ccapi_cpp/ccapi_macro.h`](include/ccapi_cpp/ccapi_macro.h). You can also override exchange urls at runtime. See [this example](example/src/override_exchange_url_at_runtime/main.cpp). These can be useful if you need to connect to test accounts (e.g. https://www.okx.com/docs-v5/en/#overview-demo-trading-services).
1077+
1078+
#### Connect to a proxy
1079+
Instantiate `Subscription` with the desired `proxyUrl`.
1080+
```
1081+
Subscription subscription("okx", "BTC-USDT", "MARKET_DEPTH", "", "", {}, "172.30.0.146:9000");
1082+
```
10771083

10781084

10791085
## Performance Tuning

include/ccapi_cpp/ccapi_subscription.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ namespace ccapi {
1616
class Subscription {
1717
public:
1818
explicit Subscription(const std::string& exchange = "", const std::string& instrument = "", const std::string& field = "", const std::string& options = "",
19-
const std::string& correlationId = "", const std::map<std::string, std::string>& credential = {})
20-
: exchange(exchange), instrument(instrument), field(field), correlationId(correlationId), credential(credential) {
19+
const std::string& correlationId = "", const std::map<std::string, std::string>& credential = {}, const std::string& proxyUrl = "")
20+
: exchange(exchange), instrument(instrument), field(field), correlationId(correlationId), credential(credential), proxyUrl(proxyUrl) {
2121
auto originalInstrumentSet = UtilString::splitToSet(instrument, ",");
2222
std::copy_if(originalInstrumentSet.begin(), originalInstrumentSet.end(), std::inserter(this->instrumentSet, this->instrumentSet.end()),
2323
[](const std::string& value) { return !value.empty(); });
@@ -68,8 +68,8 @@ class Subscription {
6868
}
6969
std::string output = "Subscription [exchange = " + exchange + ", marginType = " + marginType + ", instrumentType = " + instrumentType +
7070
", instrument = " + instrument + ", field = " + field + ", optionMap = " + ccapi::toString(optionMap) +
71-
", correlationId = " + correlationId + ", credential = " + ccapi::toString(shortCredential) + ", serviceName = " + serviceName +
72-
", timeSent = " + UtilTime::getISOTimestamp(timeSent) + "]";
71+
", correlationId = " + correlationId + ", credential = " + ccapi::toString(shortCredential) + ", proxyUrl = " + proxyUrl +
72+
", serviceName = " + serviceName + ", timeSent = " + UtilTime::getISOTimestamp(timeSent) + "]";
7373
return output;
7474
}
7575

@@ -89,6 +89,8 @@ class Subscription {
8989

9090
const std::map<std::string, std::string>& getCredential() const { return credential; }
9191

92+
const std::string& getProxyUrl() const { return proxyUrl; }
93+
9294
const std::string& getServiceName() const { return serviceName; }
9395

9496
const std::set<std::string>& getInstrumentSet() const { return instrumentSet; }
@@ -131,11 +133,14 @@ class Subscription {
131133

132134
void setField(const std::string& field) { this->field = field; }
133135

136+
void setProxyUrl(const std::string& proxyUrl) { this->proxyUrl = proxyUrl; }
137+
134138
void setTimeSent(TimePoint timeSent) { this->timeSent = timeSent; }
135139

136140
void setInstrumentType(const std::string& instrumentType) { this->instrumentType = instrumentType; }
137141

138142
void setMarginType(const std::string& marginType) { this->marginType = marginType; }
143+
139144
enum class Status {
140145
UNKNOWN,
141146
SUBSCRIBING,
@@ -180,6 +185,7 @@ class Subscription {
180185
std::map<std::string, std::string> optionMap;
181186
std::string correlationId;
182187
std::map<std::string, std::string> credential;
188+
std::string proxyUrl;
183189
std::string serviceName;
184190
std::set<std::string> instrumentSet;
185191
std::set<std::string> fieldSet;

include/ccapi_cpp/ccapi_ws_connection.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ class WsConnection {
1818
WsConnection& operator=(const WsConnection&) = delete;
1919

2020
WsConnection(const std::string& url, const std::string& group, const std::vector<Subscription>& subscriptionList,
21-
const std::map<std::string, std::string>& credential)
22-
: url(url), group(group), subscriptionList(subscriptionList), credential(credential) {
21+
const std::map<std::string, std::string>& credential, const std::string& proxyUrl = "")
22+
: url(url), group(group), subscriptionList(subscriptionList), credential(credential), proxyUrl(proxyUrl) {
2323
std::map<std::string, std::string> shortCredential;
2424
for (const auto& x : credential) {
2525
shortCredential.insert(std::make_pair(x.first, UtilString::firstNCharacter(x.second, CCAPI_CREDENTIAL_DISPLAY_LENGTH)));
@@ -51,8 +51,9 @@ class WsConnection {
5151
streamPtr);
5252
std::string output = "WsConnection [longId = " + longId + ", id = " + id + ", url = " + url + ", group = " + group +
5353
", subscriptionList = " + ccapi::toString(subscriptionList) + ", credential = " + ccapi::toString(shortCredential) +
54-
", status = " + statusToString(status) + ", headers = " + ccapi::toString(headers) + ", streamPtr = " + oss.str() +
55-
", remoteCloseCode = " + std::to_string(remoteCloseCode) + ", remoteCloseReason = " + std::string(remoteCloseReason.reason.c_str()) +
54+
", proxyUrl = " + proxyUrl + ", status = " + statusToString(status) + ", headers = " + ccapi::toString(headers) +
55+
", streamPtr = " + oss.str() + ", remoteCloseCode = " + std::to_string(remoteCloseCode) +
56+
", remoteCloseReason = " + std::string(remoteCloseReason.reason.c_str()) +
5657
", hostHttpHeaderValue = " + ccapi::toString(hostHttpHeaderValue) + ", path = " + ccapi::toString(path) +
5758
", host = " + ccapi::toString(host) + ", port = " + ccapi::toString(port) + ", isSecure = " + ccapi::toString(isSecure) + "]";
5859
return output;
@@ -145,6 +146,7 @@ class WsConnection {
145146
Status status{Status::UNKNOWN};
146147
std::map<std::string, std::string> headers;
147148
std::map<std::string, std::string> credential;
149+
std::string proxyUrl;
148150
std::variant<std::shared_ptr<beast::websocket::stream<beast::ssl_stream<beast::tcp_stream>>>, std::shared_ptr<beast::websocket::stream<beast::tcp_stream>>>
149151
streamPtr;
150152
beast::websocket::close_code remoteCloseCode{};

include/ccapi_cpp/service/ccapi_execution_management_service.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,15 @@ class ExecutionManagementService : public Service {
6161
}
6262

6363
const auto& fieldSet = subscription.getFieldSet();
64+
const auto& proxyUrl = subscription.getProxyUrl();
65+
6466
if (fieldSet.find(CCAPI_EM_WEBSOCKET_ORDER_ENTRY) != fieldSet.end()) {
65-
auto wsConnectionPtr = std::make_shared<WsConnection>(that->baseUrlWsOrderEntry, "", std::vector<Subscription>{subscription}, credential);
67+
auto wsConnectionPtr = std::make_shared<WsConnection>(that->baseUrlWsOrderEntry, "", std::vector<Subscription>{subscription}, credential, proxyUrl);
6668
that->setWsConnectionStream(wsConnectionPtr);
6769
CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr));
6870
that->prepareConnect(wsConnectionPtr);
6971
} else {
70-
auto wsConnectionPtr = std::make_shared<WsConnection>(that->baseUrlWs, "", std::vector<Subscription>{subscription}, credential);
72+
auto wsConnectionPtr = std::make_shared<WsConnection>(that->baseUrlWs, "", std::vector<Subscription>{subscription}, credential, proxyUrl);
7173
that->setWsConnectionStream(wsConnectionPtr);
7274
CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr));
7375
that->prepareConnect(wsConnectionPtr);

include/ccapi_cpp/service/ccapi_execution_management_service_ascendex.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,10 @@ class ExecutionManagementServiceAscendex : public ExecutionManagementService {
362362
credential = that->credentialDefault;
363363
}
364364
const auto& accountGroup = mapGetWithDefault(credential, that->apiAccountGroupName);
365+
const auto& proxyUrl = subscription.getProxyUrl();
365366

366367
auto wsConnectionPtr = std::make_shared<WsConnection>(that->baseUrlWs + "/" + accountGroup + "/api/pro/v1/stream", "",
367-
std::vector<Subscription>{subscription}, credential);
368+
std::vector<Subscription>{subscription}, credential, proxyUrl);
368369
that->setWsConnectionStream(wsConnectionPtr);
369370
CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr));
370371
that->prepareConnect(wsConnectionPtr);

include/ccapi_cpp/service/ccapi_execution_management_service_gateio_perpetual_futures.h

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,31 +82,32 @@ class ExecutionManagementServiceGateioPerpetualFutures : public ExecutionManagem
8282
CCAPI_LOGGER_DEBUG("this->baseUrlWs = " + this->baseUrlWs);
8383
if (this->shouldContinue.load()) {
8484
for (auto& subscription : subscriptionList) {
85-
boost::asio::post(
86-
*this->serviceContextPtr->ioContextPtr, [that = shared_from_base<ExecutionManagementServiceGateioPerpetualFutures>(), subscription]() mutable {
87-
auto now = UtilTime::now();
88-
subscription.setTimeSent(now);
89-
const auto& instrumentSet = subscription.getInstrumentSet();
90-
auto it = instrumentSet.begin();
91-
if (it != instrumentSet.end()) {
92-
std::string settle;
93-
std::string symbolId = *it;
94-
if (UtilString::endsWith(symbolId, "_USD")) {
95-
settle = "btc";
96-
} else if (UtilString::endsWith(symbolId, "_USDT")) {
97-
settle = "usdt";
98-
}
99-
auto credential = subscription.getCredential();
100-
if (credential.empty()) {
101-
credential = that->credentialDefault;
102-
}
85+
boost::asio::post(*this->serviceContextPtr->ioContextPtr, [that = shared_from_base<ExecutionManagementServiceGateioPerpetualFutures>(),
86+
subscription]() mutable {
87+
auto now = UtilTime::now();
88+
subscription.setTimeSent(now);
89+
const auto& instrumentSet = subscription.getInstrumentSet();
90+
auto it = instrumentSet.begin();
91+
if (it != instrumentSet.end()) {
92+
std::string settle;
93+
std::string symbolId = *it;
94+
if (UtilString::endsWith(symbolId, "_USD")) {
95+
settle = "btc";
96+
} else if (UtilString::endsWith(symbolId, "_USDT")) {
97+
settle = "usdt";
98+
}
99+
auto credential = subscription.getCredential();
100+
if (credential.empty()) {
101+
credential = that->credentialDefault;
102+
}
103+
const auto& proxyUrl = subscription.getProxyUrl();
103104

104-
auto wsConnectionPtr = std::make_shared<WsConnection>(that->baseUrlWs + settle, "", std::vector<Subscription>{subscription}, credential);
105-
that->setWsConnectionStream(wsConnectionPtr);
106-
CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr));
107-
that->prepareConnect(wsConnectionPtr);
108-
}
109-
});
105+
auto wsConnectionPtr = std::make_shared<WsConnection>(that->baseUrlWs + settle, "", std::vector<Subscription>{subscription}, credential, proxyUrl);
106+
that->setWsConnectionStream(wsConnectionPtr);
107+
CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr));
108+
that->prepareConnect(wsConnectionPtr);
109+
}
110+
});
110111
}
111112
}
112113
CCAPI_LOGGER_FUNCTION_EXIT;

include/ccapi_cpp/service/ccapi_market_data_service.h

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,21 @@ class MarketDataService : public Service {
5959
CCAPI_LOGGER_FUNCTION_ENTER;
6060
if (this->shouldContinue.load()) {
6161
for (auto& x : this->groupSubscriptionListByInstrumentGroup(subscriptionList)) {
62-
auto instrumentGroup = x.first;
63-
auto subscriptionListGivenInstrumentGroup = x.second;
62+
const auto& instrumentGroup = x.first;
63+
auto& subscriptionListGivenInstrumentGroup = x.second;
6464
boost::asio::post(*this->serviceContextPtr->ioContextPtr, [that = shared_from_base<MarketDataService>(), instrumentGroup,
6565
subscriptionListGivenInstrumentGroup]() mutable {
66-
auto now = UtilTime::now();
66+
const auto& now = UtilTime::now();
6767
for (auto& subscription : subscriptionListGivenInstrumentGroup) {
6868
subscription.setTimeSent(now);
6969
}
7070
std::map<std::string, std::vector<std::string>> wsConnectionIdListByInstrumentGroupMap = invertMapMulti(that->instrumentGroupByWsConnectionIdMap);
7171
if (wsConnectionIdListByInstrumentGroupMap.find(instrumentGroup) != wsConnectionIdListByInstrumentGroupMap.end() &&
7272
that->subscriptionStatusByInstrumentGroupInstrumentMap.find(instrumentGroup) != that->subscriptionStatusByInstrumentGroupInstrumentMap.end()) {
73-
auto wsConnectionId = wsConnectionIdListByInstrumentGroupMap.at(instrumentGroup).at(0);
74-
auto wsConnectionPtr = that->wsConnectionPtrByIdMap.at(wsConnectionId);
73+
const auto& wsConnectionId = wsConnectionIdListByInstrumentGroupMap.at(instrumentGroup).at(0);
74+
const auto& wsConnectionPtr = that->wsConnectionPtrByIdMap.at(wsConnectionId);
7575
for (const auto& subscription : subscriptionListGivenInstrumentGroup) {
76-
auto instrument = subscription.getInstrument();
76+
const auto& instrument = subscription.getInstrument();
7777
if (that->subscriptionStatusByInstrumentGroupInstrumentMap[instrumentGroup].find(instrument) !=
7878
that->subscriptionStatusByInstrumentGroupInstrumentMap[instrumentGroup].end()) {
7979
that->onError(Event::Type::SUBSCRIPTION_STATUS, Message::Type::SUBSCRIPTION_FAILURE, "already subscribed: " + toString(subscription));
@@ -86,13 +86,15 @@ class MarketDataService : public Service {
8686
CCAPI_LOGGER_INFO("about to subscribe to exchange");
8787
that->subscribeToExchange(wsConnectionPtr);
8888
} else {
89-
auto url = UtilString::split(instrumentGroup, "|").at(0);
89+
const auto& splittedInstrumentGroup = UtilString::split(instrumentGroup, "|");
90+
const auto& url = splittedInstrumentGroup.at(0);
9091
auto credential = subscriptionListGivenInstrumentGroup.at(0).getCredential();
9192
if (credential.empty()) {
9293
credential = that->credentialDefault;
9394
}
95+
const auto& proxyUrl = splittedInstrumentGroup.at(splittedInstrumentGroup.size() - 1);
9496

95-
auto wsConnectionPtr = std::make_shared<WsConnection>(url, instrumentGroup, subscriptionListGivenInstrumentGroup, credential);
97+
auto wsConnectionPtr = std::make_shared<WsConnection>(url, instrumentGroup, subscriptionListGivenInstrumentGroup, credential, proxyUrl);
9698
that->setWsConnectionStream(wsConnectionPtr);
9799
CCAPI_LOGGER_WARN("about to subscribe with new wsConnectionPtr " + toString(*wsConnectionPtr));
98100
that->prepareConnect(wsConnectionPtr);
@@ -122,9 +124,11 @@ class MarketDataService : public Service {
122124
virtual std::string getInstrumentGroup(const Subscription& subscription) {
123125
const auto& field = subscription.getField();
124126
if (field == CCAPI_GENERIC_PUBLIC_SUBSCRIPTION) {
125-
return this->baseUrlWs + "|" + subscription.getField() + "|" + subscription.getCorrelationId() + "|" + subscription.getSerializedCredential();
127+
return this->baseUrlWs + "|" + subscription.getField() + "|" + subscription.getCorrelationId() + "|" + subscription.getSerializedCredential() + "|" +
128+
subscription.getProxyUrl();
126129
} else {
127-
return this->baseUrlWs + "|" + subscription.getField() + "|" + subscription.getSerializedOptions() + "|" + subscription.getSerializedCredential();
130+
return this->baseUrlWs + "|" + subscription.getField() + "|" + subscription.getSerializedOptions() + "|" + subscription.getSerializedCredential() + "|" +
131+
subscription.getProxyUrl();
128132
}
129133
}
130134

include/ccapi_cpp/service/ccapi_market_data_service_gateio_perpetual_futures.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class MarketDataServiceGateioPerpetualFutures : public MarketDataServiceGateioBa
4141
} else if (UtilString::endsWith(instrument, "_USDT")) {
4242
url += "usdt";
4343
}
44-
return url + "|" + subscription.getField() + "|" + subscription.getSerializedOptions();
44+
return url + "|" + subscription.getField() + "|" + subscription.getSerializedOptions() + "|" + subscription.getProxyUrl();
4545
}
4646

4747
void substituteParamSettle(std::string& target, const std::map<std::string, std::string>& param, const std::string& symbolId) {

include/ccapi_cpp/service/ccapi_market_data_service_gemini.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ class MarketDataServiceGemini : public MarketDataService {
216216
}
217217
url += parameter + "=true";
218218
}
219-
return url;
219+
return url + "|" + subscription.getProxyUrl();
220220
}
221221

222222
void convertRequestForRest(http::request<http::string_body>& req, const Request& request, const TimePoint& now, const std::string& symbolId,

include/ccapi_cpp/service/ccapi_market_data_service_huobi_base.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class MarketDataServiceHuobiBase : public MarketDataService {
102102
url += "/ws";
103103
}
104104
}
105-
return url + "|" + field + "|" + subscription.getSerializedOptions();
105+
return url + "|" + field + "|" + subscription.getSerializedOptions() + "|" + subscription.getProxyUrl();
106106
}
107107

108108
void processTextMessage(std::shared_ptr<WsConnection> wsConnectionPtr, boost::beast::string_view textMessageView, const TimePoint& timeReceived, Event& event,

0 commit comments

Comments
 (0)