← Projects

TitaniumBOE-Sim Simulador del protocolo BOE de Cboe

Exchange-side simulator for Cboe's BOE binary protocol, with a price-time matching engine, trading bots, REST API, WebSocket and a dashboard in a single JAR.

Stack
Java 21 · Javalin · RocksDB · WebSocket · Docker
Status
Completed
Year
2025
AAPL · in-browser simulation of price-time matching
spread —

Latest trades

    Send an order and watch it cross the book.

    On the real server, 99% of acknowledgments arrive in under 3.5 ms.

    On the wire, every order is a 56-byte binary message. Tap a field to see how it decodes.

    Real New Order message · 56 bytes

    Price offset 38–45 · 8 bytes

    187.2500 USD

    8 bytes in Little Endian: 0x1C9274 = 1,872,500. With 4 implied decimals that is 187.2500, with no floating point on the wire.

    What BOE is

    BOE (Binary Order Entry) is the protocol participants use to send orders to Cboe's U.S. options markets. It isn't text: every message is an exact sequence of bytes in Little Endian, with fixed-size fields, prices with 4 implied decimals, and optional fields announced through bitfields. Above you can send an order to the book and then see its bytes, encoded the same way the simulator does it.

    What I built

    An exchange-side simulator, written from the v2.11.90 specification: it accepts TCP connections, authenticates sessions, receives BOE orders and matches them in a price-time priority matching engine. Around that:

    • Three bots (market maker, trend follower and random trader) that keep the book active.
    • A REST API and WebSocket for market data and trading.
    • A web dashboard served from the same JAR.
    • RocksDB persistence: orders, trades and sessions survive a restart.

    Under the hood

    • Every TCP connection runs on its own Java 21 virtual thread: blocking I/O code that is easy to read, without paying for an OS thread per client.
    • Matching is synchronized per symbol, not globally: AAPL and MSFT match in parallel without blocking each other.
    • Writes to RocksDB go through an asynchronous queue: the client gets its acknowledgment without waiting on disk.
    • Messages form a sealed-class hierarchy, so the compiler knows every possible type.

    How close it is to the spec

    Much of it matches the specification byte for byte, but not all of it, and the differences are documented in the repository. The Cancel and Modify codes aren't the spec's (0x39/0x3A instead of 0x45/0x4A), some text fields are padded with spaces instead of NUL, and the heartbeat is more lenient (10 s / 30 s instead of 1 s / 5 s). That last one is deliberate, so a GC pause or a breakpoint doesn't drop the session. With a real BOE client, cancelling or modifying orders would fail.

    Measured numbers

    With the repository's load test, on a 16-core machine and a freshly started server for each run:

    • 500 simultaneous TCP connections, none refused.
    • Order Acknowledgment P99 between 2.7 and 3.5 ms (900 orders per run, across 10 sessions).
    • Between 4,600 and 9,200 REST requests per second.
    • 347 automated tests, all green.

    The P99 is measured after the connection, login and REST phases, which warm up the JIT. Measuring latency alone on a cold server, one run reached 11.7 ms.

    While measuring I found the load test itself was out of date: it expected the old session codes and sent orders for a symbol the server rejects, so logins and latency hadn't been measured in a while. I fixed it before publishing these numbers. The memory phase is still not useful: it measures the client's heap, not the server's, so I don't publish that number.

    The bottleneck

    Login doesn't reach the target I had set (200 per second): it sits at around 50. Every password is checked with BCrypt at cost 12, which takes on the order of 200 ms of CPU per attempt; with 16 cores, the ceiling is around 60 logins per second. It's a deliberate cost: lowering it would make a brute-force attack cheaper.

    See it running