1use crate::prelude::*;
2
3#[derive(Clone)]
4pub struct PositionManager {
5 pub client: Client,
6 pub recv_window: u16,
7}
8
9impl PositionManager {
10 pub async fn get_info<'b>(&self, req: PositionRequest<'_>) -> Result<InfoResponse, BybitError> {
37 let mut parameters: BTreeMap<String, String> = BTreeMap::new();
38 parameters.insert("category".into(), req.category.as_str().into());
39 if let Some(v) = req.symbol {
40 parameters.insert("symbol".into(), v.into());
41 }
42 if let Some(v) = req.base_coin {
43 parameters.insert("baseCoin".into(), v.into());
44 }
45 if let Some(v) = req.settle_coin {
46 parameters.insert("settleCoin".into(), v.into());
47 }
48 if let Some(v) = req.limit {
49 parameters.insert("limit".into(), v.to_string());
50 }
51 let request = build_request(¶meters);
52 let response: InfoResponse = self
53 .client
54 .get_signed(
55 API::Position(Position::Information),
56 self.recv_window,
57 Some(request),
58 )
59 .await?;
60 Ok(response)
61 }
62
63 pub async fn set_leverage<'b>(
73 &self,
74 req: LeverageRequest<'_>,
75 ) -> Result<LeverageResponse, BybitError> {
76 let mut parameters: BTreeMap<String, String> = BTreeMap::new();
77 parameters.insert("category".into(), req.category.as_str().into());
78 parameters.insert("symbol".into(), req.symbol.into());
79 parameters.insert("buyLeverage".into(), req.leverage.to_string());
80 parameters.insert("sellLeverage".into(), req.leverage.to_string());
81 let request = build_json_request(¶meters);
82 let response: LeverageResponse = self
83 .client
84 .post_signed(
85 API::Position(Position::SetLeverage),
86 self.recv_window,
87 Some(request),
88 )
89 .await?;
90 Ok(response)
91 }
92
93 pub async fn set_margin_mode<'b>(
103 &self,
104 req: ChangeMarginRequest<'_>,
105 ) -> Result<ChangeMarginResponse, BybitError> {
106 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
107 parameters.insert("category".into(), req.category.as_str().into());
108 parameters.insert("symbol".into(), req.symbol.into());
109 parameters.insert("tradeMode".into(), req.trade_mode.into());
110 let request = build_json_request(¶meters);
111 let response: ChangeMarginResponse = self
112 .client
113 .post_signed(
114 API::Position(Position::SwitchIsolated),
115 self.recv_window,
116 Some(request),
117 )
118 .await?;
119 Ok(response)
120 }
121
122 pub async fn set_position_mode<'b>(
132 &self,
133 req: MarginModeRequest<'_>,
134 ) -> Result<MarginModeResponse, BybitError> {
135 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
136 parameters.insert("category".into(), req.category.as_str().into());
137 if let Some(v) = req.symbol {
138 parameters.insert("symbol".into(), v.into());
139 }
140 if let Some(v) = req.coin {
141 parameters.insert("coin".into(), v.into());
142 }
143 parameters.insert("mode".into(), req.mode.into());
144 let request = build_json_request(¶meters);
145 let response: MarginModeResponse = self
146 .client
147 .post_signed(
148 API::Position(Position::SwitchMode),
149 self.recv_window,
150 Some(request),
151 )
152 .await?;
153 Ok(response)
154 }
155
156 pub async fn set_risk_limit<'b>(
166 &self,
167 req: SetRiskLimit<'_>,
168 ) -> Result<SetRiskLimitResponse, BybitError> {
169 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
170 parameters.insert("category".into(), req.category.as_str().into());
171 parameters.insert("symbol".into(), req.symbol.into());
172 parameters.insert("riskId".into(), req.risk_id.into());
173 if let Some(v) = req.position_idx {
174 parameters.insert("positionIdx".into(), v.into());
175 }
176 let request = build_json_request(¶meters);
177 let response: SetRiskLimitResponse = self
178 .client
179 .post_signed(
180 API::Position(Position::SetRiskLimit),
181 self.recv_window,
182 Some(request),
183 )
184 .await?;
185 Ok(response)
186 }
187
188 pub async fn set_trading_stop<'b>(
198 &self,
199 req: TradingStopRequest<'_>,
200 ) -> Result<TradingStopResponse, BybitError> {
201 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
202 parameters.insert("category".into(), req.category.as_str().into());
203 parameters.insert("symbol".into(), req.symbol.into());
204 if let Some(v) = req.take_profit {
205 parameters.insert("takeProfit".into(), v.into());
206 }
207 if let Some(v) = req.stop_loss {
208 parameters.insert("stopLoss".into(), v.into());
209 }
210 if let Some(v) = req.tp_trigger_by {
211 parameters.insert("tpTriggerBy".into(), v.into());
212 }
213 if let Some(v) = req.sl_trigger_by {
214 parameters.insert("slTriggerBy".into(), v.into());
215 }
216 if let Some(v) = req.tpsl_mode {
217 parameters.insert("tpslMode".into(), v.into());
218 }
219 if let Some(v) = req.tp_order_type {
220 parameters.insert("tpOrderType".into(), v.as_str().into());
221 }
222 if let Some(v) = req.sl_order_type {
223 parameters.insert("slOrderType".into(), v.as_str().into());
224 }
225 if let Some(v) = req.tp_size {
226 parameters.insert("tpSize".into(), v.into());
227 }
228 if let Some(v) = req.sl_size {
229 parameters.insert("slSize".into(), v.into());
230 }
231 if let Some(v) = req.tp_limit_price {
232 parameters.insert("tpLimitPrice".into(), v.into());
233 }
234 if let Some(v) = req.sl_limit_price {
235 parameters.insert("slLimitPrice".into(), v.into());
236 }
237 parameters.insert("positionIdx".into(), req.position_idx.into());
238 let request = build_json_request(¶meters);
239 let response: TradingStopResponse = self
240 .client
241 .post_signed(
242 API::Position(Position::SetTradingStop),
243 self.recv_window,
244 Some(request),
245 )
246 .await?;
247 Ok(response)
248 }
249
250 pub async fn set_add_margin<'b>(
260 &self,
261 req: AddMarginRequest<'_>,
262 ) -> Result<AddMarginResponse, BybitError> {
263 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
265
266 parameters.insert("category".into(), req.category.as_str().into());
268 parameters.insert("symbol".into(), req.symbol.into());
269
270 if req.auto_add {
272 parameters.insert("autoAddMargin".into(), 1.into());
273 } else {
274 parameters.insert("autoAddMargin".into(), 0.into());
275 }
276
277 if let Some(v) = req.position_idx {
279 parameters.insert("positionIdx".into(), v.into());
280 }
281
282 let request = build_json_request(¶meters);
284
285 let response: AddMarginResponse = self
287 .client
288 .post_signed(
289 API::Position(Position::SetAutoaddMargin),
290 self.recv_window,
291 Some(request),
292 )
293 .await?;
294
295 Ok(response)
297 }
298
299 pub async fn add_or_reduce_margin<'b>(
309 &self,
310 req: AddReduceMarginRequest<'_>,
311 ) -> Result<AddReduceMarginResponse, BybitError> {
312 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
314
315 parameters.insert("category".into(), req.category.as_str().into());
317 parameters.insert("symbol".into(), req.symbol.into());
318
319 parameters.insert("margin".into(), req.margin.into());
321
322 if let Some(v) = req.position_idx {
324 parameters.insert("positionIdx".into(), v.into());
325 }
326
327 let request = build_json_request(¶meters);
329
330 let response: AddReduceMarginResponse = self
332 .client
333 .post_signed(
334 API::Position(Position::AddorReduceMargin),
335 self.recv_window,
336 Some(request),
337 )
338 .await?;
339
340 Ok(response)
342 }
343
344 pub async fn get_closed_pnl<'b>(
345 &self,
346 req: ClosedPnlRequest<'_>,
347 ) -> Result<ClosedPnlResponse, BybitError> {
348 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
349 parameters.insert("category".into(), req.category.as_str().into());
350 if let Some(v) = req.symbol {
351 parameters.insert("symbol".into(), v.into());
352 }
353
354 if let Some(start_time) = req.start_time {
355 parameters
356 .entry("startTime".to_owned())
357 .or_insert_with(|| start_time.to_string().into());
358 }
359 if let Some(end_time) = req.end_time {
360 parameters
361 .entry("endTime".to_owned())
362 .or_insert_with(|| end_time.to_string().into());
363 }
364 if let Some(v) = req.limit {
365 parameters.insert("limit".into(), v.into());
366 }
367 let request = build_request(¶meters);
368 let response: ClosedPnlResponse = self
369 .client
370 .get_signed(
371 API::Position(Position::ClosedPnl),
372 self.recv_window,
373 Some(request),
374 )
375 .await?;
376 Ok(response)
377 }
378
379 pub async fn move_position<'b>(
389 &self,
390 req: MovePositionRequest<'_>,
391 ) -> Result<MovePositionResponse, BybitError> {
392 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
393 parameters.insert("fromUid".into(), req.from_uid.into());
395 parameters.insert("toUid".into(), req.to_uid.into());
397 parameters.insert("list".into(), json!(req.list));
399 let request = build_json_request(¶meters);
400 let response: MovePositionResponse = self
401 .client
402 .post_signed(
403 API::Position(Position::MovePosition),
404 self.recv_window,
405 Some(request),
406 )
407 .await?;
408 Ok(response)
409 }
410
411 pub async fn move_position_history<'b>(
421 &self,
422 req: MoveHistoryRequest<'_>,
423 ) -> Result<MoveHistoryResponse, BybitError> {
424 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
426
427 if let Some(category) = req.category {
429 parameters.insert("category".into(), category.as_str().into());
430 }
431
432 if let Some(symbol) = req.symbol {
434 parameters.insert("symbol".into(), symbol.into());
435 }
436
437 if let Some(start_time) = req.start_time {
439 parameters
440 .entry("startTime".to_owned())
441 .or_insert_with(|| start_time.to_string().into());
442 }
443
444 if let Some(end_time) = req.end_time {
446 parameters
447 .entry("endTime".to_owned())
448 .or_insert_with(|| end_time.to_string().into());
449 }
450
451 if let Some(status) = req.status {
453 parameters.insert("status".into(), status.into());
454 }
455
456 if let Some(block_trade_id) = req.block_trade_id {
458 parameters.insert("blockTradeId".into(), block_trade_id.into());
459 }
460
461 if let Some(limit) = req.limit {
463 parameters.insert("limit".into(), limit.into());
464 }
465
466 let request = build_request(¶meters);
468
469 let response: MoveHistoryResponse = self
471 .client
472 .get_signed(
473 API::Position(Position::MovePositionHistory),
474 self.recv_window,
475 Some(request),
476 )
477 .await?;
478
479 Ok(response)
481 }
482}