From crypto-infra-skills
Use when designing or reviewing a crypto/financial matching engine. Covers order book data structures, matching algorithms (price-time priority, pro-rata), Go-side architecture (hexagonal/clean), single-pair vs multi-pair, in-memory vs persistent, hot-path optimization, and concurrency patterns. Use whenever the user mentions order book, matching engine, exchange backend, CEX architecture, limit order, or order matching.
How this skill is triggered — by the user, by Claude, or both
Slash command
/crypto-infra-skills:category-matching-engineThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Trigger this skill when the user asks to:
Trigger this skill when the user asks to:
Before any code:
Write these as a one-page spec before touching code. They drive every design choice downstream.
For price-time priority matching:
OrderBook
├── BidSide: sorted descending by price (best bid = highest)
│ └── PriceLevel
│ ├── price
│ └── orders: FIFO list of orders at this price
└── AskSide: sorted ascending by price (best ask = lowest)
└── PriceLevel (same shape)
Implementation choices:
| Structure | Insert | Best price | Trade-off |
|---|---|---|---|
| Red-black tree (price levels) + doubly-linked list (orders) | O(log P) | O(1) | Mature, predictable. Most production engines. |
| Skip list | O(log P) | O(1) | Easier to make concurrent |
| Sorted array | O(P) | O(1) | Only works if price range is small |
| HashMap<price, level> + sorted price list | O(log P) | O(1) | Common, with TreeMap or skip list for the price ordering |
P = number of price levels (typically 10s to 1000s, not millions).
Practical pick: map[price]*PriceLevel + a sorted slice or skip list of prices. Go's sync.Map is NOT what you want here — use a regular map with explicit locking, the access pattern is too structured for sync.Map's tradeoffs.
For an incoming buy order at price P:
1. Walk ask side from best (lowest) ask upward
2. For each ask level where ask_price <= P:
3. For each order at this level (in FIFO order):
4. match = min(incoming.remaining, resting.remaining)
5. emit fill event (incoming, resting, match, level_price)
6. decrement both
7. if resting fully filled: remove from level
8. if incoming fully filled: stop
9. if level empty: remove level from ask side
10. if incoming has remainder and is limit: add to bid side at price P
if remainder and is market: cancel (or partial fill report)
Two invariants to verify in tests:
┌──────────────────────────┐
Order API ──▶ │ │ ──▶ Event sink (Kafka, etc.)
│ Domain: MatchingEngine │
Admin API ──▶ │ │ ──▶ State snapshot
└──────────────────────────┘ ──▶ Metrics
│
▼
Pluggable storage (in-memory, Redis, etc.)
Domain layer (pure Go, no I/O):
OrderBook, Order, Fill, PriceLevelMatchingEngine.SubmitOrder(order) -> []FillApplication layer:
Adapter layer:
The domain layer is where your tests live. It should run thousands of orders/sec with zero I/O.
The cardinal rule: one engine per pair, one goroutine per engine.
Input channel ──▶ [Engine goroutine] ──▶ Output channel
│
└── owns the OrderBook exclusively
Why not multi-goroutine matching?
When you outgrow single-goroutine:
In-memory engines are fast but lose state on crash. Options:
Event sourcing (recommended):
Snapshot + replay:
Trade-offs:
For a single-pair engine: event sourcing + snapshot every N events. Replay should be <60s from snapshot.
If you've measured a real bottleneck (and only then):
sync.Pool for Order and Fill structs.interface{} boxing. Specialize containers.Don't do any of this before profiling. Premature optimization here usually makes code worse without measurable wins.
Language choice (Go vs Rust). Go is idiomatic and fast enough for most CEX hot paths; the techniques above are Go-flavored. Rust is the other top pick when you need predictable tail latency (no GC pauses) — common for the most latency-sensitive engines. Rust equivalents of the above:
sync.Pool → arena / typed-arena or a pre-sized Vec slab + free-list; reuse Order/Fill slots.impl Trait); reserve dyn Trait for cold paths.#[repr(C)] / field ordering; crossbeam for lock-free queues between stages.#[inline] hot fns, avoid Box/String in the match loop, SmallVec for bounded collections.Result + ? over panics; see [[incremental-implementation]] for the full idiom list.Whichever language: measure first (pprof/benchstat for Go, cargo flamegraph/criterion for Rust), and check [[web3-backend-reviewer]] §11 for the language-idiom review lens.
Each pair = independent engine instance + goroutine + input/output channels.
Router (round-robin or pair-based hash)
├── BTC-USD engine
├── ETH-USD engine
└── SOL-USD engine
Cross-pair concerns (e.g., position margin across pairs) live OUTSIDE the matching engines, in a separate risk service that consumes the output streams.
| Excuse | Reality |
|---|---|
| "We need lock-free data structures for performance" | Channels + single goroutine per pair beats lock-free for 99% of crypto matching workloads. Less code, fewer bugs. |
| "Let's start with Postgres for the order book" | A relational DB in the matching hot path is a dealbreaker for any non-toy volume. In-memory + WAL is the standard. |
| "We'll add persistence later" | Adding event sourcing after the engine exists is a months-long retrofit. Design it in from day one. |
| "Pro-rata is fairer than price-time" | It's also slower to implement and harder to audit. Use price-time unless you have a specific reason for pro-rata. |
| "We don't need market orders, just limit" | Market orders are a UX requirement for retail. Just IOC-with-no-price under the hood. |
Before considering the engine production-ready:
If reviewing or extending a single-pair, in-memory, hexagonal Go matching engine:
Strengths to highlight in portfolio context:
Common gaps to address:
Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub hryer/crypto-infra-skills --plugin crypto-infra-skills