ccxt_exchanges/binance/rest/futures/
positions.rs1use super::super::super::{Binance, parser};
4use ccxt_core::{Error, ParseError, Result, types::Position};
5use serde_json::Value;
6use std::sync::Arc;
7use tracing::warn;
8
9impl Binance {
10 pub async fn fetch_position(&self, symbol: &str, params: Option<Value>) -> Result<Position> {
12 let market = self.base().market(symbol).await?;
13
14 let url = if market.linear.unwrap_or(true) {
15 format!("{}/positionRisk", self.urls().fapi_private)
16 } else {
17 format!("{}/positionRisk", self.urls().dapi_private)
18 };
19
20 let data = self
21 .signed_request(url)
22 .param("symbol", &market.id)
23 .merge_json_params(params)
24 .execute()
25 .await?;
26
27 let positions_array = data.as_array().ok_or_else(|| {
28 Error::from(ParseError::invalid_format(
29 "data",
30 "Expected array of positions",
31 ))
32 })?;
33
34 for position_data in positions_array {
35 if let Some(pos_symbol) = position_data["symbol"].as_str() {
36 if pos_symbol == market.id {
37 return parser::parse_position(position_data, Some(&market));
38 }
39 }
40 }
41
42 Err(Error::from(ParseError::missing_field_owned(format!(
43 "Position not found for symbol: {}",
44 symbol
45 ))))
46 }
47
48 pub async fn fetch_positions(
50 &self,
51 symbols: Option<Vec<String>>,
52 params: Option<Value>,
53 ) -> Result<Vec<Position>> {
54 let use_coin_m = params
55 .as_ref()
56 .and_then(|p| p.get("type"))
57 .and_then(serde_json::Value::as_str)
58 .is_some_and(|t| t == "delivery" || t == "coin_m");
59
60 let url = if use_coin_m {
61 format!("{}/positionRisk", self.urls().dapi_private)
62 } else {
63 format!("{}/positionRisk", self.urls().fapi_private)
64 };
65
66 let data = self
67 .signed_request(url)
68 .merge_json_params(params)
69 .execute()
70 .await?;
71
72 let positions_array = data.as_array().ok_or_else(|| {
73 Error::from(ParseError::invalid_format(
74 "data",
75 "Expected array of positions",
76 ))
77 })?;
78
79 let cache = self.base().market_cache.read().await;
80 let markets_snapshot: std::collections::HashMap<String, Arc<ccxt_core::types::Market>> =
81 cache
82 .iter_markets()
83 .map(|(_, m)| (m.id.clone(), m))
84 .collect();
85 drop(cache);
86
87 let mut positions = Vec::new();
88 for position_data in positions_array {
89 if let Some(binance_symbol) = position_data["symbol"].as_str() {
90 if let Some(market) = markets_snapshot.get(binance_symbol) {
91 match parser::parse_position(position_data, Some(market)) {
92 Ok(position) => {
93 if position.contracts.unwrap_or(0.0) > 0.0 {
94 if let Some(ref syms) = symbols {
95 if syms.contains(&position.symbol) {
96 positions.push(position);
97 }
98 } else {
99 positions.push(position);
100 }
101 }
102 }
103 Err(e) => {
104 warn!(
105 error = %e,
106 symbol = %binance_symbol,
107 "Failed to parse position"
108 );
109 }
110 }
111 }
112 }
113 }
114
115 Ok(positions)
116 }
117
118 pub async fn fetch_positions_risk(
120 &self,
121 symbols: Option<Vec<String>>,
122 params: Option<Value>,
123 ) -> Result<Vec<Position>> {
124 self.fetch_positions(symbols, params).await
125 }
126
127 pub async fn fetch_position_risk(
129 &self,
130 symbol: Option<&str>,
131 params: Option<Value>,
132 ) -> Result<Value> {
133 let market_id = if let Some(sym) = symbol {
134 let market = self.base().market(sym).await?;
135 Some(market.id.clone())
136 } else {
137 None
138 };
139
140 let url = format!("{}/positionRisk", self.urls().fapi_private);
141
142 self.signed_request(url)
143 .optional_param("symbol", market_id)
144 .merge_json_params(params)
145 .execute()
146 .await
147 }
148}