Skip to content

Commit 7dec893

Browse files
committed
Implement order book checksum in kraken
1 parent db68d00 commit 7dec893

File tree

3 files changed

+69
-31
lines changed

3 files changed

+69
-31
lines changed

include/ccapi_cpp/ccapi_util_private.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ class Decimal {
958958
}
959959
}
960960

961-
explicit Decimal(std::string_view originalValue) {
961+
explicit Decimal(std::string_view originalValue, bool checksumEnabled=false) {
962962
if (originalValue.empty()) {
963963
throw std::invalid_argument("Decimal constructor input value cannot be empty");
964964
}
@@ -972,7 +972,7 @@ class Decimal {
972972
}
973973
std::string fixedPointValue = std::string(originalValue.substr(this->sign ? 0 : 1, this->sign ? foundE : foundE - 1));
974974
auto foundDot = fixedPointValue.find('.');
975-
if (foundDot != std::string::npos) {
975+
if (foundDot != std::string::npos and not checksumEnabled) {
976976
fixedPointValue.erase(fixedPointValue.find_last_not_of('0') + 1);
977977
fixedPointValue.erase(fixedPointValue.find_last_not_of('.') + 1);
978978
}
@@ -1017,9 +1017,9 @@ class Decimal {
10171017
}
10181018
if (foundDot != std::string::npos) {
10191019
this->frac = fixedPointValue.substr(foundDot + 1);
1020-
// if (!keepTrailingZero) {
1021-
this->frac.erase(this->frac.find_last_not_of('0') + 1);
1022-
// }
1020+
if (!checksumEnabled) {
1021+
this->frac.erase(this->frac.find_last_not_of('0') + 1);
1022+
}
10231023
}
10241024
} else {
10251025
auto found = originalValue.find('.');
@@ -1033,9 +1033,9 @@ class Decimal {
10331033
}
10341034
if (found != std::string::npos) {
10351035
this->frac = originalValue.substr(found + 1);
1036-
// if (!keepTrailingZero) {
1037-
this->frac.erase(this->frac.find_last_not_of('0') + 1);
1038-
// }
1036+
if (not checksumEnabled) {
1037+
this->frac.erase(this->frac.find_last_not_of('0') + 1);
1038+
}
10391039
}
10401040
}
10411041

include/ccapi_cpp/service/ccapi_market_data_service.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -804,15 +804,15 @@ class MarketDataService : public Service {
804804
for (auto& y : detail) {
805805
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
806806
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
807-
Decimal decimalPrice(price);
807+
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
808808
snapshotBid.emplace(decimalPrice, std::string(size));
809809
}
810810
CCAPI_LOGGER_TRACE("lastNToString(snapshotBid, " + toString(maxMarketDepth) + ") = " + lastNToString(snapshotBid, maxMarketDepth));
811811
} else if (type == MarketDataMessage::DataType::ASK) {
812812
for (auto& y : detail) {
813813
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
814814
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
815-
Decimal decimalPrice(price);
815+
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
816816
snapshotAsk.emplace(decimalPrice, std::string(size));
817817
}
818818
CCAPI_LOGGER_TRACE("firstNToString(snapshotAsk, " + toString(maxMarketDepth) + ") = " + firstNToString(snapshotAsk, maxMarketDepth));
@@ -894,14 +894,14 @@ class MarketDataService : public Service {
894894
for (auto& y : detail) {
895895
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
896896
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
897-
Decimal decimalPrice(price);
897+
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
898898
this->updateOrderBook(snapshotBid, decimalPrice, size, this->sessionOptions.enableCheckOrderBookChecksum);
899899
}
900900
} else if (type == MarketDataMessage::DataType::ASK) {
901901
for (auto& y : detail) {
902902
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
903903
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
904-
Decimal decimalPrice(price);
904+
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
905905
this->updateOrderBook(snapshotAsk, decimalPrice, size, this->sessionOptions.enableCheckOrderBookChecksum);
906906
}
907907
} else {
@@ -1098,7 +1098,7 @@ class MarketDataService : public Service {
10981098
this->highByConnectionIdChannelIdSymbolIdMap[wsConnectionPtr->id][channelId][symbolId] = Decimal(price);
10991099
this->lowByConnectionIdChannelIdSymbolIdMap[wsConnectionPtr->id][channelId][symbolId] = Decimal(price);
11001100
} else {
1101-
Decimal decimalPrice(price);
1101+
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
11021102
if (decimalPrice > this->highByConnectionIdChannelIdSymbolIdMap[wsConnectionPtr->id][channelId][symbolId]) {
11031103
this->highByConnectionIdChannelIdSymbolIdMap[wsConnectionPtr->id][channelId][symbolId] = decimalPrice;
11041104
}
@@ -1372,15 +1372,15 @@ class MarketDataService : public Service {
13721372
for (auto& y : detail) {
13731373
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
13741374
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
1375-
Decimal decimalPrice(price);
1375+
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
13761376
snapshotBid.emplace(decimalPrice, std::string(size));
13771377
}
13781378
CCAPI_LOGGER_TRACE("lastNToString(snapshotBid, " + toString(maxMarketDepth) + ") = " + lastNToString(snapshotBid, maxMarketDepth));
13791379
} else if (type == MarketDataMessage::DataType::ASK) {
13801380
for (auto& y : detail) {
13811381
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
13821382
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
1383-
Decimal decimalPrice(price);
1383+
Decimal decimalPrice(price, this->sessionOptions.enableCheckOrderBookChecksum);
13841384
snapshotAsk.emplace(decimalPrice, std::string(size));
13851385
}
13861386
CCAPI_LOGGER_TRACE("firstNToString(snapshotAsk, " + toString(maxMarketDepth) + ") = " + firstNToString(snapshotAsk, maxMarketDepth));
@@ -1520,14 +1520,14 @@ class MarketDataService : public Service {
15201520
for (const auto& y : detail) {
15211521
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
15221522
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
1523-
Decimal decimalPrice(price);
1523+
Decimal decimalPrice(price, that->sessionOptions.enableCheckOrderBookChecksum);
15241524
snapshotBid.emplace(decimalPrice, std::string(size));
15251525
}
15261526
} else if (type == MarketDataMessage::DataType::ASK) {
15271527
for (const auto& y : detail) {
15281528
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
15291529
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
1530-
Decimal decimalPrice(price);
1530+
Decimal decimalPrice(price, that->sessionOptions.enableCheckOrderBookChecksum);
15311531
snapshotAsk.emplace(decimalPrice, std::string(size));
15321532
}
15331533
}
@@ -1548,14 +1548,14 @@ class MarketDataService : public Service {
15481548
for (const auto& y : detail) {
15491549
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
15501550
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
1551-
Decimal decimalPrice(price);
1551+
Decimal decimalPrice(price, that->sessionOptions.enableCheckOrderBookChecksum);
15521552
that->updateOrderBook(snapshotBid, decimalPrice, size, that->sessionOptions.enableCheckOrderBookChecksum);
15531553
}
15541554
} else if (type == MarketDataMessage::DataType::ASK) {
15551555
for (const auto& y : detail) {
15561556
const auto& price = y.at(MarketDataMessage::DataFieldType::PRICE);
15571557
const auto& size = y.at(MarketDataMessage::DataFieldType::SIZE);
1558-
Decimal decimalPrice(price);
1558+
Decimal decimalPrice(price, that->sessionOptions.enableCheckOrderBookChecksum);
15591559
that->updateOrderBook(snapshotAsk, decimalPrice, size, that->sessionOptions.enableCheckOrderBookChecksum);
15601560
}
15611561
}
@@ -1671,6 +1671,7 @@ class MarketDataService : public Service {
16711671
Event& event, std::vector<MarketDataMessage>& marketDataMessageList) {}
16721672

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

include/ccapi_cpp/service/ccapi_market_data_service_kraken.h

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,36 @@ class MarketDataServiceKraken : public MarketDataService {
5050
}
5151
}
5252

53+
static void processForChecksum(std::string& str) {
54+
str.erase(std::remove(str.begin(), str.end(), '.'), str.end());
55+
UtilString::ltrimInPlace(str, "0");
56+
}
57+
58+
std::vector<std::string> extractTop (auto beginIt, auto endIt) {
59+
std::vector<std::string> result;
60+
int count = 0;
61+
for (auto it = beginIt; it != endIt && count < 10; ++it, ++count) {
62+
std::string price = toString(it->first);
63+
processForChecksum(price);
64+
result.push_back(std::move(price));
65+
66+
std::string volume = it->second;
67+
processForChecksum(volume);
68+
result.push_back(std::move(volume));
69+
}
70+
return result;
71+
};
72+
73+
std::string calculateOrderBookChecksum(const std::map<Decimal, std::string>& snapshotBid, const std::map<Decimal, std::string>& snapshotAsk) override {
74+
auto csAskData = extractTop(snapshotAsk.begin(), snapshotAsk.end());
75+
auto csBidData = extractTop(snapshotBid.rbegin(), snapshotBid.rend());
76+
77+
std::string csStr = UtilString::join(csAskData, "") + UtilString::join(csBidData, "");
78+
uint_fast32_t csCalc = UtilAlgorithm::crc(csStr.begin(), csStr.end());
79+
CCAPI_LOGGER_DEBUG("csStr: " + csStr + ", csCalc: " + intToHex(csCalc));
80+
return intToHex(csCalc);
81+
}
82+
5383
std::vector<std::string> createSendStringList(std::shared_ptr<WsConnection> wsConnectionPtr) override {
5484
std::vector<std::string> sendStringList;
5585
for (const auto& subscriptionListByChannelIdSymbolId : this->subscriptionListByConnectionIdChannelIdSymbolIdMap.at(wsConnectionPtr->id)) {
@@ -186,19 +216,26 @@ class MarketDataServiceKraken : public MarketDataService {
186216
marketDataMessage.exchangeSubscriptionId = exchangeSubscriptionId;
187217
marketDataMessage.tp = latestTp;
188218
marketDataMessage.recapType = MarketDataMessage::RecapType::NONE;
219+
if (this->sessionOptions.enableCheckOrderBookChecksum) {
220+
if (anonymous2.HasMember("c")) {
221+
CCAPI_LOGGER_DEBUG("Checksum for " + symbolId + ": " + anonymous2["c"].GetString());
222+
this->orderBookChecksumByConnectionIdSymbolIdMap[wsConnectionPtr->id][symbolId] =
223+
intToHex(static_cast<uint_fast32_t>(static_cast<uint32_t>(std::stoul(anonymous2["c"].GetString()))));
224+
}
225+
}
189226
if (anonymous2.HasMember("b")) {
190227
for (const auto& x : anonymous2["b"].GetArray()) {
191228
MarketDataMessage::TypeForDataPoint dataPoint;
192-
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
193-
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
229+
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
230+
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
194231
marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint));
195232
}
196233
}
197234
if (anonymous2.HasMember("a")) {
198235
for (const auto& x : anonymous2["a"].GetArray()) {
199236
MarketDataMessage::TypeForDataPoint dataPoint;
200-
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
201-
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
237+
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
238+
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
202239
marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint));
203240
}
204241
}
@@ -211,14 +248,14 @@ class MarketDataServiceKraken : public MarketDataService {
211248
marketDataMessage.tp = timeReceived;
212249
for (const auto& x : anonymous["bs"].GetArray()) {
213250
MarketDataMessage::TypeForDataPoint dataPoint;
214-
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
215-
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
251+
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
252+
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
216253
marketDataMessage.data[MarketDataMessage::DataType::BID].emplace_back(std::move(dataPoint));
217254
}
218255
for (const auto& x : anonymous["as"].GetArray()) {
219256
MarketDataMessage::TypeForDataPoint dataPoint;
220-
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
221-
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
257+
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
258+
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
222259
marketDataMessage.data[MarketDataMessage::DataType::ASK].emplace_back(std::move(dataPoint));
223260
}
224261
marketDataMessageList.emplace_back(std::move(marketDataMessage));
@@ -235,8 +272,8 @@ class MarketDataServiceKraken : public MarketDataService {
235272
tp += std::chrono::nanoseconds(timePair.second);
236273
marketDataMessage.tp = tp;
237274
MarketDataMessage::TypeForDataPoint dataPoint;
238-
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
239-
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
275+
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
276+
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
240277
dataPoint.emplace(MarketDataMessage::DataFieldType::IS_BUYER_MAKER, std::string_view(x[3].GetString()) == "s" ? "1" : "0");
241278
marketDataMessage.data[MarketDataMessage::DataType::TRADE].emplace_back(std::move(dataPoint));
242279
marketDataMessageList.emplace_back(std::move(marketDataMessage));
@@ -372,8 +409,8 @@ class MarketDataServiceKraken : public MarketDataService {
372409
tp += std::chrono::nanoseconds(timePair.second);
373410
marketDataMessage.tp = tp;
374411
MarketDataMessage::TypeForDataPoint dataPoint;
375-
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, UtilString::normalizeDecimalStringView(x[0].GetString()));
376-
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, UtilString::normalizeDecimalStringView(x[1].GetString()));
412+
dataPoint.emplace(MarketDataMessage::DataFieldType::PRICE, x[0].GetString());
413+
dataPoint.emplace(MarketDataMessage::DataFieldType::SIZE, x[1].GetString());
377414
dataPoint.emplace(MarketDataMessage::DataFieldType::IS_BUYER_MAKER, std::string_view(x[3].GetString()) == "s" ? "1" : "0");
378415
marketDataMessage.data[MarketDataMessage::DataType::TRADE].emplace_back(std::move(dataPoint));
379416
marketDataMessageList.emplace_back(std::move(marketDataMessage));

0 commit comments

Comments
 (0)