diff --git a/.gitignore b/.gitignore index 642b1fc..628501d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ -\build .vscode/ -\googletest -/Generate_Orders/orders.txt \ No newline at end of file +googletest/ +/Generate_Orders/orders.txt + +# Zig +.zig-cache/ +zig-out/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a4de430 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,70 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Build Commands + +```bash +# Clone GoogleTest (first time only) +git clone --depth 1 https://github.com/google/googletest.git + +# Build +zig build + +# Run tests +zig build test + +# Run executable +./zig-out/bin/LimitOrderBook +``` + +The project uses Zig's build system with C++20 and -O2 optimization. GoogleTest is integrated as a subdirectory. + +## Architecture + +This is a high-frequency trading limit order book matching engine implementing FIFO/Price Priority algorithm. + +### Core Data Structures (Limit_Order_Book/) + +**Three-class hierarchy with hybrid data structure design:** + +1. **Book** - Main order book engine + - Dual AVL trees for buy/sell sides (regular orders) + - Dual AVL trees for stop orders (stop buys/sells) + - Hash maps for O(1) lookups: `orderMap`, `limitBuyMap`, `limitSellMap`, `stopMap` + - Maintains `highestBuy`/`lowestSell` pointers for O(1) best bid/ask access + +2. **Limit** - Price level node + - AVL tree node (parent/leftChild/rightChild pointers) + - Contains doubly-linked list of orders at this price (headOrder/tailOrder) + - Tracks totalVolume and size (order count) + +3. **Order** - Individual order + - Doubly-linked list node within a Limit (nextOrder/prevOrder) + - Back-reference to parentLimit for O(1) limit updates + +### Time Complexities +- Add/Cancel/Modify/Execute: O(1) for existing limits, O(log M) for new price levels +- GetBestBid/Offer: O(1) +- AVL rebalancing: O(log M) when triggered + +### Supporting Modules + +- **OrderPipeline** (Process_Orders/) - Dispatcher pattern for order processing with nanosecond latency measurement +- **GenerateOrders** (Generate_Orders/) - Test data generation with normal distribution + +### Order Types Supported +- Market orders +- Limit orders +- Stop orders +- Stop-limit orders + +### Key Design Decisions + +1. **AVL + Doubly-Linked List Hybrid** - AVL for O(log M) price navigation, doubly-linked list at each level for O(1) FIFO ordering + +2. **Single-threaded matching** - Intentional design for FIFO/price priority consistency + +3. **Manual memory management** - Uses new/delete with proper cleanup in destructors + +4. **Separate stop order trees** - Parallel data structures isolate regular and stop order handling diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 07a9f51..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -cmake_minimum_required(VERSION 3.29.0) - -project(LimitOrderBook VERSION 0.1.0) - -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") - - -enable_testing() - -add_subdirectory(googletest) - -set(Headers - ./Limit_Order_Book/Book.hpp - ./Limit_Order_Book/Limit.hpp - ./Limit_Order_Book/Order.hpp - ./Process_Orders/OrderPipeline.hpp - ./Generate_Orders/GenerateOrders.hpp -) -set(Sources - ./Limit_Order_Book/Book.cpp - ./Limit_Order_Book/Limit.cpp - ./Limit_Order_Book/Order.cpp - ./Process_Orders/OrderPipeline.cpp - ./Generate_Orders/GenerateOrders.cpp -) - -# Define the library target -add_library(${PROJECT_NAME}_lib STATIC ${Sources} ${Headers}) - -# Define the executable target -add_executable(${PROJECT_NAME} main.cpp) - -# Link the executable with the library -target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_lib) - -add_subdirectory(test) - -set(CPACK_PROJECT_NAME ${PROJECT_NAME}) -set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) -include(CPack) diff --git a/README.md b/README.md index 6d58e7d..022189b 100644 --- a/README.md +++ b/README.md @@ -46,17 +46,34 @@ Limit_Order_Book/ │ ├── data_visualisation.py │ └── order_processing_times.csv ├── test/ *unit tests -│ ├── CMakeLists.txt │ ├── ExampleOrdersTests.cpp │ └── LimitOrderBookTests.cpp ├── figures/ ├── googletest/ ├── main.cpp ├── .gitignore -├── CMakeLists.txt +├── build.zig └── README.md ``` +## Build Instructions + +### Prerequisites + +- [Zig](https://ziglang.org/download/) (0.13+) +- Clone GoogleTest (first time only): +```bash +git clone --depth 1 https://github.com/google/googletest.git +``` + +### Build and Run + +```bash +zig build # Build +zig build test # Run tests +./zig-out/bin/LimitOrderBook # Run executable +``` + ## Architecture Architecture diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..bf1b78e --- /dev/null +++ b/build.zig @@ -0,0 +1,134 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // Common C++ flags + const cpp_flags: []const []const u8 = &.{ + "-std=c++20", + "-O2", + }; + + // ========================================= + // Static Library: LimitOrderBook_lib + // ========================================= + const lib_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libcpp = true, + }); + + lib_module.addCSourceFiles(.{ + .files = &.{ + "Limit_Order_Book/Book.cpp", + "Limit_Order_Book/Limit.cpp", + "Limit_Order_Book/Order.cpp", + "Process_Orders/OrderPipeline.cpp", + "Generate_Orders/GenerateOrders.cpp", + }, + .flags = cpp_flags, + }); + + const lib = b.addLibrary(.{ + .name = "LimitOrderBook_lib", + .root_module = lib_module, + }); + b.installArtifact(lib); + + // ========================================= + // Main Executable: LimitOrderBook + // ========================================= + const exe_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libcpp = true, + }); + + exe_module.addCSourceFiles(.{ + .files = &.{"main.cpp"}, + .flags = cpp_flags, + }); + + exe_module.linkLibrary(lib); + + const exe = b.addExecutable(.{ + .name = "LimitOrderBook", + .root_module = exe_module, + }); + b.installArtifact(exe); + + // Run command: zig build run + const run_cmd = b.addRunArtifact(exe); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the limit order book"); + run_step.dependOn(&run_cmd.step); + + // ========================================= + // GoogleTest Library + // ========================================= + const gtest_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libcpp = true, + }); + + gtest_module.addCSourceFiles(.{ + .files = &.{ + "googletest/googletest/src/gtest-all.cc", + "googletest/googletest/src/gtest_main.cc", + }, + .flags = cpp_flags, + }); + + gtest_module.addIncludePath(b.path("googletest/googletest/include")); + gtest_module.addIncludePath(b.path("googletest/googletest")); + + const gtest = b.addLibrary(.{ + .name = "gtest", + .root_module = gtest_module, + }); + + // ========================================= + // Test Executable: LimitOrderBookTests + // ========================================= + const test_module = b.createModule(.{ + .target = target, + .optimize = optimize, + .link_libcpp = true, + }); + + test_module.addCSourceFiles(.{ + .files = &.{ + "test/LimitOrderBookTests.cpp", + "test/ExampleOrdersTests.cpp", + }, + .flags = cpp_flags, + }); + + test_module.addIncludePath(b.path("googletest/googletest/include")); + test_module.linkLibrary(lib); + test_module.linkLibrary(gtest); + + const tests = b.addExecutable(.{ + .name = "LimitOrderBookTests", + .root_module = test_module, + }); + b.installArtifact(tests); + + // Run tests: zig build test + const run_tests = b.addRunArtifact(tests); + run_tests.step.dependOn(b.getInstallStep()); + + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_tests.step); + + // Clean step: zig build clean + const clean_step = b.step("clean", "Remove build artifacts"); + clean_step.dependOn(&b.addRemoveDirTree(b.path(".zig-cache")).step); + clean_step.dependOn(&b.addRemoveDirTree(b.path("zig-out")).step); +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index 95bb4cc..0000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -cmake_minimum_required(VERSION 3.29.0) - -set(This LimitOrderBookTests) - -set(Sources - LimitOrderBookTests.cpp - ExampleOrdersTests.cpp -) - -add_executable(${This} ${Sources}) -target_link_libraries(${This} PUBLIC - gtest_main - LimitOrderBook_lib -) - -add_test( - NAME ${This} - COMMAND ${This} -) \ No newline at end of file