Notre Dame Fake Exchange
This project is intended for the course on High-Frequency Trading Technologies at the University of Notre Dame. It is a toy version of a real exchange for students to practice trading strategies.
┌─────────────────────────────────────────────────────────────────────────┐
│ NDFEX System │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌──────────────────────────────────────┐ │
│ │ Trading Bots │◄──────►│ Matching Engine │ │
│ │ (bot_runner) │ TCP │ ┌────────────┐ ┌────────────────┐ │ │
│ └─────────────────┘ │ │ Order Entry│ │ Order Ladder │ │ │
│ │ │ Server │ │ (Book Matching)│ │ │
│ ┌─────────────────┐ │ └────────────┘ └────────────────┘ │ │
│ │ MD Viewer │◄───────│ ┌────────────┐ ┌────────────────┐ │ │
│ │ (md_viewer) │ Mcast │ │Market Data │ │ Clearing │ │ │
│ └─────────────────┘ │ │ Publisher │ │ Publisher │ │ │
│ │ └────────────┘ └────────────────┘ │ │
│ ┌─────────────────┐ └──────────────────────────────────────┘ │
│ │ MD Snapshots │◄───────── Multicast │
│ │ (md_snapshots) │ │
│ └─────────────────┘ ┌──────────────────────────────────────┐ │
│ │ Web Interface │ │
│ ┌─────────────────┐ │ ┌────────────┐ ┌────────────────┐ │ │
│ │ Web Data │◄──────►│ │ web_data │ │ clearing-web │ │ │
│ │ (WebSocket) │ │ │ server │ │ -app │ │ │
│ └─────────────────┘ │ └────────────┘ └────────────────┘ │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
-
Matching Engine (
matching_engine/): Core exchange functionality- Market Data Publisher: Sends order book changes via multicast
- Order Entry Server: TCP server for order entry protocol
- Order Ladder: Book management and order matching
- ME Broker: Queues between client order entry server and matching engine
- Clearing Publisher: Broadcasts trade/position data
-
Bot Runner (
bots/): Simulated trading strategiesbot_runner: Random walk fair value market makers and takersstable_bot_runner: Constant fair value bots for stable marketssmarter_bots: Advanced strategies including imbalance and pressure takers
-
Market Data (
market_data/): Market data snapshot service- Listens to multicast market data
- Provides TCP snapshots for late-joining clients
-
Viewer (
viewer/): Terminal-based market data viewer using FTXUI -
Web Data (
web_data/): WebSocket server for web-based dashboards -
Clearing Web App (
clearing-web-app/): Next.js web interface for clearing data
- CMake: Version 3.16 or higher
- Compiler:
clang++org++with C++17 support - spdlog: Logging library (included as git submodule)
- SPSCQueue: Lock-free queue (included as git submodule)
- pthread: Provided by glibc on Linux
- FTXUI: Terminal UI library for
md_viewer(included as git submodule, requires building) - websocketpp: WebSocket library for
web_data - libpcap: For
pcap_printertool (Linux package, optional) - GoogleTest: For running C++ tests
- Node.js: For the clearing web app
The core dependencies (spdlog, SPSCQueue, FTXUI) are included as git submodules.
# Clone the repository with submodules
git clone --recursive https://github.com/matthewbelcher/NDFEX.git
# Or if already cloned, initialize submodules
git submodule update --init --recursive
# Build FTXUI (required for viewer)
cd 3rdparty/FTXUI && mkdir build && cd build && cmake .. && make && cd ../../..
# Install GoogleTest (for tests)
# Ubuntu/Debian:
# sudo apt-get install -y libgtest-dev
# Fedora:
# sudo dnf install -y gtest-devel
# Arch:
# sudo pacman -S gtest
# For web app
cd clearing-web-app && npm installThe project uses CMake for building. All executables are output to build/bin/.
# Initialize submodules (if not already done)
git submodule update --init --recursive
# Create build directory and configure
mkdir build && cd build
cmake ..
# Build all core components
make -j$(nproc)CMake options can be set during configuration:
# Release build (optimized)
cmake -DCMAKE_BUILD_TYPE=Release ..
# Debug build (with symbols)
cmake -DCMAKE_BUILD_TYPE=Debug ..
# Build with viewer (requires FTXUI to be built first)
cmake -DBUILD_VIEWER=ON ..
# Build with web data server (requires websocketpp)
cmake -DBUILD_WEB_DATA=ON ..
# Build with tests (requires GoogleTest)
cmake -DBUILD_TESTS=ON ..
# Build everything
cmake -DBUILD_VIEWER=ON -DBUILD_WEB_DATA=ON -DBUILD_TESTS=ON ..cd 3rdparty/FTXUI
mkdir build && cd build
cmake ..
make -j$(nproc)
cd ../../..# Configure with tests enabled
cmake -S . -B build -DBUILD_TESTS=ON
# Build tests (and core targets)
cmake --build build -j$(nproc)
# Run all tests
ctest --test-dir build --output-on-failure
# Run a single test binary
ctest --test-dir build -R test_md_mcast --output-on-failureAfter building, executables are located in build/bin/:
| Executable | Description |
|---|---|
matching_engine |
Core exchange server |
md_snapshots |
Market data snapshot service |
bot_runner |
Main trading bot runner |
stable_bot_runner |
Constant fair value bots |
smarter_bots |
Advanced trading strategies |
reject_bot |
Rejection testing bot |
print_snapshots |
Snapshot printing utility |
md_viewer |
Terminal UI viewer (optional) |
bbo_printer |
BBO printer (optional) |
pcap_printer |
PCAP printer (optional, Linux only) |
web_data |
WebSocket server (optional) |
rm -rf buildThe easiest way to run NDFEX is using the control script:
# Create users file first (ndfex.sh runs from matching_engine/)
echo "99 test testuser" > matching_engine/users.txt
# Start all components
./ndfex.sh start
# Check status
./ndfex.sh status
# View logs
./ndfex.sh logs
# Stop all components
./ndfex.sh stop# Start with custom network configuration
./ndfex.sh start --bind-ip 192.168.1.100 --mcast-ip 239.1.1.1
# Start with different bot type
./ndfex.sh start --bot-type smarter_bots
# Start without bots (matching engine + snapshots only)
./ndfex.sh start --no-bots
# Start without snapshot service
./ndfex.sh start --no-snapshots
# Restart all components
./ndfex.sh restart| Bot Type | Description |
|---|---|
bot_runner |
Random walk fair value market makers (default) |
stable_bot_runner |
Constant fair value bots for stable markets |
smarter_bots |
Advanced strategies with imbalance/pressure takers |
reject_bot |
For testing order rejection scenarios |
For more control, you can start components individually:
The matching engine reads user credentials from users.txt in the working directory:
# Format: client_id username password
echo "99 test testuser" > users.txt
echo "1 student1 password1" >> users.txt./build/bin/matching_engine <bind_ip> <mcast_ip> <clearing_ip>
# Example (localhost):
./build/bin/matching_engine 127.0.0.1 239.0.0.1 239.0.0.2Arguments:
bind_ip: IP address to bind the order entry servermcast_ip: Multicast IP for market data (e.g., 239.0.0.1)clearing_ip: Multicast IP for clearing data
./build/bin/md_snapshots <md_mcast_ip> <md_port> <snapshot_mcast_ip> <snapshot_port> <mcast_bind_ip>
# Example:
./build/bin/md_snapshots 239.0.0.1 12345 239.0.0.3 12345 127.0.0.1./build/bin/bot_runner <oe_ip> <oe_port> <mcast_ip> <snapshot_ip> <mcast_bind_ip>
# Example:
./build/bin/bot_runner 127.0.0.1 1234 239.0.0.1 239.0.0.3 127.0.0.1./build/bin/md_viewer <mcast_ip> <snapshot_ip> <mcast_bind_ip>
# Example:
./build/bin/md_viewer 239.0.0.1 239.0.0.3 127.0.0.1# Terminal 1: Start web data server
./build/bin/web_data <md_mcast_ip> <snapshot_mcast_ip> <clearing_mcast_ip> <mcast_bind_ip>
# Example:
./build/bin/web_data 239.0.0.1 239.0.0.3 239.0.0.2 127.0.0.1
# Terminal 2: Start Next.js web app
cd clearing-web-app
npm run devThe exchange supports the following symbols by default:
| Symbol ID | Name | Tick Size | Min Qty | Max Qty | Max Price |
|---|---|---|---|---|---|
| 1 | GOLD | 10 | 1 | 1000 | 10000000 |
| 2 | BLUE | 5 | 1 | 1000 | 10000000 |
| Service | Protocol | Default Port |
|---|---|---|
| Order Entry | TCP | 1234 |
| Market Data Multicast | UDP | 12345 |
| Clearing Multicast | UDP | 12346 |
| Market Data Snapshot | TCP | 12345 |
| Web Data WebSocket | TCP | 9002 |
| Clearing Web App | HTTP | 3000 |
This section captures the current lab setup and the single-script workflow.
The lab build uses the per-component Makefiles (clang).
make -C matching_engine -j$(nproc)
make -C market_data -j$(nproc)
make -C bots -j$(nproc)Solarflare connectivity for the exchange host (port 47) should be configured on a private network. The monitor port (48) is configured on the switch and should remain unnumbered.
On client hosts (hftt0-3), two Solarflare NICs should be assigned with sequential IP addresses:
| Host | Interface 1 | Interface 2 |
|---|---|---|
| hftt0 | <NETWORK>.10 |
<NETWORK>.11 |
| hftt1 | <NETWORK>.12 |
<NETWORK>.13 |
| hftt2 | <NETWORK>.14 |
<NETWORK>.15 |
| hftt3 | <NETWORK>.16 |
<NETWORK>.17 |
The ndfex.sh wrapper now resolves clang-built binaries, starts components with the correct
arguments, and can add the multicast route on the Solarflare interface.
./ndfex.sh start \
--bind-ip <EXCHANGE_IP> \
--mcast-bind-ip <EXCHANGE_IP> \
--add-mcast-routeNotes:
md_snapshotsmust join the multicast group (not the host IP).- Snapshots are published on a separate multicast group (
239.0.0.3) to avoid mixing live market data and snapshot traffic. - Running from the
matching_engine/directory is required sousers.txtis found. - The multicast route is added as
239.0.0.0/8via the interface that ownsMCAST_BIND_IP.
The FTXUI market data viewer uses both multicast groups and is available as a
subcommand in ndfex.sh.
./ndfex.sh viewer --mcast-bind-ip <EXCHANGE_IP>If the viewer binary is missing, build it with:
make -C viewerUse the helper script to configure/check Solarflare IPs and verify multicast reception:
python3 scripts/check_hftt_solarflare.py --target-ip <EXCHANGE_IP>The script warns if the target IP is on the wrong switch port.
All components write logs to a logs/ directory in their working directory:
logs/ME*- Matching engine logslogs/SNAPSHOT*- Snapshot service logslogs/bot_runner*- Bot runner logslogs/viewer*- Viewer logslogs/web_data*- Web data server logs
NDFEX/
├── CMakeLists.txt # Top-level CMake configuration
├── ndfex.sh # System control script (start/stop/status)
├── matching_engine/ # Core exchange: order matching, market data, clearing
│ ├── tests/ # Unit tests for matching engine
│ └── CMakeLists.txt
├── order_entry/ # Order entry protocol and server
│ └── tests/ # Unit tests for order entry
├── market_data/ # Market data snapshot service
│ └── CMakeLists.txt
├── bots/ # Trading bot implementations
│ └── CMakeLists.txt
├── viewer/ # Terminal UI viewer
│ └── CMakeLists.txt
├── web_data/ # WebSocket server for web clients
│ └── CMakeLists.txt
├── clearing-web-app/ # Next.js web dashboard
│ └── package.json
├── 3rdparty/spdlog/ # Logging library (git submodule)
├── 3rdparty/SPSCQueue/ # Lock-free queue library (git submodule)
├── 3rdparty/FTXUI/ # Terminal UI library (git submodule)
├── build/ # Build output directory (created by cmake)
│ └── bin/ # Compiled executables
└── README.md