digdigdig3_station/data/
position_update.rs1use digdigdig3::core::types::StreamEvent;
2use serde::{Deserialize, Serialize};
3
4use crate::series::DataPoint;
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub struct PositionUpdatePoint {
19 pub ts_ms: i64,
20 pub side: u8,
22 pub qty: f64,
23 pub entry_price: f64,
24 pub mark_price: f64,
25 pub unrealized_pnl: f64,
26 pub realized_pnl: f64,
27 pub liquidation_price: f64,
28}
29
30const SIZE: usize = 64;
31
32impl PositionUpdatePoint {
33 pub fn side_label(&self) -> &'static str {
34 match self.side {
35 0 => "Long",
36 1 => "Short",
37 _ => "Net",
38 }
39 }
40}
41
42impl DataPoint for PositionUpdatePoint {
43 const RECORD_SIZE: usize = SIZE;
44
45 fn encode(&self, out: &mut [u8]) {
46 out[0..8].copy_from_slice(&(self.ts_ms as u64).to_le_bytes());
47 out[8] = self.side;
48 out[16..24].copy_from_slice(&self.qty.to_le_bytes());
50 out[24..32].copy_from_slice(&self.entry_price.to_le_bytes());
51 out[32..40].copy_from_slice(&self.mark_price.to_le_bytes());
52 out[40..48].copy_from_slice(&self.unrealized_pnl.to_le_bytes());
53 out[48..56].copy_from_slice(&self.realized_pnl.to_le_bytes());
54 out[56..64].copy_from_slice(&self.liquidation_price.to_le_bytes());
55 }
56
57 fn decode(bytes: &[u8]) -> Option<Self> {
58 if bytes.len() != SIZE {
59 return None;
60 }
61 let ts_ms = u64::from_le_bytes(bytes[0..8].try_into().ok()?) as i64;
62 let side = bytes[8];
63 let qty = f64::from_le_bytes(bytes[16..24].try_into().ok()?);
64 let entry_price = f64::from_le_bytes(bytes[24..32].try_into().ok()?);
65 let mark_price = f64::from_le_bytes(bytes[32..40].try_into().ok()?);
66 let unrealized_pnl = f64::from_le_bytes(bytes[40..48].try_into().ok()?);
67 let realized_pnl = f64::from_le_bytes(bytes[48..56].try_into().ok()?);
68 let liquidation_price = f64::from_le_bytes(bytes[56..64].try_into().ok()?);
69 Some(Self {
70 ts_ms,
71 side,
72 qty,
73 entry_price,
74 mark_price,
75 unrealized_pnl,
76 realized_pnl,
77 liquidation_price,
78 })
79 }
80
81 fn timestamp_ms(&self) -> i64 {
82 self.ts_ms
83 }
84
85 fn from_stream_event(ev: &StreamEvent) -> Option<Self> {
86 if let StreamEvent::PositionUpdate { event, .. } = ev {
87 use digdigdig3::core::types::PositionSide;
88 let side = match event.side {
89 PositionSide::Long => 0,
90 PositionSide::Short => 1,
91 PositionSide::Both => 2,
92 };
93 Some(Self {
94 ts_ms: event.timestamp,
95 side,
96 qty: event.quantity,
97 entry_price: event.entry_price,
98 mark_price: event.mark_price.unwrap_or(0.0),
99 unrealized_pnl: event.unrealized_pnl,
100 realized_pnl: event.realized_pnl.unwrap_or(0.0),
101 liquidation_price: event.liquidation_price.unwrap_or(0.0),
102 })
103 } else {
104 None
105 }
106 }
107}