Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions include/ccapi_cpp/ccapi_util_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -958,7 +958,7 @@ class Decimal {
}
}

explicit Decimal(std::string_view originalValue) {
explicit Decimal(std::string_view originalValue, bool checksumEnabled=false) {
if (originalValue.empty()) {
throw std::invalid_argument("Decimal constructor input value cannot be empty");
}
Expand All @@ -972,7 +972,7 @@ class Decimal {
}
std::string fixedPointValue = std::string(originalValue.substr(this->sign ? 0 : 1, this->sign ? foundE : foundE - 1));
auto foundDot = fixedPointValue.find('.');
if (foundDot != std::string::npos) {
if (foundDot != std::string::npos and not checksumEnabled) {
fixedPointValue.erase(fixedPointValue.find_last_not_of('0') + 1);
fixedPointValue.erase(fixedPointValue.find_last_not_of('.') + 1);
}
Expand Down Expand Up @@ -1017,9 +1017,9 @@ class Decimal {
}
if (foundDot != std::string::npos) {
this->frac = fixedPointValue.substr(foundDot + 1);
// if (!keepTrailingZero) {
this->frac.erase(this->frac.find_last_not_of('0') + 1);
// }
if (!checksumEnabled) {
this->frac.erase(this->frac.find_last_not_of('0') + 1);
}
}
} else {
auto found = originalValue.find('.');
Expand All @@ -1033,9 +1033,9 @@ class Decimal {
}
if (found != std::string::npos) {
this->frac = originalValue.substr(found + 1);
// if (!keepTrailingZero) {
this->frac.erase(this->frac.find_last_not_of('0') + 1);
// }
if (not checksumEnabled) {
this->frac.erase(this->frac.find_last_not_of('0') + 1);
}
}
}

Expand Down
23 changes: 12 additions & 11 deletions include/ccapi_cpp/service/ccapi_market_data_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -804,15 +804,15 @@ class MarketDataService : public Service {
for (auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
snapshotBid.emplace(decimalPrice, std::string(size));
}
CCAPI_LOGGER_TRACE("lastNToString(snapshotBid, " + toString(maxMarketDepth) + ") = " + lastNToString(snapshotBid, maxMarketDepth));
} else if (type == MarketDataMessage::DataType::ASK) {
for (auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
snapshotAsk.emplace(decimalPrice, std::string(size));
}
CCAPI_LOGGER_TRACE("firstNToString(snapshotAsk, " + toString(maxMarketDepth) + ") = " + firstNToString(snapshotAsk, maxMarketDepth));
Expand Down Expand Up @@ -894,14 +894,14 @@ class MarketDataService : public Service {
for (auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
this->updateOrderBook(snapshotBid, decimalPrice, size, this->sessionOptions.enableCheckOrderBookChecksum);
}
} else if (type == MarketDataMessage::DataType::ASK) {
for (auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
this->updateOrderBook(snapshotAsk, decimalPrice, size, this->sessionOptions.enableCheckOrderBookChecksum);
}
} else {
Expand Down Expand Up @@ -1098,7 +1098,7 @@ class MarketDataService : public Service {
this->highByConnectionIdChannelIdSymbolIdMap[wsConnectionPtr->id][channelId][symbolId] = Decimal(price);
this->lowByConnectionIdChannelIdSymbolIdMap[wsConnectionPtr->id][channelId][symbolId] = Decimal(price);
} else {
Decimal decimalPrice(price);
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
if (decimalPrice > this->highByConnectionIdChannelIdSymbolIdMap[wsConnectionPtr->id][channelId][symbolId]) {
this->highByConnectionIdChannelIdSymbolIdMap[wsConnectionPtr->id][channelId][symbolId] = decimalPrice;
}
Expand Down Expand Up @@ -1372,15 +1372,15 @@ class MarketDataService : public Service {
for (auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
snapshotBid.emplace(decimalPrice, std::string(size));
}
CCAPI_LOGGER_TRACE("lastNToString(snapshotBid, " + toString(maxMarketDepth) + ") = " + lastNToString(snapshotBid, maxMarketDepth));
} else if (type == MarketDataMessage::DataType::ASK) {
for (auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
snapshotAsk.emplace(decimalPrice, std::string(size));
}
CCAPI_LOGGER_TRACE("firstNToString(snapshotAsk, " + toString(maxMarketDepth) + ") = " + firstNToString(snapshotAsk, maxMarketDepth));
Expand Down Expand Up @@ -1520,14 +1520,14 @@ class MarketDataService : public Service {
for (const auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, that->sessionOptions.enableCheckOrderBookChecksum);
snapshotBid.emplace(decimalPrice, std::string(size));
}
} else if (type == MarketDataMessage::DataType::ASK) {
for (const auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, that->sessionOptions.enableCheckOrderBookChecksum);
snapshotAsk.emplace(decimalPrice, std::string(size));
}
}
Expand All @@ -1548,14 +1548,14 @@ class MarketDataService : public Service {
for (const auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, that->sessionOptions.enableCheckOrderBookChecksum);
that->updateOrderBook(snapshotBid, decimalPrice, size, that->sessionOptions.enableCheckOrderBookChecksum);
}
} else if (type == MarketDataMessage::DataType::ASK) {
for (const auto& y : detail) {
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
Decimal decimalPrice(price);
Decimal decimalPrice(price, that->sessionOptions.enableCheckOrderBookChecksum);
that->updateOrderBook(snapshotAsk, decimalPrice, size, that->sessionOptions.enableCheckOrderBookChecksum);
}
}
Expand Down Expand Up @@ -1671,6 +1671,7 @@ class MarketDataService : public Service {
Event& event, std::vector<MarketDataMessage>& marketDataMessageList) {}

virtual std::string calculateOrderBookChecksum(const std::map<Decimal, std::string>& snapshotBid, const std::map<Decimal, std::string>& snapshotAsk) {
CCAPI_LOGGER_DEBUG("calculateOrderBookChecksum is not implemented for this exchange");
return {};
}

Expand Down
72 changes: 60 additions & 12 deletions include/ccapi_cpp/service/ccapi_market_data_service_kraken.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,47 @@ class MarketDataServiceKraken : public MarketDataService {
}
}

static void processForChecksum(std::string& str) {
str.erase(std::remove(str.begin(), str.end(), '.'), str.end());
UtilString::ltrimInPlace(str, "0");
}

std::vector<std::string> extractTop(const std::map<Decimal, std::string>& snapshot, bool reverse = false) {
std::vector<std::string> result;
int count = 0;

auto process_item = [&](auto it) {
std::string price = toString(it->first);
processForChecksum(price);
result.push_back(std::move(price));

std::string volume = it->second;
processForChecksum(volume);
result.push_back(std::move(volume));
};

if (reverse) {
for (auto it = snapshot.rbegin(); it != snapshot.rend() && count < 10; ++it, ++count) {
process_item(it);
}
} else {
for (auto it = snapshot.begin(); it != snapshot.end() && count < 10; ++it, ++count) {
process_item(it);
}
}
return result;
};

std::string calculateOrderBookChecksum(const std::map<Decimal, std::string>& snapshotBid, const std::map<Decimal, std::string>& snapshotAsk) override {
auto csAskData = extractTop(snapshotAsk);
auto csBidData = extractTop(snapshotBid, true);

std::string csStr = UtilString::join(csAskData, "") + UtilString::join(csBidData, "");
uint_fast32_t csCalc = UtilAlgorithm::crc(csStr.begin(), csStr.end());
CCAPI_LOGGER_DEBUG("csStr: " + csStr + ", csCalc: " + intToHex(csCalc));
return intToHex(csCalc);
}

std::vector<std::string> createSendStringList(std::shared_ptr<WsConnection> wsConnectionPtr) override {
std::vector<std::string> sendStringList;
for (const auto& subscriptionListByChannelIdSymbolId : this->subscriptionListByConnectionIdChannelIdSymbolIdMap.at(wsConnectionPtr->id)) {
Expand Down Expand Up @@ -186,19 +227,26 @@ class MarketDataServiceKraken : public MarketDataService {
marketDataMessage.exchangeSubscriptionId = exchangeSubscriptionId;
marketDataMessage.tp = latestTp;
marketDataMessage.recapType = MarketDataMessage::RecapType::NONE;
if (this->sessionOptions.enableCheckOrderBookChecksum) {
if (anonymous2.HasMember("c")) {
CCAPI_LOGGER_DEBUG("Checksum for " + symbolId + ": " + anonymous2["c"].GetString());
this->orderBookChecksumByConnectionIdSymbolIdMap[wsConnectionPtr->id][symbolId] =
intToHex(static_cast<uint_fast32_t>(static_cast<uint32_t>(std::stoul(anonymous2["c"].GetString()))));
}
}
if (anonymous2.HasMember("b")) {
for (const auto& x : anonymous2["b"].GetArray()) {
MarketDataMessage::TypeForDataPoint dataPoint;
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint));
}
}
if (anonymous2.HasMember("a")) {
for (const auto& x : anonymous2["a"].GetArray()) {
MarketDataMessage::TypeForDataPoint dataPoint;
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint));
}
}
Expand All @@ -211,14 +259,14 @@ class MarketDataServiceKraken : public MarketDataService {
marketDataMessage.tp = timeReceived;
for (const auto& x : anonymous["bs"].GetArray()) {
MarketDataMessage::TypeForDataPoint dataPoint;
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint));
}
for (const auto& x : anonymous["as"].GetArray()) {
MarketDataMessage::TypeForDataPoint dataPoint;
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint));
}
marketDataMessageList.emplace_back(std::move(marketDataMessage));
Expand All @@ -235,8 +283,8 @@ class MarketDataServiceKraken : public MarketDataService {
tp += std::chrono::nanoseconds(timePair.second);
marketDataMessage.tp = tp;
MarketDataMessage::TypeForDataPoint dataPoint;
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
dataPoint.emplace(MarketDataMessage::DataFieldType::IS_BUYER_MAKER, std::string_view(x[3].GetString()) == "s" ? "1" : "0");
marketDataMessage.data[MarketDataMessage::DataType::TRADE].emplace_back(std::move(dataPoint));
marketDataMessageList.emplace_back(std::move(marketDataMessage));
Expand Down Expand Up @@ -372,8 +420,8 @@ class MarketDataServiceKraken : public MarketDataService {
tp += std::chrono::nanoseconds(timePair.second);
marketDataMessage.tp = tp;
MarketDataMessage::TypeForDataPoint dataPoint;
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
dataPoint.emplace(MarketDataMessage::DataFieldType::IS_BUYER_MAKER, std::string_view(x[3].GetString()) == "s" ? "1" : "0");
marketDataMessage.data[MarketDataMessage::DataType::TRADE].emplace_back(std::move(dataPoint));
marketDataMessageList.emplace_back(std::move(marketDataMessage));
Expand Down
Loading