DhanHQ 2.1.7 → 2.1.10

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -0
  3. data/examples/comprehensive_websocket_examples.rb +0 -0
  4. data/examples/instrument_finder_test.rb +0 -0
  5. data/examples/live_order_updates.rb +1 -1
  6. data/examples/market_depth_example.rb +2 -2
  7. data/examples/order_update_example.rb +0 -0
  8. data/examples/trading_fields_example.rb +1 -1
  9. data/lib/DhanHQ/client.rb +2 -1
  10. data/lib/DhanHQ/contracts/expired_options_data_contract.rb +6 -6
  11. data/lib/DhanHQ/core/base_model.rb +9 -1
  12. data/lib/DhanHQ/models/edis.rb +150 -14
  13. data/lib/DhanHQ/models/expired_options_data.rb +307 -82
  14. data/lib/DhanHQ/models/forever_order.rb +261 -22
  15. data/lib/DhanHQ/models/funds.rb +76 -10
  16. data/lib/DhanHQ/models/historical_data.rb +148 -31
  17. data/lib/DhanHQ/models/holding.rb +82 -6
  18. data/lib/DhanHQ/models/instrument_helpers.rb +39 -5
  19. data/lib/DhanHQ/models/kill_switch.rb +113 -11
  20. data/lib/DhanHQ/models/ledger_entry.rb +101 -13
  21. data/lib/DhanHQ/models/margin.rb +133 -8
  22. data/lib/DhanHQ/models/market_feed.rb +181 -17
  23. data/lib/DhanHQ/models/option_chain.rb +184 -12
  24. data/lib/DhanHQ/models/order.rb +399 -34
  25. data/lib/DhanHQ/models/position.rb +161 -10
  26. data/lib/DhanHQ/models/profile.rb +103 -7
  27. data/lib/DhanHQ/models/super_order.rb +275 -15
  28. data/lib/DhanHQ/models/trade.rb +279 -26
  29. data/lib/DhanHQ/rate_limiter.rb +78 -23
  30. data/lib/DhanHQ/resources/expired_options_data.rb +1 -1
  31. data/lib/DhanHQ/version.rb +1 -1
  32. data/lib/DhanHQ/ws/market_depth/client.rb +3 -1
  33. data/lib/DhanHQ/ws/orders/client.rb +2 -1
  34. data/lib/DhanHQ/ws/orders/connection.rb +0 -3
  35. data/lib/DhanHQ/ws/orders.rb +2 -1
  36. metadata +1 -1
@@ -4,22 +4,151 @@ require_relative "../contracts/option_chain_contract"
4
4
 
5
5
  module DhanHQ
6
6
  module Models
7
- # Model for fetching and filtering option chain snapshots.
7
+ ##
8
+ # Model for fetching option chain data for any option instrument across exchanges.
9
+ #
10
+ # The Option Chain API provides the entire option chain for any underlying instrument
11
+ # across NSE, BSE, and MCX exchanges. For each strike price, you get Open Interest (OI),
12
+ # Greeks (Delta, Theta, Gamma, Vega), Volume, Last Traded Price, Best Bid/Ask prices,
13
+ # Implied Volatility (IV), and other option analytics.
14
+ #
15
+ # @note **Rate Limits**: You can call the Option Chain API once every 3 seconds.
16
+ # This rate limit is enforced because OI data updates slowly compared to LTP or
17
+ # other data parameters. The client's internal rate limiter automatically throttles
18
+ # calls to prevent exceeding limits.
19
+ #
20
+ # @note **Data Filtering**: The model automatically filters out strikes where both
21
+ # Call (CE) and Put (PE) options have zero `last_price`, keeping the payload compact
22
+ # and focused on actively traded strikes.
23
+ #
24
+ # @example Fetch option chain for NIFTY index options
25
+ # chain = DhanHQ::Models::OptionChain.fetch(
26
+ # underlying_scrip: 13,
27
+ # underlying_seg: "IDX_I",
28
+ # expiry: "2024-10-31"
29
+ # )
30
+ # puts "Underlying LTP: ₹#{chain[:last_price]}"
31
+ # nifty_25000 = chain[:oc]["25000.000000"]
32
+ # puts "CE LTP: ₹#{nifty_25000['ce'][:last_price]}"
33
+ # puts "CE OI: #{nifty_25000['ce'][:oi]}"
34
+ #
35
+ # @example Fetch expiry list for an underlying
36
+ # expiries = DhanHQ::Models::OptionChain.fetch_expiry_list(
37
+ # underlying_scrip: 13,
38
+ # underlying_seg: "IDX_I"
39
+ # )
40
+ # expiries.each { |expiry| puts expiry }
41
+ #
42
+ # @example Access Greeks for a strike
43
+ # chain = DhanHQ::Models::OptionChain.fetch(
44
+ # underlying_scrip: 1333,
45
+ # underlying_seg: "NSE_FNO",
46
+ # expiry: "2024-12-26"
47
+ # )
48
+ # strike_data = chain[:oc]["25000.000000"]
49
+ # ce_greeks = strike_data['ce'][:greeks]
50
+ # puts "Delta: #{ce_greeks[:delta]}"
51
+ # puts "Gamma: #{ce_greeks[:gamma]}"
52
+ # puts "Theta: #{ce_greeks[:theta]}"
53
+ # puts "Vega: #{ce_greeks[:vega]}"
54
+ #
8
55
  class OptionChain < BaseModel
9
56
  attr_reader :underlying_scrip, :underlying_seg, :expiry, :last_price, :option_data
10
57
 
11
58
  class << self
12
- # Shared resource for option chain operations.
59
+ ##
60
+ # Provides a shared instance of the OptionChain resource.
13
61
  #
14
- # @return [DhanHQ::Resources::OptionChain]
62
+ # @return [DhanHQ::Resources::OptionChain] The OptionChain resource client instance
15
63
  def resource
16
64
  @resource ||= DhanHQ::Resources::OptionChain.new
17
65
  end
18
66
 
19
- # Fetch the entire option chain for an instrument
67
+ ##
68
+ # Fetches the entire option chain for a specified underlying instrument and expiry.
20
69
  #
21
- # @param params [Hash] The request parameters (snake_case format)
22
- # @return [HashWithIndifferentAccess] The filtered option chain data
70
+ # Retrieves real-time option chain data across all strikes for the given underlying.
71
+ # The response includes Open Interest (OI), Greeks, Volume, Last Traded Price,
72
+ # Best Bid/Ask prices, Implied Volatility (IV), and other option analytics for
73
+ # both Call (CE) and Put (PE) options at each strike price.
74
+ #
75
+ # @param params [Hash{Symbol => Integer, String}] Request parameters for option chain
76
+ # @option params [Integer] :underlying_scrip (required) Security ID of the underlying
77
+ # instrument. Can be found via the Instruments API.
78
+ # @option params [String] :underlying_seg (required) Exchange and segment of underlying
79
+ # for which data is to be fetched.
80
+ # Valid values: "IDX_I" (Index), "NSE_FNO" (NSE F&O), "BSE_FNO" (BSE F&O), "MCX_FO" (MCX)
81
+ # @option params [String] :expiry (required) Expiry date of the option contract for
82
+ # which the option chain is requested. Must be in "YYYY-MM-DD" format.
83
+ # List of active expiries can be fetched using {fetch_expiry_list}.
84
+ #
85
+ # @return [HashWithIndifferentAccess] Filtered option chain data.
86
+ # Response structure:
87
+ # - **:last_price** [Float] Last Traded Price (LTP) of the underlying instrument
88
+ # - **:oc** [Hash{String => Hash}] Option chain data organized by strike price.
89
+ # Strike prices are stored as string keys (e.g., "25000.000000").
90
+ # Each strike contains:
91
+ # - **"ce"** [Hash{Symbol => Float, Integer, Hash}] Call Option data for this strike:
92
+ # - **:greeks** [Hash{Symbol => Float}] Option Greeks:
93
+ # - **:delta** [Float] Measures the change of option's premium based on
94
+ # every 1 rupee change in underlying
95
+ # - **:theta** [Float] Measures how quickly an option's value decreases over time
96
+ # - **:gamma** [Float] Rate of change in an option's delta in relation to the
97
+ # price of the underlying asset
98
+ # - **:vega** [Float] Measures the change of option's premium in response to
99
+ # a 1% change in implied volatility
100
+ # - **:implied_volatility** [Float] Value of expected volatility of a stock
101
+ # over the life of the option
102
+ # - **:last_price** [Float] Last Traded Price of the Call Option Instrument
103
+ # - **:oi** [Integer] Open Interest of the Call Option Instrument
104
+ # - **:previous_close_price** [Float] Previous day close price
105
+ # - **:previous_oi** [Integer] Previous day Open Interest
106
+ # - **:previous_volume** [Integer] Previous day volume
107
+ # - **:top_ask_price** [Float] Current best ask price available
108
+ # - **:top_ask_quantity** [Integer] Quantity available at current best ask price
109
+ # - **:top_bid_price** [Float] Current best bid price available
110
+ # - **:top_bid_quantity** [Integer] Quantity available at current best bid price
111
+ # - **:volume** [Integer] Day volume for Call Option Instrument
112
+ # - **"pe"** [Hash{Symbol => Float, Integer, Hash}] Put Option data for this strike.
113
+ # Contains the same fields as "ce" (Call Option data).
114
+ #
115
+ # @note Strikes where both CE and PE have zero `last_price` are automatically filtered out.
116
+ # This keeps the payload compact and focused on actively traded strikes.
117
+ #
118
+ # @example Fetch option chain for NIFTY index options
119
+ # chain = DhanHQ::Models::OptionChain.fetch(
120
+ # underlying_scrip: 13,
121
+ # underlying_seg: "IDX_I",
122
+ # expiry: "2024-10-31"
123
+ # )
124
+ # puts "NIFTY LTP: ₹#{chain[:last_price]}"
125
+ #
126
+ # @example Access Call and Put data for a specific strike
127
+ # chain = DhanHQ::Models::OptionChain.fetch(
128
+ # underlying_scrip: 13,
129
+ # underlying_seg: "IDX_I",
130
+ # expiry: "2024-10-31"
131
+ # )
132
+ # strike_25000 = chain[:oc]["25000.000000"]
133
+ # ce_data = strike_25000["ce"]
134
+ # pe_data = strike_25000["pe"]
135
+ # puts "CE LTP: ₹#{ce_data[:last_price]}, OI: #{ce_data[:oi]}"
136
+ # puts "PE LTP: ₹#{pe_data[:last_price]}, OI: #{pe_data[:oi]}"
137
+ #
138
+ # @example Calculate OI change and analyze Greeks
139
+ # chain = DhanHQ::Models::OptionChain.fetch(
140
+ # underlying_scrip: 1333,
141
+ # underlying_seg: "NSE_FNO",
142
+ # expiry: "2024-12-26"
143
+ # )
144
+ # strike_data = chain[:oc]["25000.000000"]
145
+ # ce = strike_data["ce"]
146
+ # oi_change = ce[:oi] - ce[:previous_oi]
147
+ # puts "OI Change: #{oi_change}"
148
+ # puts "Delta: #{ce[:greeks][:delta]}"
149
+ # puts "IV: #{ce[:implied_volatility]}%"
150
+ #
151
+ # @raise [DhanHQ::ValidationError] If validation fails for any parameter or date format
23
152
  def fetch(params)
24
153
  validate_params!(params, DhanHQ::Contracts::OptionChainContract)
25
154
 
@@ -29,10 +158,44 @@ module DhanHQ
29
158
  filter_valid_strikes(response[:data]).with_indifferent_access
30
159
  end
31
160
 
32
- # Fetch the expiry list of an underlying security
161
+ ##
162
+ # Fetches the list of active expiry dates for an underlying instrument.
33
163
  #
34
- # @param params [Hash] The request parameters (snake_case format)
35
- # @return [Array<String>] The list of expiry dates
164
+ # Retrieves all expiry dates for which option instruments are active for the given
165
+ # underlying. This list is useful for selecting valid expiry dates when fetching
166
+ # option chains.
167
+ #
168
+ # @param params [Hash{Symbol => Integer, String}] Request parameters for expiry list
169
+ # @option params [Integer] :underlying_scrip (required) Security ID of the underlying
170
+ # instrument. Can be found via the Instruments API.
171
+ # @option params [String] :underlying_seg (required) Exchange and segment of underlying
172
+ # for which expiry list is to be fetched.
173
+ # Valid values: "IDX_I" (Index), "NSE_FNO" (NSE F&O), "BSE_FNO" (BSE F&O), "MCX_FO" (MCX)
174
+ #
175
+ # @return [Array<String>] Array of expiry dates in "YYYY-MM-DD" format.
176
+ # Returns empty array if the API response status is not "success" or if no expiries are found.
177
+ #
178
+ # @example Fetch expiry list for NIFTY index
179
+ # expiries = DhanHQ::Models::OptionChain.fetch_expiry_list(
180
+ # underlying_scrip: 13,
181
+ # underlying_seg: "IDX_I"
182
+ # )
183
+ # puts "Available expiries:"
184
+ # expiries.each { |expiry| puts " #{expiry}" }
185
+ #
186
+ # @example Use expiry list to fetch option chains
187
+ # expiries = DhanHQ::Models::OptionChain.fetch_expiry_list(
188
+ # underlying_scrip: 1333,
189
+ # underlying_seg: "NSE_FNO"
190
+ # )
191
+ # nearest_expiry = expiries.first
192
+ # chain = DhanHQ::Models::OptionChain.fetch(
193
+ # underlying_scrip: 1333,
194
+ # underlying_seg: "NSE_FNO",
195
+ # expiry: nearest_expiry
196
+ # )
197
+ #
198
+ # @raise [DhanHQ::ValidationError] If validation fails for any parameter
36
199
  def fetch_expiry_list(params)
37
200
  validate_params!(params, DhanHQ::Contracts::OptionChainExpiryListContract)
38
201
 
@@ -42,10 +205,17 @@ module DhanHQ
42
205
 
43
206
  private
44
207
 
45
- # **Filters valid strikes where `ce` or `pe` has `last_price > 0` and keeps strike prices as-is**
208
+ ##
209
+ # Filters valid strikes where at least one of CE or PE has a non-zero last_price.
210
+ #
211
+ # Removes strikes from the option chain where both Call (CE) and Put (PE) options
212
+ # have zero `last_price`, keeping only actively traded strikes. This keeps the
213
+ # payload compact and focused on relevant data.
214
+ #
215
+ # @param data [Hash] The API response data containing option chain information
216
+ # @return [Hash] The filtered option chain data with original strike price keys preserved
46
217
  #
47
- # @param data [Hash] The API response data
48
- # @return [Hash] The filtered option chain data with original strike price keys
218
+ # @api private
49
219
  def filter_valid_strikes(data)
50
220
  return {} unless data.is_a?(Hash) && data.key?(:oc)
51
221
 
@@ -63,6 +233,7 @@ module DhanHQ
63
233
  # Validation contract for option chain
64
234
  #
65
235
  # @return [DhanHQ::Contracts::OptionChainContract]
236
+ # @api private
66
237
  def validation_contract
67
238
  DhanHQ::Contracts::OptionChainContract.new
68
239
  end
@@ -73,6 +244,7 @@ module DhanHQ
73
244
  # Validation contract for option chain
74
245
  #
75
246
  # @return [DhanHQ::Contracts::OptionChainContract]
247
+ # @api private
76
248
  def validation_contract
77
249
  DhanHQ::Contracts::OptionChainContract.new
78
250
  end