Skip to main content

Crate betex

Crate betex 

Source
Expand description

§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::*;
use betex::engine::consumers::ResponseCallbackHandler;

// Create engine with markets
let config = Config::default();
let engine = EngineBuilder::with_markets(
    config,
    [MarketConfig::TwoRunner {
        market_id: MarketId(1),
        name: "Match Odds".to_string(),
        runner_a: RunnerId(1),
        runner_b: RunnerId(2),
        market_kind: MarketKind::InPlayCapable,
        market_state: BookMarketState::Open,
        market_phase: MarketPhase::Pre,
    }],
    "/tmp/wal",
)?
.register_handler(ResponseCallbackHandler::default(), HandlerRecovery::LiveOnly, None)
.build()?;

// Submit orders
engine.submit(Command {
    correlation_id: Some(CorrelationId("11111111-1111-1111-1111-111111111111".into())),
    market_id: MarketId(1),
    kind: CommandKind::PlaceOrder {
        runner_id: RunnerId(1),
        account_id: AccountId::from(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,
    },
})?;

§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

Re-exports§

pub use crate::engine::state::MarketConfig;
pub use crate::engine::core::CommandLane;
pub use crate::engine::core::Engine;
pub use crate::engine::core::EngineBuilder;
pub use crate::engine::core::EngineEvent;
pub use crate::engine::core::HandlerRecovery;
pub use crate::engine::journal::JournalEvent;
pub use crate::engine::journal::JournalReader;
pub use crate::snapshot::BinaryMarketSnapshot;
pub use crate::snapshot::ExchangeMarketSnapshot;
pub use crate::snapshot::MarketBookSnapshot;
pub use crate::snapshot::MarketSnapshot;
pub use crate::snapshot::RunnerRefSnapshot;
pub use crate::snapshot::RunnerSnapshot;
pub use crate::snapshot::SnapshotPriceSelection;
pub use crate::snapshot::SnapshotPriceSelections;

Modules§

book
Single-market, deterministic order book module.
config
cross_match
Cross-matching engine for multi-runner markets.
disruptor
engine
error
idempotency
metrics
prelude
snapshot
Market snapshot types for bot synchronization.
types

Macros§

btx_metrics_init
metric
metric_field
metrics_stage