use digdigdig3::core::types::{OrderbookDelta, StreamEvent};
use serde::{Deserialize, Serialize};
use crate::series::DataPoint;
pub const OB_DELTA_LEVELS_PER_SIDE: usize = 25;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObDeltaPoint {
pub ts_ms: i64,
pub bid_changes: Vec<(f64, f64)>,
pub ask_changes: Vec<(f64, f64)>,
}
const PAIR: usize = 16; const SIDE_BYTES: usize = OB_DELTA_LEVELS_PER_SIDE * PAIR;
const SIZE: usize = 8 + SIDE_BYTES + SIDE_BYTES;
impl ObDeltaPoint {
pub fn from_delta(d: &OrderbookDelta) -> Self {
let bid_changes = d
.bids
.iter()
.take(OB_DELTA_LEVELS_PER_SIDE)
.map(|l| (l.price, l.size))
.collect();
let ask_changes = d
.asks
.iter()
.take(OB_DELTA_LEVELS_PER_SIDE)
.map(|l| (l.price, l.size))
.collect();
Self { ts_ms: d.timestamp, bid_changes, ask_changes }
}
}
impl DataPoint for ObDeltaPoint {
const RECORD_SIZE: usize = SIZE;
fn encode(&self, out: &mut [u8]) {
out[0..8].copy_from_slice(&(self.ts_ms as u64).to_le_bytes());
encode_side(&self.bid_changes, &mut out[8..(8 + SIDE_BYTES)]);
encode_side(&self.ask_changes, &mut out[(8 + SIDE_BYTES)..(8 + 2 * SIDE_BYTES)]);
}
fn decode(bytes: &[u8]) -> Option<Self> {
if bytes.len() != SIZE { return None; }
let ts_ms = u64::from_le_bytes(bytes[0..8].try_into().ok()?) as i64;
let bid_changes = decode_side(&bytes[8..(8 + SIDE_BYTES)]);
let ask_changes = decode_side(&bytes[(8 + SIDE_BYTES)..(8 + 2 * SIDE_BYTES)]);
Some(Self { ts_ms, bid_changes, ask_changes })
}
fn timestamp_ms(&self) -> i64 { self.ts_ms }
fn from_stream_event(ev: &StreamEvent) -> Option<Self> {
if let StreamEvent::OrderbookDelta { delta, .. } = ev {
Some(Self::from_delta(delta))
} else {
None
}
}
}
fn encode_side(levels: &[(f64, f64)], out: &mut [u8]) {
for (i, (p, q)) in levels.iter().take(OB_DELTA_LEVELS_PER_SIDE).enumerate() {
let off = i * PAIR;
out[off..off + 8].copy_from_slice(&p.to_le_bytes());
out[off + 8..off + 16].copy_from_slice(&q.to_le_bytes());
}
}
fn decode_side(bytes: &[u8]) -> Vec<(f64, f64)> {
let mut out = Vec::with_capacity(OB_DELTA_LEVELS_PER_SIDE);
for i in 0..OB_DELTA_LEVELS_PER_SIDE {
let off = i * PAIR;
let p = f64::from_le_bytes(bytes[off..off + 8].try_into().unwrap_or_default());
let q = f64::from_le_bytes(bytes[off + 8..off + 16].try_into().unwrap_or_default());
if p == 0.0 && q == 0.0 {
break;
}
out.push((p, q));
}
out
}