DhanHQ 2.1.8 → 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 +50 -0
- 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/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/resources/expired_options_data.rb +1 -1
- data/lib/DhanHQ/version.rb +1 -1
- data/lib/DhanHQ/ws/orders/client.rb +2 -1
- data/lib/DhanHQ/ws/orders.rb +2 -1
- metadata +1 -1
data/lib/DhanHQ/models/order.rb
CHANGED
|
@@ -6,7 +6,45 @@ require_relative "../contracts/modify_order_contract"
|
|
|
6
6
|
module DhanHQ
|
|
7
7
|
# ActiveRecord-style models built on top of the REST resources.
|
|
8
8
|
module Models
|
|
9
|
-
|
|
9
|
+
##
|
|
10
|
+
# Model for managing equity and F&O orders.
|
|
11
|
+
#
|
|
12
|
+
# The Order Management API lets you place new orders, cancel or modify pending orders,
|
|
13
|
+
# and retrieve order status, trade status, order book, and trade book. This model provides
|
|
14
|
+
# an ActiveRecord-style interface for order management operations.
|
|
15
|
+
#
|
|
16
|
+
# @note **Static IP Whitelisting**: Order placement, modification, and cancellation APIs
|
|
17
|
+
# require Static IP whitelisting. Ensure your IP is whitelisted before using these endpoints.
|
|
18
|
+
#
|
|
19
|
+
# @example Place a new market order
|
|
20
|
+
# order = DhanHQ::Models::Order.place(
|
|
21
|
+
# dhan_client_id: "1000000003",
|
|
22
|
+
# transaction_type: "BUY",
|
|
23
|
+
# exchange_segment: "NSE_EQ",
|
|
24
|
+
# product_type: "INTRADAY",
|
|
25
|
+
# order_type: "MARKET",
|
|
26
|
+
# validity: "DAY",
|
|
27
|
+
# security_id: "11536",
|
|
28
|
+
# quantity: 5
|
|
29
|
+
# )
|
|
30
|
+
# puts "Order placed: #{order.order_id} - #{order.order_status}"
|
|
31
|
+
#
|
|
32
|
+
# @example Modify an existing order
|
|
33
|
+
# order = DhanHQ::Models::Order.find("112111182045")
|
|
34
|
+
# order.modify(price: 3345.8, quantity: 40)
|
|
35
|
+
# puts "Order modified: #{order.order_status}"
|
|
36
|
+
#
|
|
37
|
+
# @example Cancel an order
|
|
38
|
+
# order = DhanHQ::Models::Order.find("112111182045")
|
|
39
|
+
# if order.cancel
|
|
40
|
+
# puts "Order cancelled successfully"
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# @example Fetch all orders for the day
|
|
44
|
+
# orders = DhanHQ::Models::Order.all
|
|
45
|
+
# pending_orders = orders.select { |o| o.order_status == "PENDING" }
|
|
46
|
+
# puts "Pending orders: #{pending_orders.count}"
|
|
47
|
+
#
|
|
10
48
|
class Order < BaseModel
|
|
11
49
|
# Attributes eligible for modification requests.
|
|
12
50
|
MODIFIABLE_FIELDS = %i[
|
|
@@ -35,17 +73,36 @@ module DhanHQ
|
|
|
35
73
|
|
|
36
74
|
class << self
|
|
37
75
|
##
|
|
38
|
-
# Provides a
|
|
76
|
+
# Provides a shared instance of the Orders resource.
|
|
39
77
|
#
|
|
40
|
-
# @return [DhanHQ::Resources::Orders]
|
|
78
|
+
# @return [DhanHQ::Resources::Orders] The Orders resource client instance
|
|
41
79
|
def resource
|
|
42
80
|
@resource ||= DhanHQ::Resources::Orders.new
|
|
43
81
|
end
|
|
44
82
|
|
|
45
83
|
##
|
|
46
|
-
#
|
|
84
|
+
# Retrieves all orders placed during the current trading day.
|
|
85
|
+
#
|
|
86
|
+
# Fetches an array of all orders requested in a day with their last updated status.
|
|
87
|
+
# Returns empty array if no orders are found or if the response is not in the expected format.
|
|
88
|
+
#
|
|
89
|
+
# @return [Array<Order>] Array of Order objects. Returns empty array if no orders exist.
|
|
90
|
+
# Each Order object contains comprehensive order details including status, timestamps,
|
|
91
|
+
# quantities, prices, and error information if applicable.
|
|
92
|
+
#
|
|
93
|
+
# @example Fetch all orders for the day
|
|
94
|
+
# orders = DhanHQ::Models::Order.all
|
|
95
|
+
# puts "Total orders: #{orders.count}"
|
|
96
|
+
# orders.each do |order|
|
|
97
|
+
# puts "#{order.order_id}: #{order.order_status} - #{order.transaction_type} #{order.quantity}"
|
|
98
|
+
# end
|
|
99
|
+
#
|
|
100
|
+
# @example Filter orders by status
|
|
101
|
+
# orders = DhanHQ::Models::Order.all
|
|
102
|
+
# pending = orders.select { |o| o.order_status == "PENDING" }
|
|
103
|
+
# traded = orders.select { |o| o.order_status == "TRADED" }
|
|
104
|
+
# puts "Pending: #{pending.count}, Traded: #{traded.count}"
|
|
47
105
|
#
|
|
48
|
-
# @return [Array<Order>]
|
|
49
106
|
def all
|
|
50
107
|
response = resource.all
|
|
51
108
|
return [] unless response.is_a?(Array)
|
|
@@ -54,10 +111,61 @@ module DhanHQ
|
|
|
54
111
|
end
|
|
55
112
|
|
|
56
113
|
##
|
|
57
|
-
#
|
|
114
|
+
# Retrieves the details and status of a specific order by order ID.
|
|
115
|
+
#
|
|
116
|
+
# Fetches comprehensive order information including all order parameters, status,
|
|
117
|
+
# timestamps, trade information, and error details if the order was rejected.
|
|
118
|
+
#
|
|
119
|
+
# @param order_id [String] Order-specific identification generated by Dhan
|
|
120
|
+
#
|
|
121
|
+
# @return [Order, nil] Order object with complete details if found, nil otherwise.
|
|
122
|
+
# Response structure includes (keys normalized to snake_case):
|
|
123
|
+
# - **:dhan_client_id** [String] User-specific identification generated by Dhan
|
|
124
|
+
# - **:order_id** [String] Order-specific identification generated by Dhan
|
|
125
|
+
# - **:correlation_id** [String] User/partner generated ID for tracking
|
|
126
|
+
# - **:order_status** [String] Last updated status of the order.
|
|
127
|
+
# Valid values: "TRANSIT", "PENDING", "REJECTED", "CANCELLED", "PART_TRADED",
|
|
128
|
+
# "TRADED", "EXPIRED"
|
|
129
|
+
# - **:transaction_type** [String] The trading side of transaction. "BUY" or "SELL"
|
|
130
|
+
# - **:exchange_segment** [String] Exchange segment of instrument
|
|
131
|
+
# - **:product_type** [String] Product type. Valid values: "CNC", "INTRADAY",
|
|
132
|
+
# "MARGIN", "MTF", "CO", "BO"
|
|
133
|
+
# - **:order_type** [String] Order type. Valid values: "LIMIT", "MARKET",
|
|
134
|
+
# "STOP_LOSS", "STOP_LOSS_MARKET"
|
|
135
|
+
# - **:validity** [String] Validity of order. "DAY" or "IOC"
|
|
136
|
+
# - **:trading_symbol** [String] Trading symbol of the instrument
|
|
137
|
+
# - **:security_id** [String] Exchange standard ID for each scrip
|
|
138
|
+
# - **:quantity** [Integer] Number of shares for the order
|
|
139
|
+
# - **:disclosed_quantity** [Integer] Number of shares visible
|
|
140
|
+
# - **:price** [Float] Price at which order is placed
|
|
141
|
+
# - **:trigger_price** [Float] Price at which order is triggered (for SL-M, SL-L, CO & BO)
|
|
142
|
+
# - **:after_market_order** [Boolean] Whether the order placed is an AMO
|
|
143
|
+
# - **:bo_profit_value** [Float] Bracket Order Target Price change
|
|
144
|
+
# - **:bo_stop_loss_value** [Float] Bracket Order Stop Loss Price change
|
|
145
|
+
# - **:leg_name** [String] Leg identification in case of BO.
|
|
146
|
+
# Valid values: "ENTRY_LEG", "TARGET_LEG", "STOP_LOSS_LEG"
|
|
147
|
+
# - **:create_time** [String] Time at which the order is created
|
|
148
|
+
# - **:update_time** [String] Time at which the last activity happened
|
|
149
|
+
# - **:exchange_time** [String] Time at which order reached at exchange
|
|
150
|
+
# - **:drv_expiry_date** [String, nil] For F&O, expiry date of contract
|
|
151
|
+
# - **:drv_option_type** [String, nil] Type of Option. "CALL" or "PUT"
|
|
152
|
+
# - **:drv_strike_price** [Float] For Options, Strike Price
|
|
153
|
+
# - **:oms_error_code** [String, nil] Error code if the order is rejected or failed
|
|
154
|
+
# - **:oms_error_description** [String, nil] Description of error if the order is rejected
|
|
155
|
+
# - **:algo_id** [String] Exchange Algo ID for Dhan
|
|
156
|
+
# - **:remaining_quantity** [Integer] Quantity pending at the exchange to be traded
|
|
157
|
+
# (quantity - filled_qty)
|
|
158
|
+
# - **:average_traded_price** [Float] Average price at which order is traded
|
|
159
|
+
# - **:filled_qty** [Integer] Quantity of order traded on Exchange
|
|
160
|
+
#
|
|
161
|
+
# @example Fetch order details
|
|
162
|
+
# order = DhanHQ::Models::Order.find("112111182198")
|
|
163
|
+
# if order
|
|
164
|
+
# puts "Status: #{order.order_status}"
|
|
165
|
+
# puts "Quantity: #{order.quantity}, Filled: #{order.filled_qty}"
|
|
166
|
+
# puts "Remaining: #{order.remaining_quantity}"
|
|
167
|
+
# end
|
|
58
168
|
#
|
|
59
|
-
# @param order_id [String]
|
|
60
|
-
# @return [Order, nil]
|
|
61
169
|
def find(order_id)
|
|
62
170
|
response = resource.find(order_id)
|
|
63
171
|
return nil unless response.is_a?(Hash) || (response.is_a?(Array) && response.any?)
|
|
@@ -67,10 +175,24 @@ module DhanHQ
|
|
|
67
175
|
end
|
|
68
176
|
|
|
69
177
|
##
|
|
70
|
-
#
|
|
178
|
+
# Retrieves the status of an order using a user-supplied correlation ID.
|
|
179
|
+
#
|
|
180
|
+
# Useful when you need to track orders using your own correlation ID instead of
|
|
181
|
+
# the Dhan-generated order ID. This is helpful if you missed the order ID due to
|
|
182
|
+
# unforeseen reasons but have your correlation ID stored.
|
|
183
|
+
#
|
|
184
|
+
# @param correlation_id [String] The user/partner generated ID for tracking
|
|
185
|
+
#
|
|
186
|
+
# @return [Order, nil] Order object with complete details if found, nil otherwise.
|
|
187
|
+
# Response structure is the same as {find}.
|
|
188
|
+
#
|
|
189
|
+
# @example Fetch order by correlation ID
|
|
190
|
+
# order = DhanHQ::Models::Order.find_by_correlation("123abc678")
|
|
191
|
+
# if order
|
|
192
|
+
# puts "Order ID: #{order.order_id}"
|
|
193
|
+
# puts "Status: #{order.order_status}"
|
|
194
|
+
# end
|
|
71
195
|
#
|
|
72
|
-
# @param correlation_id [String]
|
|
73
|
-
# @return [Order, nil]
|
|
74
196
|
def find_by_correlation(correlation_id)
|
|
75
197
|
response = resource.by_correlation(correlation_id)
|
|
76
198
|
return nil unless response[:status] == "success"
|
|
@@ -78,12 +200,94 @@ module DhanHQ
|
|
|
78
200
|
new(response, skip_validation: true)
|
|
79
201
|
end
|
|
80
202
|
|
|
81
|
-
|
|
203
|
+
##
|
|
204
|
+
# Places a new order.
|
|
205
|
+
#
|
|
206
|
+
# Validates order parameters and places a new order via the API. After successful
|
|
207
|
+
# placement, fetches and returns the complete order details including the generated
|
|
208
|
+
# order ID and current status.
|
|
209
|
+
#
|
|
210
|
+
# @param params [Hash{Symbol => String, Integer, Float, Boolean}] Order placement parameters
|
|
211
|
+
# @option params [String] :dhan_client_id (required) User-specific identification generated by Dhan.
|
|
212
|
+
# Must be explicitly provided in the params hash
|
|
213
|
+
# @option params [String] :correlation_id (optional) User/partner generated ID for tracking.
|
|
214
|
+
# Max length: 25 characters
|
|
215
|
+
# @option params [String] :transaction_type (required) The trading side of transaction.
|
|
216
|
+
# Valid values: "BUY", "SELL"
|
|
217
|
+
# @option params [String] :exchange_segment (required) Exchange and segment of instrument.
|
|
218
|
+
# Valid values: See {DhanHQ::Constants::EXCHANGE_SEGMENTS}
|
|
219
|
+
# @option params [String] :product_type (required) Product type.
|
|
220
|
+
# Valid values: "CNC", "INTRADAY", "MARGIN", "MTF", "CO", "BO"
|
|
221
|
+
# @option params [String] :order_type (required) Order type.
|
|
222
|
+
# Valid values: "LIMIT", "MARKET", "STOP_LOSS", "STOP_LOSS_MARKET"
|
|
223
|
+
# @option params [String] :validity (required) Validity of order for execution.
|
|
224
|
+
# Valid values: "DAY", "IOC"
|
|
225
|
+
# @option params [String] :security_id (required) Exchange standard ID for each scrip
|
|
226
|
+
# @option params [Integer] :quantity (required) Number of shares for the order. Must be greater than 0
|
|
227
|
+
# @option params [Integer] :disclosed_quantity (optional) Number of shares visible to market.
|
|
228
|
+
# Keep more than 30% of quantity if providing. Must be >= 0 if provided
|
|
229
|
+
# @option params [Float] :price (conditionally required) Price at which order is placed.
|
|
230
|
+
# Required for LIMIT orders. Must be > 0 if provided
|
|
231
|
+
# @option params [Float] :trigger_price (conditionally required) Price at which the order is triggered.
|
|
232
|
+
# Required for STOP_LOSS and STOP_LOSS_MARKET order types. Must be > 0 if provided
|
|
233
|
+
# @option params [Boolean] :after_market_order (optional) Flag for orders placed after market hours
|
|
234
|
+
# @option params [String] :amo_time (conditionally required) Timing to place the after market order.
|
|
235
|
+
# Required when after_market_order is true.
|
|
236
|
+
# Valid values: "PRE_OPEN", "OPEN", "OPEN_30", "OPEN_60"
|
|
237
|
+
# @option params [Float] :bo_profit_value (conditionally required) Bracket Order Target Price change.
|
|
238
|
+
# Required for BO product type. Must be > 0 if provided
|
|
239
|
+
# @option params [Float] :bo_stop_loss_value (conditionally required) Bracket Order Stop Loss Price change.
|
|
240
|
+
# Required for BO product type. Must be > 0 if provided
|
|
82
241
|
#
|
|
83
|
-
# @
|
|
84
|
-
#
|
|
242
|
+
# @return [Order, nil] Order object with complete details if placement succeeds, nil otherwise.
|
|
243
|
+
# The order object includes the generated :order_id and current :order_status.
|
|
244
|
+
#
|
|
245
|
+
# @example Place a market order
|
|
246
|
+
# order = DhanHQ::Models::Order.place(
|
|
247
|
+
# dhan_client_id: "1000000003",
|
|
248
|
+
# transaction_type: "BUY",
|
|
249
|
+
# exchange_segment: "NSE_EQ",
|
|
250
|
+
# product_type: "INTRADAY",
|
|
251
|
+
# order_type: "MARKET",
|
|
252
|
+
# validity: "DAY",
|
|
253
|
+
# security_id: "11536",
|
|
254
|
+
# quantity: 5
|
|
255
|
+
# )
|
|
256
|
+
# puts "Order ID: #{order.order_id}"
|
|
257
|
+
# puts "Status: #{order.order_status}"
|
|
258
|
+
#
|
|
259
|
+
# @example Place a limit order
|
|
260
|
+
# order = DhanHQ::Models::Order.place(
|
|
261
|
+
# dhan_client_id: "1000000003",
|
|
262
|
+
# transaction_type: "BUY",
|
|
263
|
+
# exchange_segment: "NSE_EQ",
|
|
264
|
+
# product_type: "CNC",
|
|
265
|
+
# order_type: "LIMIT",
|
|
266
|
+
# validity: "DAY",
|
|
267
|
+
# security_id: "11536",
|
|
268
|
+
# quantity: 10,
|
|
269
|
+
# price: 1500.0
|
|
270
|
+
# )
|
|
271
|
+
#
|
|
272
|
+
# @example Place a stop-loss order
|
|
273
|
+
# order = DhanHQ::Models::Order.place(
|
|
274
|
+
# dhan_client_id: "1000000003",
|
|
275
|
+
# transaction_type: "SELL",
|
|
276
|
+
# exchange_segment: "NSE_EQ",
|
|
277
|
+
# product_type: "INTRADAY",
|
|
278
|
+
# order_type: "STOP_LOSS",
|
|
279
|
+
# validity: "DAY",
|
|
280
|
+
# security_id: "11536",
|
|
281
|
+
# quantity: 5,
|
|
282
|
+
# price: 1480.0,
|
|
283
|
+
# trigger_price: 1490.0
|
|
284
|
+
# )
|
|
285
|
+
#
|
|
286
|
+
# @raise [DhanHQ::ValidationError] If validation fails for any parameter
|
|
85
287
|
def place(params)
|
|
86
288
|
normalized_params = snake_case(params)
|
|
289
|
+
# Auto-inject dhan_client_id from configuration if not provided
|
|
290
|
+
normalized_params[:dhan_client_id] ||= DhanHQ.configuration.client_id if DhanHQ.configuration.client_id
|
|
87
291
|
validate_params!(normalized_params, DhanHQ::Contracts::PlaceOrderContract)
|
|
88
292
|
|
|
89
293
|
response = resource.create(camelize_keys(normalized_params))
|
|
@@ -94,11 +298,29 @@ module DhanHQ
|
|
|
94
298
|
end
|
|
95
299
|
|
|
96
300
|
##
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
#
|
|
301
|
+
# ActiveRecord-style create method.
|
|
302
|
+
#
|
|
303
|
+
# Creates a new Order instance, validates it, and saves it. This provides an
|
|
304
|
+
# ActiveRecord-like interface: `Order.create(params)` or `Order.new(params).save`.
|
|
305
|
+
#
|
|
306
|
+
# @param params [Hash{Symbol => String, Integer, Float, Boolean}] Order creation parameters.
|
|
307
|
+
# See {place} for parameter details.
|
|
308
|
+
#
|
|
309
|
+
# @return [Order] Order instance. Note that validation failures may result in an
|
|
310
|
+
# invalid order that couldn't be saved.
|
|
311
|
+
#
|
|
312
|
+
# @example Create order using AR-style method
|
|
313
|
+
# order = DhanHQ::Models::Order.create(
|
|
314
|
+
# dhan_client_id: "1000000003",
|
|
315
|
+
# transaction_type: "BUY",
|
|
316
|
+
# exchange_segment: "NSE_EQ",
|
|
317
|
+
# product_type: "INTRADAY",
|
|
318
|
+
# order_type: "MARKET",
|
|
319
|
+
# validity: "DAY",
|
|
320
|
+
# security_id: "11536",
|
|
321
|
+
# quantity: 5
|
|
322
|
+
# )
|
|
100
323
|
#
|
|
101
|
-
# For the typical usage "Order.new(...).save", we rely on #save below.
|
|
102
324
|
def create(params)
|
|
103
325
|
order = new(params) # build it
|
|
104
326
|
return order unless order.valid? # run place order contract?
|
|
@@ -108,10 +330,39 @@ module DhanHQ
|
|
|
108
330
|
end
|
|
109
331
|
end
|
|
110
332
|
|
|
111
|
-
|
|
333
|
+
##
|
|
334
|
+
# Modifies a pending order in the orderbook.
|
|
335
|
+
#
|
|
336
|
+
# Allows modification of price, quantity, order type, and validity for pending orders.
|
|
337
|
+
# The method preserves existing attributes and only updates the fields specified in
|
|
338
|
+
# `new_params`. Only modifiable fields are included in the update request.
|
|
339
|
+
#
|
|
340
|
+
# @param new_params [Hash{Symbol => String, Integer, Float}] Fields to modify.
|
|
341
|
+
# Only modifiable fields are accepted:
|
|
342
|
+
# @option new_params [String] :order_type (optional) New order type.
|
|
343
|
+
# Valid values: "LIMIT", "MARKET", "STOP_LOSS", "STOP_LOSS_MARKET"
|
|
344
|
+
# @option new_params [Integer] :quantity (optional) New quantity to modify
|
|
345
|
+
# @option new_params [Float] :price (optional) New price to modify
|
|
346
|
+
# @option new_params [Float] :trigger_price (optional) New trigger price for SL-M and SL-L orders
|
|
347
|
+
# @option new_params [Integer] :disclosed_quantity (optional) New disclosed quantity
|
|
348
|
+
# @option new_params [String] :validity (optional) New validity. "DAY" or "IOC"
|
|
349
|
+
# @option new_params [String] :leg_name (optional) Leg identification for BO & CO orders.
|
|
350
|
+
# Valid values: "ENTRY_LEG", "TARGET_LEG", "STOP_LOSS_LEG"
|
|
351
|
+
#
|
|
352
|
+
# @return [Order, ErrorObject] Updated Order object on success, ErrorObject on failure.
|
|
353
|
+
# The order's attributes are updated with the latest values from the API response.
|
|
112
354
|
#
|
|
113
|
-
# @
|
|
114
|
-
#
|
|
355
|
+
# @example Modify order price and quantity
|
|
356
|
+
# order = DhanHQ::Models::Order.find("112111182045")
|
|
357
|
+
# order.modify(price: 3345.8, quantity: 40)
|
|
358
|
+
# puts "Modified: #{order.order_status}"
|
|
359
|
+
#
|
|
360
|
+
# @example Modify order validity
|
|
361
|
+
# order = DhanHQ::Models::Order.find("112111182045")
|
|
362
|
+
# order.modify(validity: "IOC")
|
|
363
|
+
#
|
|
364
|
+
# @raise [RuntimeError] If order ID is missing
|
|
365
|
+
# @raise [DhanHQ::ValidationError] If validation fails for any parameter
|
|
115
366
|
def modify(new_params)
|
|
116
367
|
raise "Order ID is required to modify an order" unless id
|
|
117
368
|
|
|
@@ -138,9 +389,23 @@ module DhanHQ
|
|
|
138
389
|
self
|
|
139
390
|
end
|
|
140
391
|
|
|
141
|
-
|
|
392
|
+
##
|
|
393
|
+
# Cancels a pending order in the orderbook.
|
|
142
394
|
#
|
|
143
|
-
#
|
|
395
|
+
# Cancels an existing order using its order ID. Returns true if the cancellation
|
|
396
|
+
# was successful (order status becomes "CANCELLED").
|
|
397
|
+
#
|
|
398
|
+
# @return [Boolean] true if cancellation succeeds, false otherwise
|
|
399
|
+
#
|
|
400
|
+
# @example Cancel a pending order
|
|
401
|
+
# order = DhanHQ::Models::Order.find("112111182045")
|
|
402
|
+
# if order.cancel
|
|
403
|
+
# puts "Order cancelled successfully"
|
|
404
|
+
# else
|
|
405
|
+
# puts "Failed to cancel order"
|
|
406
|
+
# end
|
|
407
|
+
#
|
|
408
|
+
# @raise [RuntimeError] If order ID is missing
|
|
144
409
|
def cancel
|
|
145
410
|
raise "Order ID is required to cancel an order" unless id
|
|
146
411
|
|
|
@@ -148,9 +413,21 @@ module DhanHQ
|
|
|
148
413
|
response["orderStatus"] == "CANCELLED"
|
|
149
414
|
end
|
|
150
415
|
|
|
151
|
-
|
|
416
|
+
##
|
|
417
|
+
# Fetches the latest details and status of the order.
|
|
152
418
|
#
|
|
153
|
-
#
|
|
419
|
+
# Refreshes the order object with the most current information from the API,
|
|
420
|
+
# including updated status, trade information, and any other changes.
|
|
421
|
+
#
|
|
422
|
+
# @return [Order, nil] Updated Order object with latest details, nil if order not found
|
|
423
|
+
#
|
|
424
|
+
# @example Refresh order status
|
|
425
|
+
# order = DhanHQ::Models::Order.find("112111182198")
|
|
426
|
+
# order.refresh
|
|
427
|
+
# puts "Updated status: #{order.order_status}"
|
|
428
|
+
# puts "Filled: #{order.filled_qty}/#{order.quantity}"
|
|
429
|
+
#
|
|
430
|
+
# @raise [RuntimeError] If order ID is missing
|
|
154
431
|
def refresh
|
|
155
432
|
raise "Order ID is required to refresh an order" unless id
|
|
156
433
|
|
|
@@ -158,20 +435,56 @@ module DhanHQ
|
|
|
158
435
|
end
|
|
159
436
|
|
|
160
437
|
##
|
|
161
|
-
#
|
|
438
|
+
# Checks if this is a new (unsaved) order record.
|
|
439
|
+
#
|
|
440
|
+
# Determines whether the order has been saved to the API or is a new instance
|
|
441
|
+
# that hasn't been placed yet. Used internally to decide between create and update operations.
|
|
442
|
+
#
|
|
443
|
+
# @return [Boolean] true if order_id is nil or empty (new record), false otherwise
|
|
444
|
+
#
|
|
445
|
+
# @api private
|
|
162
446
|
def new_record?
|
|
163
447
|
order_id.nil? || order_id.to_s.empty?
|
|
164
448
|
end
|
|
165
449
|
|
|
166
450
|
##
|
|
167
|
-
#
|
|
451
|
+
# Returns the order ID used for resource calls.
|
|
452
|
+
#
|
|
453
|
+
# Provides a consistent identifier method for API operations. This is an alias
|
|
454
|
+
# for `order_id` that follows ActiveRecord conventions.
|
|
455
|
+
#
|
|
456
|
+
# @return [String, nil] Order ID if present, nil otherwise
|
|
457
|
+
#
|
|
458
|
+
# @api private
|
|
168
459
|
def id
|
|
169
460
|
order_id
|
|
170
461
|
end
|
|
171
462
|
|
|
172
463
|
##
|
|
173
|
-
#
|
|
174
|
-
#
|
|
464
|
+
# Saves the order (places new or modifies existing).
|
|
465
|
+
#
|
|
466
|
+
# For new records (no order_id), places a new order via the API.
|
|
467
|
+
# For existing records (has order_id), modifies the order via the API.
|
|
468
|
+
# The order's attributes are updated with the API response after successful save.
|
|
469
|
+
#
|
|
470
|
+
# @return [Boolean] true if save succeeds, false otherwise
|
|
471
|
+
#
|
|
472
|
+
# @example Save a new order
|
|
473
|
+
# order = DhanHQ::Models::Order.new(
|
|
474
|
+
# dhan_client_id: "1000000003",
|
|
475
|
+
# transaction_type: "BUY",
|
|
476
|
+
# exchange_segment: "NSE_EQ",
|
|
477
|
+
# product_type: "INTRADAY",
|
|
478
|
+
# order_type: "MARKET",
|
|
479
|
+
# validity: "DAY",
|
|
480
|
+
# security_id: "11536",
|
|
481
|
+
# quantity: 5
|
|
482
|
+
# )
|
|
483
|
+
# if order.save
|
|
484
|
+
# puts "Order placed: #{order.order_id}"
|
|
485
|
+
# end
|
|
486
|
+
#
|
|
487
|
+
# @note Validation is performed before save. Invalid orders will not be saved.
|
|
175
488
|
def save
|
|
176
489
|
return false unless valid?
|
|
177
490
|
|
|
@@ -200,7 +513,21 @@ module DhanHQ
|
|
|
200
513
|
end
|
|
201
514
|
|
|
202
515
|
##
|
|
203
|
-
#
|
|
516
|
+
# Cancels (destroys) the order.
|
|
517
|
+
#
|
|
518
|
+
# Cancels an existing order by calling the delete endpoint. This is an alias
|
|
519
|
+
# for the cancel operation following ActiveRecord conventions.
|
|
520
|
+
#
|
|
521
|
+
# @return [Boolean] true if cancellation succeeds (order status becomes "CANCELLED"),
|
|
522
|
+
# false otherwise
|
|
523
|
+
#
|
|
524
|
+
# @example Destroy an order
|
|
525
|
+
# order = DhanHQ::Models::Order.find("112111182045")
|
|
526
|
+
# if order.destroy
|
|
527
|
+
# puts "Order cancelled"
|
|
528
|
+
# end
|
|
529
|
+
#
|
|
530
|
+
# @note This method does nothing for new (unsaved) orders.
|
|
204
531
|
def destroy
|
|
205
532
|
return false if new_record?
|
|
206
533
|
|
|
@@ -215,8 +542,38 @@ module DhanHQ
|
|
|
215
542
|
alias delete destroy
|
|
216
543
|
|
|
217
544
|
##
|
|
218
|
-
#
|
|
219
|
-
#
|
|
545
|
+
# Slices an order into multiple legs to place orders over freeze limit quantity.
|
|
546
|
+
#
|
|
547
|
+
# This API helps you slice your order request into multiple orders to allow you
|
|
548
|
+
# to place over freeze limit quantity for F&O instruments. Returns an array of
|
|
549
|
+
# orders created from the slice operation.
|
|
550
|
+
#
|
|
551
|
+
# @param params [Hash{Symbol => String, Integer, Float, Boolean}] Order parameters for slicing.
|
|
552
|
+
# Same parameters as {place}, but quantity can exceed freeze limits as it will be
|
|
553
|
+
# automatically split into multiple orders.
|
|
554
|
+
#
|
|
555
|
+
# @return [Array<Hash>] Array of order objects created from the slice operation.
|
|
556
|
+
# Each hash contains:
|
|
557
|
+
# - **:order_id** [String] Order-specific identification generated by Dhan
|
|
558
|
+
# - **:order_status** [String] Order status. Valid values: "TRANSIT", "PENDING",
|
|
559
|
+
# "REJECTED", "CANCELLED", "TRADED", "EXPIRED", "CONFIRM"
|
|
560
|
+
#
|
|
561
|
+
# @example Slice a large order
|
|
562
|
+
# order = DhanHQ::Models::Order.find("112111182045")
|
|
563
|
+
# sliced_orders = order.slice_order(
|
|
564
|
+
# dhan_client_id: "1000000003",
|
|
565
|
+
# transaction_type: "BUY",
|
|
566
|
+
# exchange_segment: "NSE_FNO",
|
|
567
|
+
# product_type: "INTRADAY",
|
|
568
|
+
# order_type: "MARKET",
|
|
569
|
+
# validity: "DAY",
|
|
570
|
+
# security_id: "49081",
|
|
571
|
+
# quantity: 50000 # Will be split into multiple orders
|
|
572
|
+
# )
|
|
573
|
+
# puts "Created #{sliced_orders.count} orders"
|
|
574
|
+
#
|
|
575
|
+
# @raise [RuntimeError] If order ID is missing
|
|
576
|
+
# @raise [DhanHQ::ValidationError] If validation fails for any parameter
|
|
220
577
|
def slice_order(params)
|
|
221
578
|
raise "Order ID is required to slice an order" unless id
|
|
222
579
|
|
|
@@ -229,8 +586,16 @@ module DhanHQ
|
|
|
229
586
|
end
|
|
230
587
|
|
|
231
588
|
##
|
|
232
|
-
#
|
|
233
|
-
#
|
|
589
|
+
# Returns the appropriate validation contract based on order state.
|
|
590
|
+
#
|
|
591
|
+
# For new records, returns PlaceOrderContract. For existing records, returns
|
|
592
|
+
# ModifyOrderContract. This allows the same validation logic to be used for
|
|
593
|
+
# both creating and modifying orders.
|
|
594
|
+
#
|
|
595
|
+
# @return [DhanHQ::Contracts::PlaceOrderContract, DhanHQ::Contracts::ModifyOrderContract]
|
|
596
|
+
# The appropriate validation contract based on whether this is a new or existing order
|
|
597
|
+
#
|
|
598
|
+
# @api private
|
|
234
599
|
def validation_contract
|
|
235
600
|
new_record? ? DhanHQ::Contracts::PlaceOrderContract.new : DhanHQ::Contracts::ModifyOrderContract.new
|
|
236
601
|
end
|