DhanHQ 3.1.0 → 3.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.
- checksums.yaml +4 -4
- data/ARCHITECTURE.md +47 -1
- data/CHANGELOG.md +47 -0
- data/README.md +241 -3
- data/docs/AUTHENTICATION.md +3 -5
- data/docs/CONFIGURATION.md +3 -2
- data/docs/CONSTANTS_REFERENCE.md +5 -4
- data/docs/ENDPOINTS_AND_SANDBOX.md +1 -0
- data/docs/LIVE_ORDER_UPDATES.md +5 -10
- data/docs/RAILS_INTEGRATION.md +1 -1
- data/docs/RELEASE_GUIDE.md +13 -2
- data/docs/STANDALONE_RUBY_WEBSOCKET_INTEGRATION.md +2 -2
- data/docs/WEBSOCKET_INTEGRATION.md +13 -20
- data/docs/WEBSOCKET_PROTOCOL.md +7 -3
- data/lib/DhanHQ/agent/key_coercion.rb +36 -0
- data/lib/DhanHQ/agent/tool.rb +37 -0
- data/lib/DhanHQ/agent/tool_catalogue.rb +180 -0
- data/lib/DhanHQ/agent/tool_handlers.rb +116 -0
- data/lib/DhanHQ/agent/tool_registry.rb +17 -261
- data/lib/DhanHQ/agent/tool_schemas.rb +160 -0
- data/lib/DhanHQ/client.rb +58 -2
- data/lib/DhanHQ/concerns/order_audit.rb +35 -4
- data/lib/DhanHQ/configuration.rb +70 -1
- data/lib/DhanHQ/constants.rb +101 -0
- data/lib/DhanHQ/contracts/expired_options_data_contract.rb +1 -9
- data/lib/DhanHQ/contracts/global_stocks_estimator_contract.rb +28 -0
- data/lib/DhanHQ/contracts/global_stocks_modify_order_contract.rb +26 -0
- data/lib/DhanHQ/contracts/global_stocks_order_contract.rb +33 -0
- data/lib/DhanHQ/contracts/global_stocks_place_order_contract.rb +75 -0
- data/lib/DhanHQ/contracts/historical_data_contract.rb +1 -21
- data/lib/DhanHQ/contracts/multi_order_contract.rb +74 -0
- data/lib/DhanHQ/contracts/trade_history_contract.rb +1 -8
- data/lib/DhanHQ/dry_run/ledger.rb +71 -0
- data/lib/DhanHQ/dry_run/simulator.rb +140 -0
- data/lib/DhanHQ/helpers/attribute_helper.rb +23 -0
- data/lib/DhanHQ/models/alert_order.rb +5 -2
- data/lib/DhanHQ/models/global_stocks/funds.rb +56 -0
- data/lib/DhanHQ/models/global_stocks/holding.rb +101 -0
- data/lib/DhanHQ/models/global_stocks/margin.rb +54 -0
- data/lib/DhanHQ/models/global_stocks/market_status.rb +63 -0
- data/lib/DhanHQ/models/global_stocks/order.rb +189 -0
- data/lib/DhanHQ/models/global_stocks/order_estimate.rb +61 -0
- data/lib/DhanHQ/models/global_stocks/trade.rb +74 -0
- data/lib/DhanHQ/models/margin.rb +5 -1
- data/lib/DhanHQ/models/multi_order.rb +130 -0
- data/lib/DhanHQ/resources/global_stocks/funds.rb +25 -0
- data/lib/DhanHQ/resources/global_stocks/holdings.rb +22 -0
- data/lib/DhanHQ/resources/global_stocks/margin_calculator.rb +70 -0
- data/lib/DhanHQ/resources/global_stocks/market_status.rb +22 -0
- data/lib/DhanHQ/resources/global_stocks/orders.rb +112 -0
- data/lib/DhanHQ/resources/global_stocks/trades.rb +31 -0
- data/lib/DhanHQ/resources/multi_orders.rb +58 -0
- data/lib/DhanHQ/version.rb +1 -1
- data/lib/DhanHQ/write_paths.rb +57 -0
- data/lib/DhanHQ/ws/client.rb +117 -2
- data/lib/DhanHQ/ws/connection.rb +40 -11
- data/lib/DhanHQ/ws/sub_state.rb +14 -0
- data/lib/dhanhq/analysis/options_buying_advisor.rb +11 -10
- metadata +30 -40
- data/.rspec +0 -3
- data/.rubocop.yml +0 -50
- data/.rubocop_todo.yml +0 -217
- data/AGENTS.md +0 -23
- data/CODE_OF_CONDUCT.md +0 -132
- data/Rakefile +0 -14
- data/TAGS +0 -10
- data/core +0 -0
- data/diagram.html +0 -184
- data/skills/dhanhq-ruby/SKILL.md +0 -207
- data/skills/dhanhq-ruby/examples/fetch_option_chain.rb +0 -54
- data/skills/dhanhq-ruby/examples/gtt_forever_order.rb +0 -65
- data/skills/dhanhq-ruby/examples/historical_data_analysis.rb +0 -89
- data/skills/dhanhq-ruby/examples/iron_condor.rb +0 -137
- data/skills/dhanhq-ruby/examples/live_feed_setup.rb +0 -43
- data/skills/dhanhq-ruby/examples/margin_check.rb +0 -42
- data/skills/dhanhq-ruby/examples/order_management.rb +0 -105
- data/skills/dhanhq-ruby/examples/place_equity_order.rb +0 -36
- data/skills/dhanhq-ruby/examples/place_fno_order.rb +0 -76
- data/skills/dhanhq-ruby/examples/portfolio_summary.rb +0 -74
- data/skills/dhanhq-ruby/examples/super_order_with_sl.rb +0 -57
- data/skills/dhanhq-ruby/references/backtesting-with-dhan.md +0 -65
- data/skills/dhanhq-ruby/references/common-workflows.md +0 -76
- data/skills/dhanhq-ruby/references/error-codes.md +0 -50
- data/skills/dhanhq-ruby/references/funds.md +0 -67
- data/skills/dhanhq-ruby/references/instruments.md +0 -85
- data/skills/dhanhq-ruby/references/live-feed.md +0 -83
- data/skills/dhanhq-ruby/references/market-data.md +0 -119
- data/skills/dhanhq-ruby/references/option-chain.md +0 -71
- data/skills/dhanhq-ruby/references/options-analysis-patterns.md +0 -76
- data/skills/dhanhq-ruby/references/orders.md +0 -201
- data/skills/dhanhq-ruby/references/portfolio.md +0 -93
- data/skills/dhanhq-ruby/references/scanx-data.md +0 -62
- data/skills/dhanhq-ruby/scripts/dhan_helpers.rb +0 -323
- data/skills/dhanhq-ruby/scripts/resolve_security.rb +0 -168
- data/skills/dhanhq-ruby/scripts/trade_logger.rb +0 -131
- data/skills/dhanhq-ruby/scripts/validate_order.rb +0 -169
- data/watchlist.csv +0 -3
data/lib/DhanHQ/ws/client.rb
CHANGED
|
@@ -26,6 +26,9 @@ module DhanHQ
|
|
|
26
26
|
@state = SubState.new
|
|
27
27
|
@callbacks = Concurrent::Map.new { |h, k| h[k] = [] }
|
|
28
28
|
@started = Concurrent::AtomicBoolean.new(false)
|
|
29
|
+
@last_message_at = Concurrent::AtomicReference.new(nil)
|
|
30
|
+
@connected_at = Concurrent::AtomicReference.new(nil)
|
|
31
|
+
@reconnects = Concurrent::AtomicFixnum.new(0)
|
|
29
32
|
|
|
30
33
|
token = DhanHQ.configuration.resolved_access_token
|
|
31
34
|
raise DhanHQ::AuthenticationError, "Missing access token" if token.nil? || token.empty?
|
|
@@ -43,7 +46,8 @@ module DhanHQ
|
|
|
43
46
|
return self if @started.true?
|
|
44
47
|
|
|
45
48
|
@started.make_true
|
|
46
|
-
@conn = Connection.new(url: @url, mode: @mode, bus: @bus, state: @state
|
|
49
|
+
@conn = Connection.new(url: @url, mode: @mode, bus: @bus, state: @state,
|
|
50
|
+
on_event: method(:handle_connection_event)) do |binary|
|
|
47
51
|
tick = Decoder.decode(binary)
|
|
48
52
|
emit(:tick, tick) if tick
|
|
49
53
|
end
|
|
@@ -90,6 +94,80 @@ module DhanHQ
|
|
|
90
94
|
@conn&.open? || false
|
|
91
95
|
end
|
|
92
96
|
|
|
97
|
+
# Timestamp of the most recently received frame.
|
|
98
|
+
#
|
|
99
|
+
# A feed can be "connected" and still be dead — the socket stays open while
|
|
100
|
+
# the server has stopped publishing. Long-running daemons should watch this
|
|
101
|
+
# rather than {#connected?} alone.
|
|
102
|
+
#
|
|
103
|
+
# @return [Time, nil] nil until the first frame arrives.
|
|
104
|
+
def last_message_at
|
|
105
|
+
@last_message_at.get
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Seconds since the last frame arrived.
|
|
109
|
+
#
|
|
110
|
+
# @return [Float, nil] nil until the first frame arrives.
|
|
111
|
+
def seconds_since_last_message
|
|
112
|
+
stamp = last_message_at
|
|
113
|
+
return nil unless stamp
|
|
114
|
+
|
|
115
|
+
Time.now - stamp
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Whether the feed looks alive: connected and delivering frames recently.
|
|
119
|
+
#
|
|
120
|
+
# @param stale_after [Numeric] Seconds of silence after which the feed is
|
|
121
|
+
# considered stale. The server pings roughly every 10 seconds, so the
|
|
122
|
+
# default allows several missed intervals.
|
|
123
|
+
# @return [Boolean]
|
|
124
|
+
def healthy?(stale_after: 45)
|
|
125
|
+
return false unless connected?
|
|
126
|
+
|
|
127
|
+
idle = seconds_since_last_message
|
|
128
|
+
idle.nil? || idle <= stale_after
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Timestamp of the current connection's establishment.
|
|
132
|
+
#
|
|
133
|
+
# @return [Time, nil]
|
|
134
|
+
def connected_at
|
|
135
|
+
@connected_at.get
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Number of times the connection has been re-established since {#start}.
|
|
139
|
+
#
|
|
140
|
+
# @return [Integer]
|
|
141
|
+
def reconnect_count
|
|
142
|
+
@reconnects.value
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Instruments currently subscribed, as `"SEGMENT:SECURITY_ID"` strings.
|
|
146
|
+
#
|
|
147
|
+
# Survives reconnects: the connection replays this set on every new session.
|
|
148
|
+
#
|
|
149
|
+
# @return [Array<String>]
|
|
150
|
+
def subscriptions
|
|
151
|
+
@state.snapshot
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Point-in-time health snapshot, suitable for a monitoring endpoint or log line.
|
|
155
|
+
#
|
|
156
|
+
# @return [Hash]
|
|
157
|
+
def health
|
|
158
|
+
{
|
|
159
|
+
mode: @mode,
|
|
160
|
+
started: @started.true?,
|
|
161
|
+
connected: connected?,
|
|
162
|
+
healthy: healthy?,
|
|
163
|
+
connected_at: connected_at,
|
|
164
|
+
last_message_at: last_message_at,
|
|
165
|
+
seconds_since_last_message: seconds_since_last_message,
|
|
166
|
+
reconnect_count: reconnect_count,
|
|
167
|
+
subscription_count: subscriptions.size
|
|
168
|
+
}
|
|
169
|
+
end
|
|
170
|
+
|
|
93
171
|
# Subscribes to updates for a single instrument.
|
|
94
172
|
#
|
|
95
173
|
# @param segment [String, Symbol, Integer]
|
|
@@ -154,9 +232,27 @@ module DhanHQ
|
|
|
154
232
|
|
|
155
233
|
# Registers a callback for a given event.
|
|
156
234
|
#
|
|
157
|
-
#
|
|
235
|
+
# Supported events:
|
|
236
|
+
#
|
|
237
|
+
# - +:tick+ — a decoded market data packet.
|
|
238
|
+
# - +:open+ — the socket connected. Payload: `{ resubscribed: [...] }`.
|
|
239
|
+
# - +:reconnect+ — the socket re-connected after a drop. Payload:
|
|
240
|
+
# `{ attempt: Integer, resubscribed: [...] }`. Subscriptions are replayed
|
|
241
|
+
# automatically before this fires; use it to re-seed derived state such as
|
|
242
|
+
# candle builders or to alert.
|
|
243
|
+
# - +:close+ — the socket closed. Payload:
|
|
244
|
+
# `{ code:, reason:, reconnecting: Boolean }`.
|
|
245
|
+
# - +:error+ — a socket-level error. Payload: the error message.
|
|
246
|
+
#
|
|
247
|
+
# @param event [Symbol] Event name.
|
|
158
248
|
# @yieldparam payload [Object] Event payload.
|
|
159
249
|
# @return [DhanHQ::WS::Client] self.
|
|
250
|
+
#
|
|
251
|
+
# @example React to a reconnect
|
|
252
|
+
# client.on(:reconnect) do |info|
|
|
253
|
+
# logger.warn "feed reconnected (attempt #{info[:attempt]}), " \
|
|
254
|
+
# "#{info[:resubscribed].size} instruments restored"
|
|
255
|
+
# end
|
|
160
256
|
def on(event, &blk)
|
|
161
257
|
@callbacks[event] << blk
|
|
162
258
|
self
|
|
@@ -164,6 +260,25 @@ module DhanHQ
|
|
|
164
260
|
|
|
165
261
|
private
|
|
166
262
|
|
|
263
|
+
# Bridges connection-level lifecycle events onto the client's callback bus and
|
|
264
|
+
# updates the health counters. +:message+ is internal bookkeeping only — the
|
|
265
|
+
# decoded payload reaches users as +:tick+.
|
|
266
|
+
def handle_connection_event(event, payload)
|
|
267
|
+
case event
|
|
268
|
+
when :message
|
|
269
|
+
@last_message_at.set(Time.now)
|
|
270
|
+
return
|
|
271
|
+
when :open
|
|
272
|
+
@connected_at.set(Time.now)
|
|
273
|
+
when :reconnect
|
|
274
|
+
@reconnects.increment
|
|
275
|
+
when :close
|
|
276
|
+
@connected_at.set(nil)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
emit(event, payload)
|
|
280
|
+
end
|
|
281
|
+
|
|
167
282
|
def prune(hash) = { ExchangeSegment: hash[:ExchangeSegment], SecurityId: hash[:SecurityId] }
|
|
168
283
|
|
|
169
284
|
def emit(event, payload)
|
data/lib/DhanHQ/ws/connection.rb
CHANGED
|
@@ -23,13 +23,18 @@ module DhanHQ
|
|
|
23
23
|
# @param bus [DhanHQ::WS::CmdBus] Command queue feeding subscription
|
|
24
24
|
# changes.
|
|
25
25
|
# @param state [DhanHQ::WS::SubState] Tracks subscription status.
|
|
26
|
+
# @param on_event [Proc, nil] Optional callable invoked as
|
|
27
|
+
# +on_event.call(event, payload)+ for lifecycle events (+:open+, +:close+,
|
|
28
|
+
# +:error+, +:reconnect+). Lets the owning client surface connection state
|
|
29
|
+
# to user callbacks.
|
|
26
30
|
# @yield [binary]
|
|
27
31
|
# @yieldparam binary [String] Raw binary frame received from the socket.
|
|
28
|
-
def initialize(url:, mode:, bus:, state:, &on_binary)
|
|
32
|
+
def initialize(url:, mode:, bus:, state:, on_event: nil, &on_binary)
|
|
29
33
|
@url = url
|
|
30
34
|
@mode = mode
|
|
31
35
|
@bus = bus
|
|
32
36
|
@state = state
|
|
37
|
+
@on_event = on_event
|
|
33
38
|
@on_binary = on_binary
|
|
34
39
|
@stop = false
|
|
35
40
|
@stopping = false
|
|
@@ -90,11 +95,41 @@ module DhanHQ
|
|
|
90
95
|
|
|
91
96
|
private
|
|
92
97
|
|
|
98
|
+
# Notifies the owning client of a lifecycle event. Never lets a user callback
|
|
99
|
+
# take down the connection thread.
|
|
100
|
+
def notify(event, payload = nil)
|
|
101
|
+
@on_event&.call(event, payload)
|
|
102
|
+
rescue StandardError => e
|
|
103
|
+
DhanHQ.logger&.error("[DhanHQ::WS] on_event(#{event}) raised #{e.class}: #{e.message}")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Restores subscriptions and starts the command drain for a freshly opened
|
|
107
|
+
# socket, then reports the transition.
|
|
108
|
+
#
|
|
109
|
+
# @param session [Integer] 1-based index of this connection attempt. Anything
|
|
110
|
+
# past the first is a reconnect.
|
|
111
|
+
def handle_open(session)
|
|
112
|
+
DhanHQ.logger&.info("[DhanHQ::WS] open")
|
|
113
|
+
|
|
114
|
+
# The server keeps no subscription state across connections, so the desired set
|
|
115
|
+
# is replayed on every new session. See SubState#resubscribe_payload.
|
|
116
|
+
snapshot = @state.resubscribe_payload
|
|
117
|
+
send_sub(snapshot) unless snapshot.empty?
|
|
118
|
+
@timer = EM.add_periodic_timer(0.25) { drain_and_send }
|
|
119
|
+
|
|
120
|
+
# :reconnect lets callers re-seed derived state (candle builders, caches)
|
|
121
|
+
# and see exactly which instruments were restored for them.
|
|
122
|
+
notify(:reconnect, { attempt: session - 1, resubscribed: snapshot }) if session > 1
|
|
123
|
+
notify(:open, { resubscribed: snapshot })
|
|
124
|
+
end
|
|
125
|
+
|
|
93
126
|
def loop_run
|
|
94
127
|
backoff = 2.0
|
|
128
|
+
sessions = 0
|
|
95
129
|
until @stop
|
|
96
130
|
failed = false
|
|
97
131
|
got_429 = false
|
|
132
|
+
sessions += 1
|
|
98
133
|
|
|
99
134
|
# respect any active cool-off window
|
|
100
135
|
sleep (@cooloff_until - Time.now).ceil if @cooloff_until && Time.now < @cooloff_until
|
|
@@ -103,18 +138,10 @@ module DhanHQ
|
|
|
103
138
|
EM.run do
|
|
104
139
|
@ws = Faye::WebSocket::Client.new(@url, nil, headers: default_headers)
|
|
105
140
|
|
|
106
|
-
@ws.on
|
|
107
|
-
DhanHQ.logger&.info("[DhanHQ::WS] open")
|
|
108
|
-
# re-subscribe snapshot on reconnect
|
|
109
|
-
snapshot = @state.snapshot.map do |k|
|
|
110
|
-
seg, sid = k.split(":")
|
|
111
|
-
{ ExchangeSegment: seg, SecurityId: sid }
|
|
112
|
-
end
|
|
113
|
-
send_sub(snapshot) unless snapshot.empty?
|
|
114
|
-
@timer = EM.add_periodic_timer(0.25) { drain_and_send }
|
|
115
|
-
end
|
|
141
|
+
@ws.on(:open) { |_| handle_open(sessions) }
|
|
116
142
|
|
|
117
143
|
@ws.on :message do |ev|
|
|
144
|
+
notify(:message, nil)
|
|
118
145
|
@on_binary&.call(ev.data) # raw frames to decoder
|
|
119
146
|
end
|
|
120
147
|
|
|
@@ -131,12 +158,14 @@ module DhanHQ
|
|
|
131
158
|
failed = (ev.code != 1000)
|
|
132
159
|
got_429 = ev.reason.to_s.include?("429")
|
|
133
160
|
end
|
|
161
|
+
notify(:close, { code: ev.code, reason: ev.reason, reconnecting: failed })
|
|
134
162
|
EM.stop
|
|
135
163
|
end
|
|
136
164
|
|
|
137
165
|
@ws.on :error do |ev|
|
|
138
166
|
DhanHQ.logger&.error("[DhanHQ::WS] error #{ev.message}")
|
|
139
167
|
failed = true
|
|
168
|
+
notify(:error, ev.message)
|
|
140
169
|
end
|
|
141
170
|
end
|
|
142
171
|
rescue StandardError => e
|
data/lib/DhanHQ/ws/sub_state.rb
CHANGED
|
@@ -51,6 +51,20 @@ module DhanHQ
|
|
|
51
51
|
@mutex.synchronize { @set.to_a }
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
# The desired subscriptions rendered as instrument hashes, ready to be sent as a
|
|
55
|
+
# subscribe frame.
|
|
56
|
+
#
|
|
57
|
+
# The server keeps no subscription state across connections, so a reconnecting
|
|
58
|
+
# client replays this on every new session.
|
|
59
|
+
#
|
|
60
|
+
# @return [Array<Hash>] Instruments with +:ExchangeSegment+ and +:SecurityId+.
|
|
61
|
+
def resubscribe_payload
|
|
62
|
+
snapshot.map do |key|
|
|
63
|
+
segment, security_id = key.split(":")
|
|
64
|
+
{ ExchangeSegment: segment, SecurityId: security_id }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
54
68
|
private
|
|
55
69
|
|
|
56
70
|
def key_for(instrument) = "#{instrument[:ExchangeSegment]}:#{instrument[:SecurityId]}"
|
|
@@ -100,13 +100,13 @@ module DhanHQ
|
|
|
100
100
|
# Choose the nearest expiry (first element); adjust selection if API returns sorted differently
|
|
101
101
|
expiry = expiries.first
|
|
102
102
|
raw = DhanHQ::Models::OptionChain.fetch(underlying_scrip: sid.to_i, underlying_seg: seg, expiry: expiry)
|
|
103
|
-
|
|
104
|
-
# Transform
|
|
105
|
-
@data[:option_chain] =
|
|
103
|
+
strikes = raw[:strikes] || []
|
|
104
|
+
# Transform normalized strikes into advisor-friendly array [{ strike:, ce: {...}, pe: {...} }]
|
|
105
|
+
@data[:option_chain] = strikes.map do |entry|
|
|
106
106
|
{
|
|
107
|
-
strike: strike.to_f,
|
|
108
|
-
ce: normalize_leg(
|
|
109
|
-
pe: normalize_leg(
|
|
107
|
+
strike: entry[:strike].to_f,
|
|
108
|
+
ce: normalize_leg(entry[:call] || {}),
|
|
109
|
+
pe: normalize_leg(entry[:put] || {})
|
|
110
110
|
}
|
|
111
111
|
end
|
|
112
112
|
rescue StandardError
|
|
@@ -114,11 +114,12 @@ module DhanHQ
|
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
def normalize_leg(cepe)
|
|
117
|
+
greeks = cepe[:greeks] || {}
|
|
117
118
|
{
|
|
118
|
-
ltp: cepe[
|
|
119
|
-
iv: cepe[
|
|
120
|
-
delta:
|
|
121
|
-
|
|
119
|
+
ltp: cepe[:last_price], bid: cepe[:top_bid_price], ask: cepe[:top_ask_price],
|
|
120
|
+
iv: cepe[:implied_volatility], oi: cepe[:oi], volume: cepe[:volume],
|
|
121
|
+
delta: greeks[:delta], gamma: greeks[:gamma], vega: greeks[:vega], theta: greeks[:theta],
|
|
122
|
+
security_id: cepe[:security_id], tradable: true
|
|
122
123
|
}
|
|
123
124
|
end
|
|
124
125
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: DhanHQ
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shubham Taywade
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -176,21 +176,12 @@ executables:
|
|
|
176
176
|
extensions: []
|
|
177
177
|
extra_rdoc_files: []
|
|
178
178
|
files:
|
|
179
|
-
- ".rspec"
|
|
180
|
-
- ".rubocop.yml"
|
|
181
|
-
- ".rubocop_todo.yml"
|
|
182
|
-
- AGENTS.md
|
|
183
179
|
- ARCHITECTURE.md
|
|
184
180
|
- CHANGELOG.md
|
|
185
|
-
- CODE_OF_CONDUCT.md
|
|
186
181
|
- GUIDE.md
|
|
187
182
|
- LICENSE.txt
|
|
188
183
|
- README.md
|
|
189
|
-
- Rakefile
|
|
190
|
-
- TAGS
|
|
191
184
|
- config/initializers/order_update_hub.rb
|
|
192
|
-
- core
|
|
193
|
-
- diagram.html
|
|
194
185
|
- docs/API_DOCS_GAPS.md
|
|
195
186
|
- docs/API_VERIFICATION.md
|
|
196
187
|
- docs/AUTHENTICATION.md
|
|
@@ -220,9 +211,14 @@ files:
|
|
|
220
211
|
- exe/dhanhq-mcp
|
|
221
212
|
- lib/DhanHQ.rb
|
|
222
213
|
- lib/DhanHQ/agent.rb
|
|
214
|
+
- lib/DhanHQ/agent/key_coercion.rb
|
|
223
215
|
- lib/DhanHQ/agent/order_preview.rb
|
|
224
216
|
- lib/DhanHQ/agent/policy.rb
|
|
217
|
+
- lib/DhanHQ/agent/tool.rb
|
|
218
|
+
- lib/DhanHQ/agent/tool_catalogue.rb
|
|
219
|
+
- lib/DhanHQ/agent/tool_handlers.rb
|
|
225
220
|
- lib/DhanHQ/agent/tool_registry.rb
|
|
221
|
+
- lib/DhanHQ/agent/tool_schemas.rb
|
|
226
222
|
- lib/DhanHQ/ai.rb
|
|
227
223
|
- lib/DhanHQ/ai/context_builder.rb
|
|
228
224
|
- lib/DhanHQ/ai/prompt_helpers.rb
|
|
@@ -239,6 +235,10 @@ files:
|
|
|
239
235
|
- lib/DhanHQ/contracts/edis_contract.rb
|
|
240
236
|
- lib/DhanHQ/contracts/expired_options_data_contract.rb
|
|
241
237
|
- lib/DhanHQ/contracts/forever_order_contract.rb
|
|
238
|
+
- lib/DhanHQ/contracts/global_stocks_estimator_contract.rb
|
|
239
|
+
- lib/DhanHQ/contracts/global_stocks_modify_order_contract.rb
|
|
240
|
+
- lib/DhanHQ/contracts/global_stocks_order_contract.rb
|
|
241
|
+
- lib/DhanHQ/contracts/global_stocks_place_order_contract.rb
|
|
242
242
|
- lib/DhanHQ/contracts/historical_data_contract.rb
|
|
243
243
|
- lib/DhanHQ/contracts/iceberg_order_contract.rb
|
|
244
244
|
- lib/DhanHQ/contracts/instrument_list_contract.rb
|
|
@@ -246,6 +246,7 @@ files:
|
|
|
246
246
|
- lib/DhanHQ/contracts/margin_calculator_contract.rb
|
|
247
247
|
- lib/DhanHQ/contracts/market_feed_contract.rb
|
|
248
248
|
- lib/DhanHQ/contracts/modify_order_contract.rb
|
|
249
|
+
- lib/DhanHQ/contracts/multi_order_contract.rb
|
|
249
250
|
- lib/DhanHQ/contracts/multi_scrip_margin_calc_request_contract.rb
|
|
250
251
|
- lib/DhanHQ/contracts/option_chain_contract.rb
|
|
251
252
|
- lib/DhanHQ/contracts/order_contract.rb
|
|
@@ -263,6 +264,8 @@ files:
|
|
|
263
264
|
- lib/DhanHQ/core/base_model.rb
|
|
264
265
|
- lib/DhanHQ/core/base_resource.rb
|
|
265
266
|
- lib/DhanHQ/core/error_handler.rb
|
|
267
|
+
- lib/DhanHQ/dry_run/ledger.rb
|
|
268
|
+
- lib/DhanHQ/dry_run/simulator.rb
|
|
266
269
|
- lib/DhanHQ/error_object.rb
|
|
267
270
|
- lib/DhanHQ/errors.rb
|
|
268
271
|
- lib/DhanHQ/events.rb
|
|
@@ -288,6 +291,13 @@ files:
|
|
|
288
291
|
- lib/DhanHQ/models/expired_options_data.rb
|
|
289
292
|
- lib/DhanHQ/models/forever_order.rb
|
|
290
293
|
- lib/DhanHQ/models/funds.rb
|
|
294
|
+
- lib/DhanHQ/models/global_stocks/funds.rb
|
|
295
|
+
- lib/DhanHQ/models/global_stocks/holding.rb
|
|
296
|
+
- lib/DhanHQ/models/global_stocks/margin.rb
|
|
297
|
+
- lib/DhanHQ/models/global_stocks/market_status.rb
|
|
298
|
+
- lib/DhanHQ/models/global_stocks/order.rb
|
|
299
|
+
- lib/DhanHQ/models/global_stocks/order_estimate.rb
|
|
300
|
+
- lib/DhanHQ/models/global_stocks/trade.rb
|
|
291
301
|
- lib/DhanHQ/models/historical_data.rb
|
|
292
302
|
- lib/DhanHQ/models/holding.rb
|
|
293
303
|
- lib/DhanHQ/models/iceberg_order.rb
|
|
@@ -297,6 +307,7 @@ files:
|
|
|
297
307
|
- lib/DhanHQ/models/ledger_entry.rb
|
|
298
308
|
- lib/DhanHQ/models/margin.rb
|
|
299
309
|
- lib/DhanHQ/models/market_feed.rb
|
|
310
|
+
- lib/DhanHQ/models/multi_order.rb
|
|
300
311
|
- lib/DhanHQ/models/option_chain.rb
|
|
301
312
|
- lib/DhanHQ/models/order.rb
|
|
302
313
|
- lib/DhanHQ/models/order_update.rb
|
|
@@ -321,6 +332,12 @@ files:
|
|
|
321
332
|
- lib/DhanHQ/resources/expired_options_data.rb
|
|
322
333
|
- lib/DhanHQ/resources/forever_orders.rb
|
|
323
334
|
- lib/DhanHQ/resources/funds.rb
|
|
335
|
+
- lib/DhanHQ/resources/global_stocks/funds.rb
|
|
336
|
+
- lib/DhanHQ/resources/global_stocks/holdings.rb
|
|
337
|
+
- lib/DhanHQ/resources/global_stocks/margin_calculator.rb
|
|
338
|
+
- lib/DhanHQ/resources/global_stocks/market_status.rb
|
|
339
|
+
- lib/DhanHQ/resources/global_stocks/orders.rb
|
|
340
|
+
- lib/DhanHQ/resources/global_stocks/trades.rb
|
|
324
341
|
- lib/DhanHQ/resources/historical_data.rb
|
|
325
342
|
- lib/DhanHQ/resources/holdings.rb
|
|
326
343
|
- lib/DhanHQ/resources/iceberg_orders.rb
|
|
@@ -329,6 +346,7 @@ files:
|
|
|
329
346
|
- lib/DhanHQ/resources/kill_switch.rb
|
|
330
347
|
- lib/DhanHQ/resources/margin_calculator.rb
|
|
331
348
|
- lib/DhanHQ/resources/market_feed.rb
|
|
349
|
+
- lib/DhanHQ/resources/multi_orders.rb
|
|
332
350
|
- lib/DhanHQ/resources/option_chain.rb
|
|
333
351
|
- lib/DhanHQ/resources/orders.rb
|
|
334
352
|
- lib/DhanHQ/resources/pnl_exit.rb
|
|
@@ -370,6 +388,7 @@ files:
|
|
|
370
388
|
- lib/DhanHQ/strategy/base.rb
|
|
371
389
|
- lib/DhanHQ/utils/network_inspector.rb
|
|
372
390
|
- lib/DhanHQ/version.rb
|
|
391
|
+
- lib/DhanHQ/write_paths.rb
|
|
373
392
|
- lib/DhanHQ/ws.rb
|
|
374
393
|
- lib/DhanHQ/ws/base_connection.rb
|
|
375
394
|
- lib/DhanHQ/ws/client.rb
|
|
@@ -416,35 +435,6 @@ files:
|
|
|
416
435
|
- lib/ta/market_calendar.rb
|
|
417
436
|
- lib/ta/technical_analysis.rb
|
|
418
437
|
- sig/DhanHQ.rbs
|
|
419
|
-
- skills/dhanhq-ruby/SKILL.md
|
|
420
|
-
- skills/dhanhq-ruby/examples/fetch_option_chain.rb
|
|
421
|
-
- skills/dhanhq-ruby/examples/gtt_forever_order.rb
|
|
422
|
-
- skills/dhanhq-ruby/examples/historical_data_analysis.rb
|
|
423
|
-
- skills/dhanhq-ruby/examples/iron_condor.rb
|
|
424
|
-
- skills/dhanhq-ruby/examples/live_feed_setup.rb
|
|
425
|
-
- skills/dhanhq-ruby/examples/margin_check.rb
|
|
426
|
-
- skills/dhanhq-ruby/examples/order_management.rb
|
|
427
|
-
- skills/dhanhq-ruby/examples/place_equity_order.rb
|
|
428
|
-
- skills/dhanhq-ruby/examples/place_fno_order.rb
|
|
429
|
-
- skills/dhanhq-ruby/examples/portfolio_summary.rb
|
|
430
|
-
- skills/dhanhq-ruby/examples/super_order_with_sl.rb
|
|
431
|
-
- skills/dhanhq-ruby/references/backtesting-with-dhan.md
|
|
432
|
-
- skills/dhanhq-ruby/references/common-workflows.md
|
|
433
|
-
- skills/dhanhq-ruby/references/error-codes.md
|
|
434
|
-
- skills/dhanhq-ruby/references/funds.md
|
|
435
|
-
- skills/dhanhq-ruby/references/instruments.md
|
|
436
|
-
- skills/dhanhq-ruby/references/live-feed.md
|
|
437
|
-
- skills/dhanhq-ruby/references/market-data.md
|
|
438
|
-
- skills/dhanhq-ruby/references/option-chain.md
|
|
439
|
-
- skills/dhanhq-ruby/references/options-analysis-patterns.md
|
|
440
|
-
- skills/dhanhq-ruby/references/orders.md
|
|
441
|
-
- skills/dhanhq-ruby/references/portfolio.md
|
|
442
|
-
- skills/dhanhq-ruby/references/scanx-data.md
|
|
443
|
-
- skills/dhanhq-ruby/scripts/dhan_helpers.rb
|
|
444
|
-
- skills/dhanhq-ruby/scripts/resolve_security.rb
|
|
445
|
-
- skills/dhanhq-ruby/scripts/trade_logger.rb
|
|
446
|
-
- skills/dhanhq-ruby/scripts/validate_order.rb
|
|
447
|
-
- watchlist.csv
|
|
448
438
|
homepage: https://github.com/shubhamtaywade82/dhanhq-client
|
|
449
439
|
licenses:
|
|
450
440
|
- MIT
|
data/.rspec
DELETED
data/.rubocop.yml
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
inherit_from: .rubocop_todo.yml
|
|
2
|
-
|
|
3
|
-
plugins:
|
|
4
|
-
- rubocop-rspec
|
|
5
|
-
- rubocop-performance
|
|
6
|
-
|
|
7
|
-
require:
|
|
8
|
-
- rubocop-rake
|
|
9
|
-
- ./lib/rubocop/cop/dhanhq/use_constants.rb
|
|
10
|
-
|
|
11
|
-
AllCops:
|
|
12
|
-
TargetRubyVersion: 3.2
|
|
13
|
-
NewCops: enable
|
|
14
|
-
Exclude:
|
|
15
|
-
- "skills/**/*"
|
|
16
|
-
|
|
17
|
-
Style/StringLiterals:
|
|
18
|
-
EnforcedStyle: double_quotes
|
|
19
|
-
|
|
20
|
-
Style/StringLiteralsInInterpolation:
|
|
21
|
-
EnforcedStyle: double_quotes
|
|
22
|
-
|
|
23
|
-
# RSpec
|
|
24
|
-
RSpec/MultipleExpectations:
|
|
25
|
-
Max: 5
|
|
26
|
-
|
|
27
|
-
RSpec/ExampleLength:
|
|
28
|
-
Max: 15
|
|
29
|
-
|
|
30
|
-
RSpec/MultipleMemoizedHelpers:
|
|
31
|
-
Max: 10
|
|
32
|
-
|
|
33
|
-
Lint/ScriptPermission:
|
|
34
|
-
Exclude:
|
|
35
|
-
- "bin/**/*"
|
|
36
|
-
|
|
37
|
-
Metrics/AbcSize:
|
|
38
|
-
Exclude:
|
|
39
|
-
- "bin/call_all_endpoints.rb"
|
|
40
|
-
|
|
41
|
-
Layout/LineLength:
|
|
42
|
-
Exclude:
|
|
43
|
-
- "bin/call_all_endpoints.rb"
|
|
44
|
-
|
|
45
|
-
DhanHQ/UseConstants:
|
|
46
|
-
Enabled: true
|
|
47
|
-
Exclude:
|
|
48
|
-
- "lib/DhanHQ/constants.rb"
|
|
49
|
-
- "lib/DhanHQ/ws/segments.rb"
|
|
50
|
-
- "spec/**/*"
|