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:
- Commands arrive via the
Enginehandler (e.g., PlaceOrder, CancelOrder) - Validation happens in
EngineRoot::handleagainst current state - Events are emitted describing state changes (e.g., OrderAccepted, TradeMatched)
- WAL persists events durably before acknowledgment
- 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 recoverycross_match: Multi-leg cross-matching for 3-runner marketstypes: Core domain types (Money, OrderId, OddsX10000, etc.)config: Engine and market configurationsnapshot: 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