Skip to main content

digdigdig3_station/data/
agg_trade.rs

1use digdigdig3::core::types::{StreamEvent, TradeSide};
2use serde::{Deserialize, Serialize};
3
4use crate::series::DataPoint;
5
6/// 48 B record — same shape as TradePoint but separate kind / disk slot.
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct AggTradePoint {
9    pub ts_ms: i64,
10    pub price: f64,
11    pub quantity: f64,
12    pub side: u8,
13    pub agg_id: u64,
14}
15
16const SIZE: usize = 48;
17
18impl DataPoint for AggTradePoint {
19    const RECORD_SIZE: usize = SIZE;
20
21    fn encode(&self, out: &mut [u8]) {
22        out[0..8].copy_from_slice(&(self.ts_ms as u64).to_le_bytes());
23        out[8..16].copy_from_slice(&self.price.to_le_bytes());
24        out[16..24].copy_from_slice(&self.quantity.to_le_bytes());
25        out[24] = self.side;
26        out[25..33].copy_from_slice(&self.agg_id.to_le_bytes());
27    }
28
29    fn decode(bytes: &[u8]) -> Option<Self> {
30        if bytes.len() != SIZE { return None; }
31        Some(Self {
32            ts_ms: u64::from_le_bytes(bytes[0..8].try_into().ok()?) as i64,
33            price: f64::from_le_bytes(bytes[8..16].try_into().ok()?),
34            quantity: f64::from_le_bytes(bytes[16..24].try_into().ok()?),
35            side: bytes[24],
36            agg_id: u64::from_le_bytes(bytes[25..33].try_into().ok()?),
37        })
38    }
39
40    fn timestamp_ms(&self) -> i64 { self.ts_ms }
41
42    fn from_stream_event(ev: &StreamEvent) -> Option<Self> {
43        if let StreamEvent::AggTrade { price, quantity, side, timestamp, aggregate_id, .. } = ev {
44            let s = match side {
45                TradeSide::Buy => 0,
46                TradeSide::Sell => 1,
47            };
48            Some(Self {
49                ts_ms: *timestamp,
50                price: *price,
51                quantity: *quantity,
52                side: s,
53                agg_id: *aggregate_id as u64,
54            })
55        } else {
56            None
57        }
58    }
59}