1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//! # 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
//!
//! ```ignore
//! 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,
//! },
//! })?;
//! # 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
pub use crateMarketConfig;
pub use crate;
pub use crate;