use super::types::*;
use crate::{
book::protocol::command::{Persistence, Side, TimeInForce},
types::*,
};
use betex_macros::TaggedEnumBridge;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use smallvec::SmallVec;
use std::fmt;
pub type EventVec = SmallVec<[BookEventEnvelope; 4]>;
pub type EventMetadata = Option<Value>;
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub struct RunnerResultEntry {
pub runner_id: RunnerId,
pub runner_label: String,
pub result: RunnerResult,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub void_factor: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deadheat_factor: Option<String>,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub struct BookEventEnvelope {
pub market_id: MarketId,
pub market_name: String,
pub market_seq: u64,
#[rkyv(with = crate::types::DateTimeUtcAsUnixMillis)]
pub timestamp: DateTime,
#[rkyv(with = crate::types::JsonValueOptionAsStringOption)]
pub metadata: EventMetadata,
pub event: BookEvent,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum CancelCause {
UserCancel,
Replace,
FokRemainder,
BatchCancel,
CloseCancel,
SuspendLapse,
InPlayLapse,
RunnerRemoved,
Admin,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub struct CancelledOrderEntry {
pub order_id: OrderId,
pub account_id: AccountId,
pub correlation_id: Option<CorrelationId>,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub struct OrderCancellationCursor {
pub order_id: OrderId,
pub account_id: AccountId,
}
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TradeRole {
Maker,
Taker,
}
#[derive(
Debug,
Clone,
PartialEq,
Eq,
TaggedEnumBridge,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum BookEvent {
MarketCreated {
correlation_id: Option<CorrelationId>,
name: String,
market_model: MarketModel,
market_kind: MarketKind,
market_phase: MarketPhase,
runner_ids: Vec<RunnerId>,
runner_labels: Vec<String>,
},
MarketStateChanged {
to: BookMarketState,
reason: String,
},
MarketPhaseChanged {
to: MarketPhase,
reason: String,
},
OrderAccepted {
correlation_id: Option<CorrelationId>,
order_id: OrderId,
account_id: AccountId,
runner_id: RunnerId,
runner_label: String,
side: Side,
price: OddsX10000,
stake: Money,
persistence: Persistence,
time_in_force: TimeInForce,
},
BinaryOrderAccepted {
correlation_id: Option<CorrelationId>,
order_id: OrderId,
account_id: AccountId,
side: Side,
price_ticks: u16,
qty_shares: u64,
time_in_force: TimeInForce,
},
OrderCancelled {
cancelled_order: CancelledOrderEntry,
cancel_cause: CancelCause,
cause_detail: Option<String>,
},
OrderCancelledBatched {
cancelled_orders: Vec<CancelledOrderEntry>,
cursor_after: Option<OrderCancellationCursor>,
cancel_cause: CancelCause,
cause_detail: Option<String>,
},
TradeMatched {
correlation_id: Option<CorrelationId>,
order_id: OrderId,
account_id: AccountId,
role: TradeRole,
runner_id: RunnerId,
runner_label: String,
side: Side,
market_phase: MarketPhase,
price: OddsX10000,
stake: Money,
counter_party: OrderId,
counter_party_account_id: AccountId,
remaining_stake: Money,
matched_delta: Money,
},
BinaryTradeMatched {
correlation_id: Option<CorrelationId>,
order_id: OrderId,
account_id: AccountId,
role: TradeRole,
side: Side,
market_phase: MarketPhase,
price_ticks: u16,
counter_party: OrderId,
counter_party_account_id: AccountId,
remaining_qty_shares: u64,
matched_delta_shares: u64,
},
VoidTrades {
market_phase: MarketPhase,
#[rkyv(with = crate::types::DateTimeUtcAsUnixMillis)]
start_time: DateTime,
#[rkyv(with = crate::types::DateTimeUtcAsUnixMillis)]
end_time: DateTime,
void_reason: String,
},
RunnerRemoved {
runner_id: RunnerId,
runner_label: String,
reduction_factor_bps: Option<u32>,
},
MarketSettled {
runner_results: Vec<RunnerResultEntry>,
void_reason: String,
},
BatchCancelStarted {
batch_max_events: u16,
started_at_ms: i64,
from_created_at_inclusive_ms: Option<i64>,
to_created_at_inclusive_ms: Option<i64>,
account_filter: Option<AccountId>,
runner_filter: Option<RunnerId>,
reason: String,
final_event_metadata_json: Option<String>,
},
BatchProcessCompleted {
cancel_cause: CancelCause,
},
MarketRemoved {
reason: String,
},
}
impl fmt::Display for BookEventEnvelope {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"BOOK_EVENT_ENVELOPE market_id={:?} market_name={} timestamp_ms={} event={}",
self.market_id,
self.market_name,
self.timestamp.timestamp_millis(),
self.event
)
}
}
impl fmt::Display for BookEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let kind = match self {
BookEvent::MarketCreated { .. } => "MARKET_CREATED",
BookEvent::MarketStateChanged { .. } => "MARKET_STATE_CHANGED",
BookEvent::MarketPhaseChanged { .. } => "MARKET_PHASE_CHANGED",
BookEvent::OrderAccepted { .. } => "ORDER_ACCEPTED",
BookEvent::BinaryOrderAccepted { .. } => "BINARY_ORDER_ACCEPTED",
BookEvent::OrderCancelled { .. } => "ORDER_CANCELLED",
BookEvent::OrderCancelledBatched { .. } => "ORDER_CANCELLED_BATCHED",
BookEvent::TradeMatched { .. } => "TRADE_MATCHED",
BookEvent::BinaryTradeMatched { .. } => "BINARY_TRADE_MATCHED",
BookEvent::VoidTrades { .. } => "VOID_TRADES",
BookEvent::RunnerRemoved { .. } => "RUNNER_REMOVED",
BookEvent::MarketSettled { .. } => "MARKET_SETTLED",
BookEvent::BatchCancelStarted { .. } => "BATCH_CANCEL_STARTED",
BookEvent::BatchProcessCompleted { .. } => "BATCH_PROCESS_COMPLETED",
BookEvent::MarketRemoved { .. } => "MARKET_REMOVED",
};
f.write_str(kind)
}
}