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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -0
- data/examples/comprehensive_websocket_examples.rb +0 -0
- data/examples/instrument_finder_test.rb +0 -0
- data/examples/live_order_updates.rb +1 -1
- data/examples/market_depth_example.rb +2 -2
- data/examples/order_update_example.rb +0 -0
- data/examples/trading_fields_example.rb +1 -1
- data/lib/DhanHQ/client.rb +2 -1
- data/lib/DhanHQ/contracts/expired_options_data_contract.rb +6 -6
- data/lib/DhanHQ/core/base_model.rb +9 -1
- data/lib/DhanHQ/models/edis.rb +150 -14
- data/lib/DhanHQ/models/expired_options_data.rb +307 -82
- data/lib/DhanHQ/models/forever_order.rb +261 -22
- data/lib/DhanHQ/models/funds.rb +76 -10
- data/lib/DhanHQ/models/historical_data.rb +148 -31
- data/lib/DhanHQ/models/holding.rb +82 -6
- data/lib/DhanHQ/models/instrument_helpers.rb +39 -5
- data/lib/DhanHQ/models/kill_switch.rb +113 -11
- data/lib/DhanHQ/models/ledger_entry.rb +101 -13
- data/lib/DhanHQ/models/margin.rb +133 -8
- data/lib/DhanHQ/models/market_feed.rb +181 -17
- data/lib/DhanHQ/models/option_chain.rb +184 -12
- data/lib/DhanHQ/models/order.rb +399 -34
- data/lib/DhanHQ/models/position.rb +161 -10
- data/lib/DhanHQ/models/profile.rb +103 -7
- data/lib/DhanHQ/models/super_order.rb +275 -15
- data/lib/DhanHQ/models/trade.rb +279 -26
- data/lib/DhanHQ/rate_limiter.rb +78 -23
- data/lib/DhanHQ/resources/expired_options_data.rb +1 -1
- data/lib/DhanHQ/version.rb +1 -1
- data/lib/DhanHQ/ws/market_depth/client.rb +3 -1
- data/lib/DhanHQ/ws/orders/client.rb +2 -1
- data/lib/DhanHQ/ws/orders/connection.rb +0 -3
- data/lib/DhanHQ/ws/orders.rb +2 -1
- metadata +1 -1
|
@@ -3,72 +3,189 @@
|
|
|
3
3
|
module DhanHQ
|
|
4
4
|
module Models
|
|
5
5
|
##
|
|
6
|
-
# Model
|
|
7
|
-
#
|
|
6
|
+
# Model for fetching historical candle data (OHLC) for desired instruments across segments and exchanges.
|
|
7
|
+
#
|
|
8
|
+
# This API provides historical price data in the form of candlestick data with timestamp, open, high, low,
|
|
9
|
+
# close, and volume information. Data is available in two formats:
|
|
10
|
+
# - **Daily**: Daily candle data available back to the date of instrument inception
|
|
11
|
+
# - **Intraday**: Minute-level candle data (1, 5, 15, 25, 60 minutes) available for the last 5 years
|
|
12
|
+
#
|
|
13
|
+
# @example Fetch daily historical data
|
|
14
|
+
# data = DhanHQ::Models::HistoricalData.daily(
|
|
15
|
+
# security_id: "1333",
|
|
16
|
+
# exchange_segment: "NSE_EQ",
|
|
17
|
+
# instrument: "EQUITY",
|
|
18
|
+
# from_date: "2022-01-08",
|
|
19
|
+
# to_date: "2022-02-08"
|
|
20
|
+
# )
|
|
21
|
+
# puts "First day close: #{data[:close].first}"
|
|
22
|
+
#
|
|
23
|
+
# @example Fetch intraday historical data
|
|
24
|
+
# data = DhanHQ::Models::HistoricalData.intraday(
|
|
25
|
+
# security_id: "1333",
|
|
26
|
+
# exchange_segment: "NSE_EQ",
|
|
27
|
+
# instrument: "EQUITY",
|
|
28
|
+
# interval: "15",
|
|
29
|
+
# from_date: "2024-09-11",
|
|
30
|
+
# to_date: "2024-09-15"
|
|
31
|
+
# )
|
|
32
|
+
# puts "Total candles: #{data[:open].size}"
|
|
33
|
+
#
|
|
34
|
+
# @note For intraday data, only 90 days of data can be polled at once for any time interval.
|
|
35
|
+
# It is recommended to store this data locally for day-to-day analysis.
|
|
8
36
|
#
|
|
9
37
|
class HistoricalData < BaseModel
|
|
10
|
-
#
|
|
11
|
-
# because we call "daily" or "intraday" endpoints specifically.
|
|
12
|
-
# So let's rely on the resource call directly.
|
|
38
|
+
# Base path for historical data endpoints.
|
|
13
39
|
HTTP_PATH = "/v2/charts"
|
|
14
40
|
|
|
15
|
-
# If you want typed attributes, you could define them,
|
|
16
|
-
# but the endpoints return arrays. We'll keep it raw.
|
|
17
|
-
# e.g. attributes :open, :high, :low, :close, :volume, :timestamp
|
|
18
|
-
|
|
19
41
|
class << self
|
|
20
42
|
##
|
|
21
|
-
#
|
|
43
|
+
# Provides a shared instance of the HistoricalData resource.
|
|
22
44
|
#
|
|
23
|
-
# @return [DhanHQ::Resources::HistoricalData]
|
|
45
|
+
# @return [DhanHQ::Resources::HistoricalData] The HistoricalData resource client instance
|
|
24
46
|
def resource
|
|
25
47
|
@resource ||= DhanHQ::Resources::HistoricalData.new
|
|
26
48
|
end
|
|
27
49
|
|
|
28
50
|
##
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
51
|
+
# Fetches daily OHLC (Open, High, Low, Close) and volume data for the desired instrument.
|
|
52
|
+
#
|
|
53
|
+
# Retrieves daily candle data for any scrip available back to the date of its inception.
|
|
54
|
+
# The data is returned as arrays where each index corresponds to a single trading day.
|
|
55
|
+
#
|
|
56
|
+
# @param params [Hash{Symbol => String, Integer, Boolean}] Request parameters
|
|
57
|
+
# @option params [String] :security_id (required) Exchange standard ID for each scrip
|
|
58
|
+
# @option params [String] :exchange_segment (required) Exchange and segment for which data is to be fetched.
|
|
59
|
+
# Valid values: See {DhanHQ::Constants::EXCHANGE_SEGMENTS}
|
|
60
|
+
# @option params [String] :instrument (required) Instrument type of the scrip.
|
|
61
|
+
# Valid values: See {DhanHQ::Constants::INSTRUMENTS}
|
|
62
|
+
# @option params [Integer] :expiry_code (optional) Expiry of the instruments in case of derivatives.
|
|
63
|
+
# Valid values: 0, 1, 2
|
|
64
|
+
# @option params [Boolean] :oi (optional) Include Open Interest data for Futures & Options.
|
|
65
|
+
# Default: false
|
|
66
|
+
# @option params [String] :from_date (required) Start date of the desired range in YYYY-MM-DD format
|
|
67
|
+
# @option params [String] :to_date (required) End date of the desired range (non-inclusive) in YYYY-MM-DD format
|
|
68
|
+
#
|
|
69
|
+
# @return [HashWithIndifferentAccess{Symbol => Array<Float, Integer>}] Historical data hash containing:
|
|
70
|
+
# - **:open** [Array<Float>] Open prices for each trading day
|
|
71
|
+
# - **:high** [Array<Float>] High prices for each trading day
|
|
72
|
+
# - **:low** [Array<Float>] Low prices for each trading day
|
|
73
|
+
# - **:close** [Array<Float>] Close prices for each trading day
|
|
74
|
+
# - **:volume** [Array<Integer>] Volume traded for each trading day
|
|
75
|
+
# - **:timestamp** [Array<Integer>] Epoch timestamps (Unix time in seconds) for each trading day
|
|
76
|
+
# - **:open_interest** [Array<Float>] Open interest values (only included if `oi: true` was specified)
|
|
77
|
+
#
|
|
78
|
+
# @example Fetch daily data for equity
|
|
79
|
+
# data = DhanHQ::Models::HistoricalData.daily(
|
|
32
80
|
# security_id: "1333",
|
|
33
81
|
# exchange_segment: "NSE_EQ",
|
|
34
82
|
# instrument: "EQUITY",
|
|
35
|
-
# expiry_code: 0,
|
|
36
83
|
# from_date: "2022-01-08",
|
|
37
84
|
# to_date: "2022-02-08"
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
85
|
+
# )
|
|
86
|
+
# data[:open].size # => Number of trading days
|
|
87
|
+
# data[:close].first # => First day's close price
|
|
88
|
+
#
|
|
89
|
+
# @example Fetch daily data with open interest for futures
|
|
90
|
+
# data = DhanHQ::Models::HistoricalData.daily(
|
|
91
|
+
# security_id: "13",
|
|
92
|
+
# exchange_segment: "NSE_FNO",
|
|
93
|
+
# instrument: "FUTIDX",
|
|
94
|
+
# expiry_code: 0,
|
|
95
|
+
# oi: true,
|
|
96
|
+
# from_date: "2024-01-01",
|
|
97
|
+
# to_date: "2024-01-31"
|
|
98
|
+
# )
|
|
99
|
+
# puts "OI data available: #{data.key?(:open_interest)}"
|
|
100
|
+
#
|
|
101
|
+
# @raise [DhanHQ::ValidationError] If validation fails for any parameter
|
|
44
102
|
def daily(params)
|
|
45
103
|
validate_params!(params, DhanHQ::Contracts::HistoricalDataContract)
|
|
46
|
-
# You can rename the keys from snake_case to something if needed
|
|
47
104
|
resource.daily(params)
|
|
48
|
-
# return as a raw hash or transform further
|
|
49
105
|
end
|
|
50
106
|
|
|
51
107
|
##
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
108
|
+
# Fetches intraday OHLC (Open, High, Low, Close) and volume data for minute-level timeframes.
|
|
109
|
+
#
|
|
110
|
+
# Retrieves minute-level candle data (1, 5, 15, 25, or 60 minutes) for desired instruments.
|
|
111
|
+
# Data is available for the last 5 years for all exchanges and segments for all active instruments.
|
|
112
|
+
#
|
|
113
|
+
# **Important**: Only 90 days of data can be polled at once for any of the time intervals.
|
|
114
|
+
# It is recommended that you store this data locally for day-to-day analysis.
|
|
115
|
+
#
|
|
116
|
+
# @param params [Hash{Symbol => String, Integer, Boolean}] Request parameters
|
|
117
|
+
# @option params [String] :security_id (required) Exchange standard ID for each scrip
|
|
118
|
+
# @option params [String] :exchange_segment (required) Exchange and segment for which data is to be fetched.
|
|
119
|
+
# Valid values: See {DhanHQ::Constants::EXCHANGE_SEGMENTS}
|
|
120
|
+
# @option params [String] :instrument (required) Instrument type of the scrip.
|
|
121
|
+
# Valid values: See {DhanHQ::Constants::INSTRUMENTS}
|
|
122
|
+
# @option params [String] :interval (required) Minute intervals for the timeframe.
|
|
123
|
+
# Valid values: "1", "5", "15", "25", "60"
|
|
124
|
+
# @option params [Integer] :expiry_code (optional) Expiry of the instruments in case of derivatives.
|
|
125
|
+
# Valid values: 0, 1, 2
|
|
126
|
+
# @option params [Boolean] :oi (optional) Include Open Interest data for Futures & Options.
|
|
127
|
+
# Default: false
|
|
128
|
+
# @option params [String] :from_date (required) Start date of the desired range.
|
|
129
|
+
# Format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS (e.g., "2024-09-11" or "2024-09-11 09:30:00")
|
|
130
|
+
# @option params [String] :to_date (required) End date of the desired range.
|
|
131
|
+
# Format: YYYY-MM-DD or YYYY-MM-DD HH:MM:SS (e.g., "2024-09-15" or "2024-09-15 13:00:00")
|
|
132
|
+
#
|
|
133
|
+
# @return [HashWithIndifferentAccess{Symbol => Array<Float, Integer>}] Historical data hash containing:
|
|
134
|
+
# - **:open** [Array<Float>] Open prices for each timeframe
|
|
135
|
+
# - **:high** [Array<Float>] High prices for each timeframe
|
|
136
|
+
# - **:low** [Array<Float>] Low prices for each timeframe
|
|
137
|
+
# - **:close** [Array<Float>] Close prices for each timeframe
|
|
138
|
+
# - **:volume** [Array<Integer>] Volume traded for each timeframe
|
|
139
|
+
# - **:timestamp** [Array<Integer>] Epoch timestamps (Unix time in seconds) for each timeframe
|
|
140
|
+
# - **:open_interest** [Array<Float>] Open interest values (only included if `oi: true` was specified)
|
|
141
|
+
#
|
|
142
|
+
# @example Fetch 15-minute intraday data
|
|
143
|
+
# data = DhanHQ::Models::HistoricalData.intraday(
|
|
55
144
|
# security_id: "1333",
|
|
56
145
|
# exchange_segment: "NSE_EQ",
|
|
57
146
|
# instrument: "EQUITY",
|
|
58
147
|
# interval: "15",
|
|
59
148
|
# from_date: "2024-09-11",
|
|
60
149
|
# to_date: "2024-09-15"
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
150
|
+
# )
|
|
151
|
+
# puts "Total 15-min candles: #{data[:open].size}"
|
|
152
|
+
#
|
|
153
|
+
# @example Fetch 1-minute data with specific time range
|
|
154
|
+
# data = DhanHQ::Models::HistoricalData.intraday(
|
|
155
|
+
# security_id: "1333",
|
|
156
|
+
# exchange_segment: "NSE_EQ",
|
|
157
|
+
# instrument: "EQUITY",
|
|
158
|
+
# interval: "1",
|
|
159
|
+
# from_date: "2024-09-11 09:30:00",
|
|
160
|
+
# to_date: "2024-09-11 15:30:00"
|
|
161
|
+
# )
|
|
162
|
+
# # Returns 1-minute candles for the specified time range
|
|
163
|
+
#
|
|
164
|
+
# @example Fetch intraday data for futures with open interest
|
|
165
|
+
# data = DhanHQ::Models::HistoricalData.intraday(
|
|
166
|
+
# security_id: "13",
|
|
167
|
+
# exchange_segment: "NSE_FNO",
|
|
168
|
+
# instrument: "FUTIDX",
|
|
169
|
+
# interval: "5",
|
|
170
|
+
# expiry_code: 0,
|
|
171
|
+
# oi: true,
|
|
172
|
+
# from_date: "2024-01-01",
|
|
173
|
+
# to_date: "2024-01-31"
|
|
174
|
+
# )
|
|
175
|
+
#
|
|
176
|
+
# @note Maximum 90 days of data can be fetched in a single request. For longer periods,
|
|
177
|
+
# make multiple requests or store data locally for analysis.
|
|
178
|
+
# @raise [DhanHQ::ValidationError] If validation fails for any parameter
|
|
65
179
|
def intraday(params)
|
|
66
180
|
validate_params!(params, DhanHQ::Contracts::HistoricalDataContract)
|
|
67
181
|
resource.intraday(params)
|
|
68
182
|
end
|
|
69
183
|
end
|
|
70
184
|
|
|
71
|
-
|
|
185
|
+
##
|
|
186
|
+
# HistoricalData objects are read-only, so no validation contract is applied.
|
|
187
|
+
#
|
|
188
|
+
# @return [nil] No validation contract needed for read-only data
|
|
72
189
|
def validation_contract
|
|
73
190
|
nil
|
|
74
191
|
end
|
|
@@ -2,7 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
module DhanHQ
|
|
4
4
|
module Models
|
|
5
|
+
##
|
|
5
6
|
# Model representing a single portfolio holding.
|
|
7
|
+
#
|
|
8
|
+
# Holdings represent all stocks/securities bought or sold in previous trading sessions.
|
|
9
|
+
# This includes both T1 (pending delivery) and delivered quantities in your demat account.
|
|
10
|
+
# Each holding provides information about quantities, average cost price, and availability
|
|
11
|
+
# for transactions.
|
|
12
|
+
#
|
|
13
|
+
# @example Fetch all holdings
|
|
14
|
+
# holdings = DhanHQ::Models::Holding.all
|
|
15
|
+
# holdings.each do |holding|
|
|
16
|
+
# puts "#{holding.trading_symbol}: #{holding.total_qty} shares @ ₹#{holding.avg_cost_price}"
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# @example Find a specific holding by symbol
|
|
20
|
+
# holdings = DhanHQ::Models::Holding.all
|
|
21
|
+
# hdfc = holdings.find { |h| h.trading_symbol == "HDFC" }
|
|
22
|
+
# puts "Available quantity: #{hdfc.available_qty}" if hdfc
|
|
23
|
+
#
|
|
24
|
+
# @example Calculate portfolio value
|
|
25
|
+
# holdings = DhanHQ::Models::Holding.all
|
|
26
|
+
# total_value = holdings.sum { |h| h.total_qty * h.avg_cost_price }
|
|
27
|
+
# puts "Portfolio value: ₹#{total_value}"
|
|
28
|
+
#
|
|
6
29
|
class Holding < BaseModel
|
|
7
30
|
# Base path used when retrieving holdings.
|
|
8
31
|
HTTP_PATH = "/v2/holdings"
|
|
@@ -12,17 +35,51 @@ module DhanHQ
|
|
|
12
35
|
|
|
13
36
|
class << self
|
|
14
37
|
##
|
|
15
|
-
# Provides a
|
|
38
|
+
# Provides a shared instance of the Holdings resource.
|
|
16
39
|
#
|
|
17
|
-
# @return [DhanHQ::Resources::Holdings]
|
|
40
|
+
# @return [DhanHQ::Resources::Holdings] The Holdings resource client instance
|
|
18
41
|
def resource
|
|
19
42
|
@resource ||= DhanHQ::Resources::Holdings.new
|
|
20
43
|
end
|
|
21
44
|
|
|
22
45
|
##
|
|
23
|
-
#
|
|
46
|
+
# Retrieves all holdings bought/sold in previous trading sessions.
|
|
24
47
|
#
|
|
25
|
-
#
|
|
48
|
+
# Fetches all T1 (pending delivery) and delivered quantities from your portfolio.
|
|
49
|
+
# Includes information about available quantities for transaction, collateral quantities,
|
|
50
|
+
# and average cost prices for each holding.
|
|
51
|
+
#
|
|
52
|
+
# @return [Array<Holding>] Array of Holding objects. Returns empty array if no holdings exist.
|
|
53
|
+
# Each Holding object contains (keys normalized to snake_case):
|
|
54
|
+
# - **:exchange** [String] Exchange identifier (e.g., "ALL", "NSE", "BSE")
|
|
55
|
+
# - **:trading_symbol** [String] Trading symbol of the security
|
|
56
|
+
# - **:security_id** [String] Exchange standard ID for each scrip
|
|
57
|
+
# - **:isin** [String] Universal standard ID for each scrip (International Securities Identification Number)
|
|
58
|
+
# - **:total_qty** [Integer] Total quantity of the holding
|
|
59
|
+
# - **:dp_qty** [Integer] Quantity delivered in demat account
|
|
60
|
+
# - **:t1_qty** [Integer] Quantity pending delivery in demat account (T+1 settlement)
|
|
61
|
+
# - **:available_qty** [Integer] Quantity available for transaction
|
|
62
|
+
# - **:collateral_qty** [Integer] Quantity placed as collateral with broker
|
|
63
|
+
# - **:avg_cost_price** [Float] Average buy price of total quantity
|
|
64
|
+
#
|
|
65
|
+
# @example Fetch all holdings
|
|
66
|
+
# holdings = DhanHQ::Models::Holding.all
|
|
67
|
+
# holdings.each do |holding|
|
|
68
|
+
# puts "#{holding.trading_symbol}: #{holding.total_qty} @ ₹#{holding.avg_cost_price}"
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# @example Filter holdings by available quantity
|
|
72
|
+
# holdings = DhanHQ::Models::Holding.all
|
|
73
|
+
# sellable = holdings.select { |h| h.available_qty > 0 }
|
|
74
|
+
# puts "You can sell #{sellable.size} holdings"
|
|
75
|
+
#
|
|
76
|
+
# @example Calculate total investment
|
|
77
|
+
# holdings = DhanHQ::Models::Holding.all
|
|
78
|
+
# total_investment = holdings.sum { |h| h.total_qty * h.avg_cost_price }
|
|
79
|
+
# puts "Total investment: ₹#{total_investment}"
|
|
80
|
+
#
|
|
81
|
+
# @note This is a GET request with no body parameters required
|
|
82
|
+
# @note Returns empty array if no holdings exist or if {DhanHQ::NoHoldingsError} is raised
|
|
26
83
|
def all
|
|
27
84
|
response = resource.all
|
|
28
85
|
return [] unless response.is_a?(Array)
|
|
@@ -34,9 +91,28 @@ module DhanHQ
|
|
|
34
91
|
end
|
|
35
92
|
|
|
36
93
|
##
|
|
37
|
-
#
|
|
94
|
+
# Converts the Holding model attributes to a hash representation.
|
|
95
|
+
#
|
|
96
|
+
# Useful for serialization, logging, or passing holding data to other methods.
|
|
97
|
+
#
|
|
98
|
+
# @return [Hash{Symbol => String, Integer, Float}] Hash representation of the Holding model containing:
|
|
99
|
+
# - **:exchange** [String] Exchange identifier
|
|
100
|
+
# - **:trading_symbol** [String] Trading symbol
|
|
101
|
+
# - **:security_id** [String] Security ID
|
|
102
|
+
# - **:isin** [String] ISIN code
|
|
103
|
+
# - **:total_qty** [Integer] Total quantity
|
|
104
|
+
# - **:dp_qty** [Integer] Delivered quantity in demat
|
|
105
|
+
# - **:t1_qty** [Integer] T+1 pending delivery quantity
|
|
106
|
+
# - **:available_qty** [Integer] Available quantity for transaction
|
|
107
|
+
# - **:collateral_qty** [Integer] Quantity placed as collateral
|
|
108
|
+
# - **:avg_cost_price** [Float] Average cost price
|
|
109
|
+
#
|
|
110
|
+
# @example Convert holding to hash
|
|
111
|
+
# holding = DhanHQ::Models::Holding.all.first
|
|
112
|
+
# holding_hash = holding.to_h
|
|
113
|
+
# puts holding_hash[:trading_symbol] # => "HDFC"
|
|
114
|
+
# puts holding_hash[:avg_cost_price] # => 2655.0
|
|
38
115
|
#
|
|
39
|
-
# @return [Hash] Hash representation of the Holding model.
|
|
40
116
|
def to_h
|
|
41
117
|
{
|
|
42
118
|
exchange: exchange,
|
|
@@ -8,13 +8,26 @@ module DhanHQ
|
|
|
8
8
|
##
|
|
9
9
|
# Fetches last traded price (LTP) for this instrument.
|
|
10
10
|
#
|
|
11
|
-
# @return [
|
|
11
|
+
# @return [Float, nil] Last traded price value, or nil if not available
|
|
12
12
|
# @example
|
|
13
13
|
# instrument = DhanHQ::Models::Instrument.find("IDX_I", "NIFTY")
|
|
14
|
-
# instrument.ltp
|
|
14
|
+
# instrument.ltp # => 26053.9
|
|
15
15
|
def ltp
|
|
16
16
|
params = build_market_feed_params
|
|
17
|
-
DhanHQ::Models::MarketFeed.ltp(params)
|
|
17
|
+
response = DhanHQ::Models::MarketFeed.ltp(params)
|
|
18
|
+
|
|
19
|
+
# Extract last_price from nested response structure
|
|
20
|
+
# Response format: {"data" => {"EXCHANGE_SEGMENT" => {"security_id" => {"last_price" => value}}}, "status" => "success"}
|
|
21
|
+
data = response[:data] || response["data"]
|
|
22
|
+
return nil unless data
|
|
23
|
+
|
|
24
|
+
segment_data = data[exchange_segment] || data[exchange_segment.to_sym]
|
|
25
|
+
return nil unless segment_data
|
|
26
|
+
|
|
27
|
+
security_data = segment_data[security_id] || segment_data[security_id.to_s]
|
|
28
|
+
return nil unless security_data
|
|
29
|
+
|
|
30
|
+
security_data[:last_price] || security_data["last_price"]
|
|
18
31
|
end
|
|
19
32
|
|
|
20
33
|
##
|
|
@@ -82,7 +95,7 @@ module DhanHQ
|
|
|
82
95
|
def expiry_list
|
|
83
96
|
params = {
|
|
84
97
|
underlying_scrip: security_id.to_i,
|
|
85
|
-
underlying_seg:
|
|
98
|
+
underlying_seg: underlying_segment_for_options
|
|
86
99
|
}
|
|
87
100
|
DhanHQ::Models::OptionChain.fetch_expiry_list(params)
|
|
88
101
|
end
|
|
@@ -98,7 +111,7 @@ module DhanHQ
|
|
|
98
111
|
def option_chain(expiry:)
|
|
99
112
|
params = {
|
|
100
113
|
underlying_scrip: security_id.to_i,
|
|
101
|
-
underlying_seg:
|
|
114
|
+
underlying_seg: underlying_segment_for_options,
|
|
102
115
|
expiry: expiry
|
|
103
116
|
}
|
|
104
117
|
DhanHQ::Models::OptionChain.fetch(params)
|
|
@@ -136,6 +149,27 @@ module DhanHQ
|
|
|
136
149
|
|
|
137
150
|
params
|
|
138
151
|
end
|
|
152
|
+
|
|
153
|
+
##
|
|
154
|
+
# Determines the correct underlying segment for option chain APIs.
|
|
155
|
+
# Index uses IDX_I; stocks map to NSE_FNO or BSE_FNO by exchange.
|
|
156
|
+
def underlying_segment_for_options
|
|
157
|
+
seg = exchange_segment.to_s
|
|
158
|
+
ins = instrument.to_s
|
|
159
|
+
|
|
160
|
+
# If already a valid underlying seg, return as-is
|
|
161
|
+
return seg if %w[IDX_I NSE_FNO BSE_FNO MCX_FO].include?(seg)
|
|
162
|
+
|
|
163
|
+
# Index detection by instrument kind or segment
|
|
164
|
+
return "IDX_I" if ins == "INDEX" || seg == "IDX_I"
|
|
165
|
+
|
|
166
|
+
# Map equities/stock-related segments to respective FNO
|
|
167
|
+
return "NSE_FNO" if seg.start_with?("NSE")
|
|
168
|
+
return "BSE_FNO" if seg.start_with?("BSE")
|
|
169
|
+
|
|
170
|
+
# Fallback to IDX_I to avoid contract rejection
|
|
171
|
+
"IDX_I"
|
|
172
|
+
end
|
|
139
173
|
end
|
|
140
174
|
end
|
|
141
175
|
end
|
|
@@ -2,45 +2,147 @@
|
|
|
2
2
|
|
|
3
3
|
module DhanHQ
|
|
4
4
|
module Models
|
|
5
|
-
|
|
5
|
+
##
|
|
6
|
+
# Model for managing the trading kill switch feature.
|
|
7
|
+
#
|
|
8
|
+
# The Kill Switch API lets you activate or deactivate the kill switch for your account,
|
|
9
|
+
# which will disable trading for the current trading day. This is a safety feature that
|
|
10
|
+
# can be used to prevent further trading activity when needed.
|
|
11
|
+
#
|
|
12
|
+
# @note **Important**: Before activating the kill switch, you must ensure that all your
|
|
13
|
+
# positions are closed and there are no pending orders in your account. The kill switch
|
|
14
|
+
# will not activate if there are open positions or pending orders.
|
|
15
|
+
#
|
|
16
|
+
# @example Activate kill switch
|
|
17
|
+
# response = DhanHQ::Models::KillSwitch.activate
|
|
18
|
+
# puts response[:kill_switch_status]
|
|
19
|
+
# # => "Kill Switch has been successfully activated"
|
|
20
|
+
#
|
|
21
|
+
# @example Deactivate kill switch
|
|
22
|
+
# response = DhanHQ::Models::KillSwitch.deactivate
|
|
23
|
+
# puts response[:kill_switch_status]
|
|
24
|
+
#
|
|
25
|
+
# @example Update kill switch with custom status
|
|
26
|
+
# response = DhanHQ::Models::KillSwitch.update("ACTIVATE")
|
|
27
|
+
# if response[:kill_switch_status].include?("successfully")
|
|
28
|
+
# puts "Kill switch activated"
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
6
31
|
class KillSwitch < BaseModel
|
|
7
32
|
# Base path used by the kill switch resource.
|
|
8
33
|
HTTP_PATH = "/v2/killswitch"
|
|
9
34
|
|
|
10
35
|
class << self
|
|
11
|
-
|
|
36
|
+
##
|
|
37
|
+
# Provides a shared instance of the KillSwitch resource.
|
|
12
38
|
#
|
|
13
|
-
# @return [DhanHQ::Resources::KillSwitch]
|
|
39
|
+
# @return [DhanHQ::Resources::KillSwitch] The KillSwitch resource client instance
|
|
14
40
|
def resource
|
|
15
41
|
@resource ||= DhanHQ::Resources::KillSwitch.new
|
|
16
42
|
end
|
|
17
43
|
|
|
18
|
-
|
|
44
|
+
##
|
|
45
|
+
# Updates the kill switch status with the specified action.
|
|
46
|
+
#
|
|
47
|
+
# Allows you to set the kill switch to either "ACTIVATE" or "DEACTIVATE" state.
|
|
48
|
+
# The status is passed as a query parameter to the API endpoint.
|
|
49
|
+
#
|
|
50
|
+
# @param status [String] Kill switch action to perform.
|
|
51
|
+
# Valid values: "ACTIVATE", "DEACTIVATE"
|
|
52
|
+
#
|
|
53
|
+
# @return [Hash{Symbol => String}] Response hash containing kill switch operation result.
|
|
54
|
+
# Response structure (keys normalized to snake_case):
|
|
55
|
+
# - **:dhan_client_id** [String] User-specific identification generated by Dhan
|
|
56
|
+
# - **:kill_switch_status** [String] Status message indicating the result of the operation.
|
|
57
|
+
# For activation: "Kill Switch has been successfully activated"
|
|
58
|
+
# For deactivation: Status message for deactivation
|
|
59
|
+
#
|
|
60
|
+
# @example Update kill switch status
|
|
61
|
+
# response = DhanHQ::Models::KillSwitch.update("ACTIVATE")
|
|
62
|
+
# puts response[:kill_switch_status]
|
|
63
|
+
#
|
|
64
|
+
# @example Check if activation was successful
|
|
65
|
+
# response = DhanHQ::Models::KillSwitch.update("ACTIVATE")
|
|
66
|
+
# if response[:kill_switch_status].include?("successfully")
|
|
67
|
+
# puts "Kill switch is now active"
|
|
68
|
+
# end
|
|
19
69
|
#
|
|
20
|
-
# @param status [String]
|
|
21
|
-
# @return [Hash]
|
|
22
70
|
def update(status)
|
|
23
71
|
resource.update(kill_switch_status: status)
|
|
24
72
|
end
|
|
25
73
|
|
|
26
|
-
|
|
74
|
+
##
|
|
75
|
+
# Activates the kill switch for your trading account.
|
|
76
|
+
#
|
|
77
|
+
# Disables trading for the current trading day. All trading operations will be blocked
|
|
78
|
+
# until the kill switch is deactivated. This is a safety feature to prevent further
|
|
79
|
+
# trading activity.
|
|
80
|
+
#
|
|
81
|
+
# @note **Prerequisites**: All positions must be closed and there must be no pending
|
|
82
|
+
# orders in your account before activation. The API will reject the activation request
|
|
83
|
+
# if these conditions are not met.
|
|
84
|
+
#
|
|
85
|
+
# @return [Hash{Symbol => String}] Response hash containing kill switch activation result.
|
|
86
|
+
# Response structure (keys normalized to snake_case):
|
|
87
|
+
# - **:dhan_client_id** [String] User-specific identification generated by Dhan
|
|
88
|
+
# - **:kill_switch_status** [String] Status message, typically:
|
|
89
|
+
# "Kill Switch has been successfully activated"
|
|
90
|
+
#
|
|
91
|
+
# @example Activate kill switch
|
|
92
|
+
# response = DhanHQ::Models::KillSwitch.activate
|
|
93
|
+
# puts response[:kill_switch_status]
|
|
94
|
+
# # => "Kill Switch has been successfully activated"
|
|
95
|
+
#
|
|
96
|
+
# @example Activate with error handling
|
|
97
|
+
# begin
|
|
98
|
+
# response = DhanHQ::Models::KillSwitch.activate
|
|
99
|
+
# if response[:kill_switch_status].include?("successfully")
|
|
100
|
+
# puts "✓ Kill switch activated - trading disabled"
|
|
101
|
+
# end
|
|
102
|
+
# rescue => e
|
|
103
|
+
# puts "Failed to activate kill switch: #{e.message}"
|
|
104
|
+
# puts "Ensure all positions are closed and no orders are pending"
|
|
105
|
+
# end
|
|
27
106
|
#
|
|
28
|
-
# @return [Hash]
|
|
29
107
|
def activate
|
|
30
108
|
update("ACTIVATE")
|
|
31
109
|
end
|
|
32
110
|
|
|
33
|
-
|
|
111
|
+
##
|
|
112
|
+
# Deactivates the kill switch for your trading account.
|
|
113
|
+
#
|
|
114
|
+
# Re-enables trading for your account. After deactivation, you can resume placing
|
|
115
|
+
# orders and executing trades normally.
|
|
116
|
+
#
|
|
117
|
+
# @return [Hash{Symbol => String}] Response hash containing kill switch deactivation result.
|
|
118
|
+
# Response structure (keys normalized to snake_case):
|
|
119
|
+
# - **:dhan_client_id** [String] User-specific identification generated by Dhan
|
|
120
|
+
# - **:kill_switch_status** [String] Status message indicating deactivation result
|
|
121
|
+
#
|
|
122
|
+
# @example Deactivate kill switch
|
|
123
|
+
# response = DhanHQ::Models::KillSwitch.deactivate
|
|
124
|
+
# puts response[:kill_switch_status]
|
|
125
|
+
#
|
|
126
|
+
# @example Re-enable trading
|
|
127
|
+
# response = DhanHQ::Models::KillSwitch.deactivate
|
|
128
|
+
# if response[:kill_switch_status].include?("successfully")
|
|
129
|
+
# puts "✓ Trading re-enabled"
|
|
130
|
+
# end
|
|
34
131
|
#
|
|
35
|
-
# @return [Hash]
|
|
36
132
|
def deactivate
|
|
37
133
|
update("DEACTIVATE")
|
|
38
134
|
end
|
|
39
135
|
end
|
|
40
136
|
|
|
137
|
+
##
|
|
41
138
|
# No explicit validation contract is required for kill switch updates.
|
|
42
139
|
#
|
|
43
|
-
#
|
|
140
|
+
# Kill switch operations are simple status updates that don't require complex validation.
|
|
141
|
+
# The API handles validation server-side.
|
|
142
|
+
#
|
|
143
|
+
# @return [nil] Always returns nil as no validation contract is needed
|
|
144
|
+
#
|
|
145
|
+
# @api private
|
|
44
146
|
def validation_contract
|
|
45
147
|
nil
|
|
46
148
|
end
|