wiz-trader 0.17.0__py3-none-any.whl → 0.19.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.17.0"
6
+ __version__ = "0.19.0"
7
7
 
8
8
  __all__ = ["QuotesClient", "WizzerClient"]
wiz_trader/apis/client.py CHANGED
@@ -2,6 +2,7 @@ import os
2
2
  import json
3
3
  import logging
4
4
  from typing import Dict, List, Optional, Union, Any
5
+ from datetime import datetime
5
6
 
6
7
  import requests
7
8
 
@@ -86,6 +87,70 @@ class WizzerClient:
86
87
  MONEYNESS_ATM = "ATM"
87
88
  MONEYNESS_ITM = "ITM"
88
89
  MONEYNESS_OTM = "OTM"
90
+
91
+ # Expiry preference constants
92
+ EXPIRY_CURRENT_WEEKLY = "current_weekly"
93
+ EXPIRY_NEAR_MONTH = "near_month"
94
+ EXPIRY_MID_MONTH = "mid_month"
95
+ EXPIRY_FAR_MONTH = "far_month"
96
+ EXPIRY_FIRST_WEEKLY = "first_weekly"
97
+ EXPIRY_SECOND_WEEKLY = "second_weekly"
98
+ EXPIRY_THIRD_WEEKLY = "third_weekly"
99
+ EXPIRY_FOURTH_WEEKLY = "fourth_weekly"
100
+ EXPIRY_FIFTH_WEEKLY = "fifth_weekly"
101
+ EXPIRY_FIRST_WEEKLY_MID_MONTH = "first_weekly_mid_month"
102
+ EXPIRY_SECOND_WEEKLY_MID_MONTH = "second_weekly_mid_month"
103
+ EXPIRY_THIRD_WEEKLY_MID_MONTH = "third_weekly_mid_month"
104
+ EXPIRY_FOURTH_WEEKLY_MID_MONTH = "fourth_weekly_mid_month"
105
+ EXPIRY_FIFTH_WEEKLY_MID_MONTH = "fifth_weekly_mid_month"
106
+ EXPIRY_FIRST_WEEKLY_FAR_MONTH = "first_weekly_far_month"
107
+ EXPIRY_SECOND_WEEKLY_FAR_MONTH = "second_weekly_far_month"
108
+ EXPIRY_THIRD_WEEKLY_FAR_MONTH = "third_weekly_far_month"
109
+ EXPIRY_FOURTH_WEEKLY_FAR_MONTH = "fourth_weekly_far_month"
110
+ EXPIRY_FIFTH_WEEKLY_FAR_MONTH = "fifth_weekly_far_month"
111
+ EXPIRY_FIRST_QUARTER = "first_quarter"
112
+ EXPIRY_SECOND_QUARTER = "second_quarter"
113
+ EXPIRY_THIRD_QUARTER = "third_quarter"
114
+ EXPIRY_FOURTH_QUARTER = "fourth_quarter"
115
+ EXPIRY_FIRST_HALF = "first_half_yearly"
116
+ EXPIRY_SECOND_HALF = "second_half_yearly"
117
+ EXPIRY_FIRST_QUARTER_PLUS_1 = "first_quarter_plus_1"
118
+ EXPIRY_SECOND_QUARTER_PLUS_1 = "second_quarter_plus_1"
119
+ EXPIRY_THIRD_QUARTER_PLUS_1 = "third_quarter_plus_1"
120
+ EXPIRY_FOURTH_QUARTER_PLUS_1 = "fourth_quarter_plus_1"
121
+ EXPIRY_FIRST_HALF_PLUS_1 = "first_half_yearly_plus_1"
122
+ EXPIRY_SECOND_HALF_PLUS_1 = "second_half_yearly_plus_1"
123
+ EXPIRY_FIRST_QUARTER_PLUS_2 = "first_quarter_plus_2"
124
+ EXPIRY_SECOND_QUARTER_PLUS_2 = "second_quarter_plus_2"
125
+ EXPIRY_THIRD_QUARTER_PLUS_2 = "third_quarter_plus_2"
126
+ EXPIRY_FOURTH_QUARTER_PLUS_2 = "fourth_quarter_plus_2"
127
+ EXPIRY_FIRST_HALF_PLUS_2 = "first_half_yearly_plus_2"
128
+ EXPIRY_SECOND_HALF_PLUS_2 = "second_half_yearly_plus_2"
129
+ EXPIRY_FIRST_QUARTER_PLUS_3 = "first_quarter_plus_3"
130
+ EXPIRY_SECOND_QUARTER_PLUS_3 = "second_quarter_plus_3"
131
+ EXPIRY_THIRD_QUARTER_PLUS_3 = "third_quarter_plus_3"
132
+ EXPIRY_FOURTH_QUARTER_PLUS_3 = "fourth_quarter_plus_3"
133
+ EXPIRY_FIRST_HALF_PLUS_3 = "first_half_yearly_plus_3"
134
+ EXPIRY_SECOND_HALF_PLUS_3 = "second_half_yearly_plus_3"
135
+ EXPIRY_FIRST_QUARTER_PLUS_4 = "first_quarter_plus_4"
136
+ EXPIRY_SECOND_QUARTER_PLUS_4 = "second_quarter_plus_4"
137
+ EXPIRY_THIRD_QUARTER_PLUS_4 = "third_quarter_plus_4"
138
+ EXPIRY_FOURTH_QUARTER_PLUS_4 = "fourth_quarter_plus_4"
139
+ EXPIRY_FIRST_HALF_PLUS_4 = "first_half_yearly_plus_4"
140
+ EXPIRY_SECOND_HALF_PLUS_4 = "second_half_yearly_plus_4"
141
+
142
+ # Historical data interval constants
143
+ INTERVAL_1_MINUTE = "1m"
144
+ INTERVAL_2_MINUTES = "2m"
145
+ INTERVAL_3_MINUTES = "3m"
146
+ INTERVAL_5_MINUTES = "5m"
147
+ INTERVAL_10_MINUTES = "10m"
148
+ INTERVAL_15_MINUTES = "15m"
149
+ INTERVAL_30_MINUTES = "30m"
150
+ INTERVAL_45_MINUTES = "45m"
151
+ INTERVAL_1_HOUR = "1h"
152
+ INTERVAL_1_DAY = "1d"
153
+ INTERVAL_1_MONTH = "1M"
89
154
 
90
155
  # URIs to various API endpoints
91
156
  _routes = {
@@ -121,7 +186,8 @@ class WizzerClient:
121
186
 
122
187
  # Instrument & asset class endpoints
123
188
  "instrument.metrics": "/instruments/metrics",
124
- "instrument.option_chain": "/instruments/options/chain"
189
+ "instrument.option_chain": "/instruments/options/chain",
190
+ "instrument.expiry_list": "/instruments/options/chain/expirylist"
125
191
  }
126
192
 
127
193
  def __init__(
@@ -177,6 +243,33 @@ class WizzerClient:
177
243
 
178
244
  return {"id": self.strategy_id}
179
245
 
246
+ def _validate_datetime_format(self, datetime_str: str, interval: str) -> bool:
247
+ """
248
+ Validate datetime format based on interval type.
249
+
250
+ Args:
251
+ datetime_str (str): The datetime string to validate
252
+ interval (str): The interval type
253
+
254
+ Returns:
255
+ bool: True if format is valid for the interval
256
+ """
257
+ # For daily and monthly intervals, only date is required
258
+ if interval in [self.INTERVAL_1_DAY, self.INTERVAL_1_MONTH]:
259
+ try:
260
+ datetime.strptime(datetime_str, "%Y-%m-%d")
261
+ return True
262
+ except ValueError:
263
+ return False
264
+
265
+ # For intraday intervals, datetime is required
266
+ else:
267
+ try:
268
+ datetime.strptime(datetime_str, "%Y-%m-%d %H:%M:%S")
269
+ return True
270
+ except ValueError:
271
+ return False
272
+
180
273
  # ===== DATA HUB METHODS =====
181
274
 
182
275
  def get_indices(self, trading_symbol: Optional[str] = None, exchange: Optional[str] = None) -> List[Dict[str, Any]]:
@@ -220,7 +313,7 @@ class WizzerClient:
220
313
  logger.debug("Fetching index components with params: %s", params)
221
314
  response = self._make_request("GET", self._routes["datahub.index.components"], params=params)
222
315
  return response
223
-
316
+
224
317
  def get_historical_ohlcv(
225
318
  self,
226
319
  instruments: List[str],
@@ -234,14 +327,41 @@ class WizzerClient:
234
327
 
235
328
  Args:
236
329
  instruments (List[str]): List of instrument identifiers (e.g., ["NSE:SBIN:3045"]).
237
- start_date (str): Start date in YYYY-MM-DD format.
238
- end_date (str): End date in YYYY-MM-DD format.
330
+ start_date (str): Start date. For daily/monthly intervals: YYYY-MM-DD format.
331
+ For intraday intervals: YYYY-MM-DD HH:MM:SS format.
332
+ end_date (str): End date. For daily/monthly intervals: YYYY-MM-DD format.
333
+ For intraday intervals: YYYY-MM-DD HH:MM:SS format.
239
334
  ohlcv (List[str]): List of OHLCV fields to retrieve (open, high, low, close, volume).
240
- interval (str, optional): Data interval. Options: "1d" (daily, default), "1M" (monthly - last trading day of month).
335
+ interval (str, optional): Data interval. Options:
336
+ - Intraday: "1m", "2m", "3m", "5m", "10m", "15m", "30m", "45m", "1h"
337
+ - Daily: "1d" (default)
338
+ - Monthly: "1M" (last trading day of month)
339
+
340
+ Use constants like client.INTERVAL_5_MINUTES, client.INTERVAL_1_DAY, etc.
241
341
 
242
342
  Returns:
243
343
  List[Dict[str, Any]]: Historical data for requested instruments.
344
+
345
+ Note: For daily/monthly intervals, the 'date' field contains YYYY-MM-DD.
346
+ For intraday intervals, the 'date' field contains YYYY-MM-DD HH:MM:SS.
347
+
348
+ Raises:
349
+ ValueError: If datetime format doesn't match the interval requirements.
244
350
  """
351
+ # Validate datetime formats
352
+ if not self._validate_datetime_format(start_date, interval):
353
+ if interval in [self.INTERVAL_1_DAY, self.INTERVAL_1_MONTH]:
354
+ raise ValueError(f"For interval '{interval}', start_date must be in YYYY-MM-DD format")
355
+ else:
356
+ raise ValueError(f"For interval '{interval}', start_date must be in YYYY-MM-DD HH:MM:SS format")
357
+
358
+ if not self._validate_datetime_format(end_date, interval):
359
+ if interval in [self.INTERVAL_1_DAY, self.INTERVAL_1_MONTH]:
360
+ raise ValueError(f"For interval '{interval}', end_date must be in YYYY-MM-DD format")
361
+ else:
362
+ raise ValueError(f"For interval '{interval}', end_date must be in YYYY-MM-DD HH:MM:SS format")
363
+
364
+ endpoint = self._routes["datahub.historical.ohlcv"]
245
365
  data = {
246
366
  "instruments": instruments,
247
367
  "startDate": start_date,
@@ -251,7 +371,7 @@ class WizzerClient:
251
371
  }
252
372
 
253
373
  logger.debug("Fetching historical OHLCV with data: %s", data)
254
- response = self._make_request("POST", self._routes["datahub.historical.ohlcv"], json=data)
374
+ response = self._make_request("POST", endpoint, json=data)
255
375
  return response
256
376
 
257
377
  # ===== ORDER MANAGEMENT METHODS =====
@@ -1310,9 +1430,10 @@ class WizzerClient:
1310
1430
  def get_option_chain(
1311
1431
  self,
1312
1432
  identifier: str,
1313
- expiry_date: str,
1314
- option_type: List[str],
1315
- moneyness: List[str]
1433
+ expiry_date: Optional[str] = None,
1434
+ expiry_preference: Optional[str] = None,
1435
+ option_type: List[str] = None,
1436
+ moneyness: List[str] = None
1316
1437
  ) -> Dict[str, Any]:
1317
1438
  """
1318
1439
  Get option chain for a specified instrument.
@@ -1320,6 +1441,8 @@ class WizzerClient:
1320
1441
  Args:
1321
1442
  identifier (str): Instrument identifier (e.g., "NSE:SBIN:3045").
1322
1443
  expiry_date (str): Expiry date in YYYY-MM-DD format.
1444
+ expiry_preference (Optional[str]): Expiry category preference instead of exact date.
1445
+ Use the EXPIRY_* constants provided by the class.
1323
1446
  option_type (List[str]): List of option types to include.
1324
1447
  Values from [OPTION_TYPE_CE, OPTION_TYPE_PE].
1325
1448
  moneyness (List[str]): List of moneyness types to include.
@@ -1338,6 +1461,8 @@ class WizzerClient:
1338
1461
  raise ValueError("At least one option type must be specified")
1339
1462
  if not moneyness:
1340
1463
  raise ValueError("At least one moneyness type must be specified")
1464
+ if not expiry_date and not expiry_preference:
1465
+ raise ValueError("Either expiry_date or expiry_preference must be provided")
1341
1466
 
1342
1467
  # Validate option_type values
1343
1468
  valid_option_types = [self.OPTION_TYPE_CE, self.OPTION_TYPE_PE]
@@ -1353,14 +1478,55 @@ class WizzerClient:
1353
1478
 
1354
1479
  data = {
1355
1480
  "identifier": identifier,
1356
- "expiryDate": expiry_date,
1357
1481
  "optionType": option_type,
1358
1482
  "moneyness": moneyness
1359
1483
  }
1360
1484
 
1485
+ # Add either expiryDate or expiryPreference
1486
+ if expiry_date:
1487
+ data["expiryDate"] = expiry_date
1488
+ elif expiry_preference:
1489
+ data["expiryPreference"] = expiry_preference
1490
+
1361
1491
  logger.debug("Fetching option chain with data: %s", data)
1362
1492
  return self._make_request("POST", endpoint, json=data)
1363
1493
 
1494
+ def get_option_expiry_list(
1495
+ self,
1496
+ identifier: str
1497
+ ) -> Dict[str, Any]:
1498
+ """
1499
+ Get a list of available expiry dates for an instrument's options.
1500
+
1501
+ Args:
1502
+ identifier (str): Instrument identifier in the format "EXCHANGE:SYMBOL:TOKEN"
1503
+ (e.g., "NSE:SBIN:3045" or "NSE:NIFTY 50:26000").
1504
+
1505
+ Returns:
1506
+ Dict[str, Any]: Response containing the list of available expiry dates with contract types.
1507
+
1508
+ Example:
1509
+ ```python
1510
+ # Get expiry dates for a stock
1511
+ expiry_list = client.get_option_expiry_list("NSE:SBIN:3045")
1512
+
1513
+ # Get expiry dates for an index
1514
+ nifty_expiry = client.get_option_expiry_list("NSE:NIFTY 50:26000")
1515
+
1516
+ # Access the expiry dates
1517
+ for expiry in expiry_list.get('expiryList', []):
1518
+ print(f"{expiry['date']} - {expiry['contract']}")
1519
+ ```
1520
+ """
1521
+ endpoint = self._routes["instrument.expiry_list"]
1522
+
1523
+ data = {
1524
+ "identifier": identifier
1525
+ }
1526
+
1527
+ logger.debug("Fetching option expiry list for %s", identifier)
1528
+ return self._make_request("POST", endpoint, json=data)
1529
+
1364
1530
  def _make_request(
1365
1531
  self,
1366
1532
  method: str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wiz_trader
3
- Version: 0.17.0
3
+ Version: 0.19.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
@@ -388,29 +388,388 @@ for component in components[:5]:
388
388
  ```
389
389
 
390
390
  #### Get Historical OHLCV Data
391
+ ## Overview
391
392
 
392
- Fetch historical price data for instruments:
393
+ The `get_historical_ohlcv` method supports multiple time intervals for historical data retrieval, from 1-minute intraday data to monthly aggregated data.
394
+
395
+ ## Supported Intervals
396
+
397
+ ### Intraday Intervals
398
+ - `1m` - 1 minute
399
+ - `2m` - 2 minutes
400
+ - `3m` - 3 minutes
401
+ - `5m` - 5 minutes
402
+ - `10m` - 10 minutes
403
+ - `15m` - 15 minutes
404
+ - `30m` - 30 minutes
405
+ - `45m` - 45 minutes
406
+ - `1h` - 1 hour
407
+
408
+ ### Daily/Monthly Intervals
409
+ - `1d` - 1 day (default)
410
+ - `1M` - 1 month (last trading day of month)
411
+
412
+ ## Date Format Requirements
413
+
414
+ ### For Daily and Monthly Intervals (`1d`, `1M`)
415
+ - **Format**: `YYYY-MM-DD`
416
+ - **Example**: `"2024-01-15"`
417
+
418
+ ### For Intraday Intervals (all minute/hour intervals)
419
+ - **Format**: `YYYY-MM-DD HH:MM:SS`
420
+ - **Example**: `"2024-01-15 09:30:00"`
421
+
422
+ ## Using Constants
423
+
424
+ The client provides constants for all intervals:
425
+
426
+ ```python
427
+ from wiz_trader import WizzerClient
428
+
429
+ client = WizzerClient(...)
430
+
431
+ # Intraday intervals
432
+ client.INTERVAL_1_MINUTE # "1m"
433
+ client.INTERVAL_2_MINUTES # "2m"
434
+ client.INTERVAL_3_MINUTES # "3m"
435
+ client.INTERVAL_5_MINUTES # "5m"
436
+ client.INTERVAL_10_MINUTES # "10m"
437
+ client.INTERVAL_15_MINUTES # "15m"
438
+ client.INTERVAL_30_MINUTES # "30m"
439
+ client.INTERVAL_45_MINUTES # "45m"
440
+ client.INTERVAL_1_HOUR # "1h"
441
+
442
+ # Daily/Monthly intervals
443
+ client.INTERVAL_1_DAY # "1d"
444
+ client.INTERVAL_1_MONTH # "1M"
445
+ ```
446
+
447
+ ## Usage Examples
448
+
449
+ ### 1. Get 5-minute intraday data
450
+
451
+ ```python
452
+ # Get 5-minute candles for a trading session
453
+ intraday_data = client.get_historical_ohlcv(
454
+ instruments=["NSE:SBIN:3045"],
455
+ start_date="2024-01-15 09:15:00", # Market open
456
+ end_date="2024-01-15 15:30:00", # Market close
457
+ ohlcv=["open", "high", "low", "close", "volume"],
458
+ interval=client.INTERVAL_5_MINUTES
459
+ )
460
+
461
+ # Response will have date field as: "2024-01-15 09:15:00", "2024-01-15 09:20:00", etc.
462
+ ```
463
+
464
+ ### 2. Get 1-minute data for scalping
465
+
466
+ ```python
467
+ # Get 1-minute data for the first hour of trading
468
+ scalping_data = client.get_historical_ohlcv(
469
+ instruments=["NSE:RELIANCE:2885", "NSE:TCS:2953"],
470
+ start_date="2024-01-15 09:15:00",
471
+ end_date="2024-01-15 10:15:00",
472
+ ohlcv=["open", "high", "low", "close", "volume"],
473
+ interval=client.INTERVAL_1_MINUTE
474
+ )
475
+ ```
476
+
477
+ ### 3. Get hourly data for swing trading
478
+
479
+ ```python
480
+ # Get hourly data for a week
481
+ hourly_data = client.get_historical_ohlcv(
482
+ instruments=["NSE:NIFTY 50:26000"],
483
+ start_date="2024-01-15 09:15:00",
484
+ end_date="2024-01-19 15:30:00",
485
+ ohlcv=["open", "high", "low", "close", "volume"],
486
+ interval=client.INTERVAL_1_HOUR
487
+ )
488
+ ```
489
+
490
+ ### 4. Get daily data (traditional)
393
491
 
394
492
  ```python
395
- # Get daily data
493
+ # Get daily data for a month
396
494
  daily_data = client.get_historical_ohlcv(
397
495
  instruments=["NSE:SBIN:3045"],
398
- start_date="2024-01-01",
496
+ start_date="2024-01-01", # Note: No time component
399
497
  end_date="2024-01-31",
400
498
  ohlcv=["open", "high", "low", "close", "volume"],
401
- interval="1d" # Daily data (default)
499
+ interval=client.INTERVAL_1_DAY
402
500
  )
403
501
 
404
- # Get monthly data
502
+ # Response will have date field as: "2024-01-01", "2024-01-02", etc.
503
+ ```
504
+
505
+ ### 5. Get monthly data for long-term analysis
506
+
507
+ ```python
508
+ # Get monthly data for a year
405
509
  monthly_data = client.get_historical_ohlcv(
406
- instruments=["NSE:SBIN:3045", "NSE:ICICIBANK:4963"],
510
+ instruments=["NSE:SBIN:3045"],
407
511
  start_date="2023-01-01",
408
- end_date="2024-01-01",
512
+ end_date="2023-12-31",
409
513
  ohlcv=["close", "volume"],
410
- interval="1M" # Monthly data
514
+ interval=client.INTERVAL_1_MONTH
515
+ )
516
+ ```
517
+
518
+ ## Response Structure
519
+
520
+ The response structure remains the same, but the `date` field format varies:
521
+
522
+ ### For Daily/Monthly Intervals
523
+ ```json
524
+ {
525
+ "instrument": {
526
+ "exchange": "NSE",
527
+ "tradingSymbol": "SBIN",
528
+ "exchangeToken": 3045,
529
+ "identifier": "NSE:SBIN:3045"
530
+ },
531
+ "data": [
532
+ {
533
+ "date": "2024-01-15", // YYYY-MM-DD format
534
+ "open": 750.0,
535
+ "high": 765.0,
536
+ "low": 745.0,
537
+ "close": 760.0,
538
+ "volume": 1000000
539
+ }
540
+ ]
541
+ }
542
+ ```
543
+
544
+ ### For Intraday Intervals
545
+ ```json
546
+ {
547
+ "instrument": {
548
+ "exchange": "NSE",
549
+ "tradingSymbol": "SBIN",
550
+ "exchangeToken": 3045,
551
+ "identifier": "NSE:SBIN:3045"
552
+ },
553
+ "data": [
554
+ {
555
+ "date": "2024-01-15 09:15:00", // YYYY-MM-DD HH:MM:SS format
556
+ "open": 750.0,
557
+ "high": 752.0,
558
+ "low": 749.0,
559
+ "close": 751.0,
560
+ "volume": 50000
561
+ }
562
+ ]
563
+ }
564
+ ```
565
+
566
+ ## Advanced Usage Examples
567
+
568
+ ### Multiple Timeframe Analysis
569
+
570
+ ```python
571
+ def get_multi_timeframe_data(symbol, date):
572
+ """Get data across multiple timeframes for comprehensive analysis"""
573
+
574
+ # 1-minute data for entry/exit precision
575
+ minute_data = client.get_historical_ohlcv(
576
+ instruments=[symbol],
577
+ start_date=f"{date} 09:15:00",
578
+ end_date=f"{date} 15:30:00",
579
+ ohlcv=["open", "high", "low", "close", "volume"],
580
+ interval=client.INTERVAL_1_MINUTE
581
+ )
582
+
583
+ # 5-minute data for short-term trends
584
+ five_min_data = client.get_historical_ohlcv(
585
+ instruments=[symbol],
586
+ start_date=f"{date} 09:15:00",
587
+ end_date=f"{date} 15:30:00",
588
+ ohlcv=["open", "high", "low", "close", "volume"],
589
+ interval=client.INTERVAL_5_MINUTES
590
+ )
591
+
592
+ # 15-minute data for medium-term trends
593
+ fifteen_min_data = client.get_historical_ohlcv(
594
+ instruments=[symbol],
595
+ start_date=f"{date} 09:15:00",
596
+ end_date=f"{date} 15:30:00",
597
+ ohlcv=["open", "high", "low", "close", "volume"],
598
+ interval=client.INTERVAL_15_MINUTES
599
+ )
600
+
601
+ # Hourly data for major trend
602
+ hourly_data = client.get_historical_ohlcv(
603
+ instruments=[symbol],
604
+ start_date=f"{date} 09:15:00",
605
+ end_date=f"{date} 15:30:00",
606
+ ohlcv=["open", "high", "low", "close", "volume"],
607
+ interval=client.INTERVAL_1_HOUR
608
+ )
609
+
610
+ return {
611
+ "1m": minute_data,
612
+ "5m": five_min_data,
613
+ "15m": fifteen_min_data,
614
+ "1h": hourly_data
615
+ }
616
+
617
+ # Usage
618
+ multi_data = get_multi_timeframe_data("NSE:SBIN:3045", "2024-01-15")
619
+ ```
620
+
621
+ ### Building OHLC Candlestick Data
622
+
623
+ ```python
624
+ import pandas as pd
625
+ import matplotlib.pyplot as plt
626
+ from mplfinance import plot as mpf
627
+
628
+ def plot_candlestick_chart(symbol, start_date, end_date, interval):
629
+ """Create a candlestick chart from historical data"""
630
+
631
+ # Get historical data
632
+ data = client.get_historical_ohlcv(
633
+ instruments=[symbol],
634
+ start_date=start_date,
635
+ end_date=end_date,
636
+ ohlcv=["open", "high", "low", "close", "volume"],
637
+ interval=interval
638
+ )
639
+
640
+ if not data or not data[0].get('data'):
641
+ print("No data available")
642
+ return
643
+
644
+ # Convert to DataFrame
645
+ df = pd.DataFrame(data[0]['data'])
646
+ df['date'] = pd.to_datetime(df['date'])
647
+ df.set_index('date', inplace=True)
648
+
649
+ # Rename columns for mplfinance
650
+ df.columns = ['Open', 'High', 'Low', 'Close', 'Volume']
651
+
652
+ # Create candlestick chart
653
+ mpf.plot(df, type='candle', volume=True,
654
+ title=f'{symbol} - {interval} Chart',
655
+ style='charles')
656
+
657
+ # Plot 5-minute chart
658
+ plot_candlestick_chart(
659
+ "NSE:SBIN:3045",
660
+ "2024-01-15 09:15:00",
661
+ "2024-01-15 15:30:00",
662
+ client.INTERVAL_5_MINUTES
663
+ )
664
+ ```
665
+
666
+ ### Backtesting with Different Intervals
667
+
668
+ ```python
669
+ def backtest_strategy_multiple_intervals(symbol, start_date, end_date):
670
+ """Backtest a strategy across different intervals"""
671
+
672
+ intervals = [
673
+ (client.INTERVAL_5_MINUTES, "5m"),
674
+ (client.INTERVAL_15_MINUTES, "15m"),
675
+ (client.INTERVAL_30_MINUTES, "30m"),
676
+ (client.INTERVAL_1_HOUR, "1h")
677
+ ]
678
+
679
+ results = {}
680
+
681
+ for interval_code, interval_name in intervals:
682
+ # For intraday intervals, use datetime format
683
+ data = client.get_historical_ohlcv(
684
+ instruments=[symbol],
685
+ start_date=f"{start_date} 09:15:00",
686
+ end_date=f"{end_date} 15:30:00",
687
+ ohlcv=["open", "high", "low", "close", "volume"],
688
+ interval=interval_code
689
+ )
690
+
691
+ if data and data[0].get('data'):
692
+ df = pd.DataFrame(data[0]['data'])
693
+ df['date'] = pd.to_datetime(df['date'])
694
+
695
+ # Simple moving average crossover strategy
696
+ df['sma_10'] = df['close'].rolling(10).mean()
697
+ df['sma_20'] = df['close'].rolling(20).mean()
698
+
699
+ # Generate signals
700
+ df['signal'] = 0
701
+ df.loc[df['sma_10'] > df['sma_20'], 'signal'] = 1
702
+ df.loc[df['sma_10'] < df['sma_20'], 'signal'] = -1
703
+
704
+ # Calculate returns
705
+ df['returns'] = df['close'].pct_change()
706
+ df['strategy_returns'] = df['signal'].shift(1) * df['returns']
707
+
708
+ # Calculate total return
709
+ total_return = (1 + df['strategy_returns']).prod() - 1
710
+
711
+ results[interval_name] = {
712
+ 'total_return': total_return,
713
+ 'num_trades': df['signal'].diff().abs().sum() / 2,
714
+ 'num_candles': len(df)
715
+ }
716
+
717
+ return results
718
+
719
+ # Compare strategy performance across intervals
720
+ performance = backtest_strategy_multiple_intervals(
721
+ "NSE:SBIN:3045",
722
+ "2024-01-01",
723
+ "2024-01-31"
411
724
  )
725
+
726
+ for interval, metrics in performance.items():
727
+ print(f"{interval}: Return={metrics['total_return']:.2%}, "
728
+ f"Trades={metrics['num_trades']:.0f}, "
729
+ f"Candles={metrics['num_candles']}")
730
+ ```
731
+
732
+ ## Error Handling
733
+
734
+ ```python
735
+ try:
736
+ data = client.get_historical_ohlcv(
737
+ instruments=["NSE:SBIN:3045"],
738
+ start_date="2024-01-15 09:15:00",
739
+ end_date="2024-01-15 15:30:00",
740
+ ohlcv=["open", "high", "low", "close", "volume"],
741
+ interval=client.INTERVAL_5_MINUTES
742
+ )
743
+ except ValueError as e:
744
+ print(f"Date format error: {e}")
745
+ except Exception as e:
746
+ print(f"API error: {e}")
412
747
  ```
413
748
 
749
+ ## Best Practices
750
+
751
+ 1. **Use appropriate intervals for your strategy**:
752
+ - Scalping: 1m, 2m, 3m
753
+ - Day trading: 5m, 15m, 30m
754
+ - Swing trading: 1h, 1d
755
+ - Position trading: 1d, 1M
756
+
757
+ 2. **Be mindful of data volume**:
758
+ - 1-minute data generates a lot of candles
759
+ - Use shorter date ranges for minute-level data
760
+
761
+ 3. **Validate date formats**:
762
+ - The client will validate formats automatically
763
+ - Use datetime strings consistently
764
+
765
+ 4. **Consider market hours**:
766
+ - For intraday data, use market hours: 09:15:00 to 15:30:00
767
+ - Weekend dates won't have intraday data
768
+
769
+ 5. **Cache data when possible**:
770
+ - Historical data doesn't change
771
+ - Store frequently used datasets locally
772
+
414
773
  ### Order Management
415
774
 
416
775
  #### Place Regular Order
@@ -643,13 +1002,13 @@ Fetch detailed information and metrics for specific instruments:
643
1002
 
644
1003
  ```python
645
1004
  # Get metrics for a single equity instrument
646
- equity_info = client.get_instrument_metrics(instrument_identifiers=["NSE:SBIN:3045"])
1005
+ equity_info = client.get_instrument_metrics(identifiers=["NSE:SBIN:3045"])
647
1006
  print(f"SBIN Last Price: {equity_info[0]['ltp']}")
648
1007
  print(f"SBIN 52-week High: {equity_info[0]['week52High']}")
649
1008
 
650
1009
  # Get metrics for multiple instruments of different types
651
1010
  instruments_info = client.get_instrument_metrics(
652
- instrument_identifiers=[
1011
+ identifiers=[
653
1012
  "NSE:AARTIIND:7", # Equity
654
1013
  "NSE:NIFTY26DEC11000CE:61009", # Option
655
1014
  "NSE:SBIN25MAYFUT:57515" # Future
@@ -831,12 +1190,150 @@ Note that certain fields may have zero or empty values if the data is not availa
831
1190
 
832
1191
  ### Options Chain
833
1192
 
1193
+ #### Get Option Expiry List
1194
+
1195
+ Fetch available expiry dates for an instrument's options:
1196
+
1197
+ ```python
1198
+ # For a stock
1199
+ expiry_list = client.get_option_expiry_list("NSE:SBIN:3045")
1200
+
1201
+ # For an index
1202
+ nifty_expiry = client.get_option_expiry_list("NSE:NIFTY 50:26000")
1203
+
1204
+ # Print all available expiry dates
1205
+ for expiry in expiry_list.get('expiryList', []):
1206
+ print(f"{expiry['date']} - {expiry['contract']} " +
1207
+ f"(Futures: {'Yes' if expiry['isFuturesExpiry'] else 'No'}, " +
1208
+ f"Options: {'Yes' if expiry['isOptionsExpiry'] else 'No'})")
1209
+ ```
1210
+
1211
+ #### Response Structure
1212
+
1213
+ The response is a JSON object with the following structure:
1214
+
1215
+ ```json
1216
+ {
1217
+ "exchange": "NSE", // Exchange of the instrument
1218
+ "tradingSymbol": "SBIN", // Trading symbol
1219
+ "exchangeToken": 3045, // Exchange token
1220
+ "identifier": "NSE:SBIN:3045", // Full identifier
1221
+ "expiryList": [ // Array of expiry objects
1222
+ {
1223
+ "date": "2025-05-29", // Expiry date in YYYY-MM-DD format
1224
+ "contract": "near_month", // Contract type (see below)
1225
+ "isFuturesExpiry": true, // Whether futures expire on this date
1226
+ "isOptionsExpiry": true // Whether options expire on this date
1227
+ },
1228
+ // More expiry objects...
1229
+ ]
1230
+ }
1231
+ ```
1232
+
1233
+ For index options like NIFTY, the response will typically include more expiry dates, including weekly options and longer-dated quarterly options.
1234
+
1235
+ The `expiryList` array contains objects with the following fields:
1236
+ - `date`: The expiry date in YYYY-MM-DD format
1237
+ - `contract`: The type of contract (e.g., "near_month", "current_weekly")
1238
+ - `isFuturesExpiry`: Boolean indicating if futures expire on this date
1239
+ - `isOptionsExpiry`: Boolean indicating if options expire on this date
1240
+
1241
+ #### Contract Types
1242
+
1243
+ Each expiry date is categorized with a `contract` field that indicates the type of expiry. The possible contract types are:
1244
+
1245
+ 1. **Weekly Expiries (Thursdays/Wednesdays)**
1246
+ - `current_weekly`: The first non-expiry Thursday of the current week
1247
+
1248
+ 2. **Monthly Expiries (last Wed/Thu of month)**
1249
+ - `near_month`: Last Wed/Thu of this month (current month)
1250
+ - `mid_month`: Last Wed/Thu of next month
1251
+ - `far_month`: Last Wed/Thu of month after next
1252
+
1253
+ 3. **Weekly Ordinals Within Current Month**
1254
+ - `first_weekly`: 1st non-expiry Thursday of current month
1255
+ - `second_weekly`: 2nd non-expiry Thursday
1256
+ - `third_weekly`: 3rd non-expiry Thursday
1257
+ - `fourth_weekly`: 4th non-expiry Thursday
1258
+ - `fifth_weekly`: 5th non-expiry Thursday (rare)
1259
+
1260
+ 4. **Weekly Ordinals in Mid-Month Slot (next month's week-trade dates)**
1261
+ - `first_weekly_mid_month`: 1st Thursday of next month
1262
+ - `second_weekly_mid_month`: 2nd Thursday of next month
1263
+ - `third_weekly_mid_month`: 3rd Thursday of next month
1264
+ - `fourth_weekly_mid_month`: 4th Thursday of next month
1265
+ - `fifth_weekly_mid_month`: 5th Thursday of next month (rare)
1266
+
1267
+ 5. **Weekly Ordinals in Far-Month Slot (month-after-next)**
1268
+ - `first_weekly_far_month`: 1st Thursday of month after next
1269
+ - `second_weekly_far_month`: 2nd Thursday of month after next
1270
+ - `third_weekly_far_month`: 3rd Thursday of month after next
1271
+ - `fourth_weekly_far_month`: 4th Thursday of month after next
1272
+ - `fifth_weekly_far_month`: 5th Thursday of month after next (rare)
1273
+
1274
+ 6. **Quarterly Expiries (last-Thu of Mar/Jun/Sep/Dec)**
1275
+ - `first_quarter`: Last Thu of March (Q1)
1276
+ - `second_quarter`: Last Thu of June (Q2)
1277
+ - `third_quarter`: Last Thu of September (Q3)
1278
+ - `fourth_quarter`: Last Thu of December (Q4)
1279
+
1280
+ 7. **Half-Yearly Expiries**
1281
+ - `first_half_yearly`: Last Thu of June (H1)
1282
+ - `second_half_yearly`: Last Thu of December (H2)
1283
+
1284
+ 8. **Year-Plus-N Quarterly/Half-Yearly (N = years ahead)**
1285
+ - For quarterly options in future years:
1286
+ - `first_quarter_1`: Q1 (March) of next year
1287
+ - `second_quarter_1`: Q2 (June) of next year
1288
+ - `third_quarter_1`: Q3 (September) of next year
1289
+ - `fourth_quarter_1`: Q4 (December) of next year
1290
+ - For half-yearly options in future years:
1291
+ - `first_half_yearly_1`: H1 (June) of next year
1292
+ - `second_half_yearly_1`: H2 (December) of next year
1293
+ - This pattern continues with `_2`, `_3`, and `_4` suffixes for up to 4 years ahead
1294
+
1295
+ 9. **Special Case**
1296
+ - `none`: No matching expiry category
1297
+
1298
+ ### Get Options Chain
1299
+
1300
+ The Options Chain API provides detailed information about available option contracts for a specified instrument, including strike prices, premiums, and option Greeks.
1301
+
1302
+ #### Constants
1303
+
1304
+ The SDK provides constants for option types, moneyness, and expiry preferences to make your code more readable and type-safe:
1305
+
1306
+ **Option Types:**
1307
+ ```python
1308
+ client.OPTION_TYPE_CE # Call option
1309
+ client.OPTION_TYPE_PE # Put option
1310
+ ```
1311
+
1312
+ **Moneyness Types:**
1313
+ ```python
1314
+ client.MONEYNESS_ATM # At-the-money
1315
+ client.MONEYNESS_ITM # In-the-money
1316
+ client.MONEYNESS_OTM # Out-of-the-money
1317
+ ```
1318
+
1319
+ **Expiry Preferences:**
1320
+ ```python
1321
+ # Common expiry preferences
1322
+ client.EXPIRY_CURRENT_WEEKLY # Current week's expiry
1323
+ client.EXPIRY_NEAR_MONTH # Current month's expiry
1324
+ client.EXPIRY_MID_MONTH # Next month's expiry
1325
+ client.EXPIRY_FAR_MONTH # Month after next expiry
1326
+
1327
+ # Many more constants available for weekly, monthly,
1328
+ # quarterly, and yearly expiries
1329
+ ```
1330
+
834
1331
  #### Get Option Chain
835
1332
 
836
- Fetch the option chain for a specific instrument and expiry date:
1333
+ Fetch the option chain for a specific instrument using either an exact expiry date or a expiry preference:
837
1334
 
838
1335
  ```python
839
- # Get ATM call options for SBIN
1336
+ # Get ATM call options for SBIN with specific expiry date
840
1337
  options = client.get_option_chain(
841
1338
  identifier="NSE:SBIN:3045",
842
1339
  expiry_date="2025-05-30",
@@ -846,10 +1343,10 @@ options = client.get_option_chain(
846
1343
  print(f"Found {len(options['strikes'])} strikes")
847
1344
  print(f"Current underlying price: {options['underlyingPrice']}")
848
1345
 
849
- # Get both call and put options, with various moneyness
1346
+ # Get both call and put options with expiry preference
850
1347
  all_options = client.get_option_chain(
851
- identifier="NSE:SBIN:3045",
852
- expiry_date="2025-05-30",
1348
+ identifier="NSE:NIFTY 50:26000",
1349
+ expiry_preference=client.EXPIRY_CURRENT_WEEKLY, # Current week's expiry
853
1350
  option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE], # Both calls and puts
854
1351
  moneyness=[client.MONEYNESS_ATM, client.MONEYNESS_ITM, client.MONEYNESS_OTM] # All moneyness types
855
1352
  )
@@ -864,7 +1361,7 @@ for strike in all_options['strikes']:
864
1361
  print(f"{strike['tradingSymbol']} ({strike['moneyness']}): {strike['ltp']}")
865
1362
  ```
866
1363
 
867
- #### Response Structure for Option Chain
1364
+ #### Response Structure
868
1365
 
869
1366
  The `get_option_chain` method returns a dictionary with the following structure:
870
1367
 
@@ -938,133 +1435,143 @@ The `get_option_chain` method returns a dictionary with the following structure:
938
1435
  }
939
1436
  ```
940
1437
 
941
- Note that some fields like metrics may have zero values if the data is not available from the exchange or if there's no recent trading activity in those contracts.
1438
+ #### Advanced Examples
942
1439
 
943
- #### Advanced Option Chain Analysis Example
944
-
945
- Here's an example of how to use the option chain API for more advanced analysis:
1440
+ ##### Finding a Straddle/Strangle
946
1441
 
947
1442
  ```python
948
- def analyze_option_chain(underlying, expiry_date):
949
- """
950
- Analyze an option chain to find interesting trading opportunities.
1443
+ def find_straddle_strangle(identifier, expiry):
1444
+ """Find and analyze straddle/strangle opportunities."""
1445
+ # Get the option chain
1446
+ option_chain = client.get_option_chain(
1447
+ identifier=identifier,
1448
+ expiry_date=expiry,
1449
+ option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
1450
+ moneyness=[client.MONEYNESS_ATM]
1451
+ )
1452
+
1453
+ # Find ATM call and put
1454
+ calls = [s for s in option_chain["strikes"] if s["optionType"] == "CE"]
1455
+ puts = [s for s in option_chain["strikes"] if s["optionType"] == "PE"]
1456
+
1457
+ if not calls or not puts:
1458
+ print("Couldn't find both call and put options")
1459
+ return
1460
+
1461
+ # For a straddle, we want the same strike price
1462
+ atm_strike = calls[0]["strikePrice"]
1463
+ atm_call = calls[0]
1464
+ atm_put = next((p for p in puts if p["strikePrice"] == atm_strike), None)
951
1465
 
952
- Args:
953
- underlying (str): Instrument identifier (e.g., "NSE:SBIN:3045")
954
- expiry_date (str): Expiry date in YYYY-MM-DD format
955
- """
956
- client = WizzerClient(base_url="https://api-url.in", token="your-jwt-token")
1466
+ if atm_call and atm_put:
1467
+ call_premium = atm_call["ltp"]
1468
+ put_premium = atm_put["ltp"]
1469
+ total_premium = call_premium + put_premium
1470
+
1471
+ print(f"ATM Straddle Analysis for {identifier} (Expiry: {expiry})")
1472
+ print(f"Underlying Price: {option_chain['underlyingPrice']}")
1473
+ print(f"ATM Strike: {atm_strike}")
1474
+ print(f"Call Premium: {call_premium}")
1475
+ print(f"Put Premium: {put_premium}")
1476
+ print(f"Total Premium: {total_premium}")
1477
+ print(f"Breakeven Upper: {atm_strike + total_premium}")
1478
+ print(f"Breakeven Lower: {atm_strike - total_premium}")
1479
+
1480
+ # Calculate the percentage move needed for breakeven
1481
+ pct_move = (total_premium / option_chain['underlyingPrice']) * 100
1482
+ print(f"Required % Move for Breakeven: {pct_move:.2f}%")
957
1483
 
958
- # Get the full option chain
1484
+ # For a strangle, we want OTM call and put
1485
+ otm_options = client.get_option_chain(
1486
+ identifier=identifier,
1487
+ expiry_date=expiry,
1488
+ option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
1489
+ moneyness=[client.MONEYNESS_OTM]
1490
+ )
1491
+
1492
+ otm_calls = sorted([s for s in otm_options["strikes"] if s["optionType"] == "CE"],
1493
+ key=lambda x: x["strikePrice"])
1494
+ otm_puts = sorted([s for s in otm_options["strikes"] if s["optionType"] == "PE"],
1495
+ key=lambda x: x["strikePrice"], reverse=True)
1496
+
1497
+ if otm_calls and otm_puts:
1498
+ otm_call = otm_calls[0] # First OTM call
1499
+ otm_put = otm_puts[0] # First OTM put
1500
+
1501
+ call_premium = otm_call["ltp"]
1502
+ put_premium = otm_put["ltp"]
1503
+ total_premium = call_premium + put_premium
1504
+
1505
+ print(f"\nOTM Strangle Analysis for {identifier} (Expiry: {expiry})")
1506
+ print(f"Call Strike: {otm_call['strikePrice']} (Premium: {call_premium})")
1507
+ print(f"Put Strike: {otm_put['strikePrice']} (Premium: {put_premium})")
1508
+ print(f"Total Premium: {total_premium}")
1509
+ print(f"Breakeven Upper: {otm_call['strikePrice'] + total_premium}")
1510
+ print(f"Breakeven Lower: {otm_put['strikePrice'] - total_premium}")
1511
+
1512
+ return option_chain
1513
+
1514
+ # Example usage
1515
+ find_straddle_strangle("NSE:SBIN:3045", "2025-05-30")
1516
+ ```
1517
+
1518
+ ##### Option Chain Visualization
1519
+
1520
+ ```python
1521
+ def visualize_option_chain(identifier, expiry):
1522
+ """Create a visualization of the option chain."""
1523
+ import matplotlib.pyplot as plt
1524
+ import numpy as np
1525
+
1526
+ # Get the option chain
959
1527
  option_chain = client.get_option_chain(
960
- identifier=underlying,
961
- expiry_date=expiry_date,
1528
+ identifier=identifier,
1529
+ expiry_date=expiry,
962
1530
  option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
963
1531
  moneyness=[client.MONEYNESS_ATM, client.MONEYNESS_ITM, client.MONEYNESS_OTM]
964
1532
  )
965
1533
 
966
- # Extract key data
1534
+ # Extract data
967
1535
  underlying_price = option_chain["underlyingPrice"]
968
- future_price = option_chain["futurePrice"]
969
- resolved_expiry = option_chain["resolvedExpiry"]
970
1536
 
971
1537
  # Separate calls and puts
972
- calls = [s for s in option_chain["strikes"] if s["optionType"] == "CE"]
973
- puts = [s for s in option_chain["strikes"] if s["optionType"] == "PE"]
1538
+ calls = sorted([s for s in option_chain["strikes"] if s["optionType"] == "CE"],
1539
+ key=lambda x: x["strikePrice"])
1540
+ puts = sorted([s for s in option_chain["strikes"] if s["optionType"] == "PE"],
1541
+ key=lambda x: x["strikePrice"])
1542
+
1543
+ # Extract strike prices and premiums
1544
+ call_strikes = [c["strikePrice"] for c in calls]
1545
+ call_premiums = [c["ltp"] for c in calls]
1546
+
1547
+ put_strikes = [p["strikePrice"] for p in puts]
1548
+ put_premiums = [p["ltp"] for p in puts]
1549
+
1550
+ # Create figure and axis
1551
+ fig, ax = plt.subplots(figsize=(12, 8))
1552
+
1553
+ # Plot calls and puts
1554
+ ax.plot(call_strikes, call_premiums, 'b-', marker='o', label='Calls')
1555
+ ax.plot(put_strikes, put_premiums, 'r-', marker='o', label='Puts')
1556
+
1557
+ # Add vertical line for current price
1558
+ ax.axvline(x=underlying_price, color='g', linestyle='--',
1559
+ label=f'Current Price ({underlying_price})')
1560
+
1561
+ # Add labels and title
1562
+ ax.set_xlabel('Strike Price')
1563
+ ax.set_ylabel('Premium')
1564
+ ax.set_title(f'Option Chain for {identifier} (Expiry: {expiry})')
1565
+ ax.legend()
1566
+ ax.grid(True)
1567
+
1568
+ plt.tight_layout()
1569
+ plt.show()
974
1570
 
975
- # Sort by strike price
976
- calls.sort(key=lambda x: x["strikePrice"])
977
- puts.sort(key=lambda x: x["strikePrice"])
978
-
979
- # Find ATM options
980
- atm_call = next((s for s in calls if s["moneyness"] == "ATM"), None)
981
- atm_put = next((s for s in puts if s["moneyness"] == "ATM"), None)
982
- atm_strike = atm_call["strikePrice"] if atm_call else None
983
-
984
- print(f"Analysis for Option Chain (Expiry: {resolved_expiry})")
985
- print(f"Underlying Price: {underlying_price}")
986
- print(f"Future Price: {future_price}")
987
- print(f"ATM Strike: {atm_strike}")
988
- print(f"Days to Expiry: {(datetime.strptime(resolved_expiry, '%Y-%m-%d') - datetime.now()).days}")
989
- print("=" * 60)
990
-
991
- # Find interesting spreads
992
- if len(calls) >= 2 and len(puts) >= 2:
993
- # Vertical spreads
994
- bull_call_spread = {
995
- 'long': atm_call,
996
- 'short': next((c for c in calls if c["strikePrice"] > atm_strike), None)
997
- }
998
-
999
- bear_put_spread = {
1000
- 'long': atm_put,
1001
- 'short': next((p for p in puts if p["strikePrice"] < atm_strike), None)
1002
- }
1003
-
1004
- # Iron condor
1005
- iron_condor = {
1006
- 'long_put': next((p for p in puts if p["strikePrice"] < atm_strike and p["moneyness"] == "OTM"), None),
1007
- 'short_put': atm_put,
1008
- 'short_call': atm_call,
1009
- 'long_call': next((c for c in calls if c["strikePrice"] > atm_strike and c["moneyness"] == "OTM"), None)
1010
- }
1011
-
1012
- # Print potential strategies
1013
- print("Potential Strategies:")
1014
-
1015
- # Bull Call Spread
1016
- if bull_call_spread['long'] and bull_call_spread['short']:
1017
- long_premium = bull_call_spread['long']['ltp']
1018
- short_premium = bull_call_spread['short']['ltp']
1019
- net_premium = long_premium - short_premium
1020
- max_profit = bull_call_spread['short']['strikePrice'] - bull_call_spread['long']['strikePrice'] - net_premium
1021
-
1022
- print(f"Bull Call Spread: Buy {bull_call_spread['long']['tradingSymbol']} @ {long_premium}, "
1023
- f"Sell {bull_call_spread['short']['tradingSymbol']} @ {short_premium}")
1024
- print(f" Net Premium: {net_premium}")
1025
- print(f" Max Profit: {max_profit}")
1026
- print(f" Break-even: {bull_call_spread['long']['strikePrice'] + net_premium}")
1027
-
1028
- # Bear Put Spread
1029
- if bear_put_spread['long'] and bear_put_spread['short']:
1030
- long_premium = bear_put_spread['long']['ltp']
1031
- short_premium = bear_put_spread['short']['ltp']
1032
- net_premium = long_premium - short_premium
1033
- max_profit = bear_put_spread['long']['strikePrice'] - bear_put_spread['short']['strikePrice'] - net_premium
1034
-
1035
- print(f"Bear Put Spread: Buy {bear_put_spread['long']['tradingSymbol']} @ {long_premium}, "
1036
- f"Sell {bear_put_spread['short']['tradingSymbol']} @ {short_premium}")
1037
- print(f" Net Premium: {net_premium}")
1038
- print(f" Max Profit: {max_profit}")
1039
- print(f" Break-even: {bear_put_spread['long']['strikePrice'] - net_premium}")
1040
-
1041
- # Iron Condor
1042
- if all(iron_condor.values()):
1043
- long_put_premium = iron_condor['long_put']['ltp']
1044
- short_put_premium = iron_condor['short_put']['ltp']
1045
- short_call_premium = iron_condor['short_call']['ltp']
1046
- long_call_premium = iron_condor['long_call']['ltp']
1047
-
1048
- net_premium = (short_put_premium + short_call_premium) - (long_put_premium + long_call_premium)
1049
- put_wing_width = iron_condor['short_put']['strikePrice'] - iron_condor['long_put']['strikePrice']
1050
- call_wing_width = iron_condor['long_call']['strikePrice'] - iron_condor['short_call']['strikePrice']
1051
-
1052
- max_risk = max(put_wing_width, call_wing_width) - net_premium
1053
-
1054
- print(f"Iron Condor Strategy:")
1055
- print(f" Long Put: {iron_condor['long_put']['tradingSymbol']} @ {long_put_premium}")
1056
- print(f" Short Put: {iron_condor['short_put']['tradingSymbol']} @ {short_put_premium}")
1057
- print(f" Short Call: {iron_condor['short_call']['tradingSymbol']} @ {short_call_premium}")
1058
- print(f" Long Call: {iron_condor['long_call']['tradingSymbol']} @ {long_call_premium}")
1059
- print(f" Net Premium Received: {net_premium}")
1060
- print(f" Max Risk: {max_risk}")
1061
- print(f" Max Profit: {net_premium}")
1062
-
1063
- # Return the option chain for further analysis
1064
1571
  return option_chain
1065
1572
 
1066
- # Example usage:
1067
- analyze_option_chain("NSE:SBIN:3045", "2025-05-30")
1573
+ # Example usage
1574
+ visualize_option_chain("NSE:NIFTY 50:26000", "2025-05-30")
1068
1575
  ```
1069
1576
 
1070
1577
  ### Wizzer Client Examples
@@ -0,0 +1,9 @@
1
+ wiz_trader/__init__.py,sha256=iU9Crioz_4eIjYFIOJ9aqjfGXBMxvEi_836Ln39sV70,182
2
+ wiz_trader/apis/__init__.py,sha256=ItWKMOl4omiW0g2f-M7WRW3v-dss_ULd9vYnFyIIT9o,132
3
+ wiz_trader/apis/client.py,sha256=vFoKHJWfyLTX7Alb6WK2fxJimqLj7E42ri1bl_jUDWY,56281
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.19.0.dist-info/METADATA,sha256=GxrCN8ospIwoUahWVp6WC669msDd61KTNaCQvg7_Tqw,82928
7
+ wiz_trader-0.19.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
8
+ wiz_trader-0.19.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
+ wiz_trader-0.19.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,9 +0,0 @@
1
- wiz_trader/__init__.py,sha256=w6C8CU2CdbmX1NpPJZQDKK4dTvlnjy8mkfBX4HHAzo0,182
2
- wiz_trader/apis/__init__.py,sha256=ItWKMOl4omiW0g2f-M7WRW3v-dss_ULd9vYnFyIIT9o,132
3
- wiz_trader/apis/client.py,sha256=Gil47UnBWVHtUKgITJmYgzYWYNT0Gz4zl8dIzJvn7BQ,49347
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.17.0.dist-info/METADATA,sha256=bNm4bYfNSMoOkfgAHdsodIYdPVDFR4PW1lZFER3PI6Y,68861
7
- wiz_trader-0.17.0.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
8
- wiz_trader-0.17.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
- wiz_trader-0.17.0.dist-info/RECORD,,