5 releases

Uses new Rust 2024

new 0.5.3 Feb 10, 2026
0.5.2 Feb 7, 2026
0.5.1 Feb 5, 2026
0.5.0 Feb 5, 2026
0.4.0 Feb 4, 2026

#1433 in Database interfaces

Custom license

545KB
14K SLoC

BetEx Engine

A high-performance, event-sourced order matching engine for sports betting exchanges and prediction markets.

Event Sourcing Model

The engine uses a command → events → WAL → handlers architecture:

  1. Commands arrive via the Engine handler (e.g., PlaceOrder, CancelOrder)
  2. Validation happens in EngineRoot::handle against current state
  3. Events are emitted describing state changes (e.g., OrderAccepted, TradeMatched)
  4. WAL persists events durably before acknowledgment
  5. Handlers receive events via the disruptor for downstream processing

Key Guarantees

  • Durability: Events are written to the WAL before response callbacks fire
  • Ordering: Events are strictly ordered by sequence number
  • Determinism: Replaying the same event sequence produces identical state
  • Atomicity: Multi-event commands (trades) commit or rollback together

Market Models

The engine supports two market models:

  • ExchangeOdds: Traditional sports betting with BACK/LAY sides at decimal odds (e.g., 2.50 means "win $1.50 for every $1 staked")
  • BinaryYes: Prediction markets with BUY/SELL sides at tick prices (0-10000 basis points)

Quick Start

use betex::prelude::*;

// Create engine with markets
let config = Config::default();
let engine = EngineBuilder::with_markets(
    config,
    [MarketConfig::two_runner(
        MarketId(1),
        RunnerId(1),
        RunnerId(2),
        MarketKind::InPlayCapable,
    )],
    "/tmp/wal",
)?.build()?;

// Submit orders
engine.submit(Command {
    correlation_id: CorrelationId(1),
    market_id: MarketId(1),
    kind: CommandKind::PlaceOrder {
        runner_id: RunnerId(1),
        account_id: AccountId(1),
        client_order_id: None,
        side: Side::Yes,
        odds: OddsX10000(20000), // 2.0
        stake: Money(10000),     // $1.00
        persistence: Persistence::Persist,
        time_in_force: TimeInForce::Gtc,
    },
})?;
# Ok::<(), anyhow::Error>(())

Module Overview

  • book: Order book implementations (two-runner, multi-runner, binary prediction)
  • engine: Core engine and builder with WAL recovery
  • cross_match: Multi-leg cross-matching for 3-runner markets
  • types: Core domain types (Money, OrderId, OddsX10000, etc.)
  • config: Engine and market configuration
  • snapshot: Market state snapshots for external consumption
  • stream: Event streaming for downstream consumers

Dependencies

~13–20MB
~274K SLoC