Skip to main content

pragma_common/entries/
position.rs

1use super::trade::TradeSide;
2use crate::{instrument_type::InstrumentType, pair::Pair};
3#[cfg(feature = "proto")]
4use crate::{ProtoDeserialize, ProtoSerialize};
5#[cfg(feature = "proto")]
6use prost::Message;
7#[derive(Debug, Clone, PartialEq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[cfg_attr(
10    feature = "borsh",
11    derive(borsh::BorshSerialize, borsh::BorshDeserialize)
12)]
13#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
14pub struct PositionEntry {
15    pub source: String,
16    pub instrument_type: InstrumentType,
17    pub pair: Pair,
18    pub timestamp_ms: i64,
19    pub received_timestamp_ms: i64,
20    pub side: TradeSide,
21    pub notional_in_usd: f64,
22    pub size: f64,
23}
24#[cfg(feature = "proto")]
25impl PositionEntry {
26    fn to_proto(&self) -> crate::schema::PositionEntry {
27        crate::schema::PositionEntry {
28            source: self.source.clone(),
29            instrument_type: match self.instrument_type {
30                InstrumentType::Spot => crate::schema::InstrumentType::Spot as i32,
31                InstrumentType::Perp => crate::schema::InstrumentType::Perp as i32,
32            },
33            pair: Some(crate::schema::Pair {
34                base: self.pair.base.clone(),
35                quote: self.pair.quote.clone(),
36            }),
37            timestamp_ms: self.timestamp_ms,
38            received_timestamp_ms: self.received_timestamp_ms,
39            side: match self.side {
40                TradeSide::Buy => crate::schema::TradeSide::Buy as i32,
41                TradeSide::Sell => crate::schema::TradeSide::Sell as i32,
42            },
43            notional_in_usd: self.notional_in_usd,
44            size: self.size,
45        }
46    }
47    fn from_proto(proto: crate::schema::PositionEntry) -> Result<Self, prost::DecodeError> {
48        let pair = proto
49            .pair
50            .ok_or_else(|| prost::DecodeError::new("Missing pair field in PositionEntry"))?;
51
52        let instrument_type = match proto.instrument_type {
53            x if x == crate::schema::InstrumentType::Spot as i32 => InstrumentType::Spot,
54            x if x == crate::schema::InstrumentType::Perp as i32 => InstrumentType::Perp,
55            _ => {
56                return Err(prost::DecodeError::new(format!(
57                    "Invalid instrument_type value: {}",
58                    proto.instrument_type,
59                )))
60            }
61        };
62
63        let side = match proto.side {
64            x if x == crate::schema::TradeSide::Buy as i32 => TradeSide::Buy,
65            x if x == crate::schema::TradeSide::Sell as i32 => TradeSide::Sell,
66            _ => {
67                return Err(prost::DecodeError::new(format!(
68                    "Invalid side value: {}",
69                    proto.side,
70                )))
71            }
72        };
73
74        Ok(PositionEntry {
75            source: proto.source,
76            instrument_type,
77            pair: Pair {
78                base: pair.base,
79                quote: pair.quote,
80            },
81            timestamp_ms: proto.timestamp_ms,
82            received_timestamp_ms: proto.received_timestamp_ms,
83            side,
84            notional_in_usd: proto.notional_in_usd,
85            size: proto.size,
86        })
87    }
88}
89#[cfg(feature = "proto")]
90impl ProtoSerialize for PositionEntry {
91    fn to_proto_bytes(&self) -> Vec<u8> {
92        let proto = self.to_proto();
93        let mut buf = Vec::new();
94        proto
95            .encode(&mut buf)
96            .expect("Failed to encode PositionEntry to protobuf");
97        buf
98    }
99}
100#[cfg(feature = "proto")]
101impl ProtoDeserialize for PositionEntry {
102    fn from_proto_bytes(bytes: &[u8]) -> Result<Self, prost::DecodeError> {
103        let proto = crate::schema::PositionEntry::decode(bytes)?;
104        Self::from_proto(proto)
105    }
106}