Skip to main content

bybit_rust_api/ws/private/
position.rs

1//! Position stream — real-time position updates.
2//!
3//! # Topics
4//! - `position` (all categories)
5//! - `position.linear`, `position.inverse`, `position.option`
6
7use serde::Deserialize;
8
9/// Position data from private WebSocket.
10#[derive(Debug, Clone, Deserialize)]
11pub struct PositionData {
12    /// Position index (0 = one-way, 1/2 = hedge mode)
13    #[serde(rename = "positionIdx")]
14    #[serde(default)]
15    pub position_idx: Option<i32>,
16    /// Risk ID
17    #[serde(rename = "riskId")]
18    #[serde(default)]
19    pub risk_id: Option<i32>,
20    /// Symbol
21    #[serde(rename = "symbol")]
22    #[serde(default)]
23    pub symbol: Option<String>,
24    /// Side: "Buy" or "Sell" (empty for spot)
25    #[serde(rename = "side")]
26    #[serde(default)]
27    pub side: Option<String>,
28    /// Position size
29    #[serde(rename = "size")]
30    #[serde(default)]
31    pub size: Option<String>,
32    /// Position value
33    #[serde(rename = "positionValue")]
34    #[serde(default)]
35    pub position_value: Option<String>,
36    /// Entry price
37    #[serde(rename = "entryPrice")]
38    #[serde(default)]
39    pub entry_price: Option<String>,
40    /// Trade mode: 0=cross, 1=isolated
41    #[serde(rename = "tradeMode")]
42    #[serde(default)]
43    pub trade_mode: Option<i32>,
44    /// Auto add margin: 0=off, 1=on
45    #[serde(rename = "autoAddMargin")]
46    #[serde(default)]
47    pub auto_add_margin: Option<i32>,
48    /// Leverage
49    #[serde(rename = "leverage")]
50    #[serde(default)]
51    pub leverage: Option<String>,
52    /// Position status: "Normal", "Liq", "Adl"
53    #[serde(rename = "positionStatus")]
54    #[serde(default)]
55    pub position_status: Option<String>,
56    /// Mark price
57    #[serde(rename = "markPrice")]
58    #[serde(default)]
59    pub mark_price: Option<String>,
60    /// Liquidation price
61    #[serde(rename = "liqPrice")]
62    #[serde(default)]
63    pub liq_price: Option<String>,
64    /// Bankruptcy price
65    #[serde(rename = "bustPrice")]
66    #[serde(default)]
67    pub bust_price: Option<String>,
68    /// Unrealised PnL
69    #[serde(rename = "unrealisedPnl")]
70    #[serde(default)]
71    pub unrealised_pnl: Option<String>,
72    /// Cumulative realised PnL
73    #[serde(rename = "cumRealisedPnl")]
74    #[serde(default)]
75    pub cum_realised_pnl: Option<String>,
76    /// Take profit price
77    #[serde(rename = "takeProfit")]
78    #[serde(default)]
79    pub take_profit: Option<String>,
80    /// Stop loss price
81    #[serde(rename = "stopLoss")]
82    #[serde(default)]
83    pub stop_loss: Option<String>,
84    /// Trailing stop
85    #[serde(rename = "trailingStop")]
86    #[serde(default)]
87    pub trailing_stop: Option<String>,
88    /// Position IM (initial margin)
89    #[serde(rename = "positionIM")]
90    #[serde(default)]
91    pub position_im: Option<String>,
92    /// Position MM (maintenance margin)
93    #[serde(rename = "positionMM")]
94    #[serde(default)]
95    pub position_mm: Option<String>,
96    /// Created timestamp
97    #[serde(rename = "createdTime")]
98    #[serde(default)]
99    pub created_time: Option<String>,
100    /// Updated timestamp
101    #[serde(rename = "updatedTime")]
102    #[serde(default)]
103    pub updated_time: Option<String>,
104    /// Category
105    #[serde(rename = "category")]
106    #[serde(default)]
107    pub category: Option<String>,
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_parse_position() {
116        let json = serde_json::json!({
117            "positionIdx": 0,
118            "symbol": "BTCUSDT",
119            "side": "Buy",
120            "size": "0.5",
121            "entryPrice": "50000.00",
122            "markPrice": "50100.00",
123            "unrealisedPnl": "50.00",
124            "leverage": "10",
125            "category": "linear"
126        });
127
128        let pos: PositionData = serde_json::from_value(json).unwrap();
129        assert_eq!(pos.symbol.as_deref(), Some("BTCUSDT"));
130        assert_eq!(pos.side.as_deref(), Some("Buy"));
131        assert_eq!(pos.size.as_deref(), Some("0.5"));
132    }
133}