wiz-trader 0.17.0__tar.gz → 0.18.0__tar.gz

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.
@@ -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