use super::super::super::{Binance, parser};
use ccxt_core::{Error, ParseError, Result, types::Position};
use serde_json::Value;
use std::sync::Arc;
use tracing::warn;
impl Binance {
pub async fn fetch_position(&self, symbol: &str, params: Option<Value>) -> Result<Position> {
let market = self.base().market(symbol).await?;
let url = if market.linear.unwrap_or(true) {
format!("{}/positionRisk", self.urls().fapi_private)
} else {
format!("{}/positionRisk", self.urls().dapi_private)
};
let data = self
.signed_request(url)
.param("symbol", &market.id)
.merge_json_params(params)
.execute()
.await?;
let positions_array = data.as_array().ok_or_else(|| {
Error::from(ParseError::invalid_format(
"data",
"Expected array of positions",
))
})?;
for position_data in positions_array {
if let Some(pos_symbol) = position_data["symbol"].as_str() {
if pos_symbol == market.id {
return parser::parse_position(position_data, Some(&market));
}
}
}
Err(Error::from(ParseError::missing_field_owned(format!(
"Position not found for symbol: {}",
symbol
))))
}
pub async fn fetch_positions(
&self,
symbols: Option<Vec<String>>,
params: Option<Value>,
) -> Result<Vec<Position>> {
let use_coin_m = params
.as_ref()
.and_then(|p| p.get("type"))
.and_then(serde_json::Value::as_str)
.is_some_and(|t| t == "delivery" || t == "coin_m");
let url = if use_coin_m {
format!("{}/positionRisk", self.urls().dapi_private)
} else {
format!("{}/positionRisk", self.urls().fapi_private)
};
let data = self
.signed_request(url)
.merge_json_params(params)
.execute()
.await?;
let positions_array = data.as_array().ok_or_else(|| {
Error::from(ParseError::invalid_format(
"data",
"Expected array of positions",
))
})?;
let cache = self.base().market_cache.read().await;
let markets_snapshot: std::collections::HashMap<String, Arc<ccxt_core::types::Market>> =
cache
.iter_markets()
.map(|(_, m)| (m.id.clone(), m))
.collect();
drop(cache);
let mut positions = Vec::new();
for position_data in positions_array {
if let Some(binance_symbol) = position_data["symbol"].as_str() {
if let Some(market) = markets_snapshot.get(binance_symbol) {
match parser::parse_position(position_data, Some(market)) {
Ok(position) => {
if position.contracts.unwrap_or(0.0) > 0.0 {
if let Some(ref syms) = symbols {
if syms.contains(&position.symbol) {
positions.push(position);
}
} else {
positions.push(position);
}
}
}
Err(e) => {
warn!(
error = %e,
symbol = %binance_symbol,
"Failed to parse position"
);
}
}
}
}
}
Ok(positions)
}
pub async fn fetch_positions_risk(
&self,
symbols: Option<Vec<String>>,
params: Option<Value>,
) -> Result<Vec<Position>> {
self.fetch_positions(symbols, params).await
}
pub async fn fetch_position_risk(
&self,
symbol: Option<&str>,
params: Option<Value>,
) -> Result<Value> {
let market_id = if let Some(sym) = symbol {
let market = self.base().market(sym).await?;
Some(market.id.clone())
} else {
None
};
let url = format!("{}/positionRisk", self.urls().fapi_private);
self.signed_request(url)
.optional_param("symbol", market_id)
.merge_json_params(params)
.execute()
.await
}
}