#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct Level {
pub px_1e9: u64, pub sz_1e8: u64, }
impl Level {
pub const EMPTY: Self = Self {
px_1e9: 0,
sz_1e8: 0,
};
#[inline(always)]
pub fn is_valid(&self) -> bool {
self.px_1e9 > 0
}
}
#[derive(Clone, Copy)]
#[repr(C)]
pub struct L2Book {
pub bids: [Level; 20], pub asks: [Level; 20], pub bid_ct: u8, pub ask_ct: u8, pub symbol_id: u16,
pub _pad: u32,
pub recv_ns: u64, }
impl Default for L2Book {
fn default() -> Self {
Self {
bids: [Level::EMPTY; 20],
asks: [Level::EMPTY; 20],
bid_ct: 0,
ask_ct: 0,
symbol_id: 0,
_pad: 0,
recv_ns: 0,
}
}
}
impl L2Book {
#[inline(always)]
pub fn best_bid(&self) -> Option<&Level> {
if self.bid_ct > 0 && self.bids[0].px_1e9 > 0 {
Some(&self.bids[0])
} else {
None
}
}
#[inline(always)]
pub fn best_ask(&self) -> Option<&Level> {
if self.ask_ct > 0 && self.asks[0].px_1e9 > 0 {
Some(&self.asks[0])
} else {
None
}
}
#[inline(always)]
pub fn mid_px_1e9(&self) -> u64 {
if self.bid_ct == 0 || self.ask_ct == 0 {
return 0;
}
(self.bids[0].px_1e9 + self.asks[0].px_1e9) / 2
}
#[inline(always)]
pub fn spread_1e9(&self) -> u64 {
if self.bid_ct == 0 || self.ask_ct == 0 {
return u64::MAX;
}
self.asks[0].px_1e9.saturating_sub(self.bids[0].px_1e9)
}
#[inline(always)]
pub fn spread_signed_1e9(&self) -> i64 {
if self.bid_ct == 0 || self.ask_ct == 0 {
return i64::MAX;
}
self.asks[0].px_1e9 as i64 - self.bids[0].px_1e9 as i64
}
#[inline(always)]
pub fn spread_bps(&self) -> u32 {
let mid = self.mid_px_1e9();
if mid == 0 {
return u32::MAX;
}
((self.spread_1e9() * 10_000) / mid) as u32
}
#[inline(always)]
pub fn spread_bps_x1000(&self) -> i32 {
let mid = self.mid_px_1e9();
if mid == 0 {
return i32::MAX;
}
let spread = self.asks[0].px_1e9 as i128 - self.bids[0].px_1e9 as i128;
((spread * 10_000_000) / mid as i128) as i32
}
#[inline(always)]
pub fn is_crossed(&self) -> bool {
self.bid_ct > 0 && self.ask_ct > 0 && self.bids[0].px_1e9 > self.asks[0].px_1e9
}
#[inline(always)]
pub fn bid_depth_1e8(&self, levels: usize) -> u64 {
let n = levels.min(self.bid_ct as usize);
let mut sum = 0u64;
for i in 0..n {
sum += self.bids[i].sz_1e8;
}
sum
}
#[inline(always)]
pub fn ask_depth_1e8(&self, levels: usize) -> u64 {
let n = levels.min(self.ask_ct as usize);
let mut sum = 0u64;
for i in 0..n {
sum += self.asks[i].sz_1e8;
}
sum
}
#[inline(always)]
pub fn imbalance_bps(&self, levels: usize) -> i32 {
let bid_depth = self.bid_depth_1e8(levels);
let ask_depth = self.ask_depth_1e8(levels);
let total = bid_depth + ask_depth;
if total == 0 {
return 0;
}
(((bid_depth as i64 - ask_depth as i64) * 10_000) / total as i64) as i32
}
}