Skip to content

Commit

Permalink
Merge pull request #362 from crypto-chassis/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
cryptochassis authored Jan 13, 2023
2 parents 0423817 + 1f8c543 commit dd59edf
Show file tree
Hide file tree
Showing 16 changed files with 498 additions and 83 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
* Code closely follows Bloomberg's API: https://www.bloomberg.com/professional/support/api-library/.
* It is ultra fast thanks to very careful optimizations: move semantics, regex optimization, locality of reference, lock contention minimization, etc.
* Supported exchanges:
* Market data: coinbase, gemini, kraken, kraken-futures, bitstamp, bitfinex, bitmex, binance-us, binance, binance-usds-futures, binance-coin-futures, huobi, huobi-usdt-swap, huobi-coin-swap, okx, erisx, kucoin, kucoin-futures, deribit, gateio, gateio-perpetual-futures, cryptocom, bybit, bybit-derivatives, ascendex, bitget, bitget-futures, bitmart, mexc, mexc-futures.
* Market data: coinbase, gemini, kraken, kraken-futures, bitstamp, bitfinex, bitmex, binance-us, binance, binance-usds-futures, binance-coin-futures, huobi, huobi-usdt-swap, huobi-coin-swap, okx, erisx, kucoin, kucoin-futures, deribit, gateio, gateio-perpetual-futures, cryptocom, bybit, bybit-derivatives, ascendex, bitget, bitget-futures, bitmart, mexc, mexc-futures, whitebit.
* Execution Management: coinbase, gemini, kraken, kraken-futures, bitstamp, bitfinex, bitmex, binance-us, binance, binance-usds-futures, binance-coin-futures, huobi, huobi-usdt-swap, huobi-coin-swap, okx, erisx, kucoin, kucoin-futures, deribit, gateio, gateio-perpetual-futures, cryptocom, bybit, bybit-derivatives, ascendex, bitget, bitget-futures, bitmart, mexc.
* FIX: coinbase, gemini.
* A spot market making application is provided as an end-to-end solution for liquidity providers.
Expand Down
2 changes: 2 additions & 0 deletions binding/user_specified_cmake_include.cmake.example
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ include_guard(DIRECTORY)
#
# add_compile_definitions(CCAPI_ENABLE_EXCHANGE_MEXC_FUTURES)
#
# add_compile_definitions(CCAPI_ENABLE_EXCHANGE_WHITEBIT)
#
# add_compile_definitions(CCAPI_ENABLE_LOG_TRACE)
#
# add_compile_definitions(CCAPI_ENABLE_LOG_DEBUG)
Expand Down
14 changes: 14 additions & 0 deletions include/ccapi_cpp/ccapi_macro.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@
#ifndef CCAPI_EXCHANGE_NAME_MEXC_FUTURES
#define CCAPI_EXCHANGE_NAME_MEXC_FUTURES "mexc-futures"
#endif
#ifndef CCAPI_EXCHANGE_NAME_WHITEBIT
#define CCAPI_EXCHANGE_NAME_WHITEBIT "whitebit"
#endif
#ifndef CCAPI_LAST_PRICE
#define CCAPI_LAST_PRICE "LAST_PRICE"
#endif
Expand Down Expand Up @@ -325,6 +328,8 @@
#define CCAPI_WEBSOCKET_MEXC_CHANNEL_DIFF_DEPTH "[email protected]"
#define CCAPI_WEBSOCKET_MEXC_FUTURES_CHANNEL_TRANSACTION "deal"
#define CCAPI_WEBSOCKET_MEXC_FUTURES_CHANNEL_DEPTH "depth"
#define CCAPI_WEBSOCKET_WHITEBIT_CHANNEL_MARKET_TRADES "trades"
#define CCAPI_WEBSOCKET_WHITEBIT_CHANNEL_MARKET_DEPTH "depth"
#ifndef CCAPI_CHANNEL_ID
#define CCAPI_CHANNEL_ID "channelId"
#endif
Expand Down Expand Up @@ -465,6 +470,9 @@
#ifndef CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY
#define CCAPI_EM_ORDER_CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY "CUMULATIVE_FILLED_PRICE_TIMES_QUANTITY"
#endif
#ifndef CCAPI_EM_ORDER_AVERAGE_FILLED_PRICE
#define CCAPI_EM_ORDER_AVERAGE_FILLED_PRICE "AVERAGE_FILLED_PRICE"
#endif
#ifndef CCAPI_EM_ORDER_INSTRUMENT
#define CCAPI_EM_ORDER_INSTRUMENT "INSTRUMENT"
#endif
Expand Down Expand Up @@ -714,6 +722,9 @@
#ifndef CCAPI_MEXC_FUTURES_URL_REST_BASE
#define CCAPI_MEXC_FUTURES_URL_REST_BASE "https://contract.mexc.com"
#endif
#ifndef CCAPI_WHITEBIT_URL_REST_BASE
#define CCAPI_WHITEBIT_URL_REST_BASE "https://whitebit.com"
#endif
// end: exchange REST urls

// start: exchange WS urls
Expand Down Expand Up @@ -831,6 +842,9 @@
#ifndef CCAPI_MEXC_FUTURES_URL_WS_BASE
#define CCAPI_MEXC_FUTURES_URL_WS_BASE "wss://contract.mexc.com"
#endif
#ifndef CCAPI_WHITEBIT_URL_WS_BASE
#define CCAPI_WHITEBIT_URL_WS_BASE "wss://api.whitebit.com"
#endif
// end: exchange WS urls

// start: exchange FIX urls
Expand Down
4 changes: 2 additions & 2 deletions include/ccapi_cpp/ccapi_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class Message CCAPI_FINAL {
public:
enum class RecapType {
UNKNOWN,
NONE, // normal data tick; not a recap
SOLICITED, // generated on request by subscriber
NONE, // Normal data tick, not a recap. For market depth, it represents the new snapshot. For public trade, it represents the new trades.
SOLICITED, // A recap. For market depth, it represents the initial snapshot. For public trade, it represents the recent trades.
};
static std::string recapTypeToString(RecapType recapType) {
std::string output;
Expand Down
15 changes: 15 additions & 0 deletions include/ccapi_cpp/ccapi_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@
#ifdef CCAPI_ENABLE_EXCHANGE_MEXC_FUTURES
#include "ccapi_cpp/service/ccapi_market_data_service_mexc_futures.h"
#endif
#ifdef CCAPI_ENABLE_EXCHANGE_WHITEBIT
#include "ccapi_cpp/service/ccapi_market_data_service_whitebit.h"
#endif
#endif
// end: enable exchanges for market data

Expand Down Expand Up @@ -204,6 +207,9 @@
// #ifdef CCAPI_ENABLE_EXCHANGE_MEXC_FUTURES
// #include "ccapi_cpp/service/ccapi_execution_management_service_mexc_futures.h"
// #endif
#ifdef CCAPI_ENABLE_EXCHANGE_WHITEBIT
#include "ccapi_cpp/service/ccapi_execution_management_service_whitebit.h"
#endif
#endif
// end: enable exchanges for execution management

Expand Down Expand Up @@ -421,6 +427,10 @@ class Session {
this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_MEXC_FUTURES] =
std::make_shared<MarketDataServiceMexcFutures>(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr);
#endif
#ifdef CCAPI_ENABLE_EXCHANGE_WHITEBIT
this->serviceByServiceNameExchangeMap[CCAPI_MARKET_DATA][CCAPI_EXCHANGE_NAME_WHITEBIT] =
std::make_shared<MarketDataServiceWhitebit>(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr);
#endif
#endif
#ifdef CCAPI_ENABLE_SERVICE_EXECUTION_MANAGEMENT
#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE
Expand Down Expand Up @@ -555,7 +565,12 @@ class Session {
// this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_MEXC_FUTURES] =
// std::make_shared<ExecutionManagementServiceMexcFutures>(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr);
// #endif
// #ifdef CCAPI_ENABLE_EXCHANGE_WHITEBIT
// this->serviceByServiceNameExchangeMap[CCAPI_EXECUTION_MANAGEMENT][CCAPI_EXCHANGE_NAME_WHITEBIT] =
// std::make_shared<ExecutionManagementServiceWhitebit>(this->internalEventHandler, sessionOptions, sessionConfigs, this->serviceContextPtr);
// #endif
#endif

#ifdef CCAPI_ENABLE_SERVICE_FIX
#ifdef CCAPI_ENABLE_EXCHANGE_COINBASE
this->serviceByServiceNameExchangeMap[CCAPI_FIX][CCAPI_EXCHANGE_NAME_COINBASE] =
Expand Down
12 changes: 11 additions & 1 deletion include/ccapi_cpp/ccapi_session_configs.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ class SessionConfigs CCAPI_FINAL {
{CCAPI_TRADE, CCAPI_WEBSOCKET_MEXC_FUTURES_CHANNEL_TRANSACTION},
{CCAPI_MARKET_DEPTH, CCAPI_WEBSOCKET_MEXC_FUTURES_CHANNEL_DEPTH},
};
std::map<std::string, std::string> fieldWebsocketChannelMapWhitebit = {
{CCAPI_TRADE, CCAPI_WEBSOCKET_WHITEBIT_CHANNEL_MARKET_TRADES},
{CCAPI_MARKET_DEPTH, CCAPI_WEBSOCKET_WHITEBIT_CHANNEL_MARKET_DEPTH},
};
for (auto const& fieldWebsocketChannel : fieldWebsocketChannelMapCoinbase) {
this->exchangeFieldMap[CCAPI_EXCHANGE_NAME_COINBASE].push_back(fieldWebsocketChannel.first);
}
Expand Down Expand Up @@ -259,6 +263,9 @@ class SessionConfigs CCAPI_FINAL {
for (auto const& fieldWebsocketChannel : fieldWebsocketChannelMapMexcFutures) {
this->exchangeFieldMap[CCAPI_EXCHANGE_NAME_MEXC_FUTURES].push_back(fieldWebsocketChannel.first);
}
for (auto const& fieldWebsocketChannel : fieldWebsocketChannelMapWhitebit) {
this->exchangeFieldMap[CCAPI_EXCHANGE_NAME_WHITEBIT].push_back(fieldWebsocketChannel.first);
}
for (auto& x : this->exchangeFieldMap) {
x.second.push_back(CCAPI_GENERIC_PUBLIC_SUBSCRIPTION);
}
Expand Down Expand Up @@ -296,6 +303,7 @@ class SessionConfigs CCAPI_FINAL {
{CCAPI_EXCHANGE_NAME_BITMART, fieldWebsocketChannelMapBitmart},
{CCAPI_EXCHANGE_NAME_MEXC, fieldWebsocketChannelMapMexc},
{CCAPI_EXCHANGE_NAME_MEXC_FUTURES, fieldWebsocketChannelMapMexcFutures},
{CCAPI_EXCHANGE_NAME_WHITEBIT, fieldWebsocketChannelMapWhitebit},
};
this->urlWebsocketBase = {
{CCAPI_EXCHANGE_NAME_COINBASE, CCAPI_COINBASE_URL_WS_BASE},
Expand Down Expand Up @@ -334,6 +342,7 @@ class SessionConfigs CCAPI_FINAL {
{CCAPI_EXCHANGE_NAME_BITMART, CCAPI_BITMART_URL_WS_BASE},
{CCAPI_EXCHANGE_NAME_MEXC, CCAPI_MEXC_URL_WS_BASE},
{CCAPI_EXCHANGE_NAME_MEXC_FUTURES, CCAPI_MEXC_FUTURES_URL_WS_BASE},
{CCAPI_EXCHANGE_NAME_WHITEBIT, CCAPI_WHITEBIT_URL_WS_BASE},
};
this->initialSequenceByExchangeMap = {{CCAPI_EXCHANGE_NAME_GEMINI, 0}, {CCAPI_EXCHANGE_NAME_BITFINEX, 1}};
}
Expand Down Expand Up @@ -370,9 +379,10 @@ class SessionConfigs CCAPI_FINAL {
{CCAPI_EXCHANGE_NAME_ASCENDEX, CCAPI_ASCENDEX_URL_REST_BASE},
{CCAPI_EXCHANGE_NAME_BITGET, CCAPI_BITGET_URL_REST_BASE},
{CCAPI_EXCHANGE_NAME_BITGET_FUTURES, CCAPI_BITGET_FUTURES_URL_REST_BASE},
{CCAPI_EXCHANGE_NAME_BITMART, CCAPI_BITMART_URL_REST_BASE},
{CCAPI_EXCHANGE_NAME_MEXC, CCAPI_MEXC_URL_REST_BASE},
{CCAPI_EXCHANGE_NAME_MEXC_FUTURES, CCAPI_MEXC_FUTURES_URL_REST_BASE},
{CCAPI_EXCHANGE_NAME_BITMART, CCAPI_BITMART_URL_REST_BASE},
{CCAPI_EXCHANGE_NAME_WHITEBIT, CCAPI_WHITEBIT_URL_REST_BASE},
};
}
void initializUrlFixBase() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,62 +280,64 @@ class ExecutionManagementServiceKrakenFutures : public ExecutionManagementServic
if (document.FindMember("event") == document.MemberEnd()) {
if (document.FindMember("feed") != document.MemberEnd()) {
std::string feed = document["feed"].GetString();
std::string field;
if (feed == "fills") {
field = CCAPI_EM_PRIVATE_TRADE;
} else if (feed == "open_orders") {
field = CCAPI_EM_ORDER_UPDATE;
}
const auto& fieldSet = subscription.getFieldSet();
if (fieldSet.find(field) != fieldSet.end()) {
const auto& instrumentSet = subscription.getInstrumentSet();
if (field == CCAPI_EM_PRIVATE_TRADE) {
for (const auto& x : document["fills"].GetArray()) {
if (feed == "fills" || feed == "open_orders") {
std::string field;
if (feed == "fills") {
field = CCAPI_EM_PRIVATE_TRADE;
} else if (feed == "open_orders") {
field = CCAPI_EM_ORDER_UPDATE;
}
const auto& fieldSet = subscription.getFieldSet();
if (fieldSet.find(field) != fieldSet.end()) {
const auto& instrumentSet = subscription.getInstrumentSet();
if (field == CCAPI_EM_PRIVATE_TRADE) {
for (const auto& x : document["fills"].GetArray()) {
std::string instrument = x["instrument"].GetString();
if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) {
Message message;
message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_PRIVATE_TRADE);
message.setTime(UtilTime::makeTimePointFromMilliseconds(std::stoll(x["time"].GetString())));
message.setTimeReceived(timeReceived);
message.setCorrelationIdList({subscription.getCorrelationId()});
std::vector<Element> elementList;
Element element;
element.insert(CCAPI_EM_ORDER_LAST_EXECUTED_PRICE, x["price"].GetString());
element.insert(CCAPI_EM_ORDER_LAST_EXECUTED_SIZE, x["qty"].GetString());
element.insert(CCAPI_EM_ORDER_SIDE, x["buy"].GetBool() ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL);
element.insert(CCAPI_EM_ORDER_ID, std::string(x["order_id"].GetString()));
element.insert(CCAPI_EM_CLIENT_ORDER_ID, std::string(x["cli_ord_id"].GetString()));
element.insert(CCAPI_IS_MAKER, std::string(x["fill_type"].GetString()) == "maker" ? "1" : "0");
element.insert(CCAPI_EM_ORDER_INSTRUMENT, instrument);
element.insert(CCAPI_EM_ORDER_FEE_QUANTITY, std::string(x["fee_paid"].GetString()));
element.insert(CCAPI_EM_ORDER_FEE_ASSET, std::string(x["fee_currency"].GetString()));
elementList.emplace_back(std::move(element));
message.setElementList(elementList);
messageList.emplace_back(std::move(message));
}
}
} else if (field == CCAPI_EM_ORDER_UPDATE) {
const rj::Value& x = document["order"];
std::string instrument = x["instrument"].GetString();
if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) {
Message message;
message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_PRIVATE_TRADE);
message.setTime(UtilTime::makeTimePointFromMilliseconds(std::stoll(x["time"].GetString())));
message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE);
message.setTime(UtilTime::makeTimePointFromMilliseconds(std::stoll(x["last_update_time"].GetString())));
message.setTimeReceived(timeReceived);
message.setCorrelationIdList({subscription.getCorrelationId()});
std::vector<Element> elementList;
Element element;
element.insert(CCAPI_EM_ORDER_LAST_EXECUTED_PRICE, x["price"].GetString());
element.insert(CCAPI_EM_ORDER_LAST_EXECUTED_SIZE, x["qty"].GetString());
element.insert(CCAPI_EM_ORDER_SIDE, x["buy"].GetBool() ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL);
element.insert(CCAPI_EM_ORDER_ID, std::string(x["order_id"].GetString()));
element.insert(CCAPI_EM_CLIENT_ORDER_ID, std::string(x["cli_ord_id"].GetString()));
element.insert(CCAPI_IS_MAKER, std::string(x["fill_type"].GetString()) == "maker" ? "1" : "0");
element.insert(CCAPI_EM_ORDER_INSTRUMENT, instrument);
element.insert(CCAPI_EM_ORDER_FEE_QUANTITY, std::string(x["fee_paid"].GetString()));
element.insert(CCAPI_EM_ORDER_FEE_ASSET, std::string(x["fee_currency"].GetString()));
element.insert(CCAPI_EM_ORDER_QUANTITY, x["qty"].GetString());
element.insert(CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, x["filled"].GetString());
element.insert(CCAPI_EM_ORDER_LIMIT_PRICE, x["limit_price"].GetString());
element.insert(CCAPI_EM_ORDER_ID, x["order_id"].GetString());
element.insert(CCAPI_EM_ORDER_SIDE, std::string(x["direction"].GetString()) == "0" ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL);
element.insert("is_cancel", document["is_cancel"].GetBool() ? "1" : "0");
elementList.emplace_back(std::move(element));
message.setElementList(elementList);
messageList.emplace_back(std::move(message));
}
}
} else if (field == CCAPI_EM_ORDER_UPDATE) {
const rj::Value& x = document["order"];
std::string instrument = x["instrument"].GetString();
if (instrumentSet.empty() || instrumentSet.find(instrument) != instrumentSet.end()) {
Message message;
message.setType(Message::Type::EXECUTION_MANAGEMENT_EVENTS_ORDER_UPDATE);
message.setTime(UtilTime::makeTimePointFromMilliseconds(std::stoll(x["last_update_time"].GetString())));
message.setTimeReceived(timeReceived);
message.setCorrelationIdList({subscription.getCorrelationId()});
std::vector<Element> elementList;
Element element;
element.insert(CCAPI_EM_ORDER_INSTRUMENT, instrument);
element.insert(CCAPI_EM_ORDER_QUANTITY, x["qty"].GetString());
element.insert(CCAPI_EM_ORDER_CUMULATIVE_FILLED_QUANTITY, x["filled"].GetString());
element.insert(CCAPI_EM_ORDER_LIMIT_PRICE, x["limit_price"].GetString());
element.insert(CCAPI_EM_ORDER_ID, x["order_id"].GetString());
element.insert(CCAPI_EM_ORDER_SIDE, std::string(x["direction"].GetString()) == "0" ? CCAPI_EM_ORDER_SIDE_BUY : CCAPI_EM_ORDER_SIDE_SELL);
element.insert("is_cancel", document["is_cancel"].GetBool() ? "1" : "0");
elementList.emplace_back(std::move(element));
message.setElementList(elementList);
messageList.emplace_back(std::move(message));
}
}
}
}
Expand All @@ -353,25 +355,39 @@ class ExecutionManagementServiceKrakenFutures : public ExecutionManagementServic
auto signature = UtilAlgorithm::base64Encode(Hmac::hmac(Hmac::ShaVersion::SHA512, UtilAlgorithm::base64Decode(apiSecret), challengeToSignSha256));
std::vector<std::string> sendStringList;
for (const auto& field : subscription.getFieldSet()) {
std::string feed;
if (field == CCAPI_EM_PRIVATE_TRADE) {
feed = "fills";
} else if (field == CCAPI_EM_ORDER_UPDATE) {
feed = "open_orders";
{
std::string feed;
if (field == CCAPI_EM_PRIVATE_TRADE) {
feed = "fills";
} else if (field == CCAPI_EM_ORDER_UPDATE) {
feed = "open_orders";
}
rj::Document document;
document.SetObject();
auto& allocator = document.GetAllocator();
document.AddMember("event", rj::Value("subscribe").Move(), allocator);
document.AddMember("feed", rj::Value(feed.c_str(), allocator).Move(), allocator);
document.AddMember("api_key", rj::Value(apiKey.c_str(), allocator).Move(), allocator);
document.AddMember("original_challenge", rj::Value(challengeToSign.c_str(), allocator).Move(), allocator);
document.AddMember("signed_challenge", rj::Value(signature.c_str(), allocator).Move(), allocator);
rj::StringBuffer stringBuffer;
rj::Writer<rj::StringBuffer> writer(stringBuffer);
document.Accept(writer);
std::string sendString = stringBuffer.GetString();
sendStringList.push_back(sendString);
}
{
rj::Document document;
document.SetObject();
auto& allocator = document.GetAllocator();
document.AddMember("event", rj::Value("subscribe").Move(), allocator);
document.AddMember("feed", rj::Value("heartbeat").Move(), allocator);
rj::StringBuffer stringBuffer;
rj::Writer<rj::StringBuffer> writer(stringBuffer);
document.Accept(writer);
std::string sendString = stringBuffer.GetString();
sendStringList.push_back(sendString);
}
rj::Document document;
document.SetObject();
auto& allocator = document.GetAllocator();
document.AddMember("event", rj::Value("subscribe").Move(), allocator);
document.AddMember("feed", rj::Value(feed.c_str(), allocator).Move(), allocator);
document.AddMember("api_key", rj::Value(apiKey.c_str(), allocator).Move(), allocator);
document.AddMember("original_challenge", rj::Value(challengeToSign.c_str(), allocator).Move(), allocator);
document.AddMember("signed_challenge", rj::Value(signature.c_str(), allocator).Move(), allocator);
rj::StringBuffer stringBuffer;
rj::Writer<rj::StringBuffer> writer(stringBuffer);
document.Accept(writer);
std::string sendString = stringBuffer.GetString();
sendStringList.push_back(sendString);
}
for (const auto& sendString : sendStringList) {
ErrorCode ec;
Expand Down
Loading

0 comments on commit dd59edf

Please sign in to comment.