DhanHQ 2.1.8 → 2.2.0

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.rubocop_todo.yml +143 -118
  4. data/CHANGELOG.md +177 -0
  5. data/CODE_REVIEW_ISSUES.md +397 -0
  6. data/FIXES_APPLIED.md +373 -0
  7. data/GUIDE.md +41 -0
  8. data/README.md +55 -0
  9. data/RELEASING.md +60 -0
  10. data/REVIEW_SUMMARY.md +120 -0
  11. data/VERSION_UPDATE.md +82 -0
  12. data/core +0 -0
  13. data/docs/AUTHENTICATION.md +63 -0
  14. data/docs/DATA_API_PARAMETERS.md +278 -0
  15. data/docs/PR_2.2.0.md +48 -0
  16. data/docs/RELEASE_GUIDE.md +492 -0
  17. data/docs/TESTING_GUIDE.md +1514 -0
  18. data/docs/live_order_updates.md +25 -1
  19. data/docs/rails_integration.md +29 -0
  20. data/docs/websocket_integration.md +22 -0
  21. data/lib/DhanHQ/client.rb +65 -9
  22. data/lib/DhanHQ/configuration.rb +26 -0
  23. data/lib/DhanHQ/constants.rb +1 -1
  24. data/lib/DhanHQ/contracts/expired_options_data_contract.rb +6 -6
  25. data/lib/DhanHQ/contracts/place_order_contract.rb +51 -0
  26. data/lib/DhanHQ/core/base_model.rb +26 -11
  27. data/lib/DhanHQ/errors.rb +4 -0
  28. data/lib/DhanHQ/helpers/request_helper.rb +17 -2
  29. data/lib/DhanHQ/helpers/response_helper.rb +34 -13
  30. data/lib/DhanHQ/models/edis.rb +150 -14
  31. data/lib/DhanHQ/models/expired_options_data.rb +307 -88
  32. data/lib/DhanHQ/models/forever_order.rb +261 -22
  33. data/lib/DhanHQ/models/funds.rb +76 -10
  34. data/lib/DhanHQ/models/historical_data.rb +148 -31
  35. data/lib/DhanHQ/models/holding.rb +82 -6
  36. data/lib/DhanHQ/models/instrument_helpers.rb +4 -4
  37. data/lib/DhanHQ/models/kill_switch.rb +113 -11
  38. data/lib/DhanHQ/models/ledger_entry.rb +101 -13
  39. data/lib/DhanHQ/models/margin.rb +133 -8
  40. data/lib/DhanHQ/models/market_feed.rb +181 -17
  41. data/lib/DhanHQ/models/option_chain.rb +184 -12
  42. data/lib/DhanHQ/models/order.rb +418 -36
  43. data/lib/DhanHQ/models/order_update.rb +0 -4
  44. data/lib/DhanHQ/models/position.rb +161 -10
  45. data/lib/DhanHQ/models/profile.rb +103 -7
  46. data/lib/DhanHQ/models/super_order.rb +275 -15
  47. data/lib/DhanHQ/models/trade.rb +279 -26
  48. data/lib/DhanHQ/rate_limiter.rb +40 -6
  49. data/lib/DhanHQ/resources/expired_options_data.rb +1 -1
  50. data/lib/DhanHQ/version.rb +1 -1
  51. data/lib/DhanHQ/ws/client.rb +11 -5
  52. data/lib/DhanHQ/ws/connection.rb +16 -2
  53. data/lib/DhanHQ/ws/market_depth/client.rb +2 -1
  54. data/lib/DhanHQ/ws/market_depth.rb +12 -12
  55. data/lib/DhanHQ/ws/orders/client.rb +78 -12
  56. data/lib/DhanHQ/ws/orders/connection.rb +2 -1
  57. data/lib/DhanHQ/ws/orders.rb +2 -1
  58. metadata +18 -5
  59. data/lib/DhanHQ/contracts/modify_order_contract_copy.rb +0 -100
@@ -3,9 +3,45 @@
3
3
  module DhanHQ
4
4
  module Models
5
5
  ##
6
- # Represents expired options data for rolling contracts
7
- # Provides access to OHLC, volume, open interest, implied volatility, and spot data
8
- # rubocop:disable Metrics/ClassLength
6
+ # Model for fetching expired options contract data on a rolling basis.
7
+ #
8
+ # This API provides pre-processed expired options data for up to the last 5 years.
9
+ # Data is available on a minute-level basis, organized by strike price relative to spot
10
+ # (e.g., ATM, ATM+1, ATM-1, etc.). You can fetch up to 31 days of data in a single API call.
11
+ #
12
+ # Available data includes:
13
+ # - OHLC (Open, High, Low, Close) prices
14
+ # - Volume and Open Interest
15
+ # - Implied Volatility (IV)
16
+ # - Strike prices
17
+ # - Spot prices
18
+ # - Timestamps
19
+ #
20
+ # Strike ranges:
21
+ # - Index Options (near expiry): Up to ATM+10 / ATM-10
22
+ # - All other contracts: Up to ATM+3 / ATM-3
23
+ #
24
+ # @example Fetch expired options data for NIFTY
25
+ # data = DhanHQ::Models::ExpiredOptionsData.fetch(
26
+ # exchange_segment: "NSE_FNO",
27
+ # interval: "1",
28
+ # security_id: 13,
29
+ # instrument: "OPTIDX",
30
+ # expiry_flag: "MONTH",
31
+ # expiry_code: 1,
32
+ # strike: "ATM",
33
+ # drv_option_type: "CALL",
34
+ # required_data: ["open", "high", "low", "close", "volume"],
35
+ # from_date: "2021-08-01",
36
+ # to_date: "2021-09-01"
37
+ # )
38
+ # ohlc = data.ohlc_data
39
+ # volumes = data.volume_data
40
+ #
41
+ # @example Access call option data
42
+ # call_data = data.call_data
43
+ # put_data = data.put_data
44
+ #
9
45
  class ExpiredOptionsData < BaseModel
10
46
  # All expired options data attributes
11
47
  attributes :exchange_segment, :interval, :security_id, :instrument,
@@ -14,27 +50,74 @@ module DhanHQ
14
50
 
15
51
  class << self
16
52
  ##
17
- # Fetch expired options data for rolling contracts
18
- # POST /charts/rollingoption
53
+ # Fetches expired options data for rolling contracts on a minute-level basis.
19
54
  #
20
- # @param params [Hash] Parameters for the request
21
- # @option params [String] :exchange_segment Exchange segment (e.g., "NSE_FNO")
22
- # @option params [Integer] :interval Minute interval (1, 5, 15, 25, 60)
23
- # @option params [String] :security_id Security ID for the underlying
24
- # @option params [String] :instrument Instrument type ("OPTIDX" or "OPTSTK")
25
- # @option params [String] :expiry_flag Expiry interval ("WEEK" or "MONTH")
26
- # @option params [Integer] :expiry_code Expiry code
27
- # @option params [String] :strike Strike price ("ATM", "ATM+1", "ATM-1", etc.)
28
- # @option params [String] :drv_option_type Option type ("CALL" or "PUT")
29
- # @option params [Array<String>] :required_data Required data fields
30
- # @option params [String] :from_date Start date (YYYY-MM-DD)
31
- # @option params [String] :to_date End date (YYYY-MM-DD)
32
- # @return [ExpiredOptionsData] Expired options data object
55
+ # Data is organized by strike price relative to spot and can be fetched for up to
56
+ # 31 days in a single request. Historical data is available for up to the last 5 years.
57
+ #
58
+ # @param params [Hash{Symbol => String, Integer, Array<String>}] Request parameters
59
+ # @option params [String] :exchange_segment (required) Exchange and segment identifier.
60
+ # Valid values: "NSE_FNO", "BSE_FNO", "NSE_EQ", "BSE_EQ"
61
+ # @option params [String] :interval (required) Minute intervals for the timeframe.
62
+ # Valid values: "1", "5", "15", "25", "60"
63
+ # @option params [Integer] :security_id (required) Underlying exchange standard ID for each scrip
64
+ # @option params [String] :instrument (required) Instrument type of the scrip.
65
+ # Valid values: "OPTIDX" (Index Options), "OPTSTK" (Stock Options)
66
+ # @option params [String] :expiry_flag (required) Expiry interval of the instrument.
67
+ # Valid values: "WEEK", "MONTH"
68
+ # @option params [Integer] :expiry_code (required) Expiry code for the instrument
69
+ # @option params [String] :strike (required) Strike price specification.
70
+ # Format: "ATM" for At The Money, "ATM+X" or "ATM-X" for offset strikes.
71
+ # For Index Options (near expiry): Up to ATM+10 / ATM-10
72
+ # For all other contracts: Up to ATM+3 / ATM-3
73
+ # @option params [String] :drv_option_type (required) Option type.
74
+ # Valid values: "CALL", "PUT"
75
+ # @option params [Array<String>] :required_data (required) Array of required data fields.
76
+ # Valid values: "open", "high", "low", "close", "iv", "volume", "strike", "oi", "spot"
77
+ # @option params [String] :from_date (required) Start date of the desired range in YYYY-MM-DD format.
78
+ # Cannot be more than 5 years ago. Same-day ranges are allowed.
79
+ # @option params [String] :to_date (required) End date of the desired range (non-inclusive) in YYYY-MM-DD format.
80
+ # Date range cannot exceed 31 days from from_date (to_date is non-inclusive). Same-day `from_date`/`to_date` is valid.
81
+ #
82
+ # @return [ExpiredOptionsData] Expired options data object with fetched data
83
+ #
84
+ # @example Fetch NIFTY index options data
85
+ # data = DhanHQ::Models::ExpiredOptionsData.fetch(
86
+ # exchange_segment: "NSE_FNO",
87
+ # interval: "1",
88
+ # security_id: 13,
89
+ # instrument: "OPTIDX",
90
+ # expiry_flag: "MONTH",
91
+ # expiry_code: 1,
92
+ # strike: "ATM",
93
+ # drv_option_type: "CALL",
94
+ # required_data: ["open", "high", "low", "close", "volume", "iv", "oi", "spot"],
95
+ # from_date: "2021-08-01",
96
+ # to_date: "2021-09-01"
97
+ # )
98
+ #
99
+ # @example Fetch stock options data for ATM+2 strike
100
+ # data = DhanHQ::Models::ExpiredOptionsData.fetch(
101
+ # exchange_segment: "NSE_FNO",
102
+ # interval: "15",
103
+ # security_id: 11536,
104
+ # instrument: "OPTSTK",
105
+ # expiry_flag: "WEEK",
106
+ # expiry_code: 0,
107
+ # strike: "ATM+2",
108
+ # drv_option_type: "PUT",
109
+ # required_data: ["open", "high", "low", "close", "volume"],
110
+ # from_date: "2024-01-01",
111
+ # to_date: "2024-01-31"
112
+ # )
113
+ #
114
+ # @raise [DhanHQ::ValidationError] If validation fails for any parameter
33
115
  def fetch(params)
34
- validate_params(params)
116
+ normalized = normalize_params(params)
117
+ validate_params(normalized)
35
118
 
36
- response = expired_options_resource.fetch(params)
37
- new(response.merge(params), skip_validation: true)
119
+ response = expired_options_resource.fetch(normalized)
120
+ new(response.merge(normalized), skip_validation: true)
38
121
  end
39
122
 
40
123
  private
@@ -51,6 +134,50 @@ module DhanHQ
51
134
 
52
135
  raise DhanHQ::ValidationError, "Invalid parameters: #{validation_result.errors.to_h}"
53
136
  end
137
+
138
+ # Best-effort normalization: coerce convertible values into expected shapes.
139
+ # Only values that are not convertible will fail validation.
140
+ def normalize_params(params)
141
+ normalized = params.dup
142
+
143
+ # interval: accept Integer or String, normalize to String
144
+ normalized[:interval] = normalized[:interval].to_s if normalized.key?(:interval)
145
+
146
+ # security_id, expiry_code: accept String or Integer, normalize to Integer if possible
147
+ if normalized.key?(:security_id)
148
+ original = normalized[:security_id]
149
+ converted = Integer(original, exception: false)
150
+ normalized[:security_id] = converted || original
151
+ end
152
+
153
+ if normalized.key?(:expiry_code)
154
+ original = normalized[:expiry_code]
155
+ converted = Integer(original, exception: false)
156
+ normalized[:expiry_code] = converted || original
157
+ end
158
+
159
+ # Uppercase enums where appropriate
160
+ %i[exchange_segment instrument expiry_flag drv_option_type].each do |k|
161
+ next unless normalized.key?(k)
162
+
163
+ v = normalized[k]
164
+ normalized[k] = v.to_s.upcase
165
+ end
166
+
167
+ # required_data: array of strings, downcased unique
168
+ if normalized.key?(:required_data)
169
+ normalized[:required_data] = Array(normalized[:required_data]).map { |x| x.to_s.downcase }.uniq
170
+ end
171
+
172
+ # strike: ensure string
173
+ normalized[:strike] = normalized[:strike].to_s.upcase if normalized.key?(:strike)
174
+
175
+ # dates: ensure string (contract validates format)
176
+ normalized[:from_date] = normalized[:from_date].to_s if normalized.key?(:from_date)
177
+ normalized[:to_date] = normalized[:to_date].to_s if normalized.key?(:to_date)
178
+
179
+ normalized
180
+ end
54
181
  end
55
182
 
56
183
  ##
@@ -60,8 +187,21 @@ module DhanHQ
60
187
  end
61
188
 
62
189
  ##
63
- # Get call option data
64
- # @return [Hash, nil] Call option data or nil if not available
190
+ # Gets call option data from the response.
191
+ #
192
+ # @return [Hash{Symbol => Array<Float, Integer>}, nil] Call option data hash containing arrays
193
+ # of OHLC, volume, IV, OI, strike, spot, and timestamps. Returns nil if call option data
194
+ # is not available in the response. Keys are normalized to snake_case:
195
+ # - **:open** [Array<Float>] Open prices
196
+ # - **:high** [Array<Float>] High prices
197
+ # - **:low** [Array<Float>] Low prices
198
+ # - **:close** [Array<Float>] Close prices
199
+ # - **:volume** [Array<Integer>] Volume traded
200
+ # - **:iv** [Array<Float>] Implied volatility values
201
+ # - **:oi** [Array<Float>] Open interest values
202
+ # - **:strike** [Array<Float>] Strike prices
203
+ # - **:spot** [Array<Float>] Spot prices
204
+ # - **:timestamp** [Array<Integer>] Epoch timestamps
65
205
  def call_data
66
206
  return nil unless data.is_a?(Hash)
67
207
 
@@ -69,8 +209,21 @@ module DhanHQ
69
209
  end
70
210
 
71
211
  ##
72
- # Get put option data
73
- # @return [Hash, nil] Put option data or nil if not available
212
+ # Gets put option data from the response.
213
+ #
214
+ # @return [Hash{Symbol => Array<Float, Integer>}, nil] Put option data hash containing arrays
215
+ # of OHLC, volume, IV, OI, strike, spot, and timestamps. Returns nil if put option data
216
+ # is not available in the response. Keys are normalized to snake_case:
217
+ # - **:open** [Array<Float>] Open prices
218
+ # - **:high** [Array<Float>] High prices
219
+ # - **:low** [Array<Float>] Low prices
220
+ # - **:close** [Array<Float>] Close prices
221
+ # - **:volume** [Array<Integer>] Volume traded
222
+ # - **:iv** [Array<Float>] Implied volatility values
223
+ # - **:oi** [Array<Float>] Open interest values
224
+ # - **:strike** [Array<Float>] Strike prices
225
+ # - **:spot** [Array<Float>] Spot prices
226
+ # - **:timestamp** [Array<Integer>] Epoch timestamps
74
227
  def put_data
75
228
  return nil unless data.is_a?(Hash)
76
229
 
@@ -78,9 +231,11 @@ module DhanHQ
78
231
  end
79
232
 
80
233
  ##
81
- # Get data for the specified option type
82
- # @param option_type [String] "CALL" or "PUT"
83
- # @return [Hash, nil] Option data or nil if not available
234
+ # Gets data for the specified option type.
235
+ #
236
+ # @param option_type [String] Option type to retrieve. Valid values: "CALL", "PUT"
237
+ # @return [Hash{Symbol => Array<Float, Integer>}, nil] Option data hash or nil if not available.
238
+ # See {#call_data} or {#put_data} for structure details.
84
239
  def data_for_type(option_type)
85
240
  case option_type.upcase
86
241
  when "CALL"
@@ -91,10 +246,16 @@ module DhanHQ
91
246
  end
92
247
 
93
248
  ##
94
- # Get OHLC data for the specified option type
95
- # @param option_type [String] "CALL" or "PUT"
96
- # @return [Hash] OHLC data with open, high, low, close arrays
97
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
249
+ # Gets OHLC (Open, High, Low, Close) data for the specified option type.
250
+ #
251
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
252
+ # If nil, uses the {#drv_option_type} from the request.
253
+ # @return [Hash{Symbol => Array<Float>}] OHLC data hash with:
254
+ # - **:open** [Array<Float>] Open prices for each time point
255
+ # - **:high** [Array<Float>] High prices for each time point
256
+ # - **:low** [Array<Float>] Low prices for each time point
257
+ # - **:close** [Array<Float>] Close prices for each time point
258
+ # @return [Hash{Symbol => Array}] Empty hash if option data is not available
98
259
  def ohlc_data(option_type = nil)
99
260
  option_type ||= drv_option_type
100
261
  option_data = data_for_type(option_type)
@@ -107,12 +268,14 @@ module DhanHQ
107
268
  close: option_data["close"] || option_data[:close] || []
108
269
  }
109
270
  end
110
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
111
271
 
112
272
  ##
113
- # Get volume data for the specified option type
114
- # @param option_type [String] "CALL" or "PUT"
115
- # @return [Array<Integer>] Volume data array
273
+ # Gets volume data for the specified option type.
274
+ #
275
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
276
+ # If nil, uses the {#drv_option_type} from the request.
277
+ # @return [Array<Integer>] Array of volume values traded in each timeframe.
278
+ # Returns empty array if option data is not available or volume was not requested.
116
279
  def volume_data(option_type = nil)
117
280
  option_type ||= drv_option_type
118
281
  option_data = data_for_type(option_type)
@@ -122,9 +285,12 @@ module DhanHQ
122
285
  end
123
286
 
124
287
  ##
125
- # Get open interest data for the specified option type
126
- # @param option_type [String] "CALL" or "PUT"
127
- # @return [Array<Float>] Open interest data array
288
+ # Gets open interest (OI) data for the specified option type.
289
+ #
290
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
291
+ # If nil, uses the {#drv_option_type} from the request.
292
+ # @return [Array<Float>] Array of open interest values for each timeframe.
293
+ # Returns empty array if option data is not available or OI was not requested.
128
294
  def open_interest_data(option_type = nil)
129
295
  option_type ||= drv_option_type
130
296
  option_data = data_for_type(option_type)
@@ -134,9 +300,12 @@ module DhanHQ
134
300
  end
135
301
 
136
302
  ##
137
- # Get implied volatility data for the specified option type
138
- # @param option_type [String] "CALL" or "PUT"
139
- # @return [Array<Float>] Implied volatility data array
303
+ # Gets implied volatility (IV) data for the specified option type.
304
+ #
305
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
306
+ # If nil, uses the {#drv_option_type} from the request.
307
+ # @return [Array<Float>] Array of implied volatility values for each timeframe.
308
+ # Returns empty array if option data is not available or IV was not requested.
140
309
  def implied_volatility_data(option_type = nil)
141
310
  option_type ||= drv_option_type
142
311
  option_data = data_for_type(option_type)
@@ -146,9 +315,12 @@ module DhanHQ
146
315
  end
147
316
 
148
317
  ##
149
- # Get strike price data for the specified option type
150
- # @param option_type [String] "CALL" or "PUT"
151
- # @return [Array<Float>] Strike price data array
318
+ # Gets strike price data for the specified option type.
319
+ #
320
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
321
+ # If nil, uses the {#drv_option_type} from the request.
322
+ # @return [Array<Float>] Array of strike prices for each timeframe.
323
+ # Returns empty array if option data is not available or strike was not requested.
152
324
  def strike_data(option_type = nil)
153
325
  option_type ||= drv_option_type
154
326
  option_data = data_for_type(option_type)
@@ -158,9 +330,12 @@ module DhanHQ
158
330
  end
159
331
 
160
332
  ##
161
- # Get spot price data for the specified option type
162
- # @param option_type [String] "CALL" or "PUT"
163
- # @return [Array<Float>] Spot price data array
333
+ # Gets spot price data for the specified option type.
334
+ #
335
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
336
+ # If nil, uses the {#drv_option_type} from the request.
337
+ # @return [Array<Float>] Array of spot prices for each timeframe.
338
+ # Returns empty array if option data is not available or spot was not requested.
164
339
  def spot_data(option_type = nil)
165
340
  option_type ||= drv_option_type
166
341
  option_data = data_for_type(option_type)
@@ -170,9 +345,12 @@ module DhanHQ
170
345
  end
171
346
 
172
347
  ##
173
- # Get timestamp data for the specified option type
174
- # @param option_type [String] "CALL" or "PUT"
175
- # @return [Array<Integer>] Timestamp data array (epoch)
348
+ # Gets timestamp data for the specified option type.
349
+ #
350
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
351
+ # If nil, uses the {#drv_option_type} from the request.
352
+ # @return [Array<Integer>] Array of epoch timestamps (Unix time in seconds) for each timeframe.
353
+ # Returns empty array if option data is not available.
176
354
  def timestamp_data(option_type = nil)
177
355
  option_type ||= drv_option_type
178
356
  option_data = data_for_type(option_type)
@@ -182,18 +360,22 @@ module DhanHQ
182
360
  end
183
361
 
184
362
  ##
185
- # Get data points count for the specified option type
186
- # @param option_type [String] "CALL" or "PUT"
187
- # @return [Integer] Number of data points
363
+ # Gets the number of data points available for the specified option type.
364
+ #
365
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
366
+ # If nil, uses the {#drv_option_type} from the request.
367
+ # @return [Integer] Number of data points (timeframes) available. Returns 0 if no data.
188
368
  def data_points_count(option_type = nil)
189
369
  timestamps = timestamp_data(option_type)
190
370
  timestamps.size
191
371
  end
192
372
 
193
373
  ##
194
- # Get average volume for the specified option type
195
- # @param option_type [String] "CALL" or "PUT"
196
- # @return [Float] Average volume
374
+ # Calculates the average volume for the specified option type.
375
+ #
376
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
377
+ # If nil, uses the {#drv_option_type} from the request.
378
+ # @return [Float] Average volume across all timeframes. Returns 0.0 if no volume data is available.
197
379
  def average_volume(option_type = nil)
198
380
  volumes = volume_data(option_type)
199
381
  return 0.0 if volumes.empty?
@@ -202,9 +384,11 @@ module DhanHQ
202
384
  end
203
385
 
204
386
  ##
205
- # Get average open interest for the specified option type
206
- # @param option_type [String] "CALL" or "PUT"
207
- # @return [Float] Average open interest
387
+ # Calculates the average open interest for the specified option type.
388
+ #
389
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
390
+ # If nil, uses the {#drv_option_type} from the request.
391
+ # @return [Float] Average open interest across all timeframes. Returns 0.0 if no OI data is available.
208
392
  def average_open_interest(option_type = nil)
209
393
  oi_data = open_interest_data(option_type)
210
394
  return 0.0 if oi_data.empty?
@@ -213,9 +397,11 @@ module DhanHQ
213
397
  end
214
398
 
215
399
  ##
216
- # Get average implied volatility for the specified option type
217
- # @param option_type [String] "CALL" or "PUT"
218
- # @return [Float] Average implied volatility
400
+ # Calculates the average implied volatility for the specified option type.
401
+ #
402
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
403
+ # If nil, uses the {#drv_option_type} from the request.
404
+ # @return [Float] Average implied volatility across all timeframes. Returns 0.0 if no IV data is available.
219
405
  def average_implied_volatility(option_type = nil)
220
406
  iv_data = implied_volatility_data(option_type)
221
407
  return 0.0 if iv_data.empty?
@@ -224,9 +410,12 @@ module DhanHQ
224
410
  end
225
411
 
226
412
  ##
227
- # Get price range (high - low) for the specified option type
228
- # @param option_type [String] "CALL" or "PUT"
229
- # @return [Array<Float>] Price range for each data point
413
+ # Calculates price range (high - low) for each timeframe of the specified option type.
414
+ #
415
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
416
+ # If nil, uses the {#drv_option_type} from the request.
417
+ # @return [Array<Float>] Array of price ranges (high - low) for each data point.
418
+ # Returns empty array if OHLC data is not available.
230
419
  def price_ranges(option_type = nil)
231
420
  ohlc = ohlc_data(option_type)
232
421
  highs = ohlc[:high]
@@ -238,10 +427,20 @@ module DhanHQ
238
427
  end
239
428
 
240
429
  ##
241
- # Get summary statistics for the specified option type
242
- # @param option_type [String] "CALL" or "PUT"
243
- # @return [Hash] Summary statistics
244
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
430
+ # Gets comprehensive summary statistics for the specified option type.
431
+ #
432
+ # @param option_type [String, nil] Option type to retrieve ("CALL" or "PUT").
433
+ # If nil, uses the {#drv_option_type} from the request.
434
+ # @return [Hash{Symbol => Integer, Float, Array, Boolean}] Summary statistics hash containing:
435
+ # - **:data_points** [Integer] Total number of data points
436
+ # - **:avg_volume** [Float] Average volume
437
+ # - **:avg_open_interest** [Float] Average open interest
438
+ # - **:avg_implied_volatility** [Float] Average implied volatility
439
+ # - **:price_ranges** [Array<Float>] Price ranges (high - low) for each point
440
+ # - **:has_ohlc** [Boolean] Whether OHLC data is available
441
+ # - **:has_volume** [Boolean] Whether volume data is available
442
+ # - **:has_open_interest** [Boolean] Whether open interest data is available
443
+ # - **:has_implied_volatility** [Boolean] Whether implied volatility data is available
245
444
  def summary_stats(option_type = nil)
246
445
  option_type ||= drv_option_type
247
446
  ohlc = ohlc_data(option_type)
@@ -261,60 +460,81 @@ module DhanHQ
261
460
  has_implied_volatility: !iv_data.empty?
262
461
  }
263
462
  end
264
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
265
463
 
266
464
  ##
267
- # Check if this is index options data
268
- # @return [Boolean] true if instrument is OPTIDX
465
+ # Checks if this is index options data.
466
+ #
467
+ # @return [Boolean] true if instrument type is "OPTIDX", false otherwise
269
468
  def index_options?
270
469
  instrument == "OPTIDX"
271
470
  end
272
471
 
273
472
  ##
274
- # Check if this is stock options data
275
- # @return [Boolean] true if instrument is OPTSTK
473
+ # Checks if this is stock options data.
474
+ #
475
+ # @return [Boolean] true if instrument type is "OPTSTK", false otherwise
276
476
  def stock_options?
277
477
  instrument == "OPTSTK"
278
478
  end
279
479
 
280
480
  ##
281
- # Check if this is weekly expiry
282
- # @return [Boolean] true if expiry_flag is WEEK
481
+ # Checks if this is weekly expiry data.
482
+ #
483
+ # @return [Boolean] true if expiry_flag is "WEEK", false otherwise
283
484
  def weekly_expiry?
284
485
  expiry_flag == "WEEK"
285
486
  end
286
487
 
287
488
  ##
288
- # Check if this is monthly expiry
289
- # @return [Boolean] true if expiry_flag is MONTH
489
+ # Checks if this is monthly expiry data.
490
+ #
491
+ # @return [Boolean] true if expiry_flag is "MONTH", false otherwise
290
492
  def monthly_expiry?
291
493
  expiry_flag == "MONTH"
292
494
  end
293
495
 
294
496
  ##
295
- # Check if this is call option data
296
- # @return [Boolean] true if drv_option_type is CALL
497
+ # Checks if this is call option data.
498
+ #
499
+ # @return [Boolean] true if drv_option_type is "CALL", false otherwise
297
500
  def call_option?
298
501
  drv_option_type == "CALL"
299
502
  end
300
503
 
301
504
  ##
302
- # Check if this is put option data
303
- # @return [Boolean] true if drv_option_type is PUT
505
+ # Checks if this is put option data.
506
+ #
507
+ # @return [Boolean] true if drv_option_type is "PUT", false otherwise
304
508
  def put_option?
305
509
  drv_option_type == "PUT"
306
510
  end
307
511
 
308
512
  ##
309
- # Check if strike is at the money
310
- # @return [Boolean] true if strike is ATM
513
+ # Checks if the strike is at the money (ATM).
514
+ #
515
+ # @return [Boolean] true if strike is "ATM", false otherwise
311
516
  def at_the_money?
312
517
  strike == "ATM"
313
518
  end
314
519
 
315
520
  ##
316
- # Get strike offset from ATM
317
- # @return [Integer] Strike offset (0 for ATM, positive for ATM+X, negative for ATM-X)
521
+ # Calculates the strike offset from ATM (At The Money).
522
+ #
523
+ # @return [Integer] Strike offset value:
524
+ # - 0 for ATM strikes
525
+ # - Positive integer for ATM+X (e.g., ATM+3 returns 3)
526
+ # - Negative integer for ATM-X (e.g., ATM-2 returns -2)
527
+ # - 0 if strike format is invalid
528
+ #
529
+ # @example
530
+ # data.strike = "ATM+5"
531
+ # data.strike_offset # => 5
532
+ #
533
+ # data.strike = "ATM-3"
534
+ # data.strike_offset # => -3
535
+ #
536
+ # data.strike = "ATM"
537
+ # data.strike_offset # => 0
318
538
  def strike_offset
319
539
  return 0 if at_the_money?
320
540
 
@@ -326,6 +546,5 @@ module DhanHQ
326
546
  sign * offset
327
547
  end
328
548
  end
329
- # rubocop:enable Metrics/ClassLength
330
549
  end
331
550
  end