wiz-trader 0.17.0__py3-none-any.whl → 0.18.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.18.0"
7
7
 
8
8
  __all__ = ["QuotesClient", "WizzerClient"]
wiz_trader/apis/client.py CHANGED
@@ -86,6 +86,57 @@ class WizzerClient:
86
86
  MONEYNESS_ATM = "ATM"
87
87
  MONEYNESS_ITM = "ITM"
88
88
  MONEYNESS_OTM = "OTM"
89
+
90
+ # Expiry preference constants
91
+ EXPIRY_CURRENT_WEEKLY = "current_weekly"
92
+ EXPIRY_NEAR_MONTH = "near_month"
93
+ EXPIRY_MID_MONTH = "mid_month"
94
+ EXPIRY_FAR_MONTH = "far_month"
95
+ EXPIRY_FIRST_WEEKLY = "first_weekly"
96
+ EXPIRY_SECOND_WEEKLY = "second_weekly"
97
+ EXPIRY_THIRD_WEEKLY = "third_weekly"
98
+ EXPIRY_FOURTH_WEEKLY = "fourth_weekly"
99
+ EXPIRY_FIFTH_WEEKLY = "fifth_weekly"
100
+ EXPIRY_FIRST_WEEKLY_MID_MONTH = "first_weekly_mid_month"
101
+ EXPIRY_SECOND_WEEKLY_MID_MONTH = "second_weekly_mid_month"
102
+ EXPIRY_THIRD_WEEKLY_MID_MONTH = "third_weekly_mid_month"
103
+ EXPIRY_FOURTH_WEEKLY_MID_MONTH = "fourth_weekly_mid_month"
104
+ EXPIRY_FIFTH_WEEKLY_MID_MONTH = "fifth_weekly_mid_month"
105
+ EXPIRY_FIRST_WEEKLY_FAR_MONTH = "first_weekly_far_month"
106
+ EXPIRY_SECOND_WEEKLY_FAR_MONTH = "second_weekly_far_month"
107
+ EXPIRY_THIRD_WEEKLY_FAR_MONTH = "third_weekly_far_month"
108
+ EXPIRY_FOURTH_WEEKLY_FAR_MONTH = "fourth_weekly_far_month"
109
+ EXPIRY_FIFTH_WEEKLY_FAR_MONTH = "fifth_weekly_far_month"
110
+ EXPIRY_FIRST_QUARTER = "first_quarter"
111
+ EXPIRY_SECOND_QUARTER = "second_quarter"
112
+ EXPIRY_THIRD_QUARTER = "third_quarter"
113
+ EXPIRY_FOURTH_QUARTER = "fourth_quarter"
114
+ EXPIRY_FIRST_HALF = "first_half_yearly"
115
+ EXPIRY_SECOND_HALF = "second_half_yearly"
116
+ EXPIRY_FIRST_QUARTER_PLUS_1 = "first_quarter_plus_1"
117
+ EXPIRY_SECOND_QUARTER_PLUS_1 = "second_quarter_plus_1"
118
+ EXPIRY_THIRD_QUARTER_PLUS_1 = "third_quarter_plus_1"
119
+ EXPIRY_FOURTH_QUARTER_PLUS_1 = "fourth_quarter_plus_1"
120
+ EXPIRY_FIRST_HALF_PLUS_1 = "first_half_yearly_plus_1"
121
+ EXPIRY_SECOND_HALF_PLUS_1 = "second_half_yearly_plus_1"
122
+ EXPIRY_FIRST_QUARTER_PLUS_2 = "first_quarter_plus_2"
123
+ EXPIRY_SECOND_QUARTER_PLUS_2 = "second_quarter_plus_2"
124
+ EXPIRY_THIRD_QUARTER_PLUS_2 = "third_quarter_plus_2"
125
+ EXPIRY_FOURTH_QUARTER_PLUS_2 = "fourth_quarter_plus_2"
126
+ EXPIRY_FIRST_HALF_PLUS_2 = "first_half_yearly_plus_2"
127
+ EXPIRY_SECOND_HALF_PLUS_2 = "second_half_yearly_plus_2"
128
+ EXPIRY_FIRST_QUARTER_PLUS_3 = "first_quarter_plus_3"
129
+ EXPIRY_SECOND_QUARTER_PLUS_3 = "second_quarter_plus_3"
130
+ EXPIRY_THIRD_QUARTER_PLUS_3 = "third_quarter_plus_3"
131
+ EXPIRY_FOURTH_QUARTER_PLUS_3 = "fourth_quarter_plus_3"
132
+ EXPIRY_FIRST_HALF_PLUS_3 = "first_half_yearly_plus_3"
133
+ EXPIRY_SECOND_HALF_PLUS_3 = "second_half_yearly_plus_3"
134
+ EXPIRY_FIRST_QUARTER_PLUS_4 = "first_quarter_plus_4"
135
+ EXPIRY_SECOND_QUARTER_PLUS_4 = "second_quarter_plus_4"
136
+ EXPIRY_THIRD_QUARTER_PLUS_4 = "third_quarter_plus_4"
137
+ EXPIRY_FOURTH_QUARTER_PLUS_4 = "fourth_quarter_plus_4"
138
+ EXPIRY_FIRST_HALF_PLUS_4 = "first_half_yearly_plus_4"
139
+ EXPIRY_SECOND_HALF_PLUS_4 = "second_half_yearly_plus_4"
89
140
 
90
141
  # URIs to various API endpoints
91
142
  _routes = {
@@ -121,7 +172,8 @@ class WizzerClient:
121
172
 
122
173
  # Instrument & asset class endpoints
123
174
  "instrument.metrics": "/instruments/metrics",
124
- "instrument.option_chain": "/instruments/options/chain"
175
+ "instrument.option_chain": "/instruments/options/chain",
176
+ "instrument.expiry_list": "/instruments/options/chain/expirylist"
125
177
  }
126
178
 
127
179
  def __init__(
@@ -1310,9 +1362,10 @@ class WizzerClient:
1310
1362
  def get_option_chain(
1311
1363
  self,
1312
1364
  identifier: str,
1313
- expiry_date: str,
1314
- option_type: List[str],
1315
- moneyness: List[str]
1365
+ expiry_date: Optional[str] = None,
1366
+ expiry_preference: Optional[str] = None,
1367
+ option_type: List[str] = None,
1368
+ moneyness: List[str] = None
1316
1369
  ) -> Dict[str, Any]:
1317
1370
  """
1318
1371
  Get option chain for a specified instrument.
@@ -1320,6 +1373,8 @@ class WizzerClient:
1320
1373
  Args:
1321
1374
  identifier (str): Instrument identifier (e.g., "NSE:SBIN:3045").
1322
1375
  expiry_date (str): Expiry date in YYYY-MM-DD format.
1376
+ expiry_preference (Optional[str]): Expiry category preference instead of exact date.
1377
+ Use the EXPIRY_* constants provided by the class.
1323
1378
  option_type (List[str]): List of option types to include.
1324
1379
  Values from [OPTION_TYPE_CE, OPTION_TYPE_PE].
1325
1380
  moneyness (List[str]): List of moneyness types to include.
@@ -1338,6 +1393,8 @@ class WizzerClient:
1338
1393
  raise ValueError("At least one option type must be specified")
1339
1394
  if not moneyness:
1340
1395
  raise ValueError("At least one moneyness type must be specified")
1396
+ if not expiry_date and not expiry_preference:
1397
+ raise ValueError("Either expiry_date or expiry_preference must be provided")
1341
1398
 
1342
1399
  # Validate option_type values
1343
1400
  valid_option_types = [self.OPTION_TYPE_CE, self.OPTION_TYPE_PE]
@@ -1353,14 +1410,55 @@ class WizzerClient:
1353
1410
 
1354
1411
  data = {
1355
1412
  "identifier": identifier,
1356
- "expiryDate": expiry_date,
1357
1413
  "optionType": option_type,
1358
1414
  "moneyness": moneyness
1359
1415
  }
1360
1416
 
1417
+ # Add either expiryDate or expiryPreference
1418
+ if expiry_date:
1419
+ data["expiryDate"] = expiry_date
1420
+ elif expiry_preference:
1421
+ data["expiryPreference"] = expiry_preference
1422
+
1361
1423
  logger.debug("Fetching option chain with data: %s", data)
1362
1424
  return self._make_request("POST", endpoint, json=data)
1363
1425
 
1426
+ def get_option_expiry_list(
1427
+ self,
1428
+ identifier: str
1429
+ ) -> Dict[str, Any]:
1430
+ """
1431
+ Get a list of available expiry dates for an instrument's options.
1432
+
1433
+ Args:
1434
+ identifier (str): Instrument identifier in the format "EXCHANGE:SYMBOL:TOKEN"
1435
+ (e.g., "NSE:SBIN:3045" or "NSE:NIFTY 50:26000").
1436
+
1437
+ Returns:
1438
+ Dict[str, Any]: Response containing the list of available expiry dates with contract types.
1439
+
1440
+ Example:
1441
+ ```python
1442
+ # Get expiry dates for a stock
1443
+ expiry_list = client.get_option_expiry_list("NSE:SBIN:3045")
1444
+
1445
+ # Get expiry dates for an index
1446
+ nifty_expiry = client.get_option_expiry_list("NSE:NIFTY 50:26000")
1447
+
1448
+ # Access the expiry dates
1449
+ for expiry in expiry_list.get('expiryList', []):
1450
+ print(f"{expiry['date']} - {expiry['contract']}")
1451
+ ```
1452
+ """
1453
+ endpoint = self._routes["instrument.expiry_list"]
1454
+
1455
+ data = {
1456
+ "identifier": identifier
1457
+ }
1458
+
1459
+ logger.debug("Fetching option expiry list for %s", identifier)
1460
+ return self._make_request("POST", endpoint, json=data)
1461
+
1364
1462
  def _make_request(
1365
1463
  self,
1366
1464
  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.18.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
@@ -643,13 +643,13 @@ Fetch detailed information and metrics for specific instruments:
643
643
 
644
644
  ```python
645
645
  # Get metrics for a single equity instrument
646
- equity_info = client.get_instrument_metrics(instrument_identifiers=["NSE:SBIN:3045"])
646
+ equity_info = client.get_instrument_metrics(identifiers=["NSE:SBIN:3045"])
647
647
  print(f"SBIN Last Price: {equity_info[0]['ltp']}")
648
648
  print(f"SBIN 52-week High: {equity_info[0]['week52High']}")
649
649
 
650
650
  # Get metrics for multiple instruments of different types
651
651
  instruments_info = client.get_instrument_metrics(
652
- instrument_identifiers=[
652
+ identifiers=[
653
653
  "NSE:AARTIIND:7", # Equity
654
654
  "NSE:NIFTY26DEC11000CE:61009", # Option
655
655
  "NSE:SBIN25MAYFUT:57515" # Future
@@ -831,12 +831,150 @@ Note that certain fields may have zero or empty values if the data is not availa
831
831
 
832
832
  ### Options Chain
833
833
 
834
+ #### Get Option Expiry List
835
+
836
+ Fetch available expiry dates for an instrument's options:
837
+
838
+ ```python
839
+ # For a stock
840
+ expiry_list = client.get_option_expiry_list("NSE:SBIN:3045")
841
+
842
+ # For an index
843
+ nifty_expiry = client.get_option_expiry_list("NSE:NIFTY 50:26000")
844
+
845
+ # Print all available expiry dates
846
+ for expiry in expiry_list.get('expiryList', []):
847
+ print(f"{expiry['date']} - {expiry['contract']} " +
848
+ f"(Futures: {'Yes' if expiry['isFuturesExpiry'] else 'No'}, " +
849
+ f"Options: {'Yes' if expiry['isOptionsExpiry'] else 'No'})")
850
+ ```
851
+
852
+ #### Response Structure
853
+
854
+ The response is a JSON object with the following structure:
855
+
856
+ ```json
857
+ {
858
+ "exchange": "NSE", // Exchange of the instrument
859
+ "tradingSymbol": "SBIN", // Trading symbol
860
+ "exchangeToken": 3045, // Exchange token
861
+ "identifier": "NSE:SBIN:3045", // Full identifier
862
+ "expiryList": [ // Array of expiry objects
863
+ {
864
+ "date": "2025-05-29", // Expiry date in YYYY-MM-DD format
865
+ "contract": "near_month", // Contract type (see below)
866
+ "isFuturesExpiry": true, // Whether futures expire on this date
867
+ "isOptionsExpiry": true // Whether options expire on this date
868
+ },
869
+ // More expiry objects...
870
+ ]
871
+ }
872
+ ```
873
+
874
+ For index options like NIFTY, the response will typically include more expiry dates, including weekly options and longer-dated quarterly options.
875
+
876
+ The `expiryList` array contains objects with the following fields:
877
+ - `date`: The expiry date in YYYY-MM-DD format
878
+ - `contract`: The type of contract (e.g., "near_month", "current_weekly")
879
+ - `isFuturesExpiry`: Boolean indicating if futures expire on this date
880
+ - `isOptionsExpiry`: Boolean indicating if options expire on this date
881
+
882
+ #### Contract Types
883
+
884
+ Each expiry date is categorized with a `contract` field that indicates the type of expiry. The possible contract types are:
885
+
886
+ 1. **Weekly Expiries (Thursdays/Wednesdays)**
887
+ - `current_weekly`: The first non-expiry Thursday of the current week
888
+
889
+ 2. **Monthly Expiries (last Wed/Thu of month)**
890
+ - `near_month`: Last Wed/Thu of this month (current month)
891
+ - `mid_month`: Last Wed/Thu of next month
892
+ - `far_month`: Last Wed/Thu of month after next
893
+
894
+ 3. **Weekly Ordinals Within Current Month**
895
+ - `first_weekly`: 1st non-expiry Thursday of current month
896
+ - `second_weekly`: 2nd non-expiry Thursday
897
+ - `third_weekly`: 3rd non-expiry Thursday
898
+ - `fourth_weekly`: 4th non-expiry Thursday
899
+ - `fifth_weekly`: 5th non-expiry Thursday (rare)
900
+
901
+ 4. **Weekly Ordinals in Mid-Month Slot (next month's week-trade dates)**
902
+ - `first_weekly_mid_month`: 1st Thursday of next month
903
+ - `second_weekly_mid_month`: 2nd Thursday of next month
904
+ - `third_weekly_mid_month`: 3rd Thursday of next month
905
+ - `fourth_weekly_mid_month`: 4th Thursday of next month
906
+ - `fifth_weekly_mid_month`: 5th Thursday of next month (rare)
907
+
908
+ 5. **Weekly Ordinals in Far-Month Slot (month-after-next)**
909
+ - `first_weekly_far_month`: 1st Thursday of month after next
910
+ - `second_weekly_far_month`: 2nd Thursday of month after next
911
+ - `third_weekly_far_month`: 3rd Thursday of month after next
912
+ - `fourth_weekly_far_month`: 4th Thursday of month after next
913
+ - `fifth_weekly_far_month`: 5th Thursday of month after next (rare)
914
+
915
+ 6. **Quarterly Expiries (last-Thu of Mar/Jun/Sep/Dec)**
916
+ - `first_quarter`: Last Thu of March (Q1)
917
+ - `second_quarter`: Last Thu of June (Q2)
918
+ - `third_quarter`: Last Thu of September (Q3)
919
+ - `fourth_quarter`: Last Thu of December (Q4)
920
+
921
+ 7. **Half-Yearly Expiries**
922
+ - `first_half_yearly`: Last Thu of June (H1)
923
+ - `second_half_yearly`: Last Thu of December (H2)
924
+
925
+ 8. **Year-Plus-N Quarterly/Half-Yearly (N = years ahead)**
926
+ - For quarterly options in future years:
927
+ - `first_quarter_1`: Q1 (March) of next year
928
+ - `second_quarter_1`: Q2 (June) of next year
929
+ - `third_quarter_1`: Q3 (September) of next year
930
+ - `fourth_quarter_1`: Q4 (December) of next year
931
+ - For half-yearly options in future years:
932
+ - `first_half_yearly_1`: H1 (June) of next year
933
+ - `second_half_yearly_1`: H2 (December) of next year
934
+ - This pattern continues with `_2`, `_3`, and `_4` suffixes for up to 4 years ahead
935
+
936
+ 9. **Special Case**
937
+ - `none`: No matching expiry category
938
+
939
+ ### Get Options Chain
940
+
941
+ The Options Chain API provides detailed information about available option contracts for a specified instrument, including strike prices, premiums, and option Greeks.
942
+
943
+ #### Constants
944
+
945
+ The SDK provides constants for option types, moneyness, and expiry preferences to make your code more readable and type-safe:
946
+
947
+ **Option Types:**
948
+ ```python
949
+ client.OPTION_TYPE_CE # Call option
950
+ client.OPTION_TYPE_PE # Put option
951
+ ```
952
+
953
+ **Moneyness Types:**
954
+ ```python
955
+ client.MONEYNESS_ATM # At-the-money
956
+ client.MONEYNESS_ITM # In-the-money
957
+ client.MONEYNESS_OTM # Out-of-the-money
958
+ ```
959
+
960
+ **Expiry Preferences:**
961
+ ```python
962
+ # Common expiry preferences
963
+ client.EXPIRY_CURRENT_WEEKLY # Current week's expiry
964
+ client.EXPIRY_NEAR_MONTH # Current month's expiry
965
+ client.EXPIRY_MID_MONTH # Next month's expiry
966
+ client.EXPIRY_FAR_MONTH # Month after next expiry
967
+
968
+ # Many more constants available for weekly, monthly,
969
+ # quarterly, and yearly expiries
970
+ ```
971
+
834
972
  #### Get Option Chain
835
973
 
836
- Fetch the option chain for a specific instrument and expiry date:
974
+ Fetch the option chain for a specific instrument using either an exact expiry date or a expiry preference:
837
975
 
838
976
  ```python
839
- # Get ATM call options for SBIN
977
+ # Get ATM call options for SBIN with specific expiry date
840
978
  options = client.get_option_chain(
841
979
  identifier="NSE:SBIN:3045",
842
980
  expiry_date="2025-05-30",
@@ -846,10 +984,10 @@ options = client.get_option_chain(
846
984
  print(f"Found {len(options['strikes'])} strikes")
847
985
  print(f"Current underlying price: {options['underlyingPrice']}")
848
986
 
849
- # Get both call and put options, with various moneyness
987
+ # Get both call and put options with expiry preference
850
988
  all_options = client.get_option_chain(
851
- identifier="NSE:SBIN:3045",
852
- expiry_date="2025-05-30",
989
+ identifier="NSE:NIFTY 50:26000",
990
+ expiry_preference=client.EXPIRY_CURRENT_WEEKLY, # Current week's expiry
853
991
  option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE], # Both calls and puts
854
992
  moneyness=[client.MONEYNESS_ATM, client.MONEYNESS_ITM, client.MONEYNESS_OTM] # All moneyness types
855
993
  )
@@ -864,7 +1002,7 @@ for strike in all_options['strikes']:
864
1002
  print(f"{strike['tradingSymbol']} ({strike['moneyness']}): {strike['ltp']}")
865
1003
  ```
866
1004
 
867
- #### Response Structure for Option Chain
1005
+ #### Response Structure
868
1006
 
869
1007
  The `get_option_chain` method returns a dictionary with the following structure:
870
1008
 
@@ -938,133 +1076,143 @@ The `get_option_chain` method returns a dictionary with the following structure:
938
1076
  }
939
1077
  ```
940
1078
 
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.
942
-
943
- #### Advanced Option Chain Analysis Example
1079
+ #### Advanced Examples
944
1080
 
945
- Here's an example of how to use the option chain API for more advanced analysis:
1081
+ ##### Finding a Straddle/Strangle
946
1082
 
947
1083
  ```python
948
- def analyze_option_chain(underlying, expiry_date):
949
- """
950
- Analyze an option chain to find interesting trading opportunities.
1084
+ def find_straddle_strangle(identifier, expiry):
1085
+ """Find and analyze straddle/strangle opportunities."""
1086
+ # Get the option chain
1087
+ option_chain = client.get_option_chain(
1088
+ identifier=identifier,
1089
+ expiry_date=expiry,
1090
+ option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
1091
+ moneyness=[client.MONEYNESS_ATM]
1092
+ )
1093
+
1094
+ # Find ATM call and put
1095
+ calls = [s for s in option_chain["strikes"] if s["optionType"] == "CE"]
1096
+ puts = [s for s in option_chain["strikes"] if s["optionType"] == "PE"]
1097
+
1098
+ if not calls or not puts:
1099
+ print("Couldn't find both call and put options")
1100
+ return
1101
+
1102
+ # For a straddle, we want the same strike price
1103
+ atm_strike = calls[0]["strikePrice"]
1104
+ atm_call = calls[0]
1105
+ atm_put = next((p for p in puts if p["strikePrice"] == atm_strike), None)
1106
+
1107
+ if atm_call and atm_put:
1108
+ call_premium = atm_call["ltp"]
1109
+ put_premium = atm_put["ltp"]
1110
+ total_premium = call_premium + put_premium
1111
+
1112
+ print(f"ATM Straddle Analysis for {identifier} (Expiry: {expiry})")
1113
+ print(f"Underlying Price: {option_chain['underlyingPrice']}")
1114
+ print(f"ATM Strike: {atm_strike}")
1115
+ print(f"Call Premium: {call_premium}")
1116
+ print(f"Put Premium: {put_premium}")
1117
+ print(f"Total Premium: {total_premium}")
1118
+ print(f"Breakeven Upper: {atm_strike + total_premium}")
1119
+ print(f"Breakeven Lower: {atm_strike - total_premium}")
1120
+
1121
+ # Calculate the percentage move needed for breakeven
1122
+ pct_move = (total_premium / option_chain['underlyingPrice']) * 100
1123
+ print(f"Required % Move for Breakeven: {pct_move:.2f}%")
1124
+
1125
+ # For a strangle, we want OTM call and put
1126
+ otm_options = client.get_option_chain(
1127
+ identifier=identifier,
1128
+ expiry_date=expiry,
1129
+ option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
1130
+ moneyness=[client.MONEYNESS_OTM]
1131
+ )
1132
+
1133
+ otm_calls = sorted([s for s in otm_options["strikes"] if s["optionType"] == "CE"],
1134
+ key=lambda x: x["strikePrice"])
1135
+ otm_puts = sorted([s for s in otm_options["strikes"] if s["optionType"] == "PE"],
1136
+ key=lambda x: x["strikePrice"], reverse=True)
951
1137
 
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")
1138
+ if otm_calls and otm_puts:
1139
+ otm_call = otm_calls[0] # First OTM call
1140
+ otm_put = otm_puts[0] # First OTM put
1141
+
1142
+ call_premium = otm_call["ltp"]
1143
+ put_premium = otm_put["ltp"]
1144
+ total_premium = call_premium + put_premium
1145
+
1146
+ print(f"\nOTM Strangle Analysis for {identifier} (Expiry: {expiry})")
1147
+ print(f"Call Strike: {otm_call['strikePrice']} (Premium: {call_premium})")
1148
+ print(f"Put Strike: {otm_put['strikePrice']} (Premium: {put_premium})")
1149
+ print(f"Total Premium: {total_premium}")
1150
+ print(f"Breakeven Upper: {otm_call['strikePrice'] + total_premium}")
1151
+ print(f"Breakeven Lower: {otm_put['strikePrice'] - total_premium}")
957
1152
 
958
- # Get the full option chain
1153
+ return option_chain
1154
+
1155
+ # Example usage
1156
+ find_straddle_strangle("NSE:SBIN:3045", "2025-05-30")
1157
+ ```
1158
+
1159
+ ##### Option Chain Visualization
1160
+
1161
+ ```python
1162
+ def visualize_option_chain(identifier, expiry):
1163
+ """Create a visualization of the option chain."""
1164
+ import matplotlib.pyplot as plt
1165
+ import numpy as np
1166
+
1167
+ # Get the option chain
959
1168
  option_chain = client.get_option_chain(
960
- identifier=underlying,
961
- expiry_date=expiry_date,
1169
+ identifier=identifier,
1170
+ expiry_date=expiry,
962
1171
  option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
963
1172
  moneyness=[client.MONEYNESS_ATM, client.MONEYNESS_ITM, client.MONEYNESS_OTM]
964
1173
  )
965
1174
 
966
- # Extract key data
1175
+ # Extract data
967
1176
  underlying_price = option_chain["underlyingPrice"]
968
- future_price = option_chain["futurePrice"]
969
- resolved_expiry = option_chain["resolvedExpiry"]
970
1177
 
971
1178
  # 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"]
1179
+ calls = sorted([s for s in option_chain["strikes"] if s["optionType"] == "CE"],
1180
+ key=lambda x: x["strikePrice"])
1181
+ puts = sorted([s for s in option_chain["strikes"] if s["optionType"] == "PE"],
1182
+ key=lambda x: x["strikePrice"])
1183
+
1184
+ # Extract strike prices and premiums
1185
+ call_strikes = [c["strikePrice"] for c in calls]
1186
+ call_premiums = [c["ltp"] for c in calls]
1187
+
1188
+ put_strikes = [p["strikePrice"] for p in puts]
1189
+ put_premiums = [p["ltp"] for p in puts]
1190
+
1191
+ # Create figure and axis
1192
+ fig, ax = plt.subplots(figsize=(12, 8))
1193
+
1194
+ # Plot calls and puts
1195
+ ax.plot(call_strikes, call_premiums, 'b-', marker='o', label='Calls')
1196
+ ax.plot(put_strikes, put_premiums, 'r-', marker='o', label='Puts')
1197
+
1198
+ # Add vertical line for current price
1199
+ ax.axvline(x=underlying_price, color='g', linestyle='--',
1200
+ label=f'Current Price ({underlying_price})')
1201
+
1202
+ # Add labels and title
1203
+ ax.set_xlabel('Strike Price')
1204
+ ax.set_ylabel('Premium')
1205
+ ax.set_title(f'Option Chain for {identifier} (Expiry: {expiry})')
1206
+ ax.legend()
1207
+ ax.grid(True)
1208
+
1209
+ plt.tight_layout()
1210
+ plt.show()
974
1211
 
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
1212
  return option_chain
1065
1213
 
1066
- # Example usage:
1067
- analyze_option_chain("NSE:SBIN:3045", "2025-05-30")
1214
+ # Example usage
1215
+ visualize_option_chain("NSE:NIFTY 50:26000", "2025-05-30")
1068
1216
  ```
1069
1217
 
1070
1218
  ### Wizzer Client Examples
@@ -0,0 +1,9 @@
1
+ wiz_trader/__init__.py,sha256=UCNwgBmLz6fPSfo69NlZZd9pJeorYKXgTs4Y3bslEBc,182
2
+ wiz_trader/apis/__init__.py,sha256=ItWKMOl4omiW0g2f-M7WRW3v-dss_ULd9vYnFyIIT9o,132
3
+ wiz_trader/apis/client.py,sha256=Mbgzadgx__1QpUiz1itpWQL66lGFWOhSXSfWggtFqp0,53712
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.18.0.dist-info/METADATA,sha256=yzbGX_R69DE-0p8IXfQJo69hrg_S5xIRHnPXSnCih3Q,73214
7
+ wiz_trader-0.18.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
8
+ wiz_trader-0.18.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
9
+ wiz_trader-0.18.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,,