Skip to main content

deribit_http/model/response/
position.rs

1/******************************************************************************
2   Author: Joaquín Béjar García
3   Email: jb@taunais.com
4   Date: 7/3/26
5******************************************************************************/
6//! Position response models
7
8use pretty_simple_display::{DebugPretty, DisplaySimple};
9use serde::{Deserialize, Serialize};
10
11/// Result of a single position move trade
12///
13/// Represents the outcome of moving a position between subaccounts.
14#[derive(DebugPretty, DisplaySimple, Clone, PartialEq, Serialize, Deserialize)]
15pub struct MovePositionResult {
16    /// Instrument name (e.g., "BTC-PERPETUAL")
17    pub instrument_name: String,
18    /// Trade direction from source perspective ("buy" or "sell")
19    pub direction: String,
20    /// Price of the trade
21    pub price: f64,
22    /// Trade amount (USD for perpetual/inverse, base currency for options/linear)
23    pub amount: f64,
24    /// Source subaccount ID
25    pub source_uid: i64,
26    /// Target subaccount ID
27    pub target_uid: i64,
28}
29
30impl MovePositionResult {
31    /// Create a new move position result
32    pub fn new(
33        instrument_name: impl Into<String>,
34        direction: impl Into<String>,
35        price: f64,
36        amount: f64,
37        source_uid: i64,
38        target_uid: i64,
39    ) -> Self {
40        Self {
41            instrument_name: instrument_name.into(),
42            direction: direction.into(),
43            price,
44            amount,
45            source_uid,
46            target_uid,
47        }
48    }
49
50    /// Check if this is a buy trade
51    pub fn is_buy(&self) -> bool {
52        self.direction == "buy"
53    }
54
55    /// Check if this is a sell trade
56    pub fn is_sell(&self) -> bool {
57        self.direction == "sell"
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_move_position_result_new() {
67        let result = MovePositionResult::new("BTC-PERPETUAL", "buy", 35800.0, 110.0, 3, 23);
68        assert_eq!(result.instrument_name, "BTC-PERPETUAL");
69        assert_eq!(result.direction, "buy");
70        assert_eq!(result.price, 35800.0);
71        assert_eq!(result.amount, 110.0);
72        assert_eq!(result.source_uid, 3);
73        assert_eq!(result.target_uid, 23);
74    }
75
76    #[test]
77    fn test_move_position_result_is_buy() {
78        let result = MovePositionResult::new("BTC-PERPETUAL", "buy", 35800.0, 110.0, 3, 23);
79        assert!(result.is_buy());
80        assert!(!result.is_sell());
81    }
82
83    #[test]
84    fn test_move_position_result_is_sell() {
85        let result = MovePositionResult::new("BTC-PERPETUAL", "sell", 35800.0, 110.0, 3, 23);
86        assert!(result.is_sell());
87        assert!(!result.is_buy());
88    }
89
90    #[test]
91    fn test_move_position_result_deserialization() {
92        let json = r#"{
93            "instrument_name": "BTC-PERPETUAL",
94            "direction": "buy",
95            "price": 35800.0,
96            "amount": 110.0,
97            "source_uid": 3,
98            "target_uid": 23
99        }"#;
100
101        let result: MovePositionResult = serde_json::from_str(json).unwrap();
102        assert_eq!(result.instrument_name, "BTC-PERPETUAL");
103        assert_eq!(result.direction, "buy");
104        assert_eq!(result.price, 35800.0);
105        assert_eq!(result.amount, 110.0);
106        assert_eq!(result.source_uid, 3);
107        assert_eq!(result.target_uid, 23);
108    }
109}