wiz-trader 0.38.0__py3-none-any.whl → 0.40.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.38.0"
6
+ __version__ = "0.40.0"
7
7
 
8
8
  __all__ = ["QuotesClient", "WizzerClient"]
wiz_trader/apis/client.py CHANGED
@@ -278,6 +278,20 @@ class WizzerClient:
278
278
  # Analytics API endpoints - Leverage
279
279
  "analytics.leverage.debt_equity_ratio": "/analytics/leverage/debtEquityRatio",
280
280
 
281
+ # Analytics API endpoints - New Additions
282
+ "analytics.marketdata.average_volume": "/analytics/marketdata/averageVolume",
283
+ "analytics.index.max_drawdown": "/analytics/index/metrics/maxDrawdown",
284
+ "analytics.instrument.drawdown_duration": "/analytics/instrument/metrics/drawdownDuration",
285
+ "analytics.price.rolling_peak": "/analytics/price/rollingPeak",
286
+ "analytics.price.rolling_mean": "/analytics/price/rollingMean",
287
+ "analytics.volatility.realized": "/analytics/volatility/realized",
288
+ "analytics.risk.beta_90d": "/analytics/risk/beta90d",
289
+ "analytics.risk.beta_custom": "/analytics/risk/beta",
290
+ "analytics.strategy.drawdown_max": "/analytics/strategy/drawdown/max",
291
+ "analytics.product.drawdown_max": "/analytics/product/drawdown/max",
292
+ "analytics.volatility.atr": "/analytics/volatility/atr",
293
+ "analytics.returns.simple": "/analytics/returns/simple",
294
+
281
295
  }
282
296
 
283
297
  def __init__(
@@ -1822,6 +1836,7 @@ class WizzerClient:
1822
1836
  def _normalize_params(self, params: Optional[Dict[str, Any]]) -> Optional[Dict[str, str]]:
1823
1837
  """
1824
1838
  Normalize parameters for HTTP requests, converting booleans to lowercase strings.
1839
+ Preserves spaces in string values to prevent automatic URL encoding by requests library.
1825
1840
 
1826
1841
  Args:
1827
1842
  params (Optional[Dict[str, Any]]): Raw parameters dictionary.
@@ -1838,7 +1853,8 @@ class WizzerClient:
1838
1853
  # Convert Python boolean to lowercase string for API compatibility
1839
1854
  normalized[key] = "true" if value else "false"
1840
1855
  elif value is not None:
1841
- # Convert other values to strings
1856
+ # Convert other values to strings, preserving spaces
1857
+ # This prevents requests library from automatically URL-encoding spaces to '+'
1842
1858
  normalized[key] = str(value)
1843
1859
 
1844
1860
  return normalized
@@ -1867,12 +1883,28 @@ class WizzerClient:
1867
1883
  Raises:
1868
1884
  requests.RequestException: If the request fails.
1869
1885
  """
1886
+ import urllib.parse
1887
+
1870
1888
  url = f"{self.base_url}{endpoint}"
1871
1889
  request_headers = headers if headers else self.headers
1872
1890
 
1873
1891
  # Normalize parameters to handle booleans correctly
1874
1892
  normalized_params = self._normalize_params(params)
1875
1893
 
1894
+ # Handle URL construction manually to encode spaces as %20 instead of +
1895
+ if normalized_params and method.upper() == 'GET':
1896
+ # Construct query string manually to control encoding
1897
+ query_parts = []
1898
+ for key, value in normalized_params.items():
1899
+ # Use urllib.parse.quote to encode values, spaces become %20 instead of +
1900
+ encoded_key = urllib.parse.quote(str(key), safe='')
1901
+ encoded_value = urllib.parse.quote(str(value), safe='') # Properly encode all special chars
1902
+ query_parts.append(f"{encoded_key}={encoded_value}")
1903
+
1904
+ if query_parts:
1905
+ url = f"{url}?{'&'.join(query_parts)}"
1906
+ normalized_params = None # Don't pass params to requests since we built the URL manually
1907
+
1876
1908
  try:
1877
1909
  logger.debug("%s request to %s", method, url)
1878
1910
  response = requests.request(
@@ -2536,7 +2568,7 @@ class WizzerClient:
2536
2568
  self,
2537
2569
  symbol: str,
2538
2570
  as_of: str,
2539
- price_source: str = "avg_quarter",
2571
+ price_source: str = "avgQuarter",
2540
2572
  custom_price: Optional[float] = None,
2541
2573
  standalone: bool = False,
2542
2574
  currency: str = "INR"
@@ -2547,7 +2579,7 @@ class WizzerClient:
2547
2579
  Args:
2548
2580
  symbol (str): Stock symbol (e.g., "NSE:INFY").
2549
2581
  as_of (str): Reference date (YYYY-MM-DD).
2550
- price_source (str, optional): Price source: spot, avg_quarter, custom. Defaults to "avg_quarter".
2582
+ price_source (str, optional): Price source: spot, avgQuarter, custom. Defaults to "avgQuarter".
2551
2583
  custom_price (float, optional): Required if price_source=custom.
2552
2584
  standalone (bool, optional): Use standalone financials. Defaults to False.
2553
2585
  currency (str, optional): Output currency. Defaults to "INR".
@@ -2562,7 +2594,7 @@ class WizzerClient:
2562
2594
  "bookToMarket": 0.1234,
2563
2595
  "bookValuePerShare": 184.50,
2564
2596
  "marketPricePerShare": 1495.75,
2565
- "sourcePriceType": "avg_quarter",
2597
+ "sourcePriceType": "avgQuarter",
2566
2598
  "quarterRef": "Q4FY23",
2567
2599
  "standalone": false,
2568
2600
  "unit": "ratio"
@@ -2586,7 +2618,7 @@ class WizzerClient:
2586
2618
  self,
2587
2619
  symbol: str,
2588
2620
  as_of: str,
2589
- price_source: str = "avg_quarter",
2621
+ price_source: str = "avgQuarter",
2590
2622
  custom_price: Optional[float] = None,
2591
2623
  standalone: bool = False
2592
2624
  ) -> Dict[str, Any]:
@@ -2596,7 +2628,7 @@ class WizzerClient:
2596
2628
  Args:
2597
2629
  symbol (str): Stock symbol.
2598
2630
  as_of (str): Reference date (YYYY-MM-DD).
2599
- price_source (str, optional): Price source. Defaults to "avg_quarter".
2631
+ price_source (str, optional): Price source. Defaults to "avgQuarter".
2600
2632
  custom_price (float, optional): Custom price if price_source=custom.
2601
2633
  standalone (bool, optional): Use standalone financials. Defaults to False.
2602
2634
 
@@ -2634,7 +2666,7 @@ class WizzerClient:
2634
2666
  self,
2635
2667
  symbol: str,
2636
2668
  as_of: str,
2637
- price_source: str = "avg_quarter",
2669
+ price_source: str = "avgQuarter",
2638
2670
  custom_price: Optional[float] = None,
2639
2671
  standalone: bool = False
2640
2672
  ) -> Dict[str, Any]:
@@ -2644,7 +2676,7 @@ class WizzerClient:
2644
2676
  Args:
2645
2677
  symbol (str): Stock symbol.
2646
2678
  as_of (str): Reference date (YYYY-MM-DD).
2647
- price_source (str, optional): Price source. Defaults to "avg_quarter".
2679
+ price_source (str, optional): Price source. Defaults to "avgQuarter".
2648
2680
  custom_price (float, optional): Custom price if price_source=custom.
2649
2681
  standalone (bool, optional): Use standalone financials. Defaults to False.
2650
2682
 
@@ -3148,7 +3180,7 @@ class WizzerClient:
3148
3180
  }
3149
3181
  """
3150
3182
  params = self._normalize_params({
3151
- "symbol": symbol,
3183
+ "index": symbol,
3152
3184
  "startDate": start_date,
3153
3185
  "endDate": end_date
3154
3186
  })
@@ -3504,3 +3536,527 @@ class WizzerClient:
3504
3536
 
3505
3537
  logger.debug("Fetching CAGR for %s from %s to %s", symbol, start_date, end_date)
3506
3538
  return self._make_request("GET", self._routes["analytics.returns.cagr"], params=params)
3539
+
3540
+ # --- New Analytics Methods ---
3541
+
3542
+ def get_average_traded_volume(
3543
+ self,
3544
+ symbol: str,
3545
+ start_date: str,
3546
+ end_date: str,
3547
+ interval: str = "daily"
3548
+ ) -> Dict[str, Any]:
3549
+ """
3550
+ Get average traded volume for a stock over a specified period.
3551
+
3552
+ Args:
3553
+ symbol (str): Stock symbol (e.g., HDFCBANK, NSE:RELIANCE).
3554
+ start_date (str): Period start date (YYYY-MM-DD).
3555
+ end_date (str): Period end date (YYYY-MM-DD).
3556
+ interval (str, optional): Time interval ('daily', 'weekly', 'monthly'). Defaults to 'daily'.
3557
+
3558
+ Returns:
3559
+ Dict[str, Any]: Average volume data.
3560
+
3561
+ Example Response:
3562
+ {
3563
+ "symbol": "HDFCBANK",
3564
+ "startDate": "2024-04-01",
3565
+ "endDate": "2024-06-30",
3566
+ "interval": "daily",
3567
+ "averageVolume": 1234567,
3568
+ "totalDays": 61,
3569
+ "unit": "shares"
3570
+ }
3571
+ """
3572
+ params = self._normalize_params({
3573
+ "symbol": symbol,
3574
+ "startDate": start_date,
3575
+ "endDate": end_date,
3576
+ "interval": interval
3577
+ })
3578
+
3579
+ logger.debug("Fetching average traded volume for %s from %s to %s", symbol, start_date, end_date)
3580
+ return self._make_request("GET", self._routes["analytics.marketdata.average_volume"], params=params)
3581
+
3582
+ def get_index_max_drawdown(
3583
+ self,
3584
+ index_symbol: str,
3585
+ start_date: str,
3586
+ end_date: str,
3587
+ interval: str = "daily"
3588
+ ) -> Dict[str, Any]:
3589
+ """
3590
+ Get maximum drawdown for an index over a specified period.
3591
+
3592
+ Args:
3593
+ index_symbol (str): Index symbol (e.g., NIFTY50, BANKNIFTY, SENSEX).
3594
+ start_date (str): Period start date (YYYY-MM-DD).
3595
+ end_date (str): Period end date (YYYY-MM-DD).
3596
+ interval (str, optional): Time interval ('daily', 'weekly', 'monthly'). Defaults to 'daily'.
3597
+
3598
+ Returns:
3599
+ Dict[str, Any]: Maximum drawdown data.
3600
+
3601
+ Example Response:
3602
+ {
3603
+ "indexSymbol": "NIFTY50",
3604
+ "startDate": "2023-01-01",
3605
+ "endDate": "2024-01-01",
3606
+ "interval": "daily",
3607
+ "maxDrawdown": -15.23,
3608
+ "drawdownDate": "2023-10-26",
3609
+ "peakDate": "2023-09-19",
3610
+ "unit": "%"
3611
+ }
3612
+ """
3613
+ params = self._normalize_params({
3614
+ "indexSymbol": index_symbol,
3615
+ "startDate": start_date,
3616
+ "endDate": end_date,
3617
+ "interval": interval
3618
+ })
3619
+
3620
+ logger.debug("Fetching index max drawdown for %s from %s to %s", index_symbol, start_date, end_date)
3621
+ return self._make_request("GET", self._routes["analytics.index.max_drawdown"], params=params)
3622
+
3623
+ def get_drawdown_duration(
3624
+ self,
3625
+ symbol: str,
3626
+ start_date: str,
3627
+ end_date: str,
3628
+ interval: str = "daily"
3629
+ ) -> Dict[str, Any]:
3630
+ """
3631
+ Get drawdown duration analysis for a stock or index.
3632
+
3633
+ Args:
3634
+ symbol (str): Stock or index symbol (e.g., INFY, NIFTY50).
3635
+ start_date (str): Start of analysis period (YYYY-MM-DD).
3636
+ end_date (str): End of analysis period (YYYY-MM-DD).
3637
+ interval (str, optional): Time interval ('daily', 'weekly', 'monthly'). Defaults to 'daily'.
3638
+
3639
+ Returns:
3640
+ Dict[str, Any]: Drawdown duration data.
3641
+
3642
+ Example Response:
3643
+ {
3644
+ "symbol": "INFY",
3645
+ "startDate": "2022-01-01",
3646
+ "endDate": "2024-01-01",
3647
+ "interval": "daily",
3648
+ "maxDrawdownDuration": 147,
3649
+ "averageDrawdownDuration": 23.5,
3650
+ "totalDrawdowns": 12,
3651
+ "unit": "days"
3652
+ }
3653
+ """
3654
+ params = self._normalize_params({
3655
+ "symbol": symbol,
3656
+ "startDate": start_date,
3657
+ "endDate": end_date,
3658
+ "interval": interval
3659
+ })
3660
+
3661
+ logger.debug("Fetching drawdown duration for %s from %s to %s", symbol, start_date, end_date)
3662
+ return self._make_request("GET", self._routes["analytics.instrument.drawdown_duration"], params=params)
3663
+
3664
+ def get_rolling_peak_price(
3665
+ self,
3666
+ symbol: str,
3667
+ start_date: str,
3668
+ end_date: str,
3669
+ window: int,
3670
+ adjusted: bool = True,
3671
+ interval: str = "daily"
3672
+ ) -> Dict[str, Any]:
3673
+ """
3674
+ Get rolling peak price analysis for a stock.
3675
+
3676
+ Args:
3677
+ symbol (str): Stock symbol (e.g., RELIANCE, NSE:TCS).
3678
+ start_date (str): Start of evaluation period (YYYY-MM-DD).
3679
+ end_date (str): End of evaluation period (YYYY-MM-DD).
3680
+ window (int): Rolling window size in days (1-252).
3681
+ adjusted (bool, optional): Adjust for corporate actions. Defaults to True.
3682
+ interval (str, optional): Time interval ('daily', 'weekly', 'monthly'). Defaults to 'daily'.
3683
+
3684
+ Returns:
3685
+ Dict[str, Any]: Rolling peak price data.
3686
+
3687
+ Example Response:
3688
+ {
3689
+ "symbol": "NSE:TCS",
3690
+ "startDate": "2024-01-01",
3691
+ "endDate": "2024-06-30",
3692
+ "window": 20,
3693
+ "interval": "daily",
3694
+ "adjusted": true,
3695
+ "data": [
3696
+ {"date": "2024-01-01", "price": 3500.0, "rollingPeak": 3500.0},
3697
+ {"date": "2024-01-02", "price": 3520.0, "rollingPeak": 3520.0}
3698
+ ]
3699
+ }
3700
+ """
3701
+ params = self._normalize_params({
3702
+ "symbol": symbol,
3703
+ "startDate": start_date,
3704
+ "endDate": end_date,
3705
+ "window": window,
3706
+ "adjusted": adjusted,
3707
+ "interval": interval
3708
+ })
3709
+
3710
+ logger.debug("Fetching rolling peak price for %s from %s to %s with window %d", symbol, start_date, end_date, window)
3711
+ return self._make_request("GET", self._routes["analytics.price.rolling_peak"], params=params)
3712
+
3713
+ def get_rolling_price_mean(
3714
+ self,
3715
+ symbol: str,
3716
+ start_date: str,
3717
+ end_date: str,
3718
+ window: int,
3719
+ adjusted: bool = True,
3720
+ interval: str = "daily"
3721
+ ) -> Dict[str, Any]:
3722
+ """
3723
+ Get rolling mean price analysis for a stock.
3724
+
3725
+ Args:
3726
+ symbol (str): Stock symbol (e.g., HDFCBANK, NSE:WIPRO).
3727
+ start_date (str): Start of evaluation period (YYYY-MM-DD).
3728
+ end_date (str): End of evaluation period (YYYY-MM-DD).
3729
+ window (int): Rolling window size in days (1-252).
3730
+ adjusted (bool, optional): Adjust for corporate actions. Defaults to True.
3731
+ interval (str, optional): Time interval ('daily', 'weekly', 'monthly'). Defaults to 'daily'.
3732
+
3733
+ Returns:
3734
+ Dict[str, Any]: Rolling mean price data.
3735
+
3736
+ Example Response:
3737
+ {
3738
+ "symbol": "NSE:HDFCBANK",
3739
+ "startDate": "2024-01-01",
3740
+ "endDate": "2024-06-30",
3741
+ "window": 20,
3742
+ "interval": "daily",
3743
+ "adjusted": true,
3744
+ "data": [
3745
+ {"date": "2024-01-01", "price": 1500.0, "rollingMean": 1500.0},
3746
+ {"date": "2024-01-02", "price": 1510.0, "rollingMean": 1505.0}
3747
+ ]
3748
+ }
3749
+ """
3750
+ params = self._normalize_params({
3751
+ "symbol": symbol,
3752
+ "startDate": start_date,
3753
+ "endDate": end_date,
3754
+ "window": window,
3755
+ "adjusted": adjusted,
3756
+ "interval": interval
3757
+ })
3758
+
3759
+ logger.debug("Fetching rolling mean price for %s from %s to %s with window %d", symbol, start_date, end_date, window)
3760
+ return self._make_request("GET", self._routes["analytics.price.rolling_mean"], params=params)
3761
+
3762
+ def get_realized_volatility(
3763
+ self,
3764
+ symbol: str,
3765
+ start_date: str,
3766
+ end_date: str,
3767
+ adjusted: bool = True,
3768
+ interval: str = "daily"
3769
+ ) -> Dict[str, Any]:
3770
+ """
3771
+ Get realized price volatility for a stock.
3772
+
3773
+ Args:
3774
+ symbol (str): Stock symbol or instrument ID (e.g., NSE:ITC, BHARTIARTL).
3775
+ start_date (str): Start of volatility calculation window (YYYY-MM-DD).
3776
+ end_date (str): End of volatility calculation window (YYYY-MM-DD).
3777
+ adjusted (bool, optional): Adjust prices for corporate actions. Defaults to True.
3778
+ interval (str, optional): Time interval ('daily', 'weekly', 'monthly'). Defaults to 'daily'.
3779
+
3780
+ Returns:
3781
+ Dict[str, Any]: Realized volatility data.
3782
+
3783
+ Example Response:
3784
+ {
3785
+ "symbol": "NSE:ITC",
3786
+ "startDate": "2024-01-01",
3787
+ "endDate": "2024-06-30",
3788
+ "interval": "daily",
3789
+ "adjusted": true,
3790
+ "realizedVolatility": 22.45,
3791
+ "annualizedVolatility": 35.67,
3792
+ "unit": "%"
3793
+ }
3794
+ """
3795
+ params = self._normalize_params({
3796
+ "symbol": symbol,
3797
+ "startDate": start_date,
3798
+ "endDate": end_date,
3799
+ "adjusted": adjusted,
3800
+ "interval": interval
3801
+ })
3802
+
3803
+ logger.debug("Fetching realized volatility for %s from %s to %s", symbol, start_date, end_date)
3804
+ return self._make_request("GET", self._routes["analytics.volatility.realized"], params=params)
3805
+
3806
+ def get_beta_90d(
3807
+ self,
3808
+ symbol: str,
3809
+ benchmark: str = "NIFTY50"
3810
+ ) -> Dict[str, Any]:
3811
+ """
3812
+ Get 90-day CAPM Beta for a stock relative to a benchmark.
3813
+
3814
+ Args:
3815
+ symbol (str): Stock symbol (e.g., RELIANCE, ITC).
3816
+ benchmark (str, optional): Benchmark index. Defaults to 'NIFTY50'.
3817
+
3818
+ Returns:
3819
+ Dict[str, Any]: 90-day beta data.
3820
+
3821
+ Example Response:
3822
+ {
3823
+ "symbol": "ITC",
3824
+ "benchmark": "NIFTY50",
3825
+ "period": "90d",
3826
+ "beta": 0.85,
3827
+ "correlation": 0.72,
3828
+ "rSquared": 0.52,
3829
+ "alpha": 0.03,
3830
+ "unit": "ratio"
3831
+ }
3832
+ """
3833
+ params = self._normalize_params({
3834
+ "symbol": symbol,
3835
+ "benchmark": benchmark
3836
+ })
3837
+
3838
+ logger.debug("Fetching 90d beta for %s vs %s", symbol, benchmark)
3839
+ return self._make_request("GET", self._routes["analytics.risk.beta_90d"], params=params)
3840
+
3841
+ def get_beta_custom_period(
3842
+ self,
3843
+ symbol: str,
3844
+ benchmark: str,
3845
+ start_date: str,
3846
+ end_date: str
3847
+ ) -> Dict[str, Any]:
3848
+ """
3849
+ Get CAPM Beta for a stock relative to a benchmark over a custom period.
3850
+
3851
+ Args:
3852
+ symbol (str): Stock symbol.
3853
+ benchmark (str): Benchmark index symbol.
3854
+ start_date (str): Start date (YYYY-MM-DD).
3855
+ end_date (str): End date (YYYY-MM-DD).
3856
+
3857
+ Returns:
3858
+ Dict[str, Any]: Custom period beta data.
3859
+
3860
+ Example Response:
3861
+ {
3862
+ "symbol": "ITC",
3863
+ "benchmark": "NIFTY50",
3864
+ "startDate": "2023-01-01",
3865
+ "endDate": "2025-01-01",
3866
+ "beta": 0.87,
3867
+ "correlation": 0.74,
3868
+ "rSquared": 0.55,
3869
+ "alpha": 0.02,
3870
+ "unit": "ratio"
3871
+ }
3872
+ """
3873
+ params = self._normalize_params({
3874
+ "symbol": symbol,
3875
+ "benchmark": benchmark,
3876
+ "startDate": start_date,
3877
+ "endDate": end_date
3878
+ })
3879
+
3880
+ logger.debug("Fetching custom period beta for %s vs %s from %s to %s", symbol, benchmark, start_date, end_date)
3881
+ return self._make_request("GET", self._routes["analytics.risk.beta_custom"], params=params)
3882
+
3883
+ def get_strategy_max_drawdown(
3884
+ self,
3885
+ strategy_id: str,
3886
+ start_date: str,
3887
+ end_date: str,
3888
+ interval: str = "daily"
3889
+ ) -> Dict[str, Any]:
3890
+ """
3891
+ Get maximum drawdown for a strategy over a specified period.
3892
+
3893
+ Args:
3894
+ strategy_id (str): Strategy identifier.
3895
+ start_date (str): Start date (YYYY-MM-DD).
3896
+ end_date (str): End date (YYYY-MM-DD).
3897
+ interval (str): Time interval ('daily', 'weekly', 'monthly').
3898
+
3899
+ Returns:
3900
+ Dict[str, Any]: Strategy max drawdown data.
3901
+
3902
+ Example Response:
3903
+ {
3904
+ "strategyId": "str_01jspb8z36edjsp5pecqq0mpm3",
3905
+ "startDate": "2023-01-01",
3906
+ "endDate": "2024-12-31",
3907
+ "maxDrawdown": -0.15,
3908
+ "peakDate": "2023-06-15",
3909
+ "troughDate": "2023-09-20",
3910
+ "peakNav": 1.25,
3911
+ "troughNav": 1.06
3912
+ }
3913
+ """
3914
+ params = self._normalize_params({
3915
+ "strategyId": strategy_id,
3916
+ "startDate": start_date,
3917
+ "endDate": end_date,
3918
+ "interval": interval
3919
+ })
3920
+
3921
+ logger.debug("Fetching max drawdown for strategy %s from %s to %s", strategy_id, start_date, end_date)
3922
+ return self._make_request("GET", self._routes["analytics.strategy.drawdown_max"], params=params)
3923
+
3924
+ def get_product_max_drawdown(
3925
+ self,
3926
+ product_id: str,
3927
+ start_date: str,
3928
+ end_date: str,
3929
+ interval: str = "daily"
3930
+ ) -> Dict[str, Any]:
3931
+ """
3932
+ Get maximum drawdown for a product over a specified period.
3933
+
3934
+ Args:
3935
+ product_id (str): Product identifier.
3936
+ start_date (str): Start date (YYYY-MM-DD).
3937
+ end_date (str): End date (YYYY-MM-DD).
3938
+ interval (str): Time interval ('daily', 'weekly', 'monthly').
3939
+
3940
+ Returns:
3941
+ Dict[str, Any]: Product max drawdown data.
3942
+
3943
+ Example Response:
3944
+ {
3945
+ "productId": "prd_01jyrg7ffkemq9hz3rkeznh9dr",
3946
+ "startDate": "2023-01-01",
3947
+ "endDate": "2024-12-31",
3948
+ "maxDrawdown": -0.12,
3949
+ "peakDate": "2023-05-10",
3950
+ "troughDate": "2023-08-15",
3951
+ "peakNav": 1.18,
3952
+ "troughNav": 1.04
3953
+ }
3954
+ """
3955
+ params = self._normalize_params({
3956
+ "productId": product_id,
3957
+ "startDate": start_date,
3958
+ "endDate": end_date,
3959
+ "interval": interval
3960
+ })
3961
+
3962
+ logger.debug("Fetching max drawdown for product %s from %s to %s", product_id, start_date, end_date)
3963
+ return self._make_request("GET", self._routes["analytics.product.drawdown_max"], params=params)
3964
+
3965
+ def get_atr(
3966
+ self,
3967
+ symbol: str,
3968
+ start_date: str,
3969
+ end_date: str,
3970
+ window: int,
3971
+ adjusted: bool = True,
3972
+ interval: str = "daily"
3973
+ ) -> Dict[str, Any]:
3974
+ """
3975
+ Calculate Average True Range (ATR) for a security over a specified period.
3976
+
3977
+ Args:
3978
+ symbol (str): Stock symbol.
3979
+ start_date (str): Start date (YYYY-MM-DD).
3980
+ end_date (str): End date (YYYY-MM-DD).
3981
+ window (int): Lookback period (e.g., 14, 20).
3982
+ adjusted (bool): Adjust for splits/dividends.
3983
+ interval (str): Time interval ('daily', 'weekly', 'intraday').
3984
+
3985
+ Returns:
3986
+ Dict[str, Any]: ATR data.
3987
+
3988
+ Example Response:
3989
+ {
3990
+ "symbol": "AXISBANK",
3991
+ "startDate": "2023-01-01",
3992
+ "endDate": "2024-12-31",
3993
+ "window": 14,
3994
+ "adjusted": true,
3995
+ "atr": [
3996
+ {
3997
+ "date": "2023-01-15",
3998
+ "atrValue": 25.67
3999
+ }
4000
+ ]
4001
+ }
4002
+ """
4003
+ params = self._normalize_params({
4004
+ "symbol": symbol,
4005
+ "startDate": start_date,
4006
+ "endDate": end_date,
4007
+ "window": window,
4008
+ "adjusted": adjusted,
4009
+ "interval": interval
4010
+ })
4011
+
4012
+ logger.debug("Fetching ATR for %s with window %d from %s to %s", symbol, window, start_date, end_date)
4013
+ return self._make_request("GET", self._routes["analytics.volatility.atr"], params=params)
4014
+
4015
+ def get_simple_return(
4016
+ self,
4017
+ symbol: str,
4018
+ start_date: str,
4019
+ end_date: str,
4020
+ adjusted: bool = True,
4021
+ interval: str = "daily",
4022
+ benchmark: Optional[str] = None
4023
+ ) -> Dict[str, Any]:
4024
+ """
4025
+ Calculate simple return for a security or sectoral index.
4026
+
4027
+ Args:
4028
+ symbol (str): Stock/index symbol.
4029
+ start_date (str): Start date (YYYY-MM-DD).
4030
+ end_date (str): End date (YYYY-MM-DD).
4031
+ adjusted (bool): Adjust for corporate actions.
4032
+ interval (str): Time interval ('daily', 'weekly', 'monthly').
4033
+ benchmark (str, optional): Benchmark for relative return calculation.
4034
+
4035
+ Returns:
4036
+ Dict[str, Any]: Simple return data.
4037
+
4038
+ Example Response:
4039
+ {
4040
+ "symbol": "NIFTY IT",
4041
+ "startDate": "2023-01-01",
4042
+ "endDate": "2024-12-31",
4043
+ "adjusted": true,
4044
+ "totalReturn": 0.15,
4045
+ "startPrice": 1250.0,
4046
+ "endPrice": 1437.5,
4047
+ "benchmarkReturn": 0.12,
4048
+ "relativeReturn": 0.03,
4049
+ "unit": "decimal"
4050
+ }
4051
+ """
4052
+ params = self._normalize_params({
4053
+ "symbol": symbol,
4054
+ "startDate": start_date,
4055
+ "endDate": end_date,
4056
+ "adjusted": adjusted,
4057
+ "interval": interval,
4058
+ "benchmark": benchmark
4059
+ })
4060
+
4061
+ logger.debug("Fetching simple return for %s from %s to %s", symbol, start_date, end_date)
4062
+ return self._make_request("GET", self._routes["analytics.returns.simple"], params=params)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wiz_trader
3
- Version: 0.38.0
3
+ Version: 0.40.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
@@ -2632,7 +2632,7 @@ def analyze_stock(symbol):
2632
2632
  print(f"=== Analysis for {symbol} ===\n")
2633
2633
 
2634
2634
  # Fundamentals
2635
- print("📊 FUNDAMENTALS:")
2635
+ print("[FUNDAMENTALS]:")
2636
2636
  try:
2637
2637
  margin = client.get_net_profit_margin(symbol)
2638
2638
  print(f" Net Profit Margin: {margin.get('netProfitMargin', 'N/A')}%")
@@ -2649,7 +2649,7 @@ def analyze_stock(symbol):
2649
2649
  print(f" Error fetching fundamentals: {e}")
2650
2650
 
2651
2651
  # Valuation
2652
- print("\n💰 VALUATION:")
2652
+ print("\n[VALUATION]:")
2653
2653
  try:
2654
2654
  pe = client.get_pe_ratio(symbol)
2655
2655
  print(f" P/E Ratio: {pe.get('peRatio', 'N/A')}")
@@ -2677,7 +2677,7 @@ def analyze_stock(symbol):
2677
2677
  print(f" Error fetching returns: {e}")
2678
2678
 
2679
2679
  # Ownership
2680
- print("\n🏛️ OWNERSHIP:")
2680
+ print("\n[OWNERSHIP]:")
2681
2681
  try:
2682
2682
  fii_dii = client.get_fii_dii_holdings(symbol)
2683
2683
  print(f" FII Holdings: {fii_dii.get('fiiPercent', 'N/A')}%")
@@ -2689,7 +2689,7 @@ def analyze_stock(symbol):
2689
2689
  print(f" Error fetching ownership: {e}")
2690
2690
 
2691
2691
  # Market Cap
2692
- print("\n🏢 MARKET DATA:")
2692
+ print("\n[MARKET DATA]:")
2693
2693
  try:
2694
2694
  mcap = client.get_free_float_market_cap(symbol)
2695
2695
  print(f" Market Cap: ₹{mcap.get('marketCap', 'N/A')} Crores")
@@ -2699,7 +2699,7 @@ def analyze_stock(symbol):
2699
2699
  print(f" Error fetching market data: {e}")
2700
2700
 
2701
2701
  # Risk Analysis
2702
- print("\n⚠️ RISK ANALYSIS:")
2702
+ print("\n[RISK ANALYSIS]:")
2703
2703
  try:
2704
2704
  max_drawdown = client.get_max_drawdown(
2705
2705
  symbol=symbol,
@@ -2718,7 +2718,7 @@ def analyze_stock(symbol):
2718
2718
  print(f" Error fetching risk metrics: {e}")
2719
2719
 
2720
2720
  # Sector Classification
2721
- print("\n🏭 SECTOR CLASSIFICATION:")
2721
+ print("\n[SECTOR CLASSIFICATION]:")
2722
2722
  try:
2723
2723
  sector = client.get_sector_classification(symbol)
2724
2724
  print(f" Sector: {sector.get('sector', 'N/A')}")
@@ -2728,7 +2728,7 @@ def analyze_stock(symbol):
2728
2728
  print(f" Error fetching sector data: {e}")
2729
2729
 
2730
2730
  # Leverage Analysis
2731
- print("\n💳 LEVERAGE ANALYSIS:")
2731
+ print("\n[LEVERAGE ANALYSIS]:")
2732
2732
  try:
2733
2733
  debt_equity = client.get_debt_equity_ratio(symbol)
2734
2734
  print(f" Debt-to-Equity Ratio: {debt_equity.get('debtEquityRatio', 'N/A')}")
@@ -2742,8 +2742,144 @@ for stock in stocks:
2742
2742
  print("\n" + "="*50 + "\n")
2743
2743
  ```
2744
2744
 
2745
+ #### Advanced Market Data Analysis
2746
+
2747
+ Advanced volume and drawdown analysis:
2748
+
2749
+ ```python
2750
+ # Average Traded Volume
2751
+ volume_data = client.get_average_traded_volume(
2752
+ symbol="HDFCBANK",
2753
+ start_date="2024-04-01",
2754
+ end_date="2024-06-30",
2755
+ interval="daily"
2756
+ )
2757
+ print(f"Average Volume: {volume_data['averageVolume']} shares")
2758
+
2759
+ # Index Maximum Drawdown
2760
+ index_drawdown = client.get_index_max_drawdown(
2761
+ index_symbol="NIFTY50",
2762
+ start_date="2023-01-01",
2763
+ end_date="2024-01-01",
2764
+ interval="daily"
2765
+ )
2766
+ print(f"Max Drawdown: {index_drawdown['maxDrawdown']}%")
2767
+
2768
+ # Drawdown Duration Analysis
2769
+ drawdown_duration = client.get_drawdown_duration(
2770
+ symbol="INFY",
2771
+ start_date="2022-01-01",
2772
+ end_date="2024-01-01",
2773
+ interval="daily"
2774
+ )
2775
+ print(f"Max Drawdown Duration: {drawdown_duration['maxDrawdownDuration']} days")
2776
+ ```
2777
+
2778
+ #### Technical Price Analysis
2779
+
2780
+ Rolling price analysis and volatility:
2781
+
2782
+ ```python
2783
+ # Rolling Peak Price Analysis
2784
+ rolling_peak = client.get_rolling_peak_price(
2785
+ symbol="NSE:TCS",
2786
+ start_date="2024-01-01",
2787
+ end_date="2024-06-30",
2788
+ window=20,
2789
+ adjusted=True
2790
+ )
2791
+ print(f"Rolling peak data points: {len(rolling_peak['data'])}")
2792
+
2793
+ # Rolling Price Mean
2794
+ rolling_mean = client.get_rolling_price_mean(
2795
+ symbol="HDFCBANK",
2796
+ start_date="2024-01-01",
2797
+ end_date="2024-06-30",
2798
+ window=50,
2799
+ adjusted=True
2800
+ )
2801
+ print(f"Rolling mean data points: {len(rolling_mean['data'])}")
2802
+
2803
+ # Realized Volatility
2804
+ volatility = client.get_realized_volatility(
2805
+ symbol="NSE:ITC",
2806
+ start_date="2024-01-01",
2807
+ end_date="2024-06-30",
2808
+ adjusted=True
2809
+ )
2810
+ print(f"Realized Volatility: {volatility['realizedVolatility']}%")
2811
+ print(f"Annualized Volatility: {volatility['annualizedVolatility']}%")
2812
+ ```
2813
+
2814
+ #### Advanced Risk Metrics
2815
+
2816
+ CAMP Beta analysis:
2817
+
2818
+ ```python
2819
+ # 90-Day Beta Analysis
2820
+ beta_90d = client.get_beta_90d(
2821
+ symbol="ITC",
2822
+ benchmark="NIFTY50"
2823
+ )
2824
+ print(f"90-Day Beta: {beta_90d['beta']}")
2825
+ print(f"Correlation: {beta_90d['correlation']}")
2826
+ print(f"R-Squared: {beta_90d['rSquared']}")
2827
+
2828
+ # Custom Period Beta
2829
+ beta_custom = client.get_beta_custom_period(
2830
+ symbol="TCS",
2831
+ benchmark="NIFTY50",
2832
+ start_date="2020-01-01",
2833
+ end_date="2024-12-31"
2834
+ )
2835
+ print(f"Custom Period Beta: {beta_custom['beta']}")
2836
+ print(f"Alpha: {beta_custom['alpha']}")
2837
+
2838
+ # Strategy Max Drawdown
2839
+ strategy_drawdown = client.get_strategy_max_drawdown(
2840
+ strategy_id="str_01jspb8z36edjsp5pecqq0mpm3",
2841
+ start_date="2023-01-01",
2842
+ end_date="2024-12-31",
2843
+ interval="daily"
2844
+ )
2845
+ print(f"Strategy Max Drawdown: {strategy_drawdown['maxDrawdown']}")
2846
+ print(f"Peak Date: {strategy_drawdown['peakDate']}")
2847
+
2848
+ # Product Max Drawdown
2849
+ product_drawdown = client.get_product_max_drawdown(
2850
+ product_id="prd_01jyrg7ffkemq9hz3rkeznh9dr",
2851
+ start_date="2023-01-01",
2852
+ end_date="2024-12-31",
2853
+ interval="monthly"
2854
+ )
2855
+ print(f"Product Max Drawdown: {product_drawdown['maxDrawdown']}")
2856
+
2857
+ # Average True Range (ATR)
2858
+ atr_data = client.get_atr(
2859
+ symbol="AXISBANK",
2860
+ start_date="2023-01-01",
2861
+ end_date="2024-12-31",
2862
+ window=14,
2863
+ adjusted=True,
2864
+ interval="daily"
2865
+ )
2866
+ print(f"Latest ATR: {atr_data['atr'][-1]['atrValue']}")
2867
+
2868
+ # Simple Return
2869
+ simple_return = client.get_simple_return(
2870
+ symbol="NIFTY_IT",
2871
+ start_date="2023-01-01",
2872
+ end_date="2024-12-31",
2873
+ adjusted=True,
2874
+ interval="daily",
2875
+ benchmark="NIFTY 50"
2876
+ )
2877
+ print(f"Total Return: {simple_return['totalReturn']}")
2878
+ print(f"Relative Return: {simple_return['relativeReturn']}")
2879
+ ```
2880
+
2745
2881
  **Key Features:**
2746
- - **Comprehensive Coverage**: 31+ analytics endpoints covering fundamentals, valuation, returns, market data, ownership, metrics, macro data, risk analysis, sector classification, and leverage analysis
2882
+ - **Comprehensive Coverage**: 43+ analytics endpoints covering fundamentals, valuation, returns, market data, ownership, metrics, macro data, risk analysis, sector classification, leverage analysis, and advanced technical analysis
2747
2883
  - **Fundamentals Analysis**: 9 methods including ROE, ROA, margins, ratios, book-to-market, market cap-to-sales, and cash-to-market cap
2748
2884
  - **Valuation Metrics**: P/E, P/B, EV/EBITDA, FCF yield with TTM and consolidated/standalone options
2749
2885
  - **Risk-Adjusted Metrics**: Sortino ratio, upside capture ratio, maximum drawdown, and returns volatility for comprehensive risk analysis
@@ -0,0 +1,9 @@
1
+ wiz_trader/__init__.py,sha256=bog0Jn-YW5ETXusjmXX21JD2sh1K_WyEWszgbHfub_o,183
2
+ wiz_trader/apis/__init__.py,sha256=6sUr1nzmplNdld0zryMrQSt0jHT2GhOiFYgKKVHzk8U,133
3
+ wiz_trader/apis/client.py,sha256=sJe30lBXEVDrzTAlMOzAliWGRGEzRRy1lmuFgsQR7lQ,134159
4
+ wiz_trader/quotes/__init__.py,sha256=RF9g9CNP6bVWlmCh_ad8krm3-EWOIuVfLp0-H9fAeEM,108
5
+ wiz_trader/quotes/client.py,sha256=cAGaysLCljZilYgX8Sf3V88F6dWlcewJf6TMOpSKb7I,20862
6
+ wiz_trader-0.40.0.dist-info/METADATA,sha256=nokoCOhZLcliNLqhUSz0MB9PW-VZlW_2WbSwRZMey4w,172350
7
+ wiz_trader-0.40.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ wiz_trader-0.40.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
+ wiz_trader-0.40.0.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- wiz_trader/__init__.py,sha256=kJG023DP-1kCLecHAiUKJ1g-Y7XKZQia75krhk_DHvY,183
2
- wiz_trader/apis/__init__.py,sha256=6sUr1nzmplNdld0zryMrQSt0jHT2GhOiFYgKKVHzk8U,133
3
- wiz_trader/apis/client.py,sha256=IGfOUgL5UpynGsBbYK-yVKkzMYT5iziVwrjQPLywTYk,116595
4
- wiz_trader/quotes/__init__.py,sha256=RF9g9CNP6bVWlmCh_ad8krm3-EWOIuVfLp0-H9fAeEM,108
5
- wiz_trader/quotes/client.py,sha256=cAGaysLCljZilYgX8Sf3V88F6dWlcewJf6TMOpSKb7I,20862
6
- wiz_trader-0.38.0.dist-info/METADATA,sha256=xuQB9B6Q_Zb_MIOzBHwoAgvVCiZVKEy3vOncFFad54g,168905
7
- wiz_trader-0.38.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- wiz_trader-0.38.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
- wiz_trader-0.38.0.dist-info/RECORD,,