◆PRISMMatch

08 / 12Prism Systems · FinTech & Banking

An exchange core that matches, settles and replays to the exact same state

A price-time priority central limit order book with limit, market, stop, stop-limit, IOC, FOK, DAY and post-only orders, self-trade prevention, price bands and market collars, a double-entry multi-currency ledger with funds holds and maker/taker fees, a FIX 4.4 session layer and TCP gateway, and a deterministic input journal that replays to an identical state hash.

Zero dependenciesInteger fixed-pointFIX 4.4 + TCP gatewayDouble-entry ledgerDeterministic replay
Live simulator

A live BTC-USD order book with market makers, takers and stops

Three market makers quote post-only ladders and six takers trade against them. Send your own orders through a real FIX session, plant a stop cluster and let a whale sell through it, or pull the makers and watch the spread blow out.

paused
BTC-USD · central limit order book
Price · mid vs last
Trades / s by aggressor
Order ticket via FIX 4.4
My open orders
FIX wire seq —
Tape & events
Features

What's inside the engine

Real algorithms, not mock-ups. The simulator above runs the exact same code you import.

⇅

Price-time priority

Price levels are kept sorted best-first with binary search, each level is a FIFO queue, and cancels are O(1) through lazy deletion with periodic compaction.

◧

Every order type

Limit, market (converted to IOC with a 2% collar), stop and stop-limit, with GTC, IOC, FOK (pre-checked for full liquidity) and DAY, plus post-only that rejects instead of taking.

⛨

Pre-trade risk

Tick and lot checks, a fat-finger price band around the last price, max order size, funds holds at the worst possible price, and self-trade prevention (cancel-resting or cancel-taker).

⚖

Double-entry ledger

Each fill posts balanced legs for base, quote and maker/taker fees. Balances split into available and held, and verify() proves every currency sums to zero.

⌁

FIX 4.4

Encoder and parser with BodyLength and CheckSum, a session with Logon, sequence-gap ResendRequest, session Reject, and D/F/G mapped to ExecutionReport and OrderCancelReject.

↺

Cancel / replace

Reducing quantity keeps queue priority, changing price or increasing size re-queues at the back, and a replace that crosses matches immediately.

⚡

Stops that cascade

Stops trigger on the last trade price and fire as market or limit orders, which can move the price and trigger the next stop in the same command.

#

Deterministic replay

Commands are journaled before execution. Replaying the journal into a fresh engine reproduces the same SHA-256 hash over books, stops, balances and sequence numbers.

How it works

From request to result

Validate

Symbol, side, type and TIF are checked, then tick, lot, price band and max size. A market order gets a collar price so it can never sweep the whole book.

Hold funds

Buyers hold quote at the worst price plus the max fee, sellers hold base. Orders without funds are rejected before touching the book.

Match

The order walks the opposite side best price first and FIFO within a level, applying self-trade prevention. FOK checks available quantity first.

Settle

Each fill posts a balanced journal entry: base and quote move between accounts, fees go to the fee account, unused holds are released.

Rest or finish

Leftover GTC/DAY quantity rests in the book, IOC remainders cancel, then stops are checked against the new last price.

Architecture

System design

Every box is a module in src/. Data flows left to right.

last pxfillsGATEWAYSFIX 4.4 sessionseq · checksumJS APIsubmit · cancel · replaceSEQUENCERInput journalreplayablePre-trade riskband · funds · STPMATCHINGOrder booksprice-time FIFOStop booktrigger on lastPOST-TRADELedgerdouble-entryExec reportstape · settlement
Use it

Ship it in your own stack

Zero dependencies. Works in Node.js 18+ and modern browsers.

example.js
import { Engine, FixSession, FixClient, toUnits } from "prism-matching-engine";

const ex = new Engine({ fees: { maker: 2, taker: 10 }, stp: "cancel-resting" });   // bps
ex.ledger.deposit("alice", "BTC", BigInt(toUnits("2")));
ex.ledger.deposit("bob", "USD", BigInt(toUnits("200000")));

ex.submit({ account: "alice", symbol: "BTC-USD", side: "sell", px: "65000.50", qty: "1.2" });
const r = ex.submit({ account: "bob", symbol: "BTC-USD", side: "buy", type: "market", qty: "0.5" });
r.trades;    // [{ id: "T1", px: 6500050000000, qty: 50000000, buyer: "bob", seller: "alice", ... }]
r.reports;   // execution reports: new / trade / canceled / rejected / replaced / triggered

ex.submit({ account: "alice", symbol: "BTC-USD", side: "sell", type: "stop", stopPx: "64980", qty: "0.3" });
ex.replace("O1", { qty: "1.0" });          // smaller qty keeps queue priority
ex.book("BTC-USD").depth(5);               // { bids: [{ px, qty, orders }], asks: [...] }
ex.ledger.verify();                        // { ok: true } — every currency sums to zero

const again = Engine.replay(ex.input, {}, seedDeposits);
again.stateHash() === ex.stateHash();      // true

const fix = new FixSession(ex), cl = new FixClient();
fix.handle(cl.logon());
fix.handle(cl.order({ clOrdId: "a1", account: "bob", symbol: "BTC-USD", side: "buy", px: "65000.50", qty: "0.1", tif: "IOC" }));
terminal
$ npx github:krishyaa06/prism-matching-engine demo
$ npx github:krishyaa06/prism-matching-engine book --secs 30
$ npx github:krishyaa06/prism-matching-engine fix examples/orders.fix
$ npx github:krishyaa06/prism-matching-engine bench --orders 300000
$ npx github:krishyaa06/prism-matching-engine replay
$ npx github:krishyaa06/prism-matching-engine serve --port 9878
terminal
# use the CLI without installing
$ npx github:krishyaa06/prism-matching-engine --help

# or add the engine to your project
$ npm install github:krishyaa06/prism-matching-engine

# run the simulator locally
$ git clone https://github.com/krishyaa06/prism-matching-engine.git && cd prism-matching-engine
$ npx serve .   # then open http://localhost:3000