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 +1 -1
- wiz_trader/apis/client.py +103 -5
- {wiz_trader-0.17.0.dist-info → wiz_trader-0.18.0.dist-info}/METADATA +268 -120
- wiz_trader-0.18.0.dist-info/RECORD +9 -0
- {wiz_trader-0.17.0.dist-info → wiz_trader-0.18.0.dist-info}/WHEEL +1 -1
- wiz_trader-0.17.0.dist-info/RECORD +0 -9
- {wiz_trader-0.17.0.dist-info → wiz_trader-0.18.0.dist-info}/top_level.txt +0 -0
wiz_trader/__init__.py
CHANGED
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
|
-
|
1315
|
-
|
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.
|
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(
|
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
|
-
|
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
|
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
|
987
|
+
# Get both call and put options with expiry preference
|
850
988
|
all_options = client.get_option_chain(
|
851
|
-
identifier="NSE:
|
852
|
-
|
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
|
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
|
-
|
942
|
-
|
943
|
-
#### Advanced Option Chain Analysis Example
|
1079
|
+
#### Advanced Examples
|
944
1080
|
|
945
|
-
|
1081
|
+
##### Finding a Straddle/Strangle
|
946
1082
|
|
947
1083
|
```python
|
948
|
-
def
|
949
|
-
"""
|
950
|
-
|
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
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
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
|
-
|
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=
|
961
|
-
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
|
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
|
-
|
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
|
-
|
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,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,,
|
File without changes
|