DhanHQ 2.1.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 (113) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +26 -0
  4. data/CHANGELOG.md +20 -0
  5. data/CODE_OF_CONDUCT.md +132 -0
  6. data/GUIDE.md +555 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +463 -0
  9. data/README1.md +521 -0
  10. data/Rakefile +12 -0
  11. data/TAGS +10 -0
  12. data/TODO-1.md +14 -0
  13. data/TODO.md +127 -0
  14. data/app/services/live/order_update_guard_support.rb +75 -0
  15. data/app/services/live/order_update_hub.rb +76 -0
  16. data/app/services/live/order_update_persistence_support.rb +68 -0
  17. data/config/initializers/order_update_hub.rb +16 -0
  18. data/diagram.html +184 -0
  19. data/diagram.md +34 -0
  20. data/docs/rails_integration.md +304 -0
  21. data/exe/DhanHQ +4 -0
  22. data/lib/DhanHQ/client.rb +116 -0
  23. data/lib/DhanHQ/config.rb +32 -0
  24. data/lib/DhanHQ/configuration.rb +72 -0
  25. data/lib/DhanHQ/constants.rb +170 -0
  26. data/lib/DhanHQ/contracts/base_contract.rb +15 -0
  27. data/lib/DhanHQ/contracts/historical_data_contract.rb +28 -0
  28. data/lib/DhanHQ/contracts/margin_calculator_contract.rb +19 -0
  29. data/lib/DhanHQ/contracts/modify_order_contract copy.rb +100 -0
  30. data/lib/DhanHQ/contracts/modify_order_contract.rb +22 -0
  31. data/lib/DhanHQ/contracts/option_chain_contract.rb +31 -0
  32. data/lib/DhanHQ/contracts/order_contract.rb +102 -0
  33. data/lib/DhanHQ/contracts/place_order_contract.rb +119 -0
  34. data/lib/DhanHQ/contracts/position_conversion_contract.rb +24 -0
  35. data/lib/DhanHQ/contracts/slice_order_contract.rb +111 -0
  36. data/lib/DhanHQ/core/base_api.rb +105 -0
  37. data/lib/DhanHQ/core/base_model.rb +266 -0
  38. data/lib/DhanHQ/core/base_resource.rb +50 -0
  39. data/lib/DhanHQ/core/error_handler.rb +19 -0
  40. data/lib/DhanHQ/error_object.rb +49 -0
  41. data/lib/DhanHQ/errors.rb +45 -0
  42. data/lib/DhanHQ/helpers/api_helper.rb +17 -0
  43. data/lib/DhanHQ/helpers/attribute_helper.rb +72 -0
  44. data/lib/DhanHQ/helpers/model_helper.rb +7 -0
  45. data/lib/DhanHQ/helpers/request_helper.rb +69 -0
  46. data/lib/DhanHQ/helpers/response_helper.rb +98 -0
  47. data/lib/DhanHQ/helpers/validation_helper.rb +36 -0
  48. data/lib/DhanHQ/json_loader.rb +23 -0
  49. data/lib/DhanHQ/models/edis.rb +58 -0
  50. data/lib/DhanHQ/models/forever_order.rb +85 -0
  51. data/lib/DhanHQ/models/funds.rb +50 -0
  52. data/lib/DhanHQ/models/historical_data.rb +77 -0
  53. data/lib/DhanHQ/models/holding.rb +56 -0
  54. data/lib/DhanHQ/models/kill_switch.rb +49 -0
  55. data/lib/DhanHQ/models/ledger_entry.rb +60 -0
  56. data/lib/DhanHQ/models/margin.rb +54 -0
  57. data/lib/DhanHQ/models/market_feed.rb +41 -0
  58. data/lib/DhanHQ/models/option_chain.rb +79 -0
  59. data/lib/DhanHQ/models/order.rb +239 -0
  60. data/lib/DhanHQ/models/position.rb +60 -0
  61. data/lib/DhanHQ/models/profile.rb +44 -0
  62. data/lib/DhanHQ/models/super_order.rb +69 -0
  63. data/lib/DhanHQ/models/trade.rb +79 -0
  64. data/lib/DhanHQ/rate_limiter.rb +107 -0
  65. data/lib/DhanHQ/requests/optionchain/nifty.json +5 -0
  66. data/lib/DhanHQ/requests/optionchain/nifty_expiries.json +4 -0
  67. data/lib/DhanHQ/requests/orders/create.json +0 -0
  68. data/lib/DhanHQ/resources/edis.rb +44 -0
  69. data/lib/DhanHQ/resources/forever_orders.rb +53 -0
  70. data/lib/DhanHQ/resources/funds.rb +21 -0
  71. data/lib/DhanHQ/resources/historical_data.rb +34 -0
  72. data/lib/DhanHQ/resources/holdings.rb +21 -0
  73. data/lib/DhanHQ/resources/kill_switch.rb +21 -0
  74. data/lib/DhanHQ/resources/margin_calculator.rb +22 -0
  75. data/lib/DhanHQ/resources/market_feed.rb +56 -0
  76. data/lib/DhanHQ/resources/option_chain.rb +31 -0
  77. data/lib/DhanHQ/resources/orders.rb +70 -0
  78. data/lib/DhanHQ/resources/positions.rb +29 -0
  79. data/lib/DhanHQ/resources/profile.rb +25 -0
  80. data/lib/DhanHQ/resources/statements.rb +42 -0
  81. data/lib/DhanHQ/resources/super_orders.rb +46 -0
  82. data/lib/DhanHQ/resources/trades.rb +23 -0
  83. data/lib/DhanHQ/version.rb +6 -0
  84. data/lib/DhanHQ/ws/client.rb +182 -0
  85. data/lib/DhanHQ/ws/cmd_bus.rb +38 -0
  86. data/lib/DhanHQ/ws/connection.rb +240 -0
  87. data/lib/DhanHQ/ws/decoder.rb +83 -0
  88. data/lib/DhanHQ/ws/errors.rb +0 -0
  89. data/lib/DhanHQ/ws/orders/client.rb +59 -0
  90. data/lib/DhanHQ/ws/orders/connection.rb +148 -0
  91. data/lib/DhanHQ/ws/orders.rb +13 -0
  92. data/lib/DhanHQ/ws/packets/depth_delta_packet.rb +20 -0
  93. data/lib/DhanHQ/ws/packets/disconnect_packet.rb +15 -0
  94. data/lib/DhanHQ/ws/packets/full_packet.rb +40 -0
  95. data/lib/DhanHQ/ws/packets/header.rb +23 -0
  96. data/lib/DhanHQ/ws/packets/index_packet.rb +14 -0
  97. data/lib/DhanHQ/ws/packets/market_depth_level.rb +21 -0
  98. data/lib/DhanHQ/ws/packets/market_status_packet.rb +14 -0
  99. data/lib/DhanHQ/ws/packets/oi_packet.rb +15 -0
  100. data/lib/DhanHQ/ws/packets/prev_close_packet.rb +16 -0
  101. data/lib/DhanHQ/ws/packets/quote_packet.rb +26 -0
  102. data/lib/DhanHQ/ws/packets/ticker_packet.rb +16 -0
  103. data/lib/DhanHQ/ws/registry.rb +46 -0
  104. data/lib/DhanHQ/ws/segments.rb +75 -0
  105. data/lib/DhanHQ/ws/singleton_lock.rb +54 -0
  106. data/lib/DhanHQ/ws/sub_state.rb +59 -0
  107. data/lib/DhanHQ/ws/websocket_packet_parser.rb +165 -0
  108. data/lib/DhanHQ/ws.rb +37 -0
  109. data/lib/DhanHQ.rb +135 -0
  110. data/lib/ta/technical_analysis.rb +405 -0
  111. data/sig/DhanHQ.rbs +4 -0
  112. data/watchlist.csv +3 -0
  113. metadata +283 -0
@@ -0,0 +1,405 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "time"
5
+ require "date"
6
+
7
+ begin
8
+ require "ruby-technical-analysis"
9
+ rescue LoadError => e
10
+ warn "ruby-technical-analysis not available: #{e.message}"
11
+ end
12
+
13
+ begin
14
+ require "technical-analysis"
15
+ rescue LoadError => e
16
+ warn "technical-analysis not available: #{e.message}"
17
+ end
18
+
19
+ require "DhanHQ"
20
+
21
+ unless defined?(MarketCalendar)
22
+ module MarketCalendar
23
+ MARKET_HOLIDAYS = [
24
+ Date.new(2025, 8, 15),
25
+ Date.new(2025, 10, 2),
26
+ Date.new(2025, 8, 27)
27
+ ].freeze
28
+
29
+ def self.weekday?(date)
30
+ w = date.wday
31
+ w >= 1 && w <= 5
32
+ end
33
+
34
+ def self.trading_day?(date)
35
+ weekday?(date) && !MARKET_HOLIDAYS.include?(date)
36
+ end
37
+
38
+ def self.last_trading_day(from: Date.today)
39
+ d = from
40
+ d -= 1 until trading_day?(d)
41
+ d
42
+ end
43
+
44
+ def self.today_or_last_trading_day
45
+ trading_day?(Date.today) ? Date.today : last_trading_day(from: Date.today)
46
+ end
47
+
48
+ # Returns the trading day N days back from the given trading day.
49
+ # Example: trading_days_ago(2025-10-07, 0) -> 2025-10-07 (if trading day)
50
+ # trading_days_ago(2025-10-07, 1) -> previous trading day
51
+ def self.trading_days_ago(date, n)
52
+ raise ArgumentError, "n must be >= 0" if n.to_i.negative?
53
+
54
+ d = trading_day?(date) ? date : today_or_last_trading_day
55
+ count = 0
56
+ while count < n
57
+ d = last_trading_day(from: d)
58
+ count += 1
59
+ end
60
+ d
61
+ end
62
+ end
63
+ end
64
+
65
+ module TA
66
+ class TechnicalAnalysis
67
+ DEFAULTS = {
68
+ rsi_period: 14,
69
+ atr_period: 14,
70
+ adx_period: 14,
71
+ macd_fast: 12,
72
+ macd_slow: 26,
73
+ macd_signal: 9
74
+ }.freeze
75
+
76
+ def initialize(options = {})
77
+ @opts = DEFAULTS.merge(options.transform_keys(&:to_sym))
78
+ end
79
+
80
+ def compute(exchange_segment:, instrument:, security_id:, from_date: nil, to_date: nil, days_back: nil,
81
+ intervals: [1, 5, 15, 25, 60])
82
+ if to_date.nil? || to_date.to_s.strip.empty?
83
+ to_date = MarketCalendar.today_or_last_trading_day.strftime("%Y-%m-%d")
84
+ end
85
+ if (from_date.nil? || from_date.to_s.strip.empty?) && days_back && days_back.to_i > 0
86
+ to_d = Date.parse(to_date)
87
+ n_back = [days_back.to_i - 1, 0].max
88
+ from_date = MarketCalendar.trading_days_ago(to_d, n_back).strftime("%Y-%m-%d")
89
+ end
90
+ from_date ||= to_date
91
+ base_params = {
92
+ exchange_segment: exchange_segment,
93
+ instrument: instrument,
94
+ security_id: security_id,
95
+ from_date: from_date,
96
+ to_date: to_date
97
+ }
98
+
99
+ one_min_candles = candles(fetch_intraday_windowed(base_params, 1))
100
+
101
+ frames = {}
102
+ intervals.each do |ivl|
103
+ case ivl.to_i
104
+ when 1 then frames[:m1] = one_min_candles
105
+ when 5 then frames[:m5] = resample(one_min_candles, 5)
106
+ when 15 then frames[:m15] = resample(one_min_candles, 15)
107
+ when 25 then frames[:m25] = resample(one_min_candles, 25)
108
+ when 60 then frames[:m60] = resample(one_min_candles, 60)
109
+ end
110
+ end
111
+
112
+ {
113
+ meta: {
114
+ exchange_segment: exchange_segment,
115
+ instrument: instrument,
116
+ security_id: security_id,
117
+ from_date: from_date,
118
+ to_date: to_date
119
+ },
120
+ indicators: frames.transform_values { |candles| compute_for(candles) }
121
+ }
122
+ end
123
+
124
+ def compute_from_file(path:, base_interval: 1, intervals: [1, 5, 15, 25, 60])
125
+ raw = JSON.parse(File.read(path))
126
+ base = candles(raw)
127
+ frames = {}
128
+ intervals.each do |ivl|
129
+ case ivl.to_i
130
+ when 1 then frames[:m1] = (base_interval == 1 ? base : resample(base, 1))
131
+ when 5 then frames[:m5] = resample(base, 5)
132
+ when 15 then frames[:m15] = resample(base, 15)
133
+ when 25 then frames[:m25] = resample(base, 25)
134
+ when 60 then frames[:m60] = resample(base, 60)
135
+ end
136
+ end
137
+ { indicators: frames.transform_values { |candles| compute_for(candles) } }
138
+ end
139
+
140
+ private
141
+
142
+ def fetch_intraday(params, interval)
143
+ DhanHQ::Models::HistoricalData.intraday(
144
+ security_id: params[:security_id],
145
+ exchange_segment: params[:exchange_segment],
146
+ instrument: params[:instrument],
147
+ interval: interval.to_s,
148
+ from_date: params[:from_date],
149
+ to_date: params[:to_date]
150
+ )
151
+ end
152
+
153
+ def fetch_intraday_windowed(params, interval)
154
+ from_d = Date.parse(params[:from_date])
155
+ to_d = Date.parse(params[:to_date])
156
+ max_span = 90
157
+ return fetch_intraday(params, interval) if (to_d - from_d).to_i <= max_span
158
+
159
+ merged = { "open" => [], "high" => [], "low" => [], "close" => [], "volume" => [], "timestamp" => [] }
160
+ cursor = from_d
161
+ while cursor <= to_d
162
+ chunk_to = [cursor + max_span, to_d].min
163
+ chunk_params = params.merge(from_date: cursor.strftime("%Y-%m-%d"), to_date: chunk_to.strftime("%Y-%m-%d"))
164
+ part = fetch_intraday(chunk_params, interval)
165
+ %w[open high low close volume timestamp].each do |k|
166
+ ary = (part[k] || part[k.to_sym]) || []
167
+ merged[k].concat(Array(ary))
168
+ end
169
+ cursor = chunk_to + 1
170
+ end
171
+ merged
172
+ end
173
+
174
+ def parse_time_like(val)
175
+ return Time.at(val) if val.is_a?(Numeric)
176
+
177
+ s = val.to_s
178
+ return Time.at(s.to_i) if /\A\d+\z/.match?(s) && s.length >= 10 && s.length <= 13
179
+
180
+ Time.parse(s)
181
+ end
182
+
183
+ def candles(series)
184
+ ts = series["timestamp"] || series[:timestamp]
185
+ open = series["open"] || series[:open]
186
+ high = series["high"] || series[:high]
187
+ low = series["low"] || series[:low]
188
+ close = series["close"] || series[:close]
189
+ vol = series["volume"] || series[:volume]
190
+ return [] unless ts && open && high && low && close && vol
191
+ return [] if close.empty?
192
+
193
+ (0...close.size).map do |i|
194
+ { t: parse_time_like(ts[i]), o: open[i].to_f, h: high[i].to_f, l: low[i].to_f, c: close[i].to_f,
195
+ v: vol[i].to_f }
196
+ end
197
+ rescue StandardError
198
+ []
199
+ end
200
+
201
+ def resample(candles, minutes)
202
+ return candles if minutes == 1
203
+
204
+ grouped = {}
205
+ candles.each do |c|
206
+ key = Time.at((c[:t].to_i / 60) / minutes * minutes * 60)
207
+ b = (grouped[key] ||= { t: key, o: c[:o], h: c[:h], l: c[:l], c: c[:c], v: 0.0 })
208
+ b[:h] = [b[:h], c[:h]].max
209
+ b[:l] = [b[:l], c[:l]].min
210
+ b[:c] = c[:c]
211
+ b[:v] += c[:v]
212
+ end
213
+ grouped.keys.sort.map { |k| grouped[k] }
214
+ end
215
+
216
+ def closes(candles) = candles.map { |c| c[:c] }
217
+ def highs(candles) = candles.map { |c| c[:h] }
218
+ def lows(candles) = candles.map { |c| c[:l] }
219
+
220
+ def compute_for(candles)
221
+ c = closes(candles)
222
+ h = highs(candles)
223
+ l = lows(candles)
224
+ return { rsi: nil, macd: { macd: nil, signal: nil, hist: nil }, adx: nil, atr: nil } if c.empty?
225
+
226
+ {
227
+ rsi: safe_last(rsi(c, @opts[:rsi_period])),
228
+ macd: macd(c, @opts[:macd_fast], @opts[:macd_slow], @opts[:macd_signal]),
229
+ adx: safe_last(adx(h, l, c, @opts[:adx_period])),
230
+ atr: safe_last(atr(h, l, c, @opts[:atr_period]))
231
+ }
232
+ end
233
+
234
+ def safe_last(arr)
235
+ return nil unless arr.respond_to?(:last)
236
+
237
+ arr.last
238
+ rescue StandardError
239
+ nil
240
+ end
241
+
242
+ # ---- Indicator adapters (mirror bin script) ----
243
+ def rsi(series, period)
244
+ if defined?(RubyTechnicalAnalysis) && RubyTechnicalAnalysis.const_defined?(:RSI)
245
+ return RubyTechnicalAnalysis::RSI.new(series: series, period: period).call
246
+ end
247
+ if defined?(TechnicalAnalysis) && TechnicalAnalysis.respond_to?(:rsi)
248
+ return TechnicalAnalysis.rsi(series, period: period)
249
+ end
250
+
251
+ simple_rsi(series, period)
252
+ end
253
+
254
+ def macd(series, fast, slow, signal)
255
+ if defined?(RubyTechnicalAnalysis) && RubyTechnicalAnalysis.const_defined?(:MACD)
256
+ out = RubyTechnicalAnalysis::MACD.new(series: series, fast_period: fast, slow_period: slow,
257
+ signal_period: signal).call
258
+ if out.is_a?(Hash)
259
+ m = out[:macd]
260
+ s = out[:signal]
261
+ h = out[:histogram] || out[:hist]
262
+ m = m.last if m.is_a?(Array)
263
+ s = s.last if s.is_a?(Array)
264
+ h = h.last if h.is_a?(Array)
265
+ return { macd: m, signal: s, hist: h }
266
+ end
267
+ end
268
+ if defined?(TechnicalAnalysis) && TechnicalAnalysis.respond_to?(:macd)
269
+ out = TechnicalAnalysis.macd(series, fast: fast, slow: slow, signal: signal)
270
+ if out.is_a?(Hash)
271
+ m = out[:macd]
272
+ s = out[:signal]
273
+ h = out[:hist]
274
+ m = m.last if m.is_a?(Array)
275
+ s = s.last if s.is_a?(Array)
276
+ h = h.last if h.is_a?(Array)
277
+ return { macd: m, signal: s, hist: h }
278
+ end
279
+ end
280
+ simple_macd(series, fast, slow, signal)
281
+ end
282
+
283
+ def adx(high, low, close, period)
284
+ if defined?(RubyTechnicalAnalysis) && RubyTechnicalAnalysis.const_defined?(:ADX)
285
+ return RubyTechnicalAnalysis::ADX.new(high: high, low: low, close: close, period: period).call
286
+ end
287
+ if defined?(TechnicalAnalysis) && TechnicalAnalysis.respond_to?(:adx)
288
+ return TechnicalAnalysis.adx(high: high, low: low, close: close, period: period)
289
+ end
290
+
291
+ simple_adx(high, low, close, period)
292
+ end
293
+
294
+ def atr(high, low, close, period)
295
+ if defined?(RubyTechnicalAnalysis) && RubyTechnicalAnalysis.const_defined?(:ATR)
296
+ return RubyTechnicalAnalysis::ATR.new(high: high, low: low, close: close, period: period).call
297
+ end
298
+ if defined?(TechnicalAnalysis) && TechnicalAnalysis.respond_to?(:atr)
299
+ return TechnicalAnalysis.atr(high: high, low: low, close: close, period: period)
300
+ end
301
+
302
+ simple_atr(high, low, close, period)
303
+ end
304
+
305
+ # ---- Simple fallbacks ----
306
+ def ema(series, period)
307
+ return nil if series.nil? || series.empty?
308
+
309
+ k = 2.0 / (period + 1)
310
+ series.each_with_index.reduce(nil) do |ema_prev, (v, i)|
311
+ i == 0 ? v.to_f : (v.to_f * k) + ((ema_prev || v.to_f) * (1 - k))
312
+ end
313
+ end
314
+
315
+ def simple_rsi(series, period)
316
+ gains = []
317
+ losses = []
318
+ series.each_cons(2) do |a, b|
319
+ ch = b - a
320
+ gains << [ch, 0].max
321
+ losses << [(-ch), 0].max
322
+ end
323
+ avg_gain = gains.first(period).sum / period.to_f
324
+ avg_loss = losses.first(period).sum / period.to_f
325
+ rsi_vals = Array.new(series.size, nil)
326
+ gains.drop(period).each_with_index do |g, idx|
327
+ l = losses[period + idx]
328
+ avg_gain = ((avg_gain * (period - 1)) + g) / period
329
+ avg_loss = ((avg_loss * (period - 1)) + l) / period
330
+ rs = avg_loss.zero? ? 100.0 : (avg_gain / avg_loss)
331
+ rsi_vals[period + 1 + idx] = 100.0 - (100.0 / (1 + rs))
332
+ end
333
+ rsi_vals
334
+ end
335
+
336
+ def simple_macd(series, fast, slow, signal)
337
+ e_fast = ema(series, fast)
338
+ e_slow = ema(series, slow)
339
+ e_sig = ema(series, signal)
340
+ return { macd: nil, signal: nil, hist: nil } if [e_fast, e_slow, e_sig].any?(&:nil?)
341
+
342
+ macd_line = e_fast - e_slow
343
+ signal_line = e_sig
344
+ { macd: macd_line, signal: signal_line, hist: macd_line - signal_line }
345
+ end
346
+
347
+ def true_ranges(high, low, close)
348
+ trs = []
349
+ close.each_with_index do |_c, i|
350
+ if i.zero?
351
+ trs << (high[i] - low[i]).abs
352
+ else
353
+ tr = [(high[i] - low[i]).abs, (high[i] - close[i - 1]).abs, (low[i] - close[i - 1]).abs].max
354
+ trs << tr
355
+ end
356
+ end
357
+ trs
358
+ end
359
+
360
+ def simple_atr(high, low, close, period)
361
+ trs = true_ranges(high, low, close)
362
+ out = []
363
+ atr_prev = trs.first(period).sum / period.to_f
364
+ trs.each_with_index do |tr, i|
365
+ if i < period
366
+ out << nil
367
+ elsif i == period
368
+ out << atr_prev
369
+ else
370
+ atr_prev = ((atr_prev * (period - 1)) + tr) / period.to_f
371
+ out << atr_prev
372
+ end
373
+ end
374
+ out
375
+ end
376
+
377
+ def simple_adx(high, low, close, period)
378
+ plus_dm = [0]
379
+ minus_dm = [0]
380
+ (1...high.size).each do |i|
381
+ up_move = high[i] - high[i - 1]
382
+ down_move = low[i - 1] - low[i]
383
+ plus_dm << (up_move > down_move && up_move.positive? ? up_move : 0)
384
+ minus_dm << (down_move > up_move && down_move.positive? ? down_move : 0)
385
+ end
386
+ trs = true_ranges(high, low, close)
387
+ smooth_tr = trs.first(period).sum
388
+ smooth_plus_dm = plus_dm.first(period).sum
389
+ smooth_minus_dm = minus_dm.first(period).sum
390
+ adx_vals = Array.new(high.size, nil)
391
+ di_vals = []
392
+ (period...high.size).each do |i|
393
+ smooth_tr = smooth_tr - (smooth_tr / period) + trs[i]
394
+ smooth_plus_dm = smooth_plus_dm - (smooth_plus_dm / period) + plus_dm[i]
395
+ smooth_minus_dm = smooth_minus_dm - (smooth_minus_dm / period) + minus_dm[i]
396
+ plus_di = 100.0 * (smooth_plus_dm / smooth_tr)
397
+ minus_di = 100.0 * (smooth_minus_dm / smooth_tr)
398
+ dx = 100.0 * ((plus_di - minus_di).abs / (plus_di + minus_di))
399
+ di_vals << dx
400
+ adx_vals[i] = di_vals.last(period).sum / period.to_f if di_vals.size >= period
401
+ end
402
+ adx_vals
403
+ end
404
+ end
405
+ end
data/sig/DhanHQ.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module DhanHQ
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
data/watchlist.csv ADDED
@@ -0,0 +1,3 @@
1
+ segment,security_id
2
+ IDX_I,13
3
+ IDX_I,25
metadata ADDED
@@ -0,0 +1,283 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: DhanHQ
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shubham Taywade
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activesupport
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: base64
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: bindata
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: concurrent-ruby
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: dry-validation
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: eventmachine
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: faraday
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: faraday_middleware
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ - !ruby/object:Gem::Dependency
125
+ name: faye-websocket
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ type: :runtime
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ description: DhanHQ is a simple CLI for DhanHQ API.
139
+ email:
140
+ - shubhamtaywade82@gmail.com
141
+ executables:
142
+ - DhanHQ
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".rspec"
147
+ - ".rubocop.yml"
148
+ - CHANGELOG.md
149
+ - CODE_OF_CONDUCT.md
150
+ - GUIDE.md
151
+ - LICENSE.txt
152
+ - README.md
153
+ - README1.md
154
+ - Rakefile
155
+ - TAGS
156
+ - TODO-1.md
157
+ - TODO.md
158
+ - app/services/live/order_update_guard_support.rb
159
+ - app/services/live/order_update_hub.rb
160
+ - app/services/live/order_update_persistence_support.rb
161
+ - config/initializers/order_update_hub.rb
162
+ - diagram.html
163
+ - diagram.md
164
+ - docs/rails_integration.md
165
+ - exe/DhanHQ
166
+ - lib/DhanHQ.rb
167
+ - lib/DhanHQ/client.rb
168
+ - lib/DhanHQ/config.rb
169
+ - lib/DhanHQ/configuration.rb
170
+ - lib/DhanHQ/constants.rb
171
+ - lib/DhanHQ/contracts/base_contract.rb
172
+ - lib/DhanHQ/contracts/historical_data_contract.rb
173
+ - lib/DhanHQ/contracts/margin_calculator_contract.rb
174
+ - lib/DhanHQ/contracts/modify_order_contract copy.rb
175
+ - lib/DhanHQ/contracts/modify_order_contract.rb
176
+ - lib/DhanHQ/contracts/option_chain_contract.rb
177
+ - lib/DhanHQ/contracts/order_contract.rb
178
+ - lib/DhanHQ/contracts/place_order_contract.rb
179
+ - lib/DhanHQ/contracts/position_conversion_contract.rb
180
+ - lib/DhanHQ/contracts/slice_order_contract.rb
181
+ - lib/DhanHQ/core/base_api.rb
182
+ - lib/DhanHQ/core/base_model.rb
183
+ - lib/DhanHQ/core/base_resource.rb
184
+ - lib/DhanHQ/core/error_handler.rb
185
+ - lib/DhanHQ/error_object.rb
186
+ - lib/DhanHQ/errors.rb
187
+ - lib/DhanHQ/helpers/api_helper.rb
188
+ - lib/DhanHQ/helpers/attribute_helper.rb
189
+ - lib/DhanHQ/helpers/model_helper.rb
190
+ - lib/DhanHQ/helpers/request_helper.rb
191
+ - lib/DhanHQ/helpers/response_helper.rb
192
+ - lib/DhanHQ/helpers/validation_helper.rb
193
+ - lib/DhanHQ/json_loader.rb
194
+ - lib/DhanHQ/models/edis.rb
195
+ - lib/DhanHQ/models/forever_order.rb
196
+ - lib/DhanHQ/models/funds.rb
197
+ - lib/DhanHQ/models/historical_data.rb
198
+ - lib/DhanHQ/models/holding.rb
199
+ - lib/DhanHQ/models/kill_switch.rb
200
+ - lib/DhanHQ/models/ledger_entry.rb
201
+ - lib/DhanHQ/models/margin.rb
202
+ - lib/DhanHQ/models/market_feed.rb
203
+ - lib/DhanHQ/models/option_chain.rb
204
+ - lib/DhanHQ/models/order.rb
205
+ - lib/DhanHQ/models/position.rb
206
+ - lib/DhanHQ/models/profile.rb
207
+ - lib/DhanHQ/models/super_order.rb
208
+ - lib/DhanHQ/models/trade.rb
209
+ - lib/DhanHQ/rate_limiter.rb
210
+ - lib/DhanHQ/requests/optionchain/nifty.json
211
+ - lib/DhanHQ/requests/optionchain/nifty_expiries.json
212
+ - lib/DhanHQ/requests/orders/create.json
213
+ - lib/DhanHQ/resources/edis.rb
214
+ - lib/DhanHQ/resources/forever_orders.rb
215
+ - lib/DhanHQ/resources/funds.rb
216
+ - lib/DhanHQ/resources/historical_data.rb
217
+ - lib/DhanHQ/resources/holdings.rb
218
+ - lib/DhanHQ/resources/kill_switch.rb
219
+ - lib/DhanHQ/resources/margin_calculator.rb
220
+ - lib/DhanHQ/resources/market_feed.rb
221
+ - lib/DhanHQ/resources/option_chain.rb
222
+ - lib/DhanHQ/resources/orders.rb
223
+ - lib/DhanHQ/resources/positions.rb
224
+ - lib/DhanHQ/resources/profile.rb
225
+ - lib/DhanHQ/resources/statements.rb
226
+ - lib/DhanHQ/resources/super_orders.rb
227
+ - lib/DhanHQ/resources/trades.rb
228
+ - lib/DhanHQ/version.rb
229
+ - lib/DhanHQ/ws.rb
230
+ - lib/DhanHQ/ws/client.rb
231
+ - lib/DhanHQ/ws/cmd_bus.rb
232
+ - lib/DhanHQ/ws/connection.rb
233
+ - lib/DhanHQ/ws/decoder.rb
234
+ - lib/DhanHQ/ws/errors.rb
235
+ - lib/DhanHQ/ws/orders.rb
236
+ - lib/DhanHQ/ws/orders/client.rb
237
+ - lib/DhanHQ/ws/orders/connection.rb
238
+ - lib/DhanHQ/ws/packets/depth_delta_packet.rb
239
+ - lib/DhanHQ/ws/packets/disconnect_packet.rb
240
+ - lib/DhanHQ/ws/packets/full_packet.rb
241
+ - lib/DhanHQ/ws/packets/header.rb
242
+ - lib/DhanHQ/ws/packets/index_packet.rb
243
+ - lib/DhanHQ/ws/packets/market_depth_level.rb
244
+ - lib/DhanHQ/ws/packets/market_status_packet.rb
245
+ - lib/DhanHQ/ws/packets/oi_packet.rb
246
+ - lib/DhanHQ/ws/packets/prev_close_packet.rb
247
+ - lib/DhanHQ/ws/packets/quote_packet.rb
248
+ - lib/DhanHQ/ws/packets/ticker_packet.rb
249
+ - lib/DhanHQ/ws/registry.rb
250
+ - lib/DhanHQ/ws/segments.rb
251
+ - lib/DhanHQ/ws/singleton_lock.rb
252
+ - lib/DhanHQ/ws/sub_state.rb
253
+ - lib/DhanHQ/ws/websocket_packet_parser.rb
254
+ - lib/ta/technical_analysis.rb
255
+ - sig/DhanHQ.rbs
256
+ - watchlist.csv
257
+ homepage: https://github.com/shubhamtaywade82/dhanhq-client
258
+ licenses:
259
+ - MIT
260
+ metadata:
261
+ allowed_push_host: https://rubygems.org
262
+ homepage_uri: https://github.com/shubhamtaywade82/dhanhq-client
263
+ source_code_uri: https://github.com/shubhamtaywade82/dhanhq-client
264
+ changelog_uri: https://github.com/shubhamtaywade82/dhanhq-client/blob/main/CHANGELOG.md
265
+ rubygems_mfa_required: 'true'
266
+ rdoc_options: []
267
+ require_paths:
268
+ - lib
269
+ required_ruby_version: !ruby/object:Gem::Requirement
270
+ requirements:
271
+ - - ">="
272
+ - !ruby/object:Gem::Version
273
+ version: 3.1.0
274
+ required_rubygems_version: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ">="
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ requirements: []
280
+ rubygems_version: 3.6.9
281
+ specification_version: 4
282
+ summary: DhanHQ is a simple CLI for DhanHQ API.
283
+ test_files: []