Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ if(BUILD_TESTS)
tests/test_order_book.cpp
tests/test_decimal.cpp
tests/test_safe_arithmetic.cpp
tests/test_binance_utils.cpp
tests/test_prometheus_format.cpp
src/order_book.cpp
)

Expand Down
51 changes: 33 additions & 18 deletions grafana/dashboards/lob.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,27 @@
"annotations": { "list": [] },
"templating": {
"list": [
{
"name": "exchange",
"label": "Exchange",
"type": "query",
"datasource": { "type": "prometheus", "uid": "prometheus" },
"query": "label_values(lob_messages_total, exchange)",
"refresh": 1,
"multi": false,
"includeAll": true,
"allValue": ".*",
"sort": 1,
"hide": 0,
"options": [],
"current": {}
},
{
"name": "symbol",
"label": "Symbol",
"type": "query",
"datasource": { "type": "prometheus", "uid": "prometheus" },
"query": "label_values(lob_messages_total, symbol)",
"query": "label_values(lob_messages_total{exchange=~\"$exchange\"}, symbol)",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"refresh": 1,
"multi": false,
"includeAll": false,
Expand All @@ -45,7 +60,7 @@
"refId": "A"
},
{
"expr": "rate(lob_messages_total{symbol=\"$symbol\"}[1m])",
"expr": "rate(lob_messages_total{exchange=~\"$exchange\",symbol=\"$symbol\"}[1m])",
"legendFormat": "{{symbol}} msg/s",
"refId": "B"
}
Expand All @@ -66,19 +81,19 @@
{
"id": 2,
"title": "Event Lag",
"description": "Worst-case lag across all symbols, with selected symbol overlaid for comparison",
"description": "Worst-case lag per exchange, with selected symbol overlaid for comparison",
"type": "timeseries",
"gridPos": { "x": 12, "y": 0, "w": 12, "h": 8 },
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{
"expr": "max(lob_event_lag_milliseconds)",
"legendFormat": "worst lag ms (all)",
"expr": "max by(exchange) (lob_event_lag_milliseconds)",
"legendFormat": "{{exchange}} worst lag ms",
"refId": "A"
},
{
"expr": "lob_event_lag_milliseconds{symbol=\"$symbol\"}",
"legendFormat": "{{symbol}} lag ms",
"expr": "lob_event_lag_milliseconds{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "{{exchange}} {{symbol}} lag ms",
"refId": "B"
}
],
Expand Down Expand Up @@ -122,7 +137,7 @@
"refId": "B"
},
{
"expr": "lob_processing_time_microseconds{symbol=\"$symbol\"}",
"expr": "lob_processing_time_microseconds{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "{{symbol}} µs",
"refId": "C"
}
Expand Down Expand Up @@ -157,12 +172,12 @@
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{
"expr": "lob_orderbook_best_ask_price{symbol=\"$symbol\"}",
"expr": "lob_orderbook_best_ask_price{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "Best Ask",
"refId": "A"
},
{
"expr": "lob_orderbook_best_bid_price{symbol=\"$symbol\"}",
"expr": "lob_orderbook_best_bid_price{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "Best Bid",
"refId": "B"
}
Expand Down Expand Up @@ -190,7 +205,7 @@
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{
"expr": "lob_orderbook_spread_price{symbol=\"$symbol\"}",
"expr": "lob_orderbook_spread_price{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "spread USD",
"refId": "A"
}
Expand Down Expand Up @@ -218,12 +233,12 @@
"datasource": { "type": "prometheus", "uid": "prometheus" },
"targets": [
{
"expr": "lob_orderbook_asks_count{symbol=\"$symbol\"}",
"expr": "lob_orderbook_asks_count{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "Asks",
"refId": "A"
},
{
"expr": "lob_orderbook_bids_count{symbol=\"$symbol\"}",
"expr": "lob_orderbook_bids_count{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "Bids",
"refId": "B"
}
Expand Down Expand Up @@ -255,8 +270,8 @@
"refId": "A"
},
{
"expr": "max(lob_event_lag_milliseconds)",
"legendFormat": "Worst Lag (ms)",
"expr": "max by(exchange) (lob_event_lag_milliseconds)",
"legendFormat": "Event Lag (ms)",
"refId": "B"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
{
Expand All @@ -265,17 +280,17 @@
"refId": "C"
},
{
"expr": "lob_orderbook_best_ask_price{symbol=\"$symbol\"}",
"expr": "lob_orderbook_best_ask_price{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "Best Ask",
"refId": "D"
},
{
"expr": "lob_orderbook_best_bid_price{symbol=\"$symbol\"}",
"expr": "lob_orderbook_best_bid_price{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "Best Bid",
"refId": "E"
},
{
"expr": "lob_orderbook_spread_price{symbol=\"$symbol\"}",
"expr": "lob_orderbook_spread_price{exchange=~\"$exchange\",symbol=\"$symbol\"}",
"legendFormat": "Spread",
"refId": "F"
}
Expand Down
29 changes: 29 additions & 0 deletions src/binance_utils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once
#include <algorithm>
#include <cctype>
#include <string>

// Extracts the symbol from a Binance combined-stream name and uppercases it.
//
// Binance stream names look like:
// "btcusdt@depth" (basic depth stream)
// "ethusdt@depth@100ms" (depth stream with interval suffix)
//
// Returns everything before the first '@', uppercased, which is the key
/**
* Extracts the symbol portion from a Binance combined-stream name and returns it uppercased.
*
* The function takes the substring before the first '@' in `stream` and converts it to uppercase.
* If `stream` contains no '@', the entire input is uppercased. If `stream` is empty, an empty
* string is returned.
*
* @param stream Combined-stream name (e.g., "btcusdt@depth" or "ethusdt@aggTrade").
* @return Uppercased symbol extracted from before the first '@' (or the entire uppercased input if
* no '@').
*/
inline std::string streamToSymbol(const std::string& stream) {
std::string sym = stream.substr(0, stream.find('@'));
std::transform(sym.begin(), sym.end(), sym.begin(),
[](unsigned char c) { return ::toupper(c); });
return sym;
}
Loading