High-Frequency Trading

Jupiter
Low-Latency Order Book

A clean-room HFT matching engine achieving 641ns minimum latency through flat-array storage, object pooling, and zero-copy networking.

641ns
Min Latency
1.5M
Orders/Sec
O(1)
Operations

The Challenge

⚠️

Traditional Approach

  • O(log N) operations using Red-Black Trees (std::map)
  • Poor cache locality due to pointer chasing
  • Runtime allocation causing malloc/free overhead
  • Microsecond latencies unsuitable for HFT
✨

Jupiter's Solution

  • Flat-array storage for O(1) direct indexing
  • Contiguous memory maximizing cache hits
  • Object pooling eliminating runtime allocation
  • Sub-microsecond latency at 641ns minimum

System Architecture

Core components designed for maximum performance

📊

Flat-Array Storage

Prices converted to integer ticks enable direct array indexing. bids[10005] represents all orders at $100.05.

O(1) Lookup
♻️

Object Pool

Pre-allocated 100,000 Order objects. Acquire/release pattern eliminates malloc/free during trading sessions.

Zero Allocation
🌐

Zero-Copy Networking

Raw UDP sockets with packed binary structs. Direct network-to-engine data flow without deserialization overhead.

16 Bytes/Packet
🔒

Type Safety

Strong typing for Prices and Quantities prevents mixed-unit arithmetic errors at compile time.

Compile-Time Safety

Order Matching Flow

flowchart TD A[Receive UDP Packet] --> B{Decode Order} B --> C{Check Side} C -->|BID| D[Match vs Best Ask] C -->|ASK| E[Match vs Best Bid] D --> F{Price >= Ask?} E --> G{Price <= Bid?} F -->|Yes| H[Execute Trade] F -->|No| I[Add to Bid Book] G -->|Yes| H G -->|No| J[Add to Ask Book] H --> K{Quantity Remaining?} K -->|Yes| L{More Matches?} K -->|No| M[Trade Complete] L -->|Yes| H L -->|No| I L -->|No| J I --> M J --> M M --> N[Log Trade & Benchmark] style A fill:#6366f1,stroke:#818cf8,color:#fff style H fill:#10b981,stroke:#34d399,color:#fff style M fill:#8b5cf6,stroke:#a78bfa,color:#fff style N fill:#ec4899,stroke:#f472b6,color:#fff

Memory Management Architecture

graph TD A[Startup] --> B[Allocate 100K Orders] B --> C[Free List Stack] C --> D{acquire} D --> E[Pop from Stack] E --> F[Placement New] F --> G[Active Order] G --> H{Trade Complete} H --> I{release} I --> J[Call Destructor] J --> K[Push to Stack] K --> C style B fill:#6366f1,stroke:#818cf8,color:#fff style F fill:#10b981,stroke:#34d399,color:#fff style J fill:#f59e0b,stroke:#fbbf24,color:#fff style C fill:#8b5cf6,stroke:#a78bfa,color:#fff

Performance Benchmarks

Measured on consumer laptop (Linux/GCC -O3)

Latency Distribution

Throughput Analysis

⚡
Minimum Latency
641 ns
Hot cache path - true theoretical speed
📈
Average Latency
2,700 ns
Includes OS jitter and context switching
🚀
Peak Throughput
1.5M orders/s
Sustained order processing rate

Key Innovations

Code snippets highlighting technical excellence

order_book.h C++17
// Traditional: O(log N) with std::map
// std::map<double, std::list<Order*>, std::greater<double>> bids;

// Jupiter: O(1) with flat-array indexing
std::vector<std::list<Order*>> bids;  // Size: 1,000,000
std::vector<std::list<Order*>> asks;

// Price to tick conversion: $100.05 → 10005
int tick = (int)(price * 100);

// Direct O(1) access
bids[tick].push_back(newOrder);
max_bid_tick = std::max(max_bid_tick, tick);
Performance Gain: Eliminates tree traversal overhead, maximizes cache locality
order_pool.cpp C++17
template<typename T>
template<typename... Args>
T* Order_Pool<T>::acquire(Args&&... args) {
    if(free_list.size() == 0) {
        throw std::runtime_error("Order Book Size Exhausted");
    }
    
    T* ptr = free_list.back();
    free_list.pop_back();
    
    // Placement new: construct in pre-allocated memory
    new (ptr) T(std::forward<Args>(args)...);
    
    return ptr;
}

void Order_Pool<T>::release(T* obj) {
    obj->~T();  // Manual destructor call
    free_list.push_back(obj);  // Return to pool
}
Performance Gain: Zero runtime allocation, eliminates malloc/free syscalls
protocol.h + market_data_receiver.cpp C++17
// Packed binary struct (no padding)
#pragma pack(push, 1)
class OrderMessage {
public:
    MessageHeader header;
    uint32_t orderID;
    uint32_t price;     // Network byte order (Big Endian)
    uint32_t quantity;
    char side;          // 'B' or 'S'
};
#pragma pack(pop)

// Zero-copy deserialization
OrderMessage* msg = reinterpret_cast<OrderMessage*>(buffer);

// Network to host byte order conversion
uint32_t id = ntohl(msg->orderID);
uint32_t price_ticks = ntohl(msg->price);
uint32_t quantity = ntohl(msg->quantity);
Performance Gain: Direct memory interpretation, 16 bytes per packet, no deserialization overhead

Technical Stack

Core Technology

  • C++17 - Modern language features
  • CMake - Build system
  • GCC/Clang - Optimizing compilers (-O3 -march=native)

Performance Optimizations

  • Flat-array indexing - O(1) operations
  • Object pooling - Zero allocation
  • Cache locality - Contiguous memory
  • Placement new - In-place construction

Networking

  • UDP Multicast - Low-latency data feed
  • POSIX Sockets - Raw network access
  • Binary Protocol - Packed structs (16 bytes)
  • Big Endian - Network byte order

Testing & Quality

  • Google Test - Unit testing framework
  • Benchmarking - High-resolution timers
  • Strong typing - Compile-time safety
  • RAII - Resource management

Future Enhancements

1

Kernel Bypass

Port to DPDK or Solarflare OpenOnload to skip Linux kernel stack and achieve even lower latencies.

2

Lock-Free Queue

Implement SPSC ring buffer to decouple network and matching threads for higher throughput.

3

Multi-Core Scaling

Pin engine thread to dedicated CPU core with isolcpus to reduce context switching jitter.

4

TCP Recovery

Implement snapshot mechanism to rebuild order book state if UDP packets are dropped.