Skip to content

Getting Started with EduMatcher

Learning objectives

After reading this page you will understand:

  • What EduMatcher is and what you can do with it
  • The minimum steps to start an exchange and execute your first trade
  • What each process does and when to start it
  • How to quickly bootstrap a new engine_config.yaml with pm-config-gen
  • Which sections to read next based on your role

What is EduMatcher?

EduMatcher is a fully functional financial exchange matching engine built for education, research, and demo purposes. It implements the same core mechanics that underpin real stock exchanges:

  • A continuous order book that matches buyers and sellers
  • Auction phases (opening and closing) with equilibrium price calculation
  • Market-maker quoting with obligations and protection
  • Risk controls: price collars, circuit breakers, kill switches
  • Combo and OCO orders: multi-leg strategies with cascade cancellation
  • Statistics recording (OHLCV, VWAP, mid prices) in SQLite
  • Drop-copy feed for compliance monitoring
  • Autonomous AI traders to simulate real order flow

Participants connect via a terminal (the gateway) and type commands to place orders. The engine matches them and publishes fill events over a ZeroMQ message bus that all other processes subscribe to.

flowchart LR
    GW1["pm-alf-console\nParticipant A"]
    GW2["pm-alf-console\nParticipant B"]
    AI["pm-ai-trader\nAutonomous bot"]
    ENG["pm-engine\nMatching engine\nPULL :5555 / PUB :5556"]
    ADM["pm-admin\nOperator console"]
    CLR["pm-clearing\nP&L tracker"]
    STAT["pm-stats\nStatistics recorder"]
    DC["Drop-copy feed\n(built into pm-engine)\n:5557"]
    SCH["pm-scheduler\nSession phases"]

    GW1 -- "NEW|SYM=AAPL|..." --> ENG
    GW2 -- "NEW|SYM=AAPL|..." --> ENG
    AI -- "orders" --> ENG
    ADM -- "HALT / RESUME / STATUS" --> ENG
    ENG -- "fills / book / session" --> GW1
    ENG -- "fills / book / session" --> GW2
    ENG -- "trade.executed" --> CLR
    ENG -- "trade.executed / book." --> STAT
    ENG -- "per-fill drop-copy" --> DC
    SCH -- "session state" --> ENG

How to get started

Running the exchange is complex enough that you really need to read the documentation and follow the instructions in the User Guide to get a full exchange up and running. The installation below is just the very first step to get started. The rest of the User Guide will explain how to configure the exchange, start and stop processes, and run the system in a realistic way.

This might seem overwhelming at first and the best way to get started is to skim through the entirety of the user-guide. After the installation a good way to get started is through the self-paced training sections

Installation

EduMatcher supports two installation modes. Choose the one that matches your role.

VM bootstrap mode — curl + Multipass (no repo clone)

Use this mode when you want a ready-to-run EduMatcher VM without installing Python or cloning this repository on your host.

What is Multipass?

Multipass is a lightweight VM manager from Canonical. It launches Ubuntu VMs with simple CLI commands so you can run isolated Linux environments locally on macOS, Linux, or Windows.

Requirements

Requirement Notes
Multipass Install from multipass.run
curl Used to download the VM bootstrap script
Internet access Required for downloading scripts and PyPI packages
Host resources Recommended minimum: 2 vCPU, 3 GB RAM, 10 GB disk

Bootstrap with one command

curl -fsSL https://raw.githubusercontent.com/johan162/EduMatcher/main/vm/curl_setup_vm.sh | bash -s -- --version 0.15.1 --snapshot

This command downloads the VM setup scripts, launches a Multipass VM, installs EduMatcher in the VM, links all pm-* commands into /usr/local/bin, prepares /home/ubuntu/session, and optionally takes an initial snapshot.

Start using the VM

multipass shell edumatcher-vm
cd /home/ubuntu/session
pm-engine --verbose

Open additional host terminals and run multipass shell edumatcher-vm in each terminal to start pm-alf-console, pm-viewer, pm-clearing, and pm-audit.

Useful bootstrap options

# Different VM name and version
curl -fsSL https://raw.githubusercontent.com/johan162/EduMatcher/main/vm/curl_setup_vm.sh | \
    bash -s -- --name edumatcher-vm --version 0.15.1 --snapshot

# Tune resources
curl -fsSL https://raw.githubusercontent.com/johan162/EduMatcher/main/vm/curl_setup_vm.sh | \
    bash -s -- --cpus 2 --memory 3G --disk 8G

Optional: inspect script before execution

curl -fsSL https://raw.githubusercontent.com/johan162/EduMatcher/main/vm/curl_setup_vm.sh -o curl_setup_vm.sh
less curl_setup_vm.sh
bash curl_setup_vm.sh --version 0.15.1 --snapshot

This is the quickest path if you just want to run an exchange session — no source code, no Poetry, no virtual environment management.

Requirements

Requirement Notes
Python 3.13 or later Check with python --version
Three or more terminal windows Or a terminal multiplexer such as tmux

Install

If using brew then install pipx

# Install pipx using homebrew
brew install pipx
pipx ensurepath        # adds ~/.local/bin to PATH; reopen your shell after this

or on Linux

# Install pipx (once, if not already present)
pip install pipx
pipx ensurepath        # adds ~/.local/bin to PATH; reopen your shell after this

Install EduMatcher — all pm-* commands land on your PATH

pipx install edumatcher
mkdir session
cd session
pm-setup

pm-setup prints a shell snippet to add to your .zshrc / .bashrc:

export EDUMATCHER_DATA_DIR="$HOME/.local/share/edumatcher"
export EDUMATCHER_CONFIG="$HOME/my-exchange-session/engine_config.yaml"

Or use the provided one-shot script (handles pipx installation automatically):

./scripts/install-runtime.sh

After reloading your shell, every pm-* command picks up the right data directory automatically — no flags needed.

Edit the config, then start trading

If you prefer generating a starter config instead of manually writing YAML:

pm-config-gen \
    --symbols AAPL MSFT \
    --gateways TRADER01 TRADER02 OPS01:ADMIN \
    --sessions-enabled \
    --output engine_config.yaml

Then edit any remaining details and start the engine.

For full generator details (all flags, --symbol-opts, MM quote stubs, validation hints, and recipes), see Configuration.

# Edit the sample config that pm-setup copied into your directory
nano engine_config.yaml

# Start the engine
pm-engine --verbose

Developer mode — Poetry + source checkout

Use this mode if you want to modify the engine, run tests, or contribute.

Requirements

Requirement Notes
Python 3.13 or later Check with python --version
Poetry pip install poetry or pipx install poetry
Three terminal windows Or tmux / screen

Install

git clone https://github.com/johan162/EduMatcher.git
cd EduMatcher
poetry install --with dev

Data is stored in src/data/ inside the repo and engine_config.yaml is read from the repo root — no environment variables needed.

All commands are prefixed with poetry run:

poetry run pm-engine --verbose
poetry run pm-alf-console --id GW01

Switching from developer to end-user mode

You can install the locally built wheel with pipx at any time:

poetry build
pipx install dist/edumatcher-*.whl --force
pm-setup --force    # re-copy the latest sample config

Environment variables

These two variables work in both modes. Set them in your shell profile to override the defaults permanently.

Variable Default (installed) Default (source) Purpose
EDUMATCHER_DATA_DIR ~/.local/share/edumatcher <repo>/src/data/ Where all persistent data files are stored
EDUMATCHER_CONFIG ./engine_config.yaml (CWD) <repo>/engine_config.yaml Path to the engine configuration YAML

The --config flag on pm-engine and pm-scheduler always takes precedence over both the environment variable and the default.

PM command family overview

Use these tables as a quick index for every pm- entry point currently documented. All commands are shown in pipx form; in developer mode prepend poetry run. All pm- processes/utilities are described in Processes.

Runtime processes (runnable)

Command Interactivity Purpose More information
pm-engine Background Matching engine; central order-book writer Processes, Running the Engine, Configuration
pm-alf-console Interactive terminal ALF participant terminal and order entry Processes, Gateway, ALF Protocol
pm-scheduler Background Session phase transitions by schedule Processes, Auctions and Scheduling
pm-viewer Terminal display Single-symbol live order book view Processes, Order Types
pm-orders Terminal display Live cross-gateway order status monitor Processes, Messages
pm-board Terminal display Multi-symbol market board display Processes
pm-ticker Terminal display Scrolling ticker with live plus OHLCV context Processes, Statistics and Reporting
pm-stats Background Persist market statistics to SQLite Processes, Statistics and Reporting
pm-clearing Terminal display Trade recording and running P&L Processes, P&L and Clearing
pm-audit Background Full event log capture from the bus Processes, Persistence
pm-ralf-gwy Background External post-trade dissemination gateway (RALF) Processes, Post-Trade Dissemination, RALF Protocol
pm-admin Interactive terminal Interactive operational console Processes, Risk Controls
pm-ai-trader Background Single autonomous trading bot gateway Processes, AI Bot Traders
pm-ai-swarm Background Multi-agent autonomous trading swarm Processes, AI Bot Traders
pm-mm-bot Background Autonomous market-maker quoting bot Processes, Market-Maker Bot
pm-md-gwy Background Market-data distribution gateway (CALF) Processes, Market Data Feed, CALF Protocol
pm-api-gwy Background REST/WebSocket order-entry and market-data API gateway Processes, API Gateway
pm-index Background Real-time cap-weighted index calculation and dissemination Processes, Market Index

CLI utilities (runnable)

Command Purpose More information
pm-admin-cli Non-interactive admin commands for scripts Processes, Risk Controls
pm-cverifier Validate engine_config.yaml before runtime (YAML, schema, semantic, completeness checks) Processes, Configuration, Config Verifier
pm-stats-cli Query stats.db without writing SQL Processes, Statistics and Reporting
pm-index-cli Read-only query interface for index history files Processes, Commands, Market Index
pm-setup Bootstrap local session directory and defaults Processes, Installation
pm-config-gen Generate engine_config.yaml from CLI options Processes, Configuration generator

Planned runtime processes (design proposals)

Command Interactivity Purpose More information
pm-balf-gateway Background Binary order-entry gateway (BALF) Processes planned section, BALF Protocol

For startup order and a practical first-run sequence, see Processes.

Market-Maker Quick Reference

If your gateway role is MARKET_MAKER, this is the fastest practical command set for quote operation and fill recognition:

Goal Command
Submit/replace quote QUOTE\|SYM=AAPL\|BID=209.80\|ASK=210.20\|BID_QTY=500\|ASK_QTY=500\|QUOTE_ID=Q123
Cancel active quote QUOTE_CANCEL\|SYM=AAPL
Show active quote legs QLEGS
Show one-symbol quote legs QLEGS\|SYM=AAPL
Show recent completed legs QLEGS\|SHOW=RECENT
Show active + recent legs QLEGS\|SYM=AAPL\|SHOW=ALL

Recommended manual loop:

  1. Send QUOTE with an explicit QUOTE_ID.
  2. After any FILL, run QLEGS|SYM=<symbol>|SHOW=ALL.
  3. Read Filled?, Rem, and Leg status to decide whether to re-quote.

See Gateway for full QLEGS behavior and Market Making for operator workflows and policy-specific behavior.

Five-minute minimum session

This walkthrough starts a matching engine, connects two participant terminals, and executes one trade. No configuration file is required — the engine starts in unrestricted mode when engine_config.yaml is absent.

Step 1 — Start the engine

Open a terminal and run:

"Installed (pipx)" mode

pm-engine

"Developer (Poetry)" mode

poetry run pm-engine

Expected output:

[ENGINE] EduMatcher matching engine starting
[ENGINE] Listening for orders on tcp://127.0.0.1:5555
[ENGINE] Publishing events on tcp://127.0.0.1:5556
[ENGINE] Drop-copy feed on tcp://127.0.0.1:5557
[ENGINE] Session state: PRE_OPEN
[ENGINE] Ready

The engine is now running. Leave this terminal open.

Step 2 — Connect Participant A (the buyer)

Open a second terminal:

"Installed (pipx)" mode

pm-alf-console --id GW01

"Developer (Poetry)" mode

poetry run pm-alf-console --id GW01

You should see a prompt after the connection banner:

[GW01] Connected to engine
GW01>

Step 3 — Connect Participant B (the seller)

Open a third terminal:

"Installed (pipx)" mode

pm-alf-console --id GW02

"Developer (Poetry)" mode

poetry run pm-alf-console --id GW02

[GW02] Connected to engine
GW02>

Step 4 — Check the session state

On either gateway, ask what state the exchange is in:

GW01> STATUS

The engine replies with the current session state. In unrestricted mode it starts in PRE_OPEN. To enable matching, advance to CONTINUOUS:

Skipping auctions in testing

Without pm-scheduler, the session state stays where you set it. Advance to CONTINUOUS with pm-admin or the operator console. The quickest way if you just have the engine running is to start with a config that sets sessions_enabled: false (which defaults to CONTINUOUS).

For this walkthrough, start the engine with:

echo "sessions_enabled: false" > /tmp/demo.yaml
pm-engine --config /tmp/demo.yaml       # installed
# or:  poetry run pm-engine --config /tmp/demo.yaml

Step 5 — Place orders and trade

Book liquidity depends on your configuration

This walkthrough starts the engine with sessions_enabled: false and no engine_config.yaml, so the book is completely empty at startup.

If you are running against an engine_config.yaml that configures AAPL with a market_maker_quotes seed block, the book already has a two-sided MM quote resting in it when trading opens. In that case, an aggressive order from one participant will immediately match against the seed quote — before the second participant even types anything. For example, a market buy from GW01 would fill against the MM's resting ask rather than waiting for GW02's sell.

If this happens and you are surprised by an unexpected fill, check whether your config seeds the book:

grep -A5 "market_maker_quotes" engine_config.yaml
To follow this walkthrough exactly with a known-empty book, either start the engine with no config file, or use a config with no market_maker_quotes entries.

On Participant B's terminal, post a sell order at 150.00:

GW02> NEW|SYM=AAPL|SIDE=SELL|TYPE=LIMIT|QTY=100|PRICE=150.00|TIF=DAY

Expected response:

[HH:MM:SS] ORDER ACK  ord-xxxx  AAPL SELL LIMIT 100@150.00 DAY → RESTING

On Participant A's terminal, buy at the same price:

GW01> NEW|SYM=AAPL|SIDE=BUY|TYPE=LIMIT|QTY=100|PRICE=150.00|TIF=DAY

Both gateways see fill events:

[HH:MM:SS] FILL  ord-xxxx  AAPL BUY 100@150.00
[HH:MM:SS] FILL  ord-yyyy  AAPL SELL 100@150.00

A trade.executed event is published to all subscribers. Congratulations — you just ran a trade on your own exchange.

What happened under the hood

sequenceDiagram
    participant A as GW01 (buyer)
    participant E as pm-engine
    participant B as GW02 (seller)

    B->>E: NEW SELL AAPL 100@150.00
    E-->>B: order.ack → RESTING

    A->>E: NEW BUY AAPL 100@150.00
    E-->>A: order.ack → RESTING
    note over E: bid price ≥ ask price → match
    E-->>A: order.fill.GW01  AAPL BUY  100@150.00
    E-->>B: order.fill.GW02  AAPL SELL 100@150.00
    E-->>E: trade.executed published to all subscribers

Starting more processes

The engine is the only mandatory process. Add the others as you need them:

When you want to… Start this process More information
Watch P&L update in real time pm-clearing P&L and Clearing
Record OHLCV statistics pm-stats Statistics and Reporting
Query recorded statistics without SQL pm-stats-cli daily --date 2026-06-14 Statistics and Reporting
Use pm-admin operator commands pm-admin (interactive REPL) Risk Controls
Schedule opening/closing auctions pm-scheduler Auctions and Scheduling
Add autonomous AI order flow pm-ai-swarm --count 5 --duration 60 AI Traders
Add automated market-maker liquidity pm-mm-bot --symbol AAPL Market-Maker Bot
Feed external clearing/drop-copy consumers over TCP pm-ralf-gwy Post-Trade Dissemination
Feed compliance/risk systems Subscribe to :5557 (drop-copy socket) Drop Copy

For a full classroom session, use the provided launch script:

./tools/launch_all.sh

The script detects whether pm-engine is on PATH (installed mode) or falls back to poetry run automatically when running from a source checkout.

Typical architecture for a classroom demo

flowchart TD
    subgraph Instructor
        direction TB
        ADM["pm-admin\n(operator console)"]
    end
    subgraph Server
        direction TB
        ENG["pm-engine"]
        CLR["pm-clearing"]
        STAT["pm-stats"]
        SCH["pm-scheduler"]
        AI["pm-ai-swarm\n(simulated order flow)"]
    end
    subgraph Student terminals
        direction TB
        GW1["pm-alf-console --id ST01"]
        GW2["pm-alf-console --id ST02"]
        GWN["pm-alf-console --id STnn"]
    end

    ADM -- "halt / resume / session" --> ENG
    ENG -- "gateway traffic" --> GW1
    GW1 --> GW2
    GW2 --> GWN

    AI -. "orders" .-> ENG
    SCH -. "phase changes" .-> ENG
    ENG -- "trade events" --> CLR
    ENG -- "market data" --> STAT

Typical setup:

  1. Instructor creates engine_config.yaml with student gateway IDs and symbols.
  2. Instructor starts engine, scheduler, clearing, stats, and a small AI swarm.
  3. Students each ssh to the server and run their gateway.
  4. Instructor uses pm-admin to manage session phases and monitor the market.

Reading path

Use the table below to decide what to read based on your goal.

Goal Read these sections in order
Understand the full system 01 → 03 → 08 → 04 → 06 → 11 → 12 → 02 → 07 → 09 → 10
Set up a classroom session 01 → 03 → 08 → 06 → 14 (MM) → 15 (AI)
Participate as a trader 08 → 04 → 05
Run as a market maker 01 → 08 → 14 (MM)
Monitor the market 09 → 10 → 13 → 07
Write a custom client 09 → 20 → 02
Understand risk controls 12 → 06 → 04

Glossary of terms used throughout this guide

Term Meaning
Engine The pm-engine matching engine process — the authoritative order book
Gateway A pm-alf-console participant terminal; one per trader
Symbol A tradeable instrument, e.g. AAPL, MSFT
Order book Sorted list of resting bids and asks for one symbol
Fill An execution — the result of two orders matching
TIF Time-in-Force: how long an order lives (DAY, GTC, ATO, ATC)
Tick Minimum price increment (e.g. 0.01 for most equities)
Gateway ID Unique identifier for a participant connection, e.g. GW01
Session state Phase of the trading day: PRE_OPEN, OPENING_AUCTION, CONTINUOUS, CLOSING_AUCTION, CLOSED
Market maker A participant with role MARKET_MAKER who quotes two-sided prices
Circuit breaker Automatic halt triggered when price moves beyond a configured threshold
Drop copy A copy of all fill events published to a dedicated socket for compliance systems

See also