rustrade_execution/
position.rs1use chrono::{DateTime, Utc};
2use derive_more::Constructor;
3use rust_decimal::Decimal;
4use serde::{Deserialize, Serialize};
5
6#[derive(
11 Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, Constructor,
12)]
13pub struct Position {
14 pub quantity: Decimal,
19
20 pub entry_price: Option<Decimal>,
22
23 pub unrealized_pnl: Option<Decimal>,
25
26 pub margin_used: Option<Decimal>,
28
29 pub liquidation_price: Option<Decimal>,
31
32 pub leverage: Option<Decimal>,
34
35 pub time_exchange: DateTime<Utc>,
37}
38
39impl Position {
40 pub fn is_flat(&self) -> bool {
42 self.quantity.is_zero()
43 }
44
45 pub fn is_long(&self) -> bool {
47 self.quantity.is_sign_positive() && !self.quantity.is_zero()
48 }
49
50 pub fn is_short(&self) -> bool {
52 self.quantity.is_sign_negative()
53 }
54
55 pub fn abs_quantity(&self) -> Decimal {
57 self.quantity.abs()
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use rust_decimal_macros::dec;
65
66 #[test]
67 fn test_position_side_detection() {
68 let now = Utc::now();
69
70 let long = Position::new(dec!(1.5), None, None, None, None, None, now);
71 assert!(long.is_long());
72 assert!(!long.is_short());
73 assert!(!long.is_flat());
74
75 let short = Position::new(dec!(-1.5), None, None, None, None, None, now);
76 assert!(!short.is_long());
77 assert!(short.is_short());
78 assert!(!short.is_flat());
79
80 let flat = Position::new(dec!(0), None, None, None, None, None, now);
81 assert!(!flat.is_long());
82 assert!(!flat.is_short());
83 assert!(flat.is_flat());
84 }
85
86 #[test]
87 fn test_abs_quantity() {
88 let now = Utc::now();
89 let short = Position::new(dec!(-2.5), None, None, None, None, None, now);
90 assert_eq!(short.abs_quantity(), dec!(2.5));
91 }
92}