pragma_common/entries/
trade.rs1#[cfg(feature = "proto")]
2use prost::Message;
3
4use crate::{instrument_type::InstrumentType, pair::Pair, trading::Side};
5#[cfg(feature = "proto")]
6use crate::{ProtoDeserialize, ProtoSerialize};
7
8#[derive(Debug, Clone, PartialEq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10#[cfg_attr(
11 feature = "borsh",
12 derive(borsh::BorshSerialize, borsh::BorshDeserialize)
13)]
14#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
15pub struct TradeEntry {
16 pub source: String,
17 pub instrument_type: InstrumentType,
18 pub pair: Pair,
19 pub trade_id: String,
20 pub buyer_address: String,
21 pub seller_address: String,
22 pub side: TradeSide,
23 pub size: f64,
24 pub price: f64,
25 pub timestamp_ms: i64,
26 pub received_timestamp_ms: i64,
27}
28
29#[derive(Debug, Clone, PartialEq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31#[cfg_attr(
32 feature = "borsh",
33 derive(borsh::BorshSerialize, borsh::BorshDeserialize)
34)]
35#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
36pub enum TradeSide {
37 Buy,
38 Sell,
39}
40
41impl From<TradeSide> for Side {
42 fn from(value: TradeSide) -> Self {
43 match value {
44 TradeSide::Buy => Self::Long,
45 TradeSide::Sell => Self::Short,
46 }
47 }
48}
49
50#[cfg(feature = "proto")]
51impl TradeEntry {
52 fn to_proto(&self) -> crate::schema::TradeEntry {
53 crate::schema::TradeEntry {
54 source: self.source.clone(),
55 instrument_type: match self.instrument_type {
56 InstrumentType::Spot => crate::schema::InstrumentType::Spot as i32,
57 InstrumentType::Perp => crate::schema::InstrumentType::Perp as i32,
58 },
59 pair: Some(crate::schema::Pair {
60 base: self.pair.base.clone(),
61 quote: self.pair.quote.clone(),
62 }),
63 buyer_address: self.buyer_address.clone(),
64 seller_address: self.seller_address.clone(),
65 trade_id: self.trade_id.clone(),
66 side: match self.side {
67 TradeSide::Buy => crate::schema::TradeSide::Buy as i32,
68 TradeSide::Sell => crate::schema::TradeSide::Sell as i32,
69 },
70 size: self.size,
71 price: self.price,
72 timestamp_ms: self.timestamp_ms,
73 received_timestamp_ms: self.received_timestamp_ms,
74 }
75 }
76
77 fn from_proto(proto: crate::schema::TradeEntry) -> Result<Self, prost::DecodeError> {
78 let pair = proto
79 .pair
80 .ok_or_else(|| prost::DecodeError::new("Missing pair field in TradeEntry"))?;
81
82 let instrument_type = match proto.instrument_type {
83 x if x == crate::schema::InstrumentType::Spot as i32 => InstrumentType::Spot,
84 x if x == crate::schema::InstrumentType::Perp as i32 => InstrumentType::Perp,
85 _ => {
86 return Err(prost::DecodeError::new(format!(
87 "Invalid instrument_type value: {}",
88 proto.instrument_type,
89 )))
90 }
91 };
92
93 let side = match proto.side {
94 x if x == crate::schema::TradeSide::Buy as i32 => TradeSide::Buy,
95 x if x == crate::schema::TradeSide::Sell as i32 => TradeSide::Sell,
96 _ => {
97 return Err(prost::DecodeError::new(format!(
98 "Invalid side value: {}",
99 proto.side,
100 )))
101 }
102 };
103
104 Ok(TradeEntry {
105 source: proto.source,
106 instrument_type,
107 pair: Pair {
108 base: pair.base,
109 quote: pair.quote,
110 },
111 trade_id: proto.trade_id.clone(),
112 buyer_address: proto.buyer_address.clone(),
113 seller_address: proto.seller_address.clone(),
114 side,
115 size: proto.size,
116 price: proto.price,
117 timestamp_ms: proto.timestamp_ms,
118 received_timestamp_ms: proto.received_timestamp_ms,
119 })
120 }
121}
122
123#[cfg(feature = "proto")]
124impl ProtoSerialize for TradeEntry {
125 fn to_proto_bytes(&self) -> Vec<u8> {
126 let proto = self.to_proto();
127 let mut buf = Vec::new();
128 proto
129 .encode(&mut buf)
130 .expect("Failed to encode VolumeEntry to protobuf");
131 buf
132 }
133}
134
135#[cfg(feature = "proto")]
136impl ProtoDeserialize for TradeEntry {
137 fn from_proto_bytes(bytes: &[u8]) -> Result<Self, prost::DecodeError> {
138 let proto = crate::schema::TradeEntry::decode(bytes)?;
139 Self::from_proto(proto)
140 }
141}