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.buy_leverage);
80 parameters.insert("sellLeverage".into(), req.sell_leverage);
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 if let Err(e) = req.validate() {
203 return Err(BybitError::ValidationError(e));
204 }
205
206 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
207 parameters.insert("category".into(), req.category.as_str().into());
208 parameters.insert("symbol".into(), req.symbol.into());
209 parameters.insert("tpslMode".into(), req.tpsl_mode.into());
210 parameters.insert("positionIdx".into(), req.position_idx.into());
211
212 if let Some(v) = req.take_profit {
213 parameters.insert("takeProfit".into(), v.into());
214 }
215 if let Some(v) = req.stop_loss {
216 parameters.insert("stopLoss".into(), v.into());
217 }
218 if let Some(v) = req.trailing_stop {
219 parameters.insert("trailingStop".into(), v.into());
220 }
221 if let Some(v) = req.tp_trigger_by {
222 parameters.insert("tpTriggerBy".into(), v.into());
223 }
224 if let Some(v) = req.sl_trigger_by {
225 parameters.insert("slTriggerBy".into(), v.into());
226 }
227 if let Some(v) = req.active_price {
228 parameters.insert("activePrice".into(), v.into());
229 }
230 if let Some(v) = req.tp_size {
231 parameters.insert("tpSize".into(), v.into());
232 }
233 if let Some(v) = req.sl_size {
234 parameters.insert("slSize".into(), v.into());
235 }
236 if let Some(v) = req.tp_limit_price {
237 parameters.insert("tpLimitPrice".into(), v.into());
238 }
239 if let Some(v) = req.sl_limit_price {
240 parameters.insert("slLimitPrice".into(), v.into());
241 }
242 if let Some(v) = req.tp_order_type {
243 parameters.insert("tpOrderType".into(), v.as_str().into());
244 }
245 if let Some(v) = req.sl_order_type {
246 parameters.insert("slOrderType".into(), v.as_str().into());
247 }
248
249 let request = build_json_request(¶meters);
250 let response: TradingStopResponse = self
251 .client
252 .post_signed(
253 API::Position(Position::SetTradingStop),
254 self.recv_window,
255 Some(request),
256 )
257 .await?;
258 Ok(response)
259 }
260
261 pub async fn set_add_margin<'b>(
271 &self,
272 req: AddMarginRequest<'_>,
273 ) -> Result<AddMarginResponse, BybitError> {
274 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
276
277 parameters.insert("category".into(), req.category.as_str().into());
279 parameters.insert("symbol".into(), req.symbol.into());
280
281 if req.auto_add {
283 parameters.insert("autoAddMargin".into(), 1.into());
284 } else {
285 parameters.insert("autoAddMargin".into(), 0.into());
286 }
287
288 if let Some(v) = req.position_idx {
290 parameters.insert("positionIdx".into(), v.into());
291 }
292
293 let request = build_json_request(¶meters);
295
296 let response: AddMarginResponse = self
298 .client
299 .post_signed(
300 API::Position(Position::SetAutoaddMargin),
301 self.recv_window,
302 Some(request),
303 )
304 .await?;
305
306 Ok(response)
308 }
309
310 pub async fn add_or_reduce_margin<'b>(
320 &self,
321 req: AddReduceMarginRequest<'_>,
322 ) -> Result<AddReduceMarginResponse, BybitError> {
323 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
325
326 parameters.insert("category".into(), req.category.as_str().into());
328 parameters.insert("symbol".into(), req.symbol.into());
329
330 parameters.insert("margin".into(), req.margin.into());
332
333 if let Some(v) = req.position_idx {
335 parameters.insert("positionIdx".into(), v.into());
336 }
337
338 let request = build_json_request(¶meters);
340
341 let response: AddReduceMarginResponse = self
343 .client
344 .post_signed(
345 API::Position(Position::AddorReduceMargin),
346 self.recv_window,
347 Some(request),
348 )
349 .await?;
350
351 Ok(response)
353 }
354
355 pub async fn get_closed_pnl<'b>(
356 &self,
357 req: ClosedPnlRequest<'_>,
358 ) -> Result<ClosedPnlResponse, BybitError> {
359 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
360 parameters.insert("category".into(), req.category.as_str().into());
361 if let Some(v) = req.symbol {
362 parameters.insert("symbol".into(), v.into());
363 }
364
365 if let Some(start_time) = req.start_time {
366 parameters
367 .entry("startTime".to_owned())
368 .or_insert_with(|| start_time.to_string().into());
369 }
370 if let Some(end_time) = req.end_time {
371 parameters
372 .entry("endTime".to_owned())
373 .or_insert_with(|| end_time.to_string().into());
374 }
375 if let Some(v) = req.limit {
376 parameters.insert("limit".into(), v.into());
377 }
378 let request = build_request(¶meters);
379 let response: ClosedPnlResponse = self
380 .client
381 .get_signed(
382 API::Position(Position::ClosedPnl),
383 self.recv_window,
384 Some(request),
385 )
386 .await?;
387 Ok(response)
388 }
389
390 pub async fn get_closed_options_positions<'b>(
400 &self,
401 req: ClosedOptionsPositionsRequest<'_>,
402 ) -> Result<ClosedOptionsPositionsResult, BybitError> {
403 if let Err(e) = req.validate() {
405 return Err(BybitError::ValidationError(e));
406 }
407
408 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
409 parameters.insert("category".into(), req.category.as_str().into());
410
411 if let Some(v) = req.symbol {
412 parameters.insert("symbol".into(), v.into());
413 }
414
415 if let Some(v) = req.start_time {
416 parameters.insert("startTime".into(), v.to_string().into());
417 }
418
419 if let Some(v) = req.end_time {
420 parameters.insert("endTime".into(), v.to_string().into());
421 }
422
423 if let Some(v) = req.limit {
424 parameters.insert("limit".into(), v.to_string().into());
425 }
426
427 if let Some(v) = req.cursor {
428 parameters.insert("cursor".into(), v.into());
429 }
430
431 let request = build_request(¶meters);
432 let response: ClosedOptionsPositionsResult = self
433 .client
434 .get_signed(
435 API::Position(Position::GetClosedOptionsPositions),
436 self.recv_window,
437 Some(request),
438 )
439 .await?;
440 Ok(response)
441 }
442
443 pub async fn confirm_pending_mmr<'b>(
460 &self,
461 req: ConfirmPendingMmrRequest<'_>,
462 ) -> Result<ConfirmPendingMmrResponse, BybitError> {
463 if let Err(e) = req.validate() {
465 return Err(BybitError::ValidationError(e));
466 }
467
468 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
469 parameters.insert("category".into(), req.category.as_str().into());
470 parameters.insert("symbol".into(), req.symbol.into());
471
472 let request = build_json_request(¶meters);
473 let response: ConfirmPendingMmrResponse = self
474 .client
475 .post_signed(
476 API::Position(Position::ConfirmPendingMmr),
477 self.recv_window,
478 Some(request),
479 )
480 .await?;
481 Ok(response)
482 }
483
484 pub async fn move_position<'b>(
494 &self,
495 req: MovePositionRequest<'_>,
496 ) -> Result<MovePositionResponse, BybitError> {
497 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
498 parameters.insert("fromUid".into(), req.from_uid.into());
500 parameters.insert("toUid".into(), req.to_uid.into());
502 parameters.insert("list".into(), json!(req.list));
504 let request = build_json_request(¶meters);
505 let response: MovePositionResponse = self
506 .client
507 .post_signed(
508 API::Position(Position::MovePosition),
509 self.recv_window,
510 Some(request),
511 )
512 .await?;
513 Ok(response)
514 }
515
516 pub async fn move_position_history<'b>(
526 &self,
527 req: MoveHistoryRequest<'_>,
528 ) -> Result<MoveHistoryResponse, BybitError> {
529 let mut parameters: BTreeMap<String, Value> = BTreeMap::new();
531
532 if let Some(category) = req.category {
534 parameters.insert("category".into(), category.as_str().into());
535 }
536
537 if let Some(symbol) = req.symbol {
539 parameters.insert("symbol".into(), symbol.into());
540 }
541
542 if let Some(start_time) = req.start_time {
544 parameters
545 .entry("startTime".to_owned())
546 .or_insert_with(|| start_time.to_string().into());
547 }
548
549 if let Some(end_time) = req.end_time {
551 parameters
552 .entry("endTime".to_owned())
553 .or_insert_with(|| end_time.to_string().into());
554 }
555
556 if let Some(status) = req.status {
558 parameters.insert("status".into(), status.into());
559 }
560
561 if let Some(block_trade_id) = req.block_trade_id {
563 parameters.insert("blockTradeId".into(), block_trade_id.into());
564 }
565
566 if let Some(limit) = req.limit {
568 parameters.insert("limit".into(), limit.into());
569 }
570
571 let request = build_request(¶meters);
573
574 let response: MoveHistoryResponse = self
576 .client
577 .get_signed(
578 API::Position(Position::MovePositionHistory),
579 self.recv_window,
580 Some(request),
581 )
582 .await?;
583
584 Ok(response)
586 }
587}