Skip to content

Add Kraken exchange adapter and refactor multi-exchange architecture#28

Merged
bountx merged 5 commits into
mainfrom
feat/kraken-exchange
Mar 9, 2026
Merged

Add Kraken exchange adapter and refactor multi-exchange architecture#28
bountx merged 5 commits into
mainfrom
feat/kraken-exchange

Conversation

@bountx
Copy link
Copy Markdown
Owner

@bountx bountx commented Mar 9, 2026

Summary by CodeRabbit

  • New Features

    • Multi-exchange mode: run Binance and Kraken concurrently with independent per-exchange symbol sets, adapters, and metrics views.
    • Metrics endpoint now aggregates and exposes per-exchange metrics.
  • Improvements

    • Per-exchange configuration and validation with clearer startup logging and per-exchange update intervals.
    • Subscriber addressing now uses exchange-qualified stream keys for precise subscriptions.
  • Bug Fixes

    • More robust subscription and snapshot handling with early error detection and clean shutdown on failures.

Andrzej Pijanowski and others added 3 commits March 8, 2026 23:01
- Added KrakenAdapter class to handle WebSocket connections and order book updates from Kraken.
- Introduced kraken_utils.hpp for utility functions related to Kraken data processing.
- Created SymbolNormalizer class to manage symbol mappings between exchange-specific formats and canonical formats.
- Updated feed_handler.hpp to include SymbolNormalizer for symbol conversion.
- Enhanced OrderBook class with applyDelta method for processing incremental updates.
- Added tests for Kraken utilities and symbol normalization to ensure correctness.
- Updated main.cpp to support selecting between Binance and Kraken exchanges based on configuration.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Added BinanceAdapter class to handle WebSocket connections and order book updates from Binance.
- Integrated SymbolNormalizer for symbol mapping between Binance and canonical formats.
- Updated main application logic to support multiple exchanges (Binance and Kraken) with dynamic configuration.
- Enhanced MetricsServer to serve metrics for multiple exchanges.
- Refactored SubscriberServer to handle order books keyed by exchange and symbol.
- Improved error handling and validation for configuration inputs.
- Added unit tests for Kraken utility functions.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f6408646-1618-423c-87bb-245753424e21

📥 Commits

Reviewing files that changed from the base of the PR and between 3eb3167 and a334081.

📒 Files selected for processing (6)
  • src/kraken_adapter.cpp
  • src/kraken_adapter.hpp
  • src/main.cpp
  • src/metrics_server.hpp
  • src/prometheus_format.hpp
  • tests/test_kraken_utils.cpp
✅ Files skipped from review due to trivial changes (1)
  • tests/test_kraken_utils.cpp

📝 Walkthrough

Walkthrough

Refactors single-exchange architecture to support multiple exchanges: replaces feed_handler with exchange-specific adapters (Binance, Kraken), introduces per-exchange runtimes, updates subscription/metrics servers to use composite exchange.symbol keys, and adjusts related utilities and build stubs. (49 words)

Changes

Cohort / File(s) Summary
Build Configuration
CMakeLists.txt, Dockerfile
Replaced src/feed_handler.cpp with src/binance_adapter.cpp in the build target; Docker builder now touches src/binance_adapter.cpp and src/kraken_adapter.cpp in addition to existing stubs.
Application Core
src/main.cpp
Added multi-exchange orchestration: ExchangeRuntime struct, per-exchange OrderBook/Metrics maps, per-exchange adapter instantiation and lifecycle, per-exchange config parsing, and runtime loops updated to iterate exchanges and symbols.
Binance Adapter
src/binance_adapter.hpp, src/binance_adapter.cpp
Renamed/updated adapter files; changed fetchAndApplySnapshot signature to accept binanceSym and canonical; added SymbolNormalizer and binanceToCanonical_ members; minor formatting adjustments.
Kraken Adapter & Utils
src/kraken_adapter.hpp, src/kraken_adapter.cpp, src/kraken_utils.hpp
Added subscribeError_ flag; strengthened WebSocket message and payload validation; explicit per-canonical→Kraken symbol mapping/validation in start(); small formatting tweaks in utilities.
Server Components
src/metrics_server.hpp, src/subscriber_server.hpp
MetricsServer refactored to accept std::vector<ExchangeMetricsView> and aggregate across views; SubscriberServer constructor/signature changed to accept const std::unordered_map<std::string, OrderBook*> & and subscription lookup uses composite exchange + "." + symbol keys.
Prometheus & Metrics Formatting
src/prometheus_format.hpp
buildPrometheusOutput signature extended with bool emitHeaders to control header emission; header lines gated by emitHeaders to avoid duplicate headers across views.
Symbol Utilities & Tests
src/symbol_normalizer.hpp, tests/test_kraken_utils.cpp
Formatting and line-wrapping only; no behavioral changes.
New/Removed Files
src/binance_adapter.cpp, src/binance_adapter.hpp, src/kraken_adapter.cpp (added), src/feed_handler.cpp (removed from build)
Adapter files added/activated for multi-exchange support; feed handler removed from build target.

Sequence Diagram

sequenceDiagram
    participant Main as Main (main.cpp)
    participant Bin as BinanceAdapter
    participant Krk as KrakenAdapter
    participant Norm as SymbolNormalizer
    participant OB as OrderBook
    participant Sub as SubscriberServer
    participant Met as MetricsServer

    Main->>Main: Parse exchanges config
    Main->>Norm: Create/seed normalizer per exchange
    Main->>Bin: Instantiate BinanceAdapter (per-exchange)
    Main->>Krk: Instantiate KrakenAdapter (per-exchange)
    loop Per-Exchange Startup
        Bin->>OB: fetchAndApplySnapshot(binanceSym, canonical)
        OB->>OB: update book state
        Bin->>Sub: updateCallback("exchange.symbol", snapshot)
        Krk->>OB: apply websocket updates
        Krk->>Sub: updateCallback("exchange.symbol", update)
    end
    Main->>Met: Start MetricsServer with ExchangeMetricsView[]
    Met->>Met: buildPrometheusOutput per view (emitHeaders controlled)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #27: Modifies the same exchange-adapter and symbol-normalization code paths (BinanceAdapter fetchAndApplySnapshot and Kraken utilities).
  • PR #21: Related to Binance adapter and adapter/metrics wiring that this change extends to multi-exchange orchestration.
  • PR #22: Changes SubscriberServer integration and subscription handling which overlap with the composite keying updates here.

Poem

🐰 Hops of code across exchange and sea,

Binance and Kraken now dance for me.
Adapters planted, symbols aligned,
Composite keys knit all streams combined.
A rabbit cheers — multi-exchange, set free!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objectives of the changeset: adding a Kraken exchange adapter and refactoring the codebase to support multiple exchanges.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/kraken-exchange

Comment @coderabbitai help to get the list of available commands and usage tips.

@bountx bountx changed the title Feat/kraken exchange Add Kraken exchange adapter and refactor multi-exchange architecture Mar 9, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/metrics_server.hpp (1)

19-23: Consider documenting or enforcing non-null pointer invariant.

The struct uses raw non-owning pointers which is appropriate for a view, but metricsMap and books are dereferenced unconditionally in buildPrometheusMetrics. Consider either:

  • Adding a comment that these must never be null, or
  • Adding debug assertions in the constructor/start method
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/metrics_server.hpp` around lines 19 - 23, ExchangeMetricsView holds
non-owning raw pointers (metricsMap, books) but buildPrometheusMetrics
dereferences them unconditionally; add an explicit non-null invariant by
documenting that metricsMap and books must not be null in the
ExchangeMetricsView definition and enforce it with debug-time checks where the
view is constructed or before buildPrometheusMetrics runs (e.g.,
assert(metricsMap && books) or similar), referencing the ExchangeMetricsView
type and the metricsMap/books members and ensuring buildPrometheusMetrics only
executes when those checks pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/kraken_adapter.cpp`:
- Around line 143-155: The guard in KrakenAdapter::start() drops subscribe
ack/error messages because it expects book channel payloads with
"channel"/"type"/"data"; update the receive logic to first check for top-level
subscribe acknowledgements (presence of "method" == "subscribe" and a
"result"/"success" or "error" field) before applying the existing
channel/type/data checks, and if a subscribe ack indicates failure (success ==
false or error present) mark the startup as failed and resolve/clear the
corresponding pendingSnapshots_ entry so the startup does not wait for a
snapshot timeout; ensure you reference and update the code paths that touch
pendingSnapshots_ and the startup state handling so a subscription error
triggers immediate failure rather than being ignored.

In `@src/main.cpp`:
- Around line 171-172: The partial-startup path can destroy subServer while some
adapters in runtimes are still live; ensure started adapters are stopped before
returning by adding an explicit rollback that iterates the runtimes vector and
calls each adapter's teardown/stop method (the same function used on normal
shutdown) when any ExchangeRuntime::start() fails, or alternatively move the
subServer declaration so it is created before runtimes (making subServer outlive
the adapters). Update the failure branch that currently returns -1 (after the
ExchangeRuntime::start() loop) to first stop/teardown all previously-started
ExchangeRuntime instances in runtimes, then proceed to return, and keep
references to subServer valid until that rollback completes.
- Around line 203-215: SubscriberServer is started before the exchange adapters
finish their initial sync so clients can subscribe while books are not yet
applied (snap.applied == false) and miss the initial snapshot; fix by deferring
SubscriberServer::start() (the subServer instance created with booksPtrs) until
all books have completed their initial sync (e.g., wait for each Book/BookPtr in
booksPtrs to report applied/resynced or for the adapters' start() loops to
signal completion), or alternatively implement a path in
SubscriberServer::handleSubscribe() that detects an un-applied book and pushes a
fresh snapshot when that book becomes applied/resynced; update the startup flow
around the subServer start call and/or add a watcher/callback to emit snapshots
on the transition to applied to ensure subscribers always receive the initial
snapshot.

In `@src/metrics_server.hpp`:
- Around line 108-111: The loop over views_ calls buildPrometheusOutput
repeatedly and causes duplicate `# TYPE`/`# HELP` headers; fix by emitting
headers only once—either (A) refactor buildPrometheusMetrics to call a new
buildPrometheusHeaders helper once before the for (const auto& v : views_) loop
and then call buildPrometheusOutput for each view with headers suppressed, or
(B) add a boolean parameter to buildPrometheusOutput (e.g., emit_headers = true)
and pass false for subsequent iterations (use &v == &views_.front() to decide),
updating all internal header emission sites in buildPrometheusOutput to check
that flag so headers are written only on the first call.

---

Nitpick comments:
In `@src/metrics_server.hpp`:
- Around line 19-23: ExchangeMetricsView holds non-owning raw pointers
(metricsMap, books) but buildPrometheusMetrics dereferences them
unconditionally; add an explicit non-null invariant by documenting that
metricsMap and books must not be null in the ExchangeMetricsView definition and
enforce it with debug-time checks where the view is constructed or before
buildPrometheusMetrics runs (e.g., assert(metricsMap && books) or similar),
referencing the ExchangeMetricsView type and the metricsMap/books members and
ensuring buildPrometheusMetrics only executes when those checks pass.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 72c84324-f5ab-4b15-bf7d-4010817e3d42

📥 Commits

Reviewing files that changed from the base of the PR and between f4df3e8 and 3eb3167.

📒 Files selected for processing (10)
  • CMakeLists.txt
  • Dockerfile
  • src/binance_adapter.cpp
  • src/binance_adapter.hpp
  • src/kraken_adapter.cpp
  • src/kraken_utils.hpp
  • src/main.cpp
  • src/metrics_server.hpp
  • src/subscriber_server.hpp
  • src/symbol_normalizer.hpp

Comment thread src/kraken_adapter.cpp
Comment thread src/main.cpp
Comment thread src/main.cpp Outdated
Comment thread src/metrics_server.hpp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant