wiz-trader 0.13.0__py3-none-any.whl → 0.15.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wiz_trader/__init__.py CHANGED
@@ -3,6 +3,6 @@
3
3
  from .quotes import QuotesClient
4
4
  from .apis import WizzerClient
5
5
 
6
- __version__ = "0.13.0"
6
+ __version__ = "0.15.0"
7
7
 
8
8
  __all__ = ["QuotesClient", "WizzerClient"]
wiz_trader/apis/client.py CHANGED
@@ -61,11 +61,29 @@ class WizzerClient:
61
61
  SEGMENT_BSE_CM = "BSECM" # BSE Cash Market
62
62
  SEGMENT_NSE_FO = "NSEFO" # NSE Futures and Options
63
63
  SEGMENT_WZREQ = "WZREQ" # Wizzer Basket Segment
64
+
65
+ # Order status constants
66
+ ORDER_STATUS_OPEN = "OPEN"
67
+ ORDER_STATUS_CANCELLED = "CANCELLED"
68
+ ORDER_STATUS_REJECTED = "REJECTED"
69
+ ORDER_STATUS_PENDING = "PENDING"
70
+ ORDER_STATUS_COMPLETED = "COMPLETED"
71
+
72
+ # Trading mode constants
73
+ TRADING_MODE_PAPER = "paper_trading"
74
+ TRADING_MODE_ADVICES = "advices"
75
+ TRADING_MODE_TRADING_AND_ADVICES = "trading_and_advices"
76
+
77
+ # Rebalance execution policies
78
+ REBALANCE_FULL = "full_rebalance"
79
+ REBALANCE_ENTRY_ONLY = "entry_only"
80
+ REBALANCE_EXIT_ONLY = "exit_only"
64
81
 
65
82
  # URIs to various API endpoints
66
83
  _routes = {
67
84
  # Order related endpoints
68
85
  "order.place": "/orders",
86
+ "order.get": "/orders",
69
87
  "order.modify": "/orders/{order_id}",
70
88
  "order.cancel": "/orders/{order_id}",
71
89
  "order.info": "/orders/{order_id}",
@@ -92,6 +110,9 @@ class WizzerClient:
92
110
  "datahub.indices": "/datahub/indices",
93
111
  "datahub.index.components": "/datahub/index/components",
94
112
  "datahub.historical.ohlcv": "/datahub/historical/ohlcv",
113
+
114
+ # Instrument & asset class endpoints
115
+ "instrument.metrics": "/instruments/metrics",
95
116
  }
96
117
 
97
118
  def __init__(
@@ -241,7 +262,6 @@ class WizzerClient:
241
262
  variety: str = None,
242
263
  stoploss: float = 0,
243
264
  target: float = 0,
244
- segment: Optional[str] = None,
245
265
  exchange_token: Optional[int] = None,
246
266
  broker: str = None,
247
267
  strategy: Optional[Dict[str, str]] = None
@@ -283,16 +303,6 @@ class WizzerClient:
283
303
  if variety is None:
284
304
  variety = self.VARIETY_REGULAR
285
305
 
286
- # Determine segment if not provided
287
- if not segment:
288
- segment = f"{exchange}CM"
289
- # If exchange is NSE, use the NSE_CM constant
290
- if exchange == self.EXCHANGE_NSE:
291
- segment = self.SEGMENT_NSE_CM
292
- # If exchange is BSE, use the BSE_CM constant
293
- elif exchange == self.EXCHANGE_BSE:
294
- segment = self.SEGMENT_BSE_CM
295
-
296
306
  # Get strategy information
297
307
  strategy_info = self._get_strategy(strategy)
298
308
 
@@ -310,7 +320,6 @@ class WizzerClient:
310
320
  "variety": variety,
311
321
  "stoploss": stoploss,
312
322
  "target": target,
313
- "segment": segment,
314
323
  "strategy": strategy_info
315
324
  }
316
325
 
@@ -319,7 +328,7 @@ class WizzerClient:
319
328
  data["exchangeToken"] = exchange_token
320
329
 
321
330
  logger.debug("Placing order: %s", data)
322
- return self._make_request("POST", self._routes["order.place"], json=data)
331
+ return self._make_request("POST", endpoint, json=data)
323
332
 
324
333
  def modify_order(
325
334
  self,
@@ -355,7 +364,480 @@ class WizzerClient:
355
364
 
356
365
  logger.debug("Cancelling order: %s", order_id)
357
366
  return self._make_request("DELETE", endpoint)
358
-
367
+
368
+ def get_orders(
369
+ self,
370
+ trading_modes: Optional[List[str]] = None,
371
+ order_statuses: Optional[List[str]] = None,
372
+ from_date: Optional[str] = None,
373
+ to_date: Optional[str] = None,
374
+ trading_symbols: Optional[List[str]] = None,
375
+ page_no: int = 1,
376
+ paginate: bool = False
377
+ ) -> List[Dict[str, Any]]:
378
+ """
379
+ Get orders with optional filtering.
380
+
381
+ Args:
382
+ trading_modes (Optional[List[str]], optional): Filter by trading modes.
383
+ Valid values: "paper_trading", "advices", "trading_and_advices".
384
+ order_statuses (Optional[List[str]], optional): Filter by order statuses.
385
+ Valid values: "OPEN", "CANCELLED", "REJECTED", "PENDING", "COMPLETED".
386
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format. Defaults to today.
387
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format. Defaults to today.
388
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
389
+ page_no (int, optional): Page number for pagination. Defaults to 1.
390
+ paginate (bool, optional): Whether to automatically fetch all pages. Defaults to False.
391
+
392
+ Returns:
393
+ List[Dict[str, Any]]: List of orders matching the filter criteria.
394
+ """
395
+ endpoint = self._routes["order.get"]
396
+
397
+ # Build the base parameters without list items
398
+ params = {}
399
+
400
+ # Handle single parameters
401
+ if from_date:
402
+ params["fromDateRange"] = from_date
403
+
404
+ if to_date:
405
+ params["toDateRange"] = to_date
406
+
407
+ if not paginate:
408
+ params["pageNo"] = page_no
409
+
410
+ # Validate trading modes
411
+ if trading_modes:
412
+ for mode in trading_modes:
413
+ if mode not in [self.TRADING_MODE_PAPER, self.TRADING_MODE_ADVICES, self.TRADING_MODE_TRADING_AND_ADVICES]:
414
+ raise ValueError(f"Invalid trading mode: {mode}")
415
+
416
+ # Validate order statuses
417
+ if order_statuses:
418
+ for status in order_statuses:
419
+ if status not in [self.ORDER_STATUS_OPEN, self.ORDER_STATUS_CANCELLED,
420
+ self.ORDER_STATUS_REJECTED, self.ORDER_STATUS_PENDING,
421
+ self.ORDER_STATUS_COMPLETED]:
422
+ raise ValueError(f"Invalid order status: {status}")
423
+
424
+ # Handle pagination with properly formatted parameters
425
+ if paginate:
426
+ return self._paginate_orders(endpoint, params, trading_modes, order_statuses, trading_symbols)
427
+ else:
428
+ logger.debug("Fetching orders with params: %s", params)
429
+ return self._make_request_with_multi_params(
430
+ "GET",
431
+ endpoint,
432
+ params=params,
433
+ trading_modes=trading_modes,
434
+ order_statuses=order_statuses,
435
+ trading_symbols=trading_symbols
436
+ )
437
+
438
+ def _make_request_with_multi_params(
439
+ self,
440
+ method: str,
441
+ endpoint: str,
442
+ params: Dict[str, Any],
443
+ trading_modes: Optional[List[str]] = None,
444
+ order_statuses: Optional[List[str]] = None,
445
+ trading_symbols: Optional[List[str]] = None
446
+ ) -> Any:
447
+ """
448
+ Make an HTTP request with multiple parameters having the same name.
449
+
450
+ Args:
451
+ method (str): HTTP method (GET, POST, etc.)
452
+ endpoint (str): API endpoint path.
453
+ params (Dict[str, Any]): Base query parameters.
454
+ trading_modes (Optional[List[str]]): List of trading modes.
455
+ order_statuses (Optional[List[str]]): List of order statuses.
456
+ trading_symbols (Optional[List[str]]): List of trading symbols.
457
+
458
+ Returns:
459
+ Any: Parsed JSON response.
460
+ """
461
+ url = f"{self.base_url}{endpoint}"
462
+
463
+ # Start with the base parameters
464
+ all_params = params.copy()
465
+
466
+ # Create a session to manually handle parameter encoding
467
+ session = requests.Session()
468
+ req = requests.Request(method, url, headers=self.headers, params=all_params)
469
+ prepped = req.prepare()
470
+
471
+ # Build the URL with additional repeated parameters
472
+ query_parts = []
473
+ if prepped.url.find('?') >= 0:
474
+ query_parts.append(prepped.url.split('?', 1)[1])
475
+
476
+ # Add repeated parameters
477
+ if trading_modes:
478
+ for mode in trading_modes:
479
+ query_parts.append(f"tradingMode={mode}")
480
+
481
+ if order_statuses:
482
+ for status in order_statuses:
483
+ query_parts.append(f"orderStatus={status}")
484
+
485
+ if trading_symbols:
486
+ for symbol in trading_symbols:
487
+ query_parts.append(f"tradingSymbols={symbol}")
488
+
489
+ # Build the final URL
490
+ final_url = prepped.url.split('?')[0]
491
+ if query_parts:
492
+ final_url += '?' + '&'.join(query_parts)
493
+
494
+ try:
495
+ logger.debug("%s request to %s", method, final_url)
496
+ response = session.send(prepped)
497
+ response.url = final_url
498
+ response.raise_for_status()
499
+ return response.json()
500
+ except requests.RequestException as e:
501
+ logger.error("API request failed: %s", e, exc_info=True)
502
+ if hasattr(e.response, 'text'):
503
+ logger.error("Response content: %s", e.response.text)
504
+ raise
505
+
506
+ def _paginate_orders(
507
+ self,
508
+ endpoint: str,
509
+ params: Dict[str, Any],
510
+ trading_modes: Optional[List[str]] = None,
511
+ order_statuses: Optional[List[str]] = None,
512
+ trading_symbols: Optional[List[str]] = None
513
+ ) -> List[Dict[str, Any]]:
514
+ """
515
+ Internal method to handle pagination for orders API with multi-value parameters.
516
+
517
+ Args:
518
+ endpoint (str): API endpoint.
519
+ params (Dict[str, Any]): Base query parameters.
520
+ trading_modes (Optional[List[str]]): List of trading modes.
521
+ order_statuses (Optional[List[str]]): List of order statuses.
522
+ trading_symbols (Optional[List[str]]): List of trading symbols.
523
+
524
+ Returns:
525
+ List[Dict[str, Any]]: Combined results from all pages.
526
+ """
527
+ all_orders = []
528
+ page_no = 1
529
+ total_count = None
530
+ page_size = 50 # API returns 50 orders per page
531
+
532
+ while True:
533
+ current_params = params.copy()
534
+ current_params["pageNo"] = page_no
535
+ logger.debug("Fetching orders page %d", page_no)
536
+
537
+ # Build the URL with the session to get the properly formatted parameters
538
+ session = requests.Session()
539
+ req = requests.Request("GET", f"{self.base_url}{endpoint}", headers=self.headers, params=current_params)
540
+ prepped = req.prepare()
541
+
542
+ # Build the URL with additional repeated parameters
543
+ query_parts = []
544
+ if prepped.url.find('?') >= 0:
545
+ query_parts.append(prepped.url.split('?', 1)[1])
546
+
547
+ # Add repeated parameters
548
+ if trading_modes:
549
+ for mode in trading_modes:
550
+ query_parts.append(f"tradingMode={mode}")
551
+
552
+ if order_statuses:
553
+ for status in order_statuses:
554
+ query_parts.append(f"orderStatus={status}")
555
+
556
+ if trading_symbols:
557
+ for symbol in trading_symbols:
558
+ query_parts.append(f"tradingSymbols={symbol}")
559
+
560
+ # Build the final URL
561
+ final_url = prepped.url.split('?')[0]
562
+ if query_parts:
563
+ final_url += '?' + '&'.join(query_parts)
564
+
565
+ # Make the request
566
+ try:
567
+ logger.debug("GET request to %s", final_url)
568
+ prepped.url = final_url
569
+ response = session.send(prepped)
570
+ response.raise_for_status()
571
+
572
+ # Get orders from the current page
573
+ orders = response.json()
574
+ all_orders.extend(orders)
575
+
576
+ # Check if we need to fetch more pages
577
+ if total_count is None and "X-Total-Count" in response.headers:
578
+ try:
579
+ total_count = int(response.headers["X-Total-Count"])
580
+ logger.debug("Total orders count: %d", total_count)
581
+ except (ValueError, TypeError):
582
+ logger.warning("Could not parse X-Total-Count header")
583
+ break
584
+
585
+ # If we've fetched all orders or there are no more pages, stop
586
+ if not orders or len(all_orders) >= total_count or total_count is None:
587
+ break
588
+
589
+ # Move to the next page
590
+ page_no += 1
591
+
592
+ except requests.RequestException as e:
593
+ logger.error("API request failed during pagination: %s", e, exc_info=True)
594
+ if hasattr(e.response, 'text'):
595
+ logger.error("Response content: %s", e.response.text)
596
+ raise
597
+
598
+ logger.info("Fetched %d orders in total", len(all_orders))
599
+ return all_orders
600
+
601
+ def get_open_orders(
602
+ self,
603
+ trading_modes: Optional[List[str]] = None,
604
+ from_date: Optional[str] = None,
605
+ to_date: Optional[str] = None,
606
+ trading_symbols: Optional[List[str]] = None,
607
+ paginate: bool = False
608
+ ) -> List[Dict[str, Any]]:
609
+ """
610
+ Get open orders with optional filtering.
611
+
612
+ Args:
613
+ trading_modes (Optional[List[str]], optional): Filter by trading modes.
614
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format.
615
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format.
616
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
617
+ paginate (bool, optional): Whether to automatically fetch all pages.
618
+
619
+ Returns:
620
+ List[Dict[str, Any]]: List of open orders matching the filter criteria.
621
+ """
622
+ return self.get_orders(
623
+ trading_modes=trading_modes,
624
+ order_statuses=[self.ORDER_STATUS_OPEN],
625
+ from_date=from_date,
626
+ to_date=to_date,
627
+ trading_symbols=trading_symbols,
628
+ paginate=paginate
629
+ )
630
+
631
+ def get_completed_orders(
632
+ self,
633
+ trading_modes: Optional[List[str]] = None,
634
+ from_date: Optional[str] = None,
635
+ to_date: Optional[str] = None,
636
+ trading_symbols: Optional[List[str]] = None,
637
+ paginate: bool = False
638
+ ) -> List[Dict[str, Any]]:
639
+ """
640
+ Get completed orders with optional filtering.
641
+
642
+ Args:
643
+ trading_modes (Optional[List[str]], optional): Filter by trading modes.
644
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format.
645
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format.
646
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
647
+ paginate (bool, optional): Whether to automatically fetch all pages.
648
+
649
+ Returns:
650
+ List[Dict[str, Any]]: List of completed orders matching the filter criteria.
651
+ """
652
+ return self.get_orders(
653
+ trading_modes=trading_modes,
654
+ order_statuses=[self.ORDER_STATUS_COMPLETED],
655
+ from_date=from_date,
656
+ to_date=to_date,
657
+ trading_symbols=trading_symbols,
658
+ paginate=paginate
659
+ )
660
+
661
+ def get_pending_orders(
662
+ self,
663
+ trading_modes: Optional[List[str]] = None,
664
+ from_date: Optional[str] = None,
665
+ to_date: Optional[str] = None,
666
+ trading_symbols: Optional[List[str]] = None,
667
+ paginate: bool = False
668
+ ) -> List[Dict[str, Any]]:
669
+ """
670
+ Get pending orders with optional filtering.
671
+
672
+ Args:
673
+ trading_modes (Optional[List[str]], optional): Filter by trading modes.
674
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format.
675
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format.
676
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
677
+ paginate (bool, optional): Whether to automatically fetch all pages.
678
+
679
+ Returns:
680
+ List[Dict[str, Any]]: List of pending orders matching the filter criteria.
681
+ """
682
+ return self.get_orders(
683
+ trading_modes=trading_modes,
684
+ order_statuses=[self.ORDER_STATUS_PENDING],
685
+ from_date=from_date,
686
+ to_date=to_date,
687
+ trading_symbols=trading_symbols,
688
+ paginate=paginate
689
+ )
690
+
691
+ def get_cancelled_orders(
692
+ self,
693
+ trading_modes: Optional[List[str]] = None,
694
+ from_date: Optional[str] = None,
695
+ to_date: Optional[str] = None,
696
+ trading_symbols: Optional[List[str]] = None,
697
+ paginate: bool = False
698
+ ) -> List[Dict[str, Any]]:
699
+ """
700
+ Get cancelled orders with optional filtering.
701
+
702
+ Args:
703
+ trading_modes (Optional[List[str]], optional): Filter by trading modes.
704
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format.
705
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format.
706
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
707
+ paginate (bool, optional): Whether to automatically fetch all pages.
708
+
709
+ Returns:
710
+ List[Dict[str, Any]]: List of cancelled orders matching the filter criteria.
711
+ """
712
+ return self.get_orders(
713
+ trading_modes=trading_modes,
714
+ order_statuses=[self.ORDER_STATUS_CANCELLED],
715
+ from_date=from_date,
716
+ to_date=to_date,
717
+ trading_symbols=trading_symbols,
718
+ paginate=paginate
719
+ )
720
+
721
+ def get_rejected_orders(
722
+ self,
723
+ trading_modes: Optional[List[str]] = None,
724
+ from_date: Optional[str] = None,
725
+ to_date: Optional[str] = None,
726
+ trading_symbols: Optional[List[str]] = None,
727
+ paginate: bool = False
728
+ ) -> List[Dict[str, Any]]:
729
+ """
730
+ Get rejected orders with optional filtering.
731
+
732
+ Args:
733
+ trading_modes (Optional[List[str]], optional): Filter by trading modes.
734
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format.
735
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format.
736
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
737
+ paginate (bool, optional): Whether to automatically fetch all pages.
738
+
739
+ Returns:
740
+ List[Dict[str, Any]]: List of rejected orders matching the filter criteria.
741
+ """
742
+ return self.get_orders(
743
+ trading_modes=trading_modes,
744
+ order_statuses=[self.ORDER_STATUS_REJECTED],
745
+ from_date=from_date,
746
+ to_date=to_date,
747
+ trading_symbols=trading_symbols,
748
+ paginate=paginate
749
+ )
750
+
751
+ def get_paper_traded_orders(
752
+ self,
753
+ order_statuses: Optional[List[str]] = None,
754
+ from_date: Optional[str] = None,
755
+ to_date: Optional[str] = None,
756
+ trading_symbols: Optional[List[str]] = None,
757
+ paginate: bool = False
758
+ ) -> List[Dict[str, Any]]:
759
+ """
760
+ Get paper traded orders with optional filtering.
761
+
762
+ Args:
763
+ order_statuses (Optional[List[str]], optional): Filter by order statuses.
764
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format.
765
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format.
766
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
767
+ paginate (bool, optional): Whether to automatically fetch all pages.
768
+
769
+ Returns:
770
+ List[Dict[str, Any]]: List of paper traded orders matching the filter criteria.
771
+ """
772
+ return self.get_orders(
773
+ trading_modes=[self.TRADING_MODE_PAPER],
774
+ order_statuses=order_statuses,
775
+ from_date=from_date,
776
+ to_date=to_date,
777
+ trading_symbols=trading_symbols,
778
+ paginate=paginate
779
+ )
780
+
781
+ def get_advised_orders(
782
+ self,
783
+ order_statuses: Optional[List[str]] = None,
784
+ from_date: Optional[str] = None,
785
+ to_date: Optional[str] = None,
786
+ trading_symbols: Optional[List[str]] = None,
787
+ paginate: bool = False
788
+ ) -> List[Dict[str, Any]]:
789
+ """
790
+ Get advised orders with optional filtering.
791
+
792
+ Args:
793
+ order_statuses (Optional[List[str]], optional): Filter by order statuses.
794
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format.
795
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format.
796
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
797
+ paginate (bool, optional): Whether to automatically fetch all pages.
798
+
799
+ Returns:
800
+ List[Dict[str, Any]]: List of advised orders matching the filter criteria.
801
+ """
802
+ return self.get_orders(
803
+ trading_modes=[self.TRADING_MODE_ADVICES],
804
+ order_statuses=order_statuses,
805
+ from_date=from_date,
806
+ to_date=to_date,
807
+ trading_symbols=trading_symbols,
808
+ paginate=paginate
809
+ )
810
+
811
+ def get_live_traded_orders(
812
+ self,
813
+ order_statuses: Optional[List[str]] = None,
814
+ from_date: Optional[str] = None,
815
+ to_date: Optional[str] = None,
816
+ trading_symbols: Optional[List[str]] = None,
817
+ paginate: bool = False
818
+ ) -> List[Dict[str, Any]]:
819
+ """
820
+ Get live traded orders with optional filtering.
821
+
822
+ Args:
823
+ order_statuses (Optional[List[str]], optional): Filter by order statuses.
824
+ from_date (Optional[str], optional): Start date in YYYY-MM-DD format.
825
+ to_date (Optional[str], optional): End date in YYYY-MM-DD format.
826
+ trading_symbols (Optional[List[str]], optional): Filter by trading symbols.
827
+ paginate (bool, optional): Whether to automatically fetch all pages.
828
+
829
+ Returns:
830
+ List[Dict[str, Any]]: List of live traded orders matching the filter criteria.
831
+ """
832
+ return self.get_orders(
833
+ trading_modes=[self.TRADING_MODE_TRADING_AND_ADVICES],
834
+ order_statuses=order_statuses,
835
+ from_date=from_date,
836
+ to_date=to_date,
837
+ trading_symbols=trading_symbols,
838
+ paginate=paginate
839
+ )
840
+
359
841
  def get_order(self, order_id: str) -> Dict[str, Any]:
360
842
  """
361
843
  Get details of a specific order by ID.
@@ -682,7 +1164,8 @@ class WizzerClient:
682
1164
  def rebalance_basket(
683
1165
  self,
684
1166
  trading_symbol: str,
685
- instruments: List[str]
1167
+ instruments: List[str],
1168
+ execution_policy: str
686
1169
  ) -> Dict[str, Any]:
687
1170
  """
688
1171
  Rebalance a basket with new instruments.
@@ -690,6 +1173,8 @@ class WizzerClient:
690
1173
  Args:
691
1174
  trading_symbol (str): Basket trading symbol.
692
1175
  instruments (List[str]): List of instrument identifiers for the new basket composition.
1176
+ execution_policy (str): Rebalance execution policy.
1177
+ Options: "full_rebalance", "entry_only", "exit_only".
693
1178
 
694
1179
  Returns:
695
1180
  Dict[str, Any]: Rebalance response.
@@ -698,10 +1183,14 @@ class WizzerClient:
698
1183
 
699
1184
  data = {
700
1185
  "tradingSymbol": trading_symbol,
701
- "instruments": instruments
1186
+ "instruments": instruments,
1187
+ "policies": {
1188
+ "execution": execution_policy
1189
+ }
702
1190
  }
703
1191
 
704
- logger.debug("Rebalancing basket %s with instruments: %s", trading_symbol, instruments)
1192
+ logger.debug("Rebalancing basket %s with instruments: %s, policy: %s",
1193
+ trading_symbol, instruments, execution_policy)
705
1194
  return self._make_request("POST", endpoint, json=data)
706
1195
 
707
1196
  def exit_all_positions(self) -> Dict[str, Any]:
@@ -747,6 +1236,35 @@ class WizzerClient:
747
1236
  logger.debug("Exiting all positions for strategy: %s", strategy_id)
748
1237
  return self._make_request("POST", endpoint, json=data)
749
1238
 
1239
+ # =====INSTRUMENT & ASSET CLASS METHODS =====
1240
+
1241
+ def get_instrument_metrics(self, identifiers: List[str]) -> List[Dict[str, Any]]:
1242
+ """
1243
+ Get detailed metrics for instruments by their identifiers.
1244
+
1245
+ Args:
1246
+ identifiers (List[str]): List of instrument identifiers in the format
1247
+ "EXCHANGE:SYMBOL:TOKEN" (e.g., "NSE:SBIN:3045").
1248
+
1249
+ Returns:
1250
+ List[Dict[str, Any]]: List of instrument metrics.
1251
+
1252
+ Example:
1253
+ >>> client.get_instrument_metrics([
1254
+ ... "NSE:SBIN:3045",
1255
+ ... "NSE:RELIANCE:2885",
1256
+ ... "NSE:NIFTY26DEC11000CE:61009"
1257
+ ... ])
1258
+ """
1259
+ endpoint = self._routes["instrument.metrics"]
1260
+ data = {
1261
+ "identifiers": identifiers
1262
+ }
1263
+
1264
+ logger.debug("Fetching instrument metrics for identifiers: %s", identifiers)
1265
+ response = self._make_request("POST", endpoint, json=data)
1266
+ return response
1267
+
750
1268
  def _make_request(
751
1269
  self,
752
1270
  method: str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wiz_trader
3
- Version: 0.13.0
3
+ Version: 0.15.0
4
4
  Summary: A Python SDK for connecting to the Wizzer.
5
5
  Home-page: https://bitbucket.org/wizzer-tech/quotes_sdk.git
6
6
  Author: Pawan Wagh
@@ -0,0 +1,9 @@
1
+ wiz_trader/__init__.py,sha256=3fwdVbFYiQATRbAy1qYqyHPOW1Z0Nw56KDb1zeKEB14,182
2
+ wiz_trader/apis/__init__.py,sha256=ItWKMOl4omiW0g2f-M7WRW3v-dss_ULd9vYnFyIIT9o,132
3
+ wiz_trader/apis/client.py,sha256=HoMFXfWoO3HdAwPCfOD2_U8nfZJ6iBCB6FnWxzlzl5E,45295
4
+ wiz_trader/quotes/__init__.py,sha256=RF9g9CNP6bVWlmCh_ad8krm3-EWOIuVfLp0-H9fAeEM,108
5
+ wiz_trader/quotes/client.py,sha256=LJeMcQPjJIRxrTIGalWsLYh_XfinDXBP5-4cNS7qCxc,9709
6
+ wiz_trader-0.15.0.dist-info/METADATA,sha256=imCNht3nXlWeViNIFt0_sPyuUv5criLgusNjjkrvUhU,54024
7
+ wiz_trader-0.15.0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
8
+ wiz_trader-0.15.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
+ wiz_trader-0.15.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.0)
2
+ Generator: setuptools (80.3.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,9 +0,0 @@
1
- wiz_trader/__init__.py,sha256=0UAS-iwEWGpAmzSwXW_1ux-uiKRn07Yv1imLq-h2xKI,182
2
- wiz_trader/apis/__init__.py,sha256=ItWKMOl4omiW0g2f-M7WRW3v-dss_ULd9vYnFyIIT9o,132
3
- wiz_trader/apis/client.py,sha256=QVarYhQbGcS0j8aVqmG34Bi_FXwpr6zwbqblEExrHxI,25656
4
- wiz_trader/quotes/__init__.py,sha256=RF9g9CNP6bVWlmCh_ad8krm3-EWOIuVfLp0-H9fAeEM,108
5
- wiz_trader/quotes/client.py,sha256=LJeMcQPjJIRxrTIGalWsLYh_XfinDXBP5-4cNS7qCxc,9709
6
- wiz_trader-0.13.0.dist-info/METADATA,sha256=2CwKcC2dAgRxH1lULjTiUHW1XSLrzkEpXLMSVT1XwgQ,54024
7
- wiz_trader-0.13.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
8
- wiz_trader-0.13.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
- wiz_trader-0.13.0.dist-info/RECORD,,