DhanHQ 2.1.7 → 2.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -0
  3. data/examples/comprehensive_websocket_examples.rb +0 -0
  4. data/examples/instrument_finder_test.rb +0 -0
  5. data/examples/live_order_updates.rb +1 -1
  6. data/examples/market_depth_example.rb +2 -2
  7. data/examples/order_update_example.rb +0 -0
  8. data/examples/trading_fields_example.rb +1 -1
  9. data/lib/DhanHQ/client.rb +2 -1
  10. data/lib/DhanHQ/contracts/expired_options_data_contract.rb +6 -6
  11. data/lib/DhanHQ/core/base_model.rb +9 -1
  12. data/lib/DhanHQ/models/edis.rb +150 -14
  13. data/lib/DhanHQ/models/expired_options_data.rb +307 -82
  14. data/lib/DhanHQ/models/forever_order.rb +261 -22
  15. data/lib/DhanHQ/models/funds.rb +76 -10
  16. data/lib/DhanHQ/models/historical_data.rb +148 -31
  17. data/lib/DhanHQ/models/holding.rb +82 -6
  18. data/lib/DhanHQ/models/instrument_helpers.rb +39 -5
  19. data/lib/DhanHQ/models/kill_switch.rb +113 -11
  20. data/lib/DhanHQ/models/ledger_entry.rb +101 -13
  21. data/lib/DhanHQ/models/margin.rb +133 -8
  22. data/lib/DhanHQ/models/market_feed.rb +181 -17
  23. data/lib/DhanHQ/models/option_chain.rb +184 -12
  24. data/lib/DhanHQ/models/order.rb +399 -34
  25. data/lib/DhanHQ/models/position.rb +161 -10
  26. data/lib/DhanHQ/models/profile.rb +103 -7
  27. data/lib/DhanHQ/models/super_order.rb +275 -15
  28. data/lib/DhanHQ/models/trade.rb +279 -26
  29. data/lib/DhanHQ/rate_limiter.rb +78 -23
  30. data/lib/DhanHQ/resources/expired_options_data.rb +1 -1
  31. data/lib/DhanHQ/version.rb +1 -1
  32. data/lib/DhanHQ/ws/market_depth/client.rb +3 -1
  33. data/lib/DhanHQ/ws/orders/client.rb +2 -1
  34. data/lib/DhanHQ/ws/orders/connection.rb +0 -3
  35. data/lib/DhanHQ/ws/orders.rb +2 -1
  36. metadata +1 -1
@@ -3,72 +3,189 @@
3
3
  module DhanHQ
4
4
  module Models
5
5
  ##
6
- # Model class for fetching Daily & Intraday data
7
- # The default response is a Hash with arrays of "open", "high", "low", etc.
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
- # Typically, we won't define a single resource path,
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
- # Provide a **shared instance** of the `HistoricalData` resource
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
- # Daily historical data
30
- # @param params [Hash] The request parameters, e.g.:
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
- # @return [HashWithIndifferentAccess]
40
- # {
41
- # open: [...], high: [...], low: [...], close: [...],
42
- # volume: [...], timestamp: [...]
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
- # Intraday historical data
53
- # @param params [Hash], e.g.:
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
- # @return [HashWithIndifferentAccess]
63
- # { open: [...], high: [...], low: [...], close: [...],
64
- # volume: [...], timestamp: [...] }
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
- # For a read-only type of data, we might skip validations or specify a contract if needed
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 **shared instance** of the `Holdings` resource.
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
- # Fetch all holdings.
46
+ # Retrieves all holdings bought/sold in previous trading sessions.
24
47
  #
25
- # @return [Array<Holding>]
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
- # Convert model attributes to a hash.
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 [Hash] Market feed LTP response
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: exchange_segment
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: exchange_segment,
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
- # Model helper to toggle the trading kill switch.
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
- # Shared resource for kill switch operations.
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
- # Updates the kill switch status.
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
- # Activates the kill switch for the account.
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
- # Deactivates the kill switch for the account.
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
- # @return [nil]
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