opendeviationbar_core/
trade.rs1use crate::fixed_point::FixedPoint;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
10#[cfg_attr(feature = "api", derive(utoipa::ToSchema))]
11pub enum DataSource {
12 BinanceSpot,
14 #[default]
16 BinanceFuturesUM,
17 BinanceFuturesCM,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
26#[cfg_attr(feature = "api", derive(utoipa::ToSchema))]
27pub struct AggTrade {
28 pub agg_trade_id: i64,
30
31 pub price: FixedPoint,
33
34 pub volume: FixedPoint,
36
37 pub first_trade_id: i64,
39
40 pub last_trade_id: i64,
42
43 pub timestamp: i64,
45
46 pub is_buyer_maker: bool,
49
50 #[serde(skip_serializing_if = "Option::is_none")]
53 pub is_best_match: Option<bool>,
54}
55
56impl AggTrade {
57 #[inline]
63 pub fn individual_trade_count(&self) -> i64 {
64 self.last_trade_id - self.first_trade_id + 1
65 }
66
67 #[inline]
70 pub fn turnover(&self) -> i128 {
71 (self.price.0 as i128) * (self.volume.0 as i128)
72 }
73}
74
75#[cfg(test)]
77mod tests {
78 use super::*;
79
80 fn make_trade(price: &str, volume: &str, first_id: i64, last_id: i64) -> AggTrade {
81 AggTrade {
82 agg_trade_id: 1,
83 price: FixedPoint::from_str(price).unwrap(),
84 volume: FixedPoint::from_str(volume).unwrap(),
85 first_trade_id: first_id,
86 last_trade_id: last_id,
87 timestamp: 1000,
88 is_buyer_maker: false,
89 is_best_match: None,
90 }
91 }
92
93 #[test]
94 fn test_individual_trade_count_single() {
95 let trade = make_trade("100.0", "1.0", 5, 5);
96 assert_eq!(trade.individual_trade_count(), 1);
97 }
98
99 #[test]
100 fn test_individual_trade_count_multiple() {
101 let trade = make_trade("100.0", "1.0", 100, 199);
102 assert_eq!(trade.individual_trade_count(), 100);
103 }
104
105 #[test]
106 fn test_individual_trade_count_large_range() {
107 let trade = make_trade("100.0", "1.0", 0, 999_999);
108 assert_eq!(trade.individual_trade_count(), 1_000_000);
109 }
110
111 #[test]
112 fn test_turnover_basic() {
113 let trade = make_trade("100.0", "2.0", 1, 1);
115 let expected = 10_000_000_000i128 * 200_000_000i128;
116 assert_eq!(trade.turnover(), expected);
117 }
118
119 #[test]
120 fn test_turnover_zero_volume() {
121 let trade = make_trade("100.0", "0.0", 1, 1);
122 assert_eq!(trade.turnover(), 0);
123 }
124
125 #[test]
126 fn test_turnover_large_values_no_overflow() {
127 let trade = make_trade("0.00002", "10000000000.0", 1, 1);
130 let turnover = trade.turnover();
131 assert!(turnover > 0, "Turnover should be positive for valid trade");
132 let _as_f64 = turnover as f64;
134 }
135
136 #[test]
137 fn test_turnover_tiny_price() {
138 let trade = make_trade("0.00000001", "1.0", 1, 1);
139 assert_eq!(trade.turnover(), 100_000_000);
141 }
142}