A C++ based Trading Server powered by the Deribit API.
A global data structure that stores market data (asks and bids) for multiple instruments.
For each instrument, it maintains two std::map<double, double>, one for asks and another for bids.
Functionalities:
-
Build new instrument data from a snapshot. (
$O(n \log n)$ , where$n$ = snapshot length) -
Apply updates (new/change/delete) received from Deribit efficiently. (Each update: $O( \log n)$)
-
Fetch the top
$n$ asks and bids for any instrument. (Time Complexity: $O(n)$) -
Check symbol existence quickly. (Time Complexity: $O( \log n)$)
Handles the WebSocket connection to Deribit, continuously receiving real-time market data for subscribed symbols.
Runs independently on a dedicated thread using the libwebsockets library.
Functionalities:
- Connect and authenticate with the Deribit WebSocket server.
- Subscribe or unsubscribe to a symbol.
- Parse incoming market data and update the global MarketDataStore.
Handles REST API interactions with Deribit using cpp-httplib and OpenSSL.
Has methods implemented to:
- Authenticate with
client_id,client_secretto obtainaccess_token. - Place / Modify / Cancel orders across different currencies and types (like
marketorlimit). - Fetch current positions and current orderbook.
Maintains symbols' subscription and a set of order_id for every client.
Has methods implemented to:
- Subscribe / Unsubscribe a symbol for a certain client.
- Update / Fetch the set of order_id for a certain client.
Uses std::set to store both kinds of information, performing every operation in
A web-socket server that accepts TCP connections from clients and lets them place/cancel/modify orders, get their orderbook/positions, subscribe/unsubscribe to symbols, and display real-time market data for instruments.
It uses DeribitRestClient to handle order-related queries, and MarketDataStore to provide the clients' real-time market data. It also uses the instance of DeribitWSClient to subscribe / unsubscribe to symbols.
Has methods implemented to:
- Authenticate a connection using an internally stored map of usernames and passwords.
- Handle clients' requests to place/cancel/modify orders.
- Handle clients' requests to subscribe to symbols.
- Handle clients' requests to get real-time market data.
- Handle clients' requests to get their positions and open orders list.
A utility function that parses and displays different types of output data from the Deribit API.
There's also an ExampleClient folder, which is an entirely distinct CPP project, which, when run, connects and communicates with the server.
C++Compiler (supportsC++17or later)CMake(version 3.10 or above)libwebsocketslibraryOpenSSLlibrarynlohmann/json(header-only)cpp-httplib(header-only)
- Clone the repository
git clone https://github.com/navjeet-py/DeribitTradeManager
cd DeribitTradeManager
mkdir build
cd build
- Update the CMakeLists.txt
Set the correct paths for OpenSSL and libwebsockets libraries if CMake cannot find them automatically.
- Build the Project
cmake ..
make- Create a
.envfile inside the main directory with the following content
CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret
- Run
./server-
Machine: MacBook M1 Pro
-
Network: University WiFi
-
Tools Used:
std::chrono. Logged timestamps at critical points(before/after network calls, data processing, etc.) -
Methods Used:
- Performing a task
$t$ times, dividing total time taken by$t$ - Building two global variables(
total_time,count) which updates whenever the function in question is called during the regular app flow recording total number of times it was called and total time it took. - Any real-time market data received from Deribit comes with a timestamp (time measured in milliseconds). Whenever we receive the data, we can find the current time (in ms) and subtract the Deribit timestamp to get an estimate of the delay.
- Performing a task
-
Order Placement: Through the
HTTPrequest, it is taking ~600 ms to place the order and receive the response. -
Market data processing: Once the market data is available in the system, it takes less than 1ms to process and update the MarketDataStore. Building from a snapshot takes ~1ms, while updating from a change takes much less (negligible).
-
WebSocket Message Propagation: I tried to measure it using the third method. The average delay is in the range of 15ms to 50ms.
-
End-to-End Trading Loop: Again, it takes around 1000ms, with major portion of time from HTTP calls (Placing order and Getting Orderbook).
- HTTP Requests: All HTTP Requests are taking more than 500ms. I researched a little about this and learnt that since Deribit servers are located on a different continent. Packets' to and fro movement should take 100- 200ms, and they may also take >200ms to process the order. I am not sure about this, though.
- WebSocket Context Update: The websocket library I'm using (
libwebsockets) processes messages by polling the context every 100ms. This introduces a maximum latency of ~100ms for message propagation. I tried to decrease it to ~5ms, but it caused CPU usage to become 85%.
-
Data Structure: Usage of std::map and std::set at multiple instances caused CRUD operations to be performed quickly (in logarithmic time).
-
Memory Management:
- JSON responses are parsed once and worked with directly. No repeated serialisation/deserialization once parsed.
- Wherever possible, large objects (like
string,vector,json) were passed asconst&references. - MarketDataStore is maintained as a single global instance, so memory isn't wasted creating multiple redundant copies across clients.
- Shift all requests to web sockets and remove usages of HTTP requests completely
- WebSocket compression to minimise payload size.
- Batching multiple orders together.
- Pre-allocated memory buffers for parsing and writing JSON responses.
- Efficiently handle queues.
I was confused whether I had to serve multiple clients (and build my own server) or serve just one client. So, I also built one prototype without the server with architecture like this:

To use this architecture, remove the main.cpp from executables list of CMakeLists.txt and add single-client.cpp instead. Files related to TradingServer could be removed as well (they won't run anyway, they will be compiled though).
