use std::num::NonZeroU64;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Symbol(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OrderId(pub u64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AccountId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct CurrencyId(pub u32);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AccountBalance {
pub currency: CurrencyId,
pub free: u64,
pub reserved: u64,
}
impl AccountBalance {
pub const ZERO: Self = Self {
currency: CurrencyId(0),
free: 0,
reserved: 0,
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InstrumentSpec {
pub symbol: Symbol,
pub base: CurrencyId,
pub quote: CurrencyId,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct RiskLimits {
pub max_order_qty: Option<Quantity>,
pub max_order_notional: Option<u64>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct CircuitBreakerConfig {
pub price_band_lower: Option<Price>,
pub price_band_upper: Option<Price>,
pub halted: bool,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct FeeSchedule {
pub maker_fee_bps: i16,
pub taker_fee_bps: i16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Price(pub NonZeroU64);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Quantity(pub NonZeroU64);
impl Quantity {
pub fn get(self) -> u64 {
self.0.get()
}
pub fn checked_sub(self, other: Quantity) -> Option<Quantity> {
self.0
.get()
.checked_sub(other.0.get())
.and_then(NonZeroU64::new)
.map(Quantity)
}
pub fn min(self, other: Quantity) -> Quantity {
Quantity(self.0.min(other.0))
}
}
impl Price {
pub fn get(self) -> u64 {
self.0.get()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum InstrumentStatus {
Enabled = 0,
Disabled = 1,
Removed = 2,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Side {
Buy,
Sell,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OrderType {
Market,
Limit { price: Price, post_only: bool },
Stop { trigger_price: Price },
StopLimit {
trigger_price: Price,
limit_price: Price,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TimeInForce {
GTC,
IOC,
FOK,
Day,
GTD,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SelfTradeProtection {
Allow,
#[default]
CancelNewest,
CancelOldest,
CancelBoth,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Order {
pub id: OrderId,
pub account: AccountId,
pub side: Side,
pub order_type: OrderType,
pub time_in_force: TimeInForce,
pub quantity: Quantity,
pub stp: SelfTradeProtection,
pub expiry_ns: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExecutionReport {
Placed {
order_id: OrderId,
symbol: Symbol,
account: AccountId,
side: Side,
price: Price,
quantity: Quantity,
},
Fill {
maker_order_id: OrderId,
taker_order_id: OrderId,
symbol: Symbol,
maker_account: AccountId,
taker_account: AccountId,
price: Price,
quantity: Quantity,
maker_fee: i64,
taker_fee: i64,
},
Cancelled {
order_id: OrderId,
symbol: Symbol,
account: AccountId,
remaining_quantity: Quantity,
},
Triggered {
order_id: OrderId,
symbol: Symbol,
account: AccountId,
trigger_price: Price,
},
Rejected {
order_id: OrderId,
symbol: Symbol,
account: AccountId,
reason: RejectReason,
},
Replaced {
order_id: OrderId,
symbol: Symbol,
account: AccountId,
side: Side,
old_price: Price,
new_price: Price,
old_remaining: Quantity,
new_remaining: Quantity,
},
InstrumentStatusChanged {
symbol: Symbol,
status: InstrumentStatus,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(clippy::large_enum_variant)]
pub enum QueryResponse {
Stats {
active_connections: u64,
events_processed: u64,
journal_sequence: u64,
},
Position {
account: AccountId,
balances: [AccountBalance; 16],
count: u8,
},
RequestSeqHwm { hwm: u64 },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RejectReason {
NoLiquidity,
FOKCannotFill,
InsufficientBalance,
UnknownAccount,
UnknownSymbol,
SelfTradePrevented,
DuplicateOrderId,
ExceedsMaxOrderQty,
ExceedsMaxNotional,
TradingHalted,
OutsidePriceBand,
UnknownOrder,
PriceWouldCross,
PostOnlyWouldCross,
HasRestingOrders,
DuplicateRequest,
ReplicaDisconnected,
Superseded,
InvalidExpiry,
InstrumentDisabled,
ExceedsMaxOpenOrders,
ExceedsOrderRate,
}
#[cfg(test)]
mod tests {
use super::*;
fn qty(n: u64) -> Quantity {
Quantity(NonZeroU64::new(n).unwrap())
}
#[test]
fn quantity_checked_sub_partial() {
assert_eq!(qty(10).checked_sub(qty(3)), Some(qty(7)));
}
#[test]
fn quantity_checked_sub_exact_returns_none() {
assert_eq!(qty(10).checked_sub(qty(10)), None);
}
#[test]
fn quantity_checked_sub_overflow_returns_none() {
assert_eq!(qty(3).checked_sub(qty(10)), None);
}
#[test]
fn niche_optimization() {
assert_eq!(
std::mem::size_of::<Option<Price>>(),
std::mem::size_of::<Price>()
);
assert_eq!(
std::mem::size_of::<Option<Quantity>>(),
std::mem::size_of::<Quantity>()
);
}
}