Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: C++ CI

on:
push:
branches:
- main
- polishes
pull_request:
branches:
- main

jobs:
build-test-sanitize:
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Build release executable
run: make

- name: Run automated tests
run: make test

- name: Run AddressSanitizer and UndefinedBehaviorSanitizer
run: make sanitize
42 changes: 35 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
CXX = g++
CXXFLAGS = -std=c++17 -O2 -Wall -Wextra -Iinclude
CXX ?= g++
CPPFLAGS := -Iinclude
COMMON_FLAGS := -std=c++17 -Wall -Wextra -Wpedantic -Wconversion -Wshadow
RELEASE_FLAGS := -O2 -DNDEBUG
DEBUG_FLAGS := -O0 -g3
SANITIZER_FLAGS := -fsanitize=address,undefined -fno-omit-frame-pointer

SRC = src/main.cpp src/OrderBook.cpp
OUT = matching_engine
BUILD_DIR := build
ENGINE := $(BUILD_DIR)/matching_engine
TEST_BIN := $(BUILD_DIR)/order_book_tests
SANITIZER_TEST_BIN := $(BUILD_DIR)/order_book_tests_sanitize

all:
$(CXX) $(CXXFLAGS) $(SRC) -o $(OUT)
ENGINE_SOURCES := src/main.cpp src/OrderBook.cpp
TEST_SOURCES := tests/OrderBookTests.cpp src/OrderBook.cpp

.PHONY: all test sanitize clean

all: $(ENGINE)

$(BUILD_DIR):
mkdir -p $(BUILD_DIR)

$(ENGINE): $(ENGINE_SOURCES) | $(BUILD_DIR)
$(CXX) $(CPPFLAGS) $(COMMON_FLAGS) $(RELEASE_FLAGS) $(ENGINE_SOURCES) -o $(ENGINE)

$(TEST_BIN): $(TEST_SOURCES) | $(BUILD_DIR)
$(CXX) $(CPPFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $(TEST_SOURCES) -o $(TEST_BIN)

test: $(TEST_BIN)
./$(TEST_BIN)

$(SANITIZER_TEST_BIN): $(TEST_SOURCES) | $(BUILD_DIR)
$(CXX) $(CPPFLAGS) $(COMMON_FLAGS) $(DEBUG_FLAGS) $(SANITIZER_FLAGS) $(TEST_SOURCES) -o $(SANITIZER_TEST_BIN)

sanitize: $(SANITIZER_TEST_BIN)
ASAN_OPTIONS=detect_leaks=1 ./$(SANITIZER_TEST_BIN)

clean:
rm -f $(OUT) matching_engine.exe
rm -rf $(BUILD_DIR)
26 changes: 12 additions & 14 deletions include/OrderBook.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <functional>
#include <list>
#include <map>
#include <optional>
#include <unordered_map>
#include <vector>

Expand All @@ -17,13 +18,9 @@ class OrderBook {
using BuyBook = std::map<Price, OrderQueue, std::greater<Price>>;
using SellBook = std::map<Price, OrderQueue>;

// Buy book: highest price first
BuyBook buyBook;

// Sell book: lowest price first
SellBook sellBook;

// Stores where an order currently exists in the book
struct OrderLocation {
Side side;
Price price;
Expand All @@ -36,31 +33,32 @@ class OrderBook {
std::size_t tradesGenerated;
};

// Fast lookup by order ID for cancel/modify
std::unordered_map<int, OrderLocation> orderMap;

// Stores all executed trades
std::vector<Trade> trades;

// Used to preserve time priority
long long timestampCounter;
bool verboseOutput;

// Internal helper functions
void matchBuyOrder(Order& incomingOrder);
void matchSellOrder(Order& incomingOrder);
void addToBook(const Order& order);
BenchmarkResult runBenchmarkOnce(int numberOfOrders, unsigned int seed);

public:
OrderBook();
explicit OrderBook(bool verbose = true);

void addOrder(int orderId, Side side, int price, int quantity);
void cancelOrder(int orderId);
void modifyOrder(int orderId, int newPrice, int newQuantity);
bool addOrder(int orderId, Side side, int price, int quantity);
bool cancelOrder(int orderId);
bool modifyOrder(int orderId, int newPrice, int newQuantity);

void printBook() const;
void printTrades() const;
void runBenchmark(int numberOfOrders);
void runBenchmarkMultiple(int numberOfOrders, int runs);

[[nodiscard]] bool hasOrder(int orderId) const noexcept;
[[nodiscard]] std::optional<Order> getOrder(int orderId) const;
[[nodiscard]] const std::vector<Trade>& getTrades() const noexcept;
[[nodiscard]] std::size_t activeOrderCount() const noexcept;
[[nodiscard]] std::optional<int> bestBid() const noexcept;
[[nodiscard]] std::optional<int> bestAsk() const noexcept;
};
Loading
Loading