wiz-trader 0.16.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 +161 -0
- {wiz_trader-0.16.0.dist-info → wiz_trader-0.18.0.dist-info}/METADATA +583 -1
- wiz_trader-0.18.0.dist-info/RECORD +9 -0
- {wiz_trader-0.16.0.dist-info → wiz_trader-0.18.0.dist-info}/WHEEL +1 -1
- wiz_trader-0.16.0.dist-info/RECORD +0 -9
- {wiz_trader-0.16.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
@@ -78,6 +78,65 @@ class WizzerClient:
|
|
78
78
|
REBALANCE_FULL = "full_rebalance"
|
79
79
|
REBALANCE_ENTRY_ONLY = "entry_only"
|
80
80
|
REBALANCE_EXIT_ONLY = "exit_only"
|
81
|
+
|
82
|
+
# Add constants for option types and moneyness
|
83
|
+
OPTION_TYPE_CE = "CE"
|
84
|
+
OPTION_TYPE_PE = "PE"
|
85
|
+
|
86
|
+
MONEYNESS_ATM = "ATM"
|
87
|
+
MONEYNESS_ITM = "ITM"
|
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"
|
81
140
|
|
82
141
|
# URIs to various API endpoints
|
83
142
|
_routes = {
|
@@ -113,6 +172,8 @@ class WizzerClient:
|
|
113
172
|
|
114
173
|
# Instrument & asset class endpoints
|
115
174
|
"instrument.metrics": "/instruments/metrics",
|
175
|
+
"instrument.option_chain": "/instruments/options/chain",
|
176
|
+
"instrument.expiry_list": "/instruments/options/chain/expirylist"
|
116
177
|
}
|
117
178
|
|
118
179
|
def __init__(
|
@@ -1298,6 +1359,106 @@ class WizzerClient:
|
|
1298
1359
|
response = self._make_request("POST", endpoint, json=data)
|
1299
1360
|
return response
|
1300
1361
|
|
1362
|
+
def get_option_chain(
|
1363
|
+
self,
|
1364
|
+
identifier: str,
|
1365
|
+
expiry_date: Optional[str] = None,
|
1366
|
+
expiry_preference: Optional[str] = None,
|
1367
|
+
option_type: List[str] = None,
|
1368
|
+
moneyness: List[str] = None
|
1369
|
+
) -> Dict[str, Any]:
|
1370
|
+
"""
|
1371
|
+
Get option chain for a specified instrument.
|
1372
|
+
|
1373
|
+
Args:
|
1374
|
+
identifier (str): Instrument identifier (e.g., "NSE:SBIN:3045").
|
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.
|
1378
|
+
option_type (List[str]): List of option types to include.
|
1379
|
+
Values from [OPTION_TYPE_CE, OPTION_TYPE_PE].
|
1380
|
+
moneyness (List[str]): List of moneyness types to include.
|
1381
|
+
Values from [MONEYNESS_ATM, MONEYNESS_ITM, MONEYNESS_OTM].
|
1382
|
+
|
1383
|
+
Returns:
|
1384
|
+
Dict[str, Any]: Option chain data including strikes.
|
1385
|
+
|
1386
|
+
Raises:
|
1387
|
+
ValueError: If option_type or moneyness lists are empty.
|
1388
|
+
"""
|
1389
|
+
endpoint = self._routes["instrument.option_chain"]
|
1390
|
+
|
1391
|
+
# Validate option_type and moneyness parameters
|
1392
|
+
if not option_type:
|
1393
|
+
raise ValueError("At least one option type must be specified")
|
1394
|
+
if not moneyness:
|
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")
|
1398
|
+
|
1399
|
+
# Validate option_type values
|
1400
|
+
valid_option_types = [self.OPTION_TYPE_CE, self.OPTION_TYPE_PE]
|
1401
|
+
for opt_type in option_type:
|
1402
|
+
if opt_type not in valid_option_types:
|
1403
|
+
raise ValueError(f"Invalid option type: {opt_type}. Must be one of {valid_option_types}")
|
1404
|
+
|
1405
|
+
# Validate moneyness values
|
1406
|
+
valid_moneyness = [self.MONEYNESS_ATM, self.MONEYNESS_ITM, self.MONEYNESS_OTM]
|
1407
|
+
for money in moneyness:
|
1408
|
+
if money not in valid_moneyness:
|
1409
|
+
raise ValueError(f"Invalid moneyness: {money}. Must be one of {valid_moneyness}")
|
1410
|
+
|
1411
|
+
data = {
|
1412
|
+
"identifier": identifier,
|
1413
|
+
"optionType": option_type,
|
1414
|
+
"moneyness": moneyness
|
1415
|
+
}
|
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
|
+
|
1423
|
+
logger.debug("Fetching option chain with data: %s", data)
|
1424
|
+
return self._make_request("POST", endpoint, json=data)
|
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
|
+
|
1301
1462
|
def _make_request(
|
1302
1463
|
self,
|
1303
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
|
@@ -47,6 +47,7 @@ Dynamic: requires-python
|
|
47
47
|
- [Order Management](#order-management)
|
48
48
|
- [Portfolio Management](#portfolio-management)
|
49
49
|
- [Basket Management](#basket-management)
|
50
|
+
- [Instrument Management](#instrument-management)
|
50
51
|
- [Complete Examples](#wizzer-client-examples)
|
51
52
|
6. [Common Use Cases](#common-use-cases)
|
52
53
|
7. [Error Handling](#error-handling)
|
@@ -633,6 +634,587 @@ rebalance_response = client.rebalance_basket(
|
|
633
634
|
)
|
634
635
|
```
|
635
636
|
|
637
|
+
### Instrument Management
|
638
|
+
## Instrument Data APIs
|
639
|
+
|
640
|
+
### Get Instrument Metrics
|
641
|
+
|
642
|
+
Fetch detailed information and metrics for specific instruments:
|
643
|
+
|
644
|
+
```python
|
645
|
+
# Get metrics for a single equity instrument
|
646
|
+
equity_info = client.get_instrument_metrics(identifiers=["NSE:SBIN:3045"])
|
647
|
+
print(f"SBIN Last Price: {equity_info[0]['ltp']}")
|
648
|
+
print(f"SBIN 52-week High: {equity_info[0]['week52High']}")
|
649
|
+
|
650
|
+
# Get metrics for multiple instruments of different types
|
651
|
+
instruments_info = client.get_instrument_metrics(
|
652
|
+
identifiers=[
|
653
|
+
"NSE:AARTIIND:7", # Equity
|
654
|
+
"NSE:NIFTY26DEC11000CE:61009", # Option
|
655
|
+
"NSE:SBIN25MAYFUT:57515" # Future
|
656
|
+
]
|
657
|
+
)
|
658
|
+
|
659
|
+
# Print detailed information for each instrument
|
660
|
+
for instrument in instruments_info:
|
661
|
+
print(f"{instrument['tradingSymbol']} ({instrument['instrumentType']}):")
|
662
|
+
print(f" LTP: {instrument['ltp']}")
|
663
|
+
print(f" Exchange: {instrument['exchange']}")
|
664
|
+
print(f" Segment: {instrument['segment']}")
|
665
|
+
if instrument.get('bhavcopy'):
|
666
|
+
print(f" Volume: {instrument['bhavcopy']['volume']}")
|
667
|
+
print(f" OHLC: {instrument['bhavcopy']['open']}/{instrument['bhavcopy']['high']}/"
|
668
|
+
f"{instrument['bhavcopy']['low']}/{instrument['bhavcopy']['close']}")
|
669
|
+
```
|
670
|
+
|
671
|
+
#### Response Structure for Instrument Metrics
|
672
|
+
|
673
|
+
The `get_instrument_metrics` method returns a list of dictionaries, each with the following structure:
|
674
|
+
|
675
|
+
```python
|
676
|
+
[
|
677
|
+
{
|
678
|
+
# Instrument name if available
|
679
|
+
"name": "",
|
680
|
+
|
681
|
+
# Trading symbol
|
682
|
+
"tradingSymbol": "AARTIIND",
|
683
|
+
|
684
|
+
# Exchange code
|
685
|
+
"exchange": "NSE",
|
686
|
+
|
687
|
+
# Bid price if available
|
688
|
+
"bid": 0,
|
689
|
+
|
690
|
+
# Size of total bids at best bid price
|
691
|
+
"bidSize": 0,
|
692
|
+
|
693
|
+
# Ask (offer) price
|
694
|
+
"ask": 0,
|
695
|
+
|
696
|
+
# Size of total asks at best ask price
|
697
|
+
"askSize": 0,
|
698
|
+
|
699
|
+
# Last traded price
|
700
|
+
"ltp": 450.05,
|
701
|
+
|
702
|
+
# Trading volume
|
703
|
+
"volume": 0,
|
704
|
+
|
705
|
+
# Lot size for the instrument
|
706
|
+
"lotSize": 1,
|
707
|
+
|
708
|
+
# Mid price ((bid+ask)/2)
|
709
|
+
"mid": 0,
|
710
|
+
|
711
|
+
# Market capitalization (for equities)
|
712
|
+
"marketCap": 0,
|
713
|
+
|
714
|
+
# Dividend yield percentage (for equities)
|
715
|
+
"dividendYield": 0,
|
716
|
+
|
717
|
+
# Last dividend date
|
718
|
+
"dividendDate": "",
|
719
|
+
|
720
|
+
# Daily Open-High-Low-Close values
|
721
|
+
"ohlc": {
|
722
|
+
"open": 0,
|
723
|
+
"high": 0,
|
724
|
+
"low": 0,
|
725
|
+
"close": 0
|
726
|
+
},
|
727
|
+
|
728
|
+
# Industry classification (for equities)
|
729
|
+
"industry": "",
|
730
|
+
|
731
|
+
# Sector classification (for equities)
|
732
|
+
"sector": "",
|
733
|
+
|
734
|
+
# Relevant indicators for underlying assets (for derivatives)
|
735
|
+
"underlyingIndicators": "",
|
736
|
+
|
737
|
+
# Net change in price
|
738
|
+
"netChange": 0,
|
739
|
+
|
740
|
+
# Net change in percentage
|
741
|
+
"netChangePercentage": 0,
|
742
|
+
|
743
|
+
# Beta value (for equities)
|
744
|
+
"beta": 0,
|
745
|
+
|
746
|
+
# Liquidity rating
|
747
|
+
"liquidityRating": 0,
|
748
|
+
|
749
|
+
# Implied volatility metrics (for options)
|
750
|
+
"iv": {
|
751
|
+
"index": 0,
|
752
|
+
"indexRank": 0,
|
753
|
+
"percentile": 0,
|
754
|
+
"change5Days": 0,
|
755
|
+
"change30Days": 0,
|
756
|
+
"ivHvChange30Days": 0
|
757
|
+
},
|
758
|
+
|
759
|
+
# Historical volatility metrics
|
760
|
+
"hv": {
|
761
|
+
"change30Days": 0,
|
762
|
+
"change60Days": 0,
|
763
|
+
"change90Days": 0
|
764
|
+
},
|
765
|
+
|
766
|
+
# Minimum price movement
|
767
|
+
"tickSize": 0.05,
|
768
|
+
|
769
|
+
# Previous day's trading summary
|
770
|
+
"bhavcopy": {
|
771
|
+
"open": 458.4,
|
772
|
+
"high": 470.9,
|
773
|
+
"low": 440.75,
|
774
|
+
"close": 448.55,
|
775
|
+
"volume": 3544523,
|
776
|
+
"turnover": 1632822505.15,
|
777
|
+
"totalTrades": 59999
|
778
|
+
},
|
779
|
+
|
780
|
+
# Exchange token identifier
|
781
|
+
"exchangeToken": 7,
|
782
|
+
|
783
|
+
# Market segment
|
784
|
+
"segment": "NSECM",
|
785
|
+
|
786
|
+
# Whether the instrument is actively traded
|
787
|
+
"isTraded": false,
|
788
|
+
|
789
|
+
# Complete instrument identifier
|
790
|
+
"identifier": "NSE:AARTIIND:7",
|
791
|
+
|
792
|
+
# Instrument type code
|
793
|
+
"instrumentType": "EQLC",
|
794
|
+
|
795
|
+
# Option type (for options) - CE or PE
|
796
|
+
"optionType": "",
|
797
|
+
|
798
|
+
# Expiry date (for derivatives)
|
799
|
+
"expiry": "",
|
800
|
+
|
801
|
+
# International Securities Identification Number
|
802
|
+
"isin": "INE769A01020",
|
803
|
+
|
804
|
+
# Margin requirement percentage
|
805
|
+
"margin": 19.43,
|
806
|
+
|
807
|
+
# 52-week high price
|
808
|
+
"week52High": 765.5,
|
809
|
+
|
810
|
+
# 52-week low price
|
811
|
+
"week52Low": 344.2,
|
812
|
+
|
813
|
+
# Maximum allowed trade volume
|
814
|
+
"maxTradeVolume": 2147483647,
|
815
|
+
|
816
|
+
# Price band limits
|
817
|
+
"priceBand": {
|
818
|
+
"high": 493.4,
|
819
|
+
"low": 403.7,
|
820
|
+
"creditRating": {
|
821
|
+
"lower": 403.7,
|
822
|
+
"higher": 493.4
|
823
|
+
}
|
824
|
+
}
|
825
|
+
},
|
826
|
+
# Additional instruments...
|
827
|
+
]
|
828
|
+
```
|
829
|
+
|
830
|
+
Note that certain fields may have zero or empty values if the data is not available from the exchange or if it's not applicable to that instrument type.
|
831
|
+
|
832
|
+
### Options Chain
|
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
|
+
|
972
|
+
#### Get Option Chain
|
973
|
+
|
974
|
+
Fetch the option chain for a specific instrument using either an exact expiry date or a expiry preference:
|
975
|
+
|
976
|
+
```python
|
977
|
+
# Get ATM call options for SBIN with specific expiry date
|
978
|
+
options = client.get_option_chain(
|
979
|
+
identifier="NSE:SBIN:3045",
|
980
|
+
expiry_date="2025-05-30",
|
981
|
+
option_type=[client.OPTION_TYPE_CE], # Call options
|
982
|
+
moneyness=[client.MONEYNESS_ATM] # At-the-money
|
983
|
+
)
|
984
|
+
print(f"Found {len(options['strikes'])} strikes")
|
985
|
+
print(f"Current underlying price: {options['underlyingPrice']}")
|
986
|
+
|
987
|
+
# Get both call and put options with expiry preference
|
988
|
+
all_options = client.get_option_chain(
|
989
|
+
identifier="NSE:NIFTY 50:26000",
|
990
|
+
expiry_preference=client.EXPIRY_CURRENT_WEEKLY, # Current week's expiry
|
991
|
+
option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE], # Both calls and puts
|
992
|
+
moneyness=[client.MONEYNESS_ATM, client.MONEYNESS_ITM, client.MONEYNESS_OTM] # All moneyness types
|
993
|
+
)
|
994
|
+
|
995
|
+
# Print option chain details
|
996
|
+
print(f"Resolved expiry: {all_options['resolvedExpiry']}")
|
997
|
+
print(f"Underlying price: {all_options['underlyingPrice']}")
|
998
|
+
print(f"Future price: {all_options['futurePrice']}")
|
999
|
+
|
1000
|
+
# Process options data
|
1001
|
+
for strike in all_options['strikes']:
|
1002
|
+
print(f"{strike['tradingSymbol']} ({strike['moneyness']}): {strike['ltp']}")
|
1003
|
+
```
|
1004
|
+
|
1005
|
+
#### Response Structure
|
1006
|
+
|
1007
|
+
The `get_option_chain` method returns a dictionary with the following structure:
|
1008
|
+
|
1009
|
+
```python
|
1010
|
+
{
|
1011
|
+
# The actual expiry date that was resolved (may differ slightly from requested date)
|
1012
|
+
"resolvedExpiry": "2025-05-29",
|
1013
|
+
|
1014
|
+
# Current price of the underlying stock/index
|
1015
|
+
"underlyingPrice": 792.1,
|
1016
|
+
|
1017
|
+
# Price of the corresponding futures contract (if applicable)
|
1018
|
+
"futurePrice": 793.35,
|
1019
|
+
|
1020
|
+
# Array of available strike prices matching the query criteria
|
1021
|
+
"strikes": [
|
1022
|
+
{
|
1023
|
+
# The strike price of the option
|
1024
|
+
"strikePrice": 790,
|
1025
|
+
|
1026
|
+
# Option type: "CE" (Call) or "PE" (Put)
|
1027
|
+
"optionType": "CE",
|
1028
|
+
|
1029
|
+
# Exchange token for the option contract
|
1030
|
+
"exchangeToken": 136169,
|
1031
|
+
|
1032
|
+
# Exchange where the option is traded
|
1033
|
+
"exchange": "NSE",
|
1034
|
+
|
1035
|
+
# Trading symbol for the option contract
|
1036
|
+
"tradingSymbol": "SBIN25MAY790CE",
|
1037
|
+
|
1038
|
+
# Moneyness classification: "ATM", "ITM", or "OTM"
|
1039
|
+
"moneyness": "ATM",
|
1040
|
+
|
1041
|
+
# Expiry date of the option contract
|
1042
|
+
"expiry": "2025-05-29",
|
1043
|
+
|
1044
|
+
# Last traded price of the option
|
1045
|
+
"ltp": 15.1,
|
1046
|
+
|
1047
|
+
# Option Greeks and metrics (if available)
|
1048
|
+
"metrics": {
|
1049
|
+
# Option premium
|
1050
|
+
"premium": 0,
|
1051
|
+
|
1052
|
+
# Open interest
|
1053
|
+
"oi": 0,
|
1054
|
+
|
1055
|
+
# Implied volatility
|
1056
|
+
"iv": 0,
|
1057
|
+
|
1058
|
+
# Delta - rate of change of option price with respect to underlying
|
1059
|
+
"delta": 0,
|
1060
|
+
|
1061
|
+
# Gamma - rate of change of delta with respect to underlying
|
1062
|
+
"gamma": 0,
|
1063
|
+
|
1064
|
+
# Theta - rate of change of option price with respect to time
|
1065
|
+
"theta": 0,
|
1066
|
+
|
1067
|
+
# Vega - rate of change of option price with respect to volatility
|
1068
|
+
"vega": 0,
|
1069
|
+
|
1070
|
+
# Rho - rate of change of option price with respect to interest rate
|
1071
|
+
"rho": 0
|
1072
|
+
}
|
1073
|
+
},
|
1074
|
+
# Additional strikes...
|
1075
|
+
]
|
1076
|
+
}
|
1077
|
+
```
|
1078
|
+
|
1079
|
+
#### Advanced Examples
|
1080
|
+
|
1081
|
+
##### Finding a Straddle/Strangle
|
1082
|
+
|
1083
|
+
```python
|
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)
|
1137
|
+
|
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}")
|
1152
|
+
|
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
|
1168
|
+
option_chain = client.get_option_chain(
|
1169
|
+
identifier=identifier,
|
1170
|
+
expiry_date=expiry,
|
1171
|
+
option_type=[client.OPTION_TYPE_CE, client.OPTION_TYPE_PE],
|
1172
|
+
moneyness=[client.MONEYNESS_ATM, client.MONEYNESS_ITM, client.MONEYNESS_OTM]
|
1173
|
+
)
|
1174
|
+
|
1175
|
+
# Extract data
|
1176
|
+
underlying_price = option_chain["underlyingPrice"]
|
1177
|
+
|
1178
|
+
# Separate calls and puts
|
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()
|
1211
|
+
|
1212
|
+
return option_chain
|
1213
|
+
|
1214
|
+
# Example usage
|
1215
|
+
visualize_option_chain("NSE:NIFTY 50:26000", "2025-05-30")
|
1216
|
+
```
|
1217
|
+
|
636
1218
|
### Wizzer Client Examples
|
637
1219
|
|
638
1220
|
#### Market Data and Analysis Example
|
@@ -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=ScYHyaz49WDqsMZQVcJLXExQJp_ZOdSeqRvLIiAS-lI,182
|
2
|
-
wiz_trader/apis/__init__.py,sha256=ItWKMOl4omiW0g2f-M7WRW3v-dss_ULd9vYnFyIIT9o,132
|
3
|
-
wiz_trader/apis/client.py,sha256=JDw0lMCw79LSU9E0YRHt_2FCAzZTZddweB5EsJChTb4,47054
|
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.16.0.dist-info/METADATA,sha256=Xwzf-z6y-ovu7lq-c5K4tlkiyWafGTzUxwgDKJqrJTk,54024
|
7
|
-
wiz_trader-0.16.0.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
8
|
-
wiz_trader-0.16.0.dist-info/top_level.txt,sha256=lnYS_g8LlA6ryKYnvY8xIQ6K2K-xzOsd-99AWgnW6VY,11
|
9
|
-
wiz_trader-0.16.0.dist-info/RECORD,,
|
File without changes
|