Skip to main content

Command Palette

Search for a command to run...

Understanding CQRS in Trading Systems: A Beginner's Guide with ElysiaJS

Published
5 min read
Understanding CQRS in Trading Systems: A Beginner's Guide with ElysiaJS

Introduction

Trading systems are not ordinary software systems.

They process high-velocity writes, serve read-heavy analytics, demand low latency, and must remain correct under failure.
Trying to handle all of this with a single data model often leads to complexity, contention, and fragile systems.

This is where CQRS (Command Query Responsibility Segregation) becomes a powerful architectural choice.

Instead of forcing one model to handle everything, CQRS embraces a simple but profound idea:

Writes and reads have fundamentally different responsibilities—and should be treated differently.

In this article, we’ll explore:

  • What CQRS really is (beyond the definition)

  • Why it fits trading and quantitative finance so well

  • Real CQRS use cases in trading engines

  • Trade-offs and when not to use CQRS

  • A hands-on CQRS implementation using ElysiaJS


What Is CQRS?

CQRS (Command Query Responsibility Segregation) is an architectural pattern that separates state-changing operations from read-only operations into distinct models.

Core CQRS Models

1. Command Model (Write Side)

Responsible for changing the system state.

Examples in trading:

  • Place order

  • Cancel order

  • Modify position

  • Rebalance portfolio

Commands:

  • Represent intent

  • Perform validation

  • Enforce business rules

  • Produce state changes (often as events)

2. Query Model (Read Side)

Responsible for data retrieval and projections.

Examples in trading:

  • Fetch order book

  • Retrieve trade history

  • Compute PnL

  • Display portfolio snapshot

Queries:

  • Are side-effect-free

  • Optimized for fast reads

  • Often backed by denormalized views

Key Rule:
👉 Commands never return data. Queries never modify state.


Why CQRS Matters in Trading Systems

Trading platforms are naturally write-constrained and read-intensive.

The Core Tension

  • Writes must be correct, ordered, and validated

  • Reads must be fast, scalable, and flexible

  • Combining both leads to:

    • Lock contention

    • Complex schemas

    • Latency spikes

    • Fragile code paths

CQRS resolves this by decoupling concerns.


CQRS Use Cases in Trading & Quantitative Finance

1. Order Management Systems (OMS)

Command Side

  • PlaceOrder

  • CancelOrder

  • AmendOrder

Strict validation:

  • Risk checks

  • Balance checks

  • Order state transitions

Query Side

  • Open orders

  • Order history

  • Execution reports

Each optimized independently.


2. Portfolio & Position Management

Commands

  • ApplyTrade

  • AdjustPosition

  • RebalancePortfolio

Queries

  • Portfolio snapshot

  • Exposure breakdown

  • Greeks / risk metrics

This separation is especially valuable for real-time dashboards.


3. Market Data & Analytics

Market data ingestion often updates internal state, while quants need:

  • Fast reads

  • Aggregations

  • Rolling statistics

CQRS allows:

  • Write pipeline for ingestion

  • Read-optimized projections for analytics


4. Backtesting & Simulation Engines

Commands replay historical trades.
Queries compute:

  • PnL

  • Drawdown

  • Sharpe ratio

This aligns naturally with event-driven CQRS systems.


5. Risk & Compliance Systems

Commands:

  • Update limits

  • Block trading

  • Trigger liquidations

Queries:

  • Audit logs

  • Exposure views

  • Compliance reports

CQRS improves traceability and auditability.


CQRS vs CRUD in Trading Systems

AspectCRUDCQRS
ModelSingleSplit read/write
ScalabilityLimitedHigh
Read optimizationHardEasy
Write validationMixedCentralized
Trading suitabilityLowHigh

CQRS + Event-Driven Architectures

CQRS pairs naturally with Event Sourcing (though it doesn’t require it).

Typical flow:

  1. Command validates intent

  2. State changes occur

  3. Events are emitted

  4. Read models update asynchronously

This enables:

  • Replay

  • Auditing

  • Deterministic recovery


When Not to Use CQRS

CQRS introduces complexity. Avoid it when:

  • The system is small

  • Reads and writes are trivial

  • You don’t need scale or flexibility

CQRS is an architectural investment, not a default.


Hands-On Tutorial: CQRS with ElysiaJS (Trading Example)

Let’s build a minimal CQRS trading service using ElysiaJS.


Step 1: Project Setup

bun init
bun add elysia
import { Elysia } from "elysia"

Step 2: Define Domain Commands

Commands represent intent, not implementation.

type PlaceOrderCommand = {
  orderId: string
  symbol: string
  side: "BUY" | "SELL"
  quantity: number
  price: number
}

Step 3: Command Handler (Write Model)

const orders = new Map<string, any>()

function handlePlaceOrder(cmd: PlaceOrderCommand) {
  if (cmd.quantity <= 0) throw new Error("Invalid quantity")

  orders.set(cmd.orderId, {
    ...cmd,
    status: "OPEN"
  })
}

Step 4: Query Model (Read-Optimized View)

function getOpenOrders() {
  return Array.from(orders.values()).filter(
    o => o.status === "OPEN"
  )
}

Note:

  • Query does not mutate state

  • Optimized for fast reads


Step 5: Expose Command & Query APIs

const app = new Elysia()

// Command endpoint
app.post("/orders", ({ body }) => {
  handlePlaceOrder(body)
  return { status: "accepted" }
})

// Query endpoint
app.get("/orders/open", () => {
  return getOpenOrders()
})

app.listen(3000)

Step 6: Enforcing CQRS Discipline

RuleEnforced By
Commands don’t return dataAPI contract
Queries don’t change stateRead-only functions
Business rules live in commandsDomain layer

Extending This for Real Trading Systems

To make this production-grade, we can include the following:

  • Add event emission

  • Persist commands/events

  • Build async read projections

  • Introduce Saga workflows

  • Add idempotency

  • Add deterministic replay

CQRS becomes the backbone for:

  • Trading engines

  • Portfolio services

  • Risk systems

  • Quant pipelines


Final Thoughts & Conclusion

CQRS is not about complexity—it’s about clarity of responsibility.

In trading and quantitative finance, where:

  • Writings must be correct

  • Reads must be fast

  • Failures must be recoverable

CQRS provides a clean, scalable mental model.

The real power emerges when CQRS is combined with:

  • Event-driven systems

  • Durable workflows

  • Deterministic execution

The question isn’t “Should I use CQRS?”
It’s “Where does separating intent from observation unlock leverage in my system?”

You can read more about Deterministic systems in my previous article on Optimizing Trading Engine Workflow