DhanHQ 2.1.10 → 2.2.1
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/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +143 -118
- data/CHANGELOG.md +127 -0
- data/CODE_REVIEW_ISSUES.md +397 -0
- data/FIXES_APPLIED.md +373 -0
- data/GUIDE.md +41 -0
- data/README.md +55 -0
- data/RELEASING.md +60 -0
- data/REVIEW_SUMMARY.md +120 -0
- data/VERSION_UPDATE.md +82 -0
- data/core +0 -0
- data/docs/AUTHENTICATION.md +63 -0
- data/docs/DATA_API_PARAMETERS.md +278 -0
- data/docs/PR_2.2.0.md +48 -0
- data/docs/RELEASE_GUIDE.md +492 -0
- data/docs/TESTING_GUIDE.md +1514 -0
- data/docs/live_order_updates.md +25 -1
- data/docs/rails_integration.md +29 -0
- data/docs/websocket_integration.md +22 -0
- data/lib/DhanHQ/client.rb +65 -9
- data/lib/DhanHQ/configuration.rb +27 -0
- data/lib/DhanHQ/constants.rb +1 -1
- data/lib/DhanHQ/contracts/place_order_contract.rb +51 -0
- data/lib/DhanHQ/core/base_model.rb +17 -10
- data/lib/DhanHQ/errors.rb +4 -0
- data/lib/DhanHQ/helpers/request_helper.rb +17 -2
- data/lib/DhanHQ/helpers/response_helper.rb +34 -13
- data/lib/DhanHQ/models/expired_options_data.rb +0 -6
- data/lib/DhanHQ/models/instrument_helpers.rb +4 -4
- data/lib/DhanHQ/models/order.rb +19 -2
- data/lib/DhanHQ/models/order_update.rb +0 -4
- data/lib/DhanHQ/rate_limiter.rb +40 -6
- data/lib/DhanHQ/version.rb +1 -1
- data/lib/DhanHQ/ws/client.rb +12 -5
- data/lib/DhanHQ/ws/connection.rb +16 -2
- data/lib/DhanHQ/ws/market_depth/client.rb +3 -1
- data/lib/DhanHQ/ws/market_depth.rb +12 -12
- data/lib/DhanHQ/ws/orders/client.rb +76 -11
- data/lib/DhanHQ/ws/orders/connection.rb +3 -1
- metadata +18 -5
- data/lib/DhanHQ/contracts/modify_order_contract_copy.rb +0 -100
|
@@ -0,0 +1,1514 @@
|
|
|
1
|
+
# DhanHQ Client Gem - Comprehensive Testing Guide
|
|
2
|
+
|
|
3
|
+
This guide provides interactive testing examples for all features of the DhanHQ client gem. You can use these examples in `bin/console` to test and explore the gem's functionality.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [Setup & Configuration](#setup--configuration)
|
|
8
|
+
2. [WebSocket Testing](#websocket-testing)
|
|
9
|
+
- [Market Feed WebSocket](#market-feed-websocket)
|
|
10
|
+
- [Order Update WebSocket](#order-update-websocket)
|
|
11
|
+
- [Market Depth WebSocket](#market-depth-websocket)
|
|
12
|
+
3. [Model Testing](#model-testing)
|
|
13
|
+
- [Orders](#orders)
|
|
14
|
+
- [Positions](#positions)
|
|
15
|
+
- [Holdings](#holdings)
|
|
16
|
+
- [Funds](#funds)
|
|
17
|
+
- [Trades](#trades)
|
|
18
|
+
- [Profile](#profile)
|
|
19
|
+
- [Market Feed](#market-feed)
|
|
20
|
+
- [Historical Data](#historical-data)
|
|
21
|
+
- [Option Chain](#option-chain)
|
|
22
|
+
- [Instruments](#instruments)
|
|
23
|
+
- [Super Orders](#super-orders)
|
|
24
|
+
- [Forever Orders (GTT)](#forever-orders-gtt)
|
|
25
|
+
- [EDIS](#edis)
|
|
26
|
+
- [Kill Switch](#kill-switch)
|
|
27
|
+
- [Expired Options Data](#expired-options-data)
|
|
28
|
+
- [Margin Calculator](#margin-calculator)
|
|
29
|
+
- [Ledger Entries](#ledger-entries)
|
|
30
|
+
4. [Validation Contracts Testing](#validation-contracts-testing)
|
|
31
|
+
5. [Error Handling Testing](#error-handling-testing)
|
|
32
|
+
6. [Rate Limiting Testing](#rate-limiting-testing)
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Setup & Configuration
|
|
37
|
+
|
|
38
|
+
### Basic Setup in Console
|
|
39
|
+
|
|
40
|
+
```ruby
|
|
41
|
+
# Start console: bin/console
|
|
42
|
+
|
|
43
|
+
# Configure from environment variables
|
|
44
|
+
DhanHQ.configure_with_env
|
|
45
|
+
|
|
46
|
+
# Or configure manually
|
|
47
|
+
DhanHQ.configure do |config|
|
|
48
|
+
config.client_id = "your_client_id"
|
|
49
|
+
config.access_token = "your_access_token"
|
|
50
|
+
config.ws_user_type = "SELF" # or "PARTNER"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Optional: dynamic token at request time (e.g. from DB or OAuth)
|
|
54
|
+
# DhanHQ.configure do |config|
|
|
55
|
+
# config.client_id = ENV["DHAN_CLIENT_ID"]
|
|
56
|
+
# config.access_token_provider = -> { YourTokenStore.active_token }
|
|
57
|
+
# config.on_token_expired = ->(err) { YourTokenStore.refresh! }
|
|
58
|
+
# end
|
|
59
|
+
|
|
60
|
+
# Set log level for debugging
|
|
61
|
+
DhanHQ.logger.level = Logger::DEBUG
|
|
62
|
+
|
|
63
|
+
# Verify configuration
|
|
64
|
+
puts "Client ID: #{DhanHQ.configuration.client_id}"
|
|
65
|
+
puts "Access Token: #{DhanHQ.configuration.access_token ? 'Set' : 'Not Set'}"
|
|
66
|
+
puts "Token provider: #{DhanHQ.configuration.access_token_provider ? 'Set' : 'Not Set'}"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Environment Variables
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
# Check current environment variables
|
|
73
|
+
puts "CLIENT_ID: #{ENV['CLIENT_ID']}"
|
|
74
|
+
puts "ACCESS_TOKEN: #{ENV['ACCESS_TOKEN'] ? 'Set' : 'Not Set'}"
|
|
75
|
+
puts "DHAN_LOG_LEVEL: #{ENV['DHAN_LOG_LEVEL'] || 'INFO'}"
|
|
76
|
+
puts "DHAN_CONNECT_TIMEOUT: #{ENV['DHAN_CONNECT_TIMEOUT'] || '10'}"
|
|
77
|
+
puts "DHAN_READ_TIMEOUT: #{ENV['DHAN_READ_TIMEOUT'] || '30'}"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## WebSocket Testing
|
|
83
|
+
|
|
84
|
+
### Market Feed WebSocket
|
|
85
|
+
|
|
86
|
+
#### Basic Ticker Subscription
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
# Create market feed WebSocket connection
|
|
90
|
+
market_client = DhanHQ::WS.connect(mode: :ticker) do |tick|
|
|
91
|
+
timestamp = tick[:ts] ? Time.at(tick[:ts]) : Time.now
|
|
92
|
+
puts "[#{timestamp}] #{tick[:segment]}:#{tick[:security_id]} = ₹#{tick[:ltp]}"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Subscribe to NIFTY (Security ID: 13, Segment: IDX_I)
|
|
96
|
+
market_client.subscribe_one(segment: "IDX_I", security_id: "13")
|
|
97
|
+
|
|
98
|
+
# Subscribe to BANKNIFTY (Security ID: 25, Segment: IDX_I)
|
|
99
|
+
market_client.subscribe_one(segment: "IDX_I", security_id: "25")
|
|
100
|
+
|
|
101
|
+
# Wait for data (in console, you can continue working)
|
|
102
|
+
sleep(10)
|
|
103
|
+
|
|
104
|
+
# Stop connection
|
|
105
|
+
market_client.stop
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### OHLC Subscription
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
# Create OHLC WebSocket connection
|
|
112
|
+
ohlc_client = DhanHQ::WS.connect(mode: :ohlc) do |data|
|
|
113
|
+
puts "OHLC: #{data[:segment]}:#{data[:security_id]}"
|
|
114
|
+
puts " Open: ₹#{data[:open]}, High: ₹#{data[:high]}, Low: ₹#{data[:low]}, Close: ₹#{data[:close]}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Subscribe to NIFTY
|
|
118
|
+
ohlc_client.subscribe_one(segment: "IDX_I", security_id: "13")
|
|
119
|
+
|
|
120
|
+
sleep(10)
|
|
121
|
+
ohlc_client.stop
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Quote Subscription (Full Market Depth)
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
# Create quote WebSocket connection
|
|
128
|
+
quote_client = DhanHQ::WS.connect(mode: :quote) do |data|
|
|
129
|
+
puts "Quote: #{data[:segment]}:#{data[:security_id]}"
|
|
130
|
+
puts " LTP: ₹#{data[:ltp]}"
|
|
131
|
+
puts " Volume: #{data[:volume]}"
|
|
132
|
+
puts " Open Interest: #{data[:oi]}" if data[:oi]
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Subscribe to NIFTY
|
|
136
|
+
quote_client.subscribe_one(segment: "IDX_I", security_id: "13")
|
|
137
|
+
|
|
138
|
+
sleep(10)
|
|
139
|
+
quote_client.stop
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### Multiple Subscriptions
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
# Subscribe to multiple instruments
|
|
146
|
+
market_client = DhanHQ::WS.connect(mode: :ticker) do |tick|
|
|
147
|
+
puts "#{tick[:segment]}:#{tick[:security_id]} = ₹#{tick[:ltp]}"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Subscribe to multiple indices
|
|
151
|
+
indices = [
|
|
152
|
+
{ segment: "IDX_I", security_id: "13" }, # NIFTY
|
|
153
|
+
{ segment: "IDX_I", security_id: "25" }, # BANKNIFTY
|
|
154
|
+
{ segment: "IDX_I", security_id: "29" }, # NIFTYIT
|
|
155
|
+
{ segment: "IDX_I", security_id: "51" } # SENSEX
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
indices.each do |idx|
|
|
159
|
+
market_client.subscribe_one(segment: idx[:segment], security_id: idx[:security_id])
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
sleep(15)
|
|
163
|
+
market_client.stop
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Testing Connection State
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
market_client = DhanHQ::WS.connect(mode: :ticker) { |tick| puts tick[:ltp] }
|
|
170
|
+
market_client.subscribe_one(segment: "IDX_I", security_id: "13")
|
|
171
|
+
|
|
172
|
+
# Check connection state
|
|
173
|
+
puts "Connected: #{market_client.connected?}"
|
|
174
|
+
|
|
175
|
+
sleep(5)
|
|
176
|
+
market_client.stop
|
|
177
|
+
puts "Connected after stop: #{market_client.connected?}"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Order Update WebSocket
|
|
181
|
+
|
|
182
|
+
#### Basic Order Tracking
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
# Create order update client
|
|
186
|
+
orders_client = DhanHQ::WS::Orders.client
|
|
187
|
+
|
|
188
|
+
# Track all order updates
|
|
189
|
+
orders_client.on(:update) do |order|
|
|
190
|
+
puts "\n📋 Order Update: #{order.order_no}"
|
|
191
|
+
puts " Symbol: #{order.symbol}"
|
|
192
|
+
puts " Status: #{order.status}"
|
|
193
|
+
puts " Quantity: #{order.traded_qty}/#{order.quantity}"
|
|
194
|
+
puts " Price: ₹#{order.price}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Start monitoring
|
|
198
|
+
orders_client.start
|
|
199
|
+
puts "✅ Order tracking started. Place orders to see updates..."
|
|
200
|
+
|
|
201
|
+
# In console, you can continue working while tracking orders
|
|
202
|
+
# Stop when done
|
|
203
|
+
# orders_client.stop
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
#### Comprehensive Event Handling
|
|
207
|
+
|
|
208
|
+
```ruby
|
|
209
|
+
orders_client = DhanHQ::WS::Orders.client
|
|
210
|
+
|
|
211
|
+
# Track status changes
|
|
212
|
+
orders_client.on(:status_change) do |data|
|
|
213
|
+
order = data[:order_update]
|
|
214
|
+
puts "\n🔄 Status Change: #{order.order_no}"
|
|
215
|
+
puts " #{data[:previous_status]} -> #{data[:new_status]}"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Track executions
|
|
219
|
+
orders_client.on(:execution) do |data|
|
|
220
|
+
order = data[:order_update]
|
|
221
|
+
puts "\n💰 Execution: #{order.order_no}"
|
|
222
|
+
puts " Traded: #{data[:previous_traded_qty]} -> #{data[:new_traded_qty]} shares"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Track fully traded orders
|
|
226
|
+
orders_client.on(:order_traded) do |order|
|
|
227
|
+
puts "\n✅ Order Fully Executed: #{order.order_no}"
|
|
228
|
+
puts " Average Price: ₹#{order.avg_traded_price}"
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Track rejected orders
|
|
232
|
+
orders_client.on(:order_rejected) do |order|
|
|
233
|
+
puts "\n❌ Order Rejected: #{order.order_no}"
|
|
234
|
+
puts " Reason: #{order.reason_description}"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Track cancelled orders
|
|
238
|
+
orders_client.on(:order_cancelled) do |order|
|
|
239
|
+
puts "\n🚫 Order Cancelled: #{order.order_no}"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
orders_client.start
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### Querying Tracked Orders
|
|
246
|
+
|
|
247
|
+
```ruby
|
|
248
|
+
orders_client = DhanHQ::WS::Orders.client
|
|
249
|
+
orders_client.start
|
|
250
|
+
|
|
251
|
+
# Get all tracked orders
|
|
252
|
+
all_orders = orders_client.all_orders
|
|
253
|
+
puts "Total tracked orders: #{all_orders.size}"
|
|
254
|
+
|
|
255
|
+
# Get specific order
|
|
256
|
+
if all_orders.any?
|
|
257
|
+
order_no = all_orders.keys.first
|
|
258
|
+
order = orders_client.order(order_no)
|
|
259
|
+
puts "Order #{order_no}:"
|
|
260
|
+
puts " Status: #{order.status}"
|
|
261
|
+
puts " Symbol: #{order.symbol}"
|
|
262
|
+
puts " Execution: #{order.execution_percentage}%"
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Check if order is tracked
|
|
266
|
+
order_no = "112111182045"
|
|
267
|
+
if orders_client.tracked?(order_no)
|
|
268
|
+
puts "Order #{order_no} is being tracked"
|
|
269
|
+
else
|
|
270
|
+
puts "Order #{order_no} is not tracked"
|
|
271
|
+
end
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Market Depth WebSocket
|
|
275
|
+
|
|
276
|
+
#### Basic Market Depth
|
|
277
|
+
|
|
278
|
+
```ruby
|
|
279
|
+
# First, find instruments
|
|
280
|
+
reliance = DhanHQ::Models::Instrument.find("NSE_EQ", "RELIANCE")
|
|
281
|
+
tcs = DhanHQ::Models::Instrument.find("NSE_EQ", "TCS")
|
|
282
|
+
|
|
283
|
+
# Prepare symbols
|
|
284
|
+
symbols = []
|
|
285
|
+
if reliance
|
|
286
|
+
symbols << {
|
|
287
|
+
symbol: "RELIANCE",
|
|
288
|
+
exchange_segment: reliance.exchange_segment,
|
|
289
|
+
security_id: reliance.security_id
|
|
290
|
+
}
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
if tcs
|
|
294
|
+
symbols << {
|
|
295
|
+
symbol: "TCS",
|
|
296
|
+
exchange_segment: tcs.exchange_segment,
|
|
297
|
+
security_id: tcs.security_id
|
|
298
|
+
}
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Create market depth client
|
|
302
|
+
depth_client = DhanHQ::WS::MarketDepth.connect(symbols: symbols) do |depth_data|
|
|
303
|
+
puts "\n📊 Market Depth: #{depth_data[:symbol]}"
|
|
304
|
+
puts " Best Bid: ₹#{depth_data[:best_bid]}"
|
|
305
|
+
puts " Best Ask: ₹#{depth_data[:best_ask]}"
|
|
306
|
+
puts " Spread: ₹#{depth_data[:spread]}"
|
|
307
|
+
puts " Bid Levels: #{depth_data[:bids].size}"
|
|
308
|
+
puts " Ask Levels: #{depth_data[:asks].size}"
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
sleep(10)
|
|
312
|
+
depth_client.stop
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Model Testing
|
|
318
|
+
|
|
319
|
+
### Orders
|
|
320
|
+
|
|
321
|
+
#### Place Order
|
|
322
|
+
|
|
323
|
+
```ruby
|
|
324
|
+
# Place a market order
|
|
325
|
+
order = DhanHQ::Models::Order.place(
|
|
326
|
+
dhan_client_id: "1000000003",
|
|
327
|
+
transaction_type: "BUY",
|
|
328
|
+
exchange_segment: "NSE_EQ",
|
|
329
|
+
product_type: "INTRADAY",
|
|
330
|
+
order_type: "MARKET",
|
|
331
|
+
validity: "DAY",
|
|
332
|
+
security_id: "11536", # TCS
|
|
333
|
+
quantity: 1
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
puts "Order placed: #{order.order_id}"
|
|
337
|
+
puts "Status: #{order.order_status}"
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
#### Place Limit Order
|
|
341
|
+
|
|
342
|
+
```ruby
|
|
343
|
+
# Place a limit order
|
|
344
|
+
order = DhanHQ::Models::Order.place(
|
|
345
|
+
dhan_client_id: "1000000003",
|
|
346
|
+
transaction_type: "BUY",
|
|
347
|
+
exchange_segment: "NSE_EQ",
|
|
348
|
+
product_type: "INTRADAY",
|
|
349
|
+
order_type: "LIMIT",
|
|
350
|
+
validity: "DAY",
|
|
351
|
+
security_id: "11536",
|
|
352
|
+
quantity: 1,
|
|
353
|
+
price: 3500.0
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
puts "Order ID: #{order.order_id}"
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
#### Place Stop Loss Order
|
|
360
|
+
|
|
361
|
+
```ruby
|
|
362
|
+
# Place stop loss order
|
|
363
|
+
order = DhanHQ::Models::Order.place(
|
|
364
|
+
dhan_client_id: "1000000003",
|
|
365
|
+
transaction_type: "BUY",
|
|
366
|
+
exchange_segment: "NSE_EQ",
|
|
367
|
+
product_type: "INTRADAY",
|
|
368
|
+
order_type: "STOPLOSS",
|
|
369
|
+
validity: "DAY",
|
|
370
|
+
security_id: "11536",
|
|
371
|
+
quantity: 1,
|
|
372
|
+
price: 3500.0,
|
|
373
|
+
trigger_price: 3450.0
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
puts "Order ID: #{order.order_id}"
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
#### Find Order
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
# Find order by ID
|
|
383
|
+
order = DhanHQ::Models::Order.find("112111182045")
|
|
384
|
+
puts "Order Status: #{order.order_status}"
|
|
385
|
+
puts "Symbol: #{order.trading_symbol}"
|
|
386
|
+
puts "Quantity: #{order.quantity}"
|
|
387
|
+
puts "Traded Qty: #{order.traded_qty}"
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
#### Find Order by Correlation ID
|
|
391
|
+
|
|
392
|
+
```ruby
|
|
393
|
+
# Find order by correlation ID
|
|
394
|
+
correlation_id = "my-unique-id-123"
|
|
395
|
+
order = DhanHQ::Models::Order.find_by_correlation(correlation_id)
|
|
396
|
+
if order
|
|
397
|
+
puts "Order found: #{order.order_id}"
|
|
398
|
+
else
|
|
399
|
+
puts "Order not found"
|
|
400
|
+
end
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
#### Get All Orders
|
|
404
|
+
|
|
405
|
+
```ruby
|
|
406
|
+
# Get all orders for the day
|
|
407
|
+
orders = DhanHQ::Models::Order.all
|
|
408
|
+
puts "Total orders: #{orders.size}"
|
|
409
|
+
|
|
410
|
+
# Filter pending orders
|
|
411
|
+
pending = orders.select { |o| o.order_status == "PENDING" }
|
|
412
|
+
puts "Pending orders: #{pending.size}"
|
|
413
|
+
|
|
414
|
+
# Filter executed orders
|
|
415
|
+
executed = orders.select { |o| o.order_status == "TRADED" }
|
|
416
|
+
puts "Executed orders: #{executed.size}"
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
#### Modify Order
|
|
420
|
+
|
|
421
|
+
```ruby
|
|
422
|
+
# Find order
|
|
423
|
+
order = DhanHQ::Models::Order.find("112111182045")
|
|
424
|
+
|
|
425
|
+
# Modify price and quantity
|
|
426
|
+
if order.modify(price: 3501.0, quantity: 2)
|
|
427
|
+
puts "Order modified successfully"
|
|
428
|
+
order.refresh
|
|
429
|
+
puts "New price: #{order.price}"
|
|
430
|
+
puts "New quantity: #{order.quantity}"
|
|
431
|
+
else
|
|
432
|
+
puts "Order modification failed"
|
|
433
|
+
end
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
#### Cancel Order
|
|
437
|
+
|
|
438
|
+
```ruby
|
|
439
|
+
# Cancel order
|
|
440
|
+
order = DhanHQ::Models::Order.find("112111182045")
|
|
441
|
+
if order.cancel
|
|
442
|
+
puts "Order cancelled successfully"
|
|
443
|
+
else
|
|
444
|
+
puts "Order cancellation failed"
|
|
445
|
+
end
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
#### Slice Order
|
|
449
|
+
|
|
450
|
+
```ruby
|
|
451
|
+
# Slice order into multiple smaller orders
|
|
452
|
+
order = DhanHQ::Models::Order.find("112111182045")
|
|
453
|
+
|
|
454
|
+
# Slice into 3 orders of 10 shares each
|
|
455
|
+
sliced_orders = order.slice_order(
|
|
456
|
+
slice_count: 3,
|
|
457
|
+
slice_size: 10,
|
|
458
|
+
price: 3500.0
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
puts "Created #{sliced_orders.size} sliced orders"
|
|
462
|
+
sliced_orders.each do |sliced_order|
|
|
463
|
+
puts " Order ID: #{sliced_order.order_id}, Quantity: #{sliced_order.quantity}"
|
|
464
|
+
end
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### Create Order (ActiveRecord-style)
|
|
468
|
+
|
|
469
|
+
```ruby
|
|
470
|
+
# Create order instance
|
|
471
|
+
order = DhanHQ::Models::Order.new(
|
|
472
|
+
dhan_client_id: "1000000003",
|
|
473
|
+
transaction_type: "BUY",
|
|
474
|
+
exchange_segment: "NSE_EQ",
|
|
475
|
+
product_type: "INTRADAY",
|
|
476
|
+
order_type: "MARKET",
|
|
477
|
+
validity: "DAY",
|
|
478
|
+
security_id: "11536",
|
|
479
|
+
quantity: 1
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
# Save (places order)
|
|
483
|
+
if order.save
|
|
484
|
+
puts "Order placed: #{order.order_id}"
|
|
485
|
+
else
|
|
486
|
+
puts "Order placement failed"
|
|
487
|
+
end
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Positions
|
|
491
|
+
|
|
492
|
+
#### Get All Positions
|
|
493
|
+
|
|
494
|
+
```ruby
|
|
495
|
+
# Get all positions
|
|
496
|
+
positions = DhanHQ::Models::Position.all
|
|
497
|
+
puts "Total positions: #{positions.size}"
|
|
498
|
+
|
|
499
|
+
# Filter by exchange
|
|
500
|
+
nse_positions = positions.select { |p| p.exchange_segment == "NSE_EQ" }
|
|
501
|
+
puts "NSE positions: #{nse_positions.size}"
|
|
502
|
+
|
|
503
|
+
# Filter long positions
|
|
504
|
+
long_positions = positions.select { |p| p.net_qty > 0 }
|
|
505
|
+
puts "Long positions: #{long_positions.size}"
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
#### Convert Position
|
|
509
|
+
|
|
510
|
+
```ruby
|
|
511
|
+
# Find position
|
|
512
|
+
position = DhanHQ::Models::Position.all.first
|
|
513
|
+
|
|
514
|
+
# Convert position (e.g., from INTRADAY to DELIVERY)
|
|
515
|
+
if position
|
|
516
|
+
result = position.convert(
|
|
517
|
+
dhan_client_id: "1000000003",
|
|
518
|
+
from_product_type: "INTRADAY",
|
|
519
|
+
to_product_type: "MARGIN",
|
|
520
|
+
quantity: position.net_qty.abs
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
if result
|
|
524
|
+
puts "Position converted successfully"
|
|
525
|
+
else
|
|
526
|
+
puts "Position conversion failed"
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### Holdings
|
|
532
|
+
|
|
533
|
+
#### Get All Holdings
|
|
534
|
+
|
|
535
|
+
```ruby
|
|
536
|
+
# Get all holdings
|
|
537
|
+
holdings = DhanHQ::Models::Holding.all
|
|
538
|
+
puts "Total holdings: #{holdings.size}"
|
|
539
|
+
|
|
540
|
+
# Display holdings
|
|
541
|
+
holdings.each do |holding|
|
|
542
|
+
puts "#{holding.trading_symbol}: #{holding.quantity} shares"
|
|
543
|
+
puts " Average Price: ₹#{holding.average_price}"
|
|
544
|
+
puts " Current Value: ₹#{holding.current_value}"
|
|
545
|
+
end
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Funds
|
|
549
|
+
|
|
550
|
+
#### Get Funds
|
|
551
|
+
|
|
552
|
+
```ruby
|
|
553
|
+
# Get account funds
|
|
554
|
+
funds = DhanHQ::Models::Funds.fetch
|
|
555
|
+
puts "Available Margin: ₹#{funds.available_margin}"
|
|
556
|
+
puts "Collateral: ₹#{funds.collateral}"
|
|
557
|
+
puts "Utilized Margin: ₹#{funds.utilized_margin}"
|
|
558
|
+
puts "Opening Balance: ₹#{funds.opening_balance}"
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Trades
|
|
562
|
+
|
|
563
|
+
#### Get Today's Trades
|
|
564
|
+
|
|
565
|
+
```ruby
|
|
566
|
+
# Get today's trades
|
|
567
|
+
trades = DhanHQ::Models::Trade.today
|
|
568
|
+
puts "Total trades today: #{trades.size}"
|
|
569
|
+
|
|
570
|
+
trades.each do |trade|
|
|
571
|
+
puts "#{trade.trading_symbol}: #{trade.traded_qty} @ ₹#{trade.traded_price}"
|
|
572
|
+
end
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
#### Get Trade History
|
|
576
|
+
|
|
577
|
+
```ruby
|
|
578
|
+
# Get trade history
|
|
579
|
+
from_date = Date.today - 7
|
|
580
|
+
to_date = Date.today
|
|
581
|
+
|
|
582
|
+
trades = DhanHQ::Models::Trade.history(from_date: from_date, to_date: to_date)
|
|
583
|
+
puts "Total trades: #{trades.size}"
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
#### Find Trades by Order ID
|
|
587
|
+
|
|
588
|
+
```ruby
|
|
589
|
+
# Find trades for specific order
|
|
590
|
+
order_id = "112111182045"
|
|
591
|
+
trades = DhanHQ::Models::Trade.find_by_order_id(order_id)
|
|
592
|
+
puts "Trades for order #{order_id}: #{trades.size}"
|
|
593
|
+
|
|
594
|
+
trades.each do |trade|
|
|
595
|
+
puts " Trade ID: #{trade.trade_id}"
|
|
596
|
+
puts " Quantity: #{trade.traded_qty}"
|
|
597
|
+
puts " Price: ₹#{trade.traded_price}"
|
|
598
|
+
end
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Profile
|
|
602
|
+
|
|
603
|
+
#### Get Profile
|
|
604
|
+
|
|
605
|
+
```ruby
|
|
606
|
+
# Get user profile
|
|
607
|
+
profile = DhanHQ::Models::Profile.fetch
|
|
608
|
+
puts "Name: #{profile.name}"
|
|
609
|
+
puts "Email: #{profile.email}"
|
|
610
|
+
puts "Mobile: #{profile.mobile}"
|
|
611
|
+
puts "PAN: #{profile.pan}"
|
|
612
|
+
puts "Client ID: #{profile.dhan_client_id}"
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### Market Feed
|
|
616
|
+
|
|
617
|
+
#### Get LTP (Last Traded Price)
|
|
618
|
+
|
|
619
|
+
```ruby
|
|
620
|
+
# Get LTP for multiple instruments
|
|
621
|
+
payload = {
|
|
622
|
+
"NSE_EQ" => [11536, 3456], # TCS, RELIANCE
|
|
623
|
+
"NSE_FNO" => [49081, 49082]
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
response = DhanHQ::Models::MarketFeed.ltp(payload)
|
|
627
|
+
puts "LTP Data:"
|
|
628
|
+
response[:data].each do |segment, instruments|
|
|
629
|
+
instruments.each do |security_id, data|
|
|
630
|
+
puts " #{segment}:#{security_id} = ₹#{data[:last_price]}"
|
|
631
|
+
end
|
|
632
|
+
end
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
#### Get OHLC Data
|
|
636
|
+
|
|
637
|
+
```ruby
|
|
638
|
+
# Get OHLC for instruments
|
|
639
|
+
payload = {
|
|
640
|
+
"NSE_EQ" => [11536]
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
response = DhanHQ::Models::MarketFeed.ohlc(payload)
|
|
644
|
+
tcs_data = response[:data]["NSE_EQ"]["11536"]
|
|
645
|
+
puts "TCS OHLC:"
|
|
646
|
+
puts " Open: ₹#{tcs_data[:ohlc][:open]}"
|
|
647
|
+
puts " High: ₹#{tcs_data[:ohlc][:high]}"
|
|
648
|
+
puts " Low: ₹#{tcs_data[:ohlc][:low]}"
|
|
649
|
+
puts " Close: ₹#{tcs_data[:ohlc][:close]}"
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
#### Get Quote (Full Market Depth)
|
|
653
|
+
|
|
654
|
+
```ruby
|
|
655
|
+
# Get full quote
|
|
656
|
+
payload = {
|
|
657
|
+
"NSE_FNO" => [49081]
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
response = DhanHQ::Models::MarketFeed.quote(payload)
|
|
661
|
+
quote_data = response[:data]["NSE_FNO"]["49081"]
|
|
662
|
+
puts "Quote Data:"
|
|
663
|
+
puts " LTP: ₹#{quote_data[:ltp]}"
|
|
664
|
+
puts " Volume: #{quote_data[:volume]}"
|
|
665
|
+
puts " Open Interest: #{quote_data[:oi]}"
|
|
666
|
+
puts " Bid Price: ₹#{quote_data[:bid_price]}"
|
|
667
|
+
puts " Ask Price: ₹#{quote_data[:ask_price]}"
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Historical Data
|
|
671
|
+
|
|
672
|
+
#### Get Daily Historical Data
|
|
673
|
+
|
|
674
|
+
```ruby
|
|
675
|
+
# Get daily candles
|
|
676
|
+
historical_data = DhanHQ::Models::HistoricalData.daily(
|
|
677
|
+
security_id: "11536",
|
|
678
|
+
exchange_segment: "NSE_EQ",
|
|
679
|
+
from_date: Date.today - 30,
|
|
680
|
+
to_date: Date.today
|
|
681
|
+
)
|
|
682
|
+
|
|
683
|
+
puts "Total candles: #{historical_data.size}"
|
|
684
|
+
historical_data.first(5).each do |candle|
|
|
685
|
+
puts "#{candle[:date]}: O=₹#{candle[:open]}, H=₹#{candle[:high]}, L=₹#{candle[:low]}, C=₹#{candle[:close]}"
|
|
686
|
+
end
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
#### Get Intraday Historical Data
|
|
690
|
+
|
|
691
|
+
```ruby
|
|
692
|
+
# Get intraday candles (5-minute interval)
|
|
693
|
+
historical_data = DhanHQ::Models::HistoricalData.intraday(
|
|
694
|
+
security_id: "11536",
|
|
695
|
+
exchange_segment: "NSE_EQ",
|
|
696
|
+
from_date: Date.today,
|
|
697
|
+
to_date: Date.today,
|
|
698
|
+
interval: 5
|
|
699
|
+
)
|
|
700
|
+
|
|
701
|
+
puts "Total candles: #{historical_data.size}"
|
|
702
|
+
historical_data.first(5).each do |candle|
|
|
703
|
+
puts "#{candle[:time]}: O=₹#{candle[:open]}, H=₹#{candle[:high]}, L=₹#{candle[:low]}, C=₹#{candle[:close]}"
|
|
704
|
+
end
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### Option Chain
|
|
708
|
+
|
|
709
|
+
#### Get Expiry List
|
|
710
|
+
|
|
711
|
+
```ruby
|
|
712
|
+
# Get expiry list for NIFTY
|
|
713
|
+
expiry_list = DhanHQ::Models::OptionChain.fetch_expiry_list(
|
|
714
|
+
underlying_scrip: "NIFTY",
|
|
715
|
+
underlying_seg: "IDX_I"
|
|
716
|
+
)
|
|
717
|
+
|
|
718
|
+
puts "Available expiries:"
|
|
719
|
+
expiry_list.each do |expiry|
|
|
720
|
+
puts " #{expiry[:expiry_date]}"
|
|
721
|
+
end
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
#### Get Option Chain
|
|
725
|
+
|
|
726
|
+
```ruby
|
|
727
|
+
# Get option chain for NIFTY
|
|
728
|
+
expiry_date = expiry_list.first[:expiry_date] # Use first expiry from above
|
|
729
|
+
|
|
730
|
+
option_chain = DhanHQ::Models::OptionChain.fetch(
|
|
731
|
+
underlying_scrip: "NIFTY",
|
|
732
|
+
underlying_seg: "IDX_I",
|
|
733
|
+
expiry: expiry_date
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
puts "Option Chain for #{expiry_date}:"
|
|
737
|
+
puts "Total strikes: #{option_chain.size}"
|
|
738
|
+
|
|
739
|
+
# Display first few strikes
|
|
740
|
+
option_chain.first(5).each do |strike|
|
|
741
|
+
puts " Strike: #{strike[:strike_price]}"
|
|
742
|
+
puts " CE: #{strike[:call_option]&.dig(:trading_symbol)}"
|
|
743
|
+
puts " PE: #{strike[:put_option]&.dig(:trading_symbol)}"
|
|
744
|
+
end
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Instruments
|
|
748
|
+
|
|
749
|
+
#### Find Instrument
|
|
750
|
+
|
|
751
|
+
```ruby
|
|
752
|
+
# Find instrument by symbol
|
|
753
|
+
tcs = DhanHQ::Models::Instrument.find("NSE_EQ", "TCS")
|
|
754
|
+
if tcs
|
|
755
|
+
puts "Found: #{tcs.symbol_name}"
|
|
756
|
+
puts "Security ID: #{tcs.security_id}"
|
|
757
|
+
puts "Exchange Segment: #{tcs.exchange_segment}"
|
|
758
|
+
puts "Instrument Type: #{tcs.instrument}"
|
|
759
|
+
end
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
#### Find Instrument Anywhere
|
|
763
|
+
|
|
764
|
+
```ruby
|
|
765
|
+
# Search across all exchanges
|
|
766
|
+
reliance = DhanHQ::Models::Instrument.find_anywhere("RELIANCE")
|
|
767
|
+
if reliance
|
|
768
|
+
puts "Found: #{reliance.symbol_name}"
|
|
769
|
+
puts "Exchange: #{reliance.exchange_segment}"
|
|
770
|
+
puts "Security ID: #{reliance.security_id}"
|
|
771
|
+
end
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
#### Use Instrument Helper Methods
|
|
775
|
+
|
|
776
|
+
```ruby
|
|
777
|
+
# Get instrument
|
|
778
|
+
instrument = DhanHQ::Models::Instrument.find("NSE_EQ", "TCS")
|
|
779
|
+
|
|
780
|
+
# Use convenience methods
|
|
781
|
+
if instrument
|
|
782
|
+
# Get LTP
|
|
783
|
+
ltp_data = instrument.ltp
|
|
784
|
+
puts "LTP: ₹#{ltp_data[:last_price]}"
|
|
785
|
+
|
|
786
|
+
# Get OHLC
|
|
787
|
+
ohlc_data = instrument.ohlc
|
|
788
|
+
puts "OHLC: #{ohlc_data[:ohlc]}"
|
|
789
|
+
|
|
790
|
+
# Get Quote
|
|
791
|
+
quote_data = instrument.quote
|
|
792
|
+
puts "Quote: #{quote_data[:ltp]}"
|
|
793
|
+
|
|
794
|
+
# Get Daily Historical Data
|
|
795
|
+
daily_data = instrument.daily(
|
|
796
|
+
from_date: Date.today - 7,
|
|
797
|
+
to_date: Date.today
|
|
798
|
+
)
|
|
799
|
+
puts "Daily candles: #{daily_data.size}"
|
|
800
|
+
|
|
801
|
+
# Get Intraday Historical Data
|
|
802
|
+
intraday_data = instrument.intraday(
|
|
803
|
+
from_date: Date.today,
|
|
804
|
+
to_date: Date.today,
|
|
805
|
+
interval: 5
|
|
806
|
+
)
|
|
807
|
+
puts "Intraday candles: #{intraday_data.size}"
|
|
808
|
+
|
|
809
|
+
# Get Expiry List (for F&O instruments)
|
|
810
|
+
if instrument.instrument == "FUTSTK" || instrument.instrument == "OPTSTK"
|
|
811
|
+
expiry_list = instrument.expiry_list
|
|
812
|
+
puts "Expiries: #{expiry_list.size}"
|
|
813
|
+
end
|
|
814
|
+
end
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
### Super Orders
|
|
818
|
+
|
|
819
|
+
#### Get All Super Orders
|
|
820
|
+
|
|
821
|
+
```ruby
|
|
822
|
+
# Get all super orders
|
|
823
|
+
super_orders = DhanHQ::Models::SuperOrder.all
|
|
824
|
+
puts "Total super orders: #{super_orders.size}"
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
#### Create Super Order
|
|
828
|
+
|
|
829
|
+
```ruby
|
|
830
|
+
# Create a multi-leg super order
|
|
831
|
+
super_order = DhanHQ::Models::SuperOrder.create(
|
|
832
|
+
dhan_client_id: "1000000003",
|
|
833
|
+
legs: [
|
|
834
|
+
{
|
|
835
|
+
leg_name: "ENTRY_LEG",
|
|
836
|
+
transaction_type: "BUY",
|
|
837
|
+
exchange_segment: "NSE_FNO",
|
|
838
|
+
product_type: "MARGIN",
|
|
839
|
+
order_type: "LIMIT",
|
|
840
|
+
validity: "DAY",
|
|
841
|
+
security_id: "49081",
|
|
842
|
+
quantity: 50,
|
|
843
|
+
price: 18000.0
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
leg_name: "EXIT_LEG",
|
|
847
|
+
transaction_type: "SELL",
|
|
848
|
+
exchange_segment: "NSE_FNO",
|
|
849
|
+
product_type: "MARGIN",
|
|
850
|
+
order_type: "LIMIT",
|
|
851
|
+
validity: "DAY",
|
|
852
|
+
security_id: "49081",
|
|
853
|
+
quantity: 50,
|
|
854
|
+
price: 18100.0
|
|
855
|
+
}
|
|
856
|
+
]
|
|
857
|
+
)
|
|
858
|
+
|
|
859
|
+
puts "Super Order ID: #{super_order.super_order_id}"
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
#### Cancel Super Order
|
|
863
|
+
|
|
864
|
+
```ruby
|
|
865
|
+
# Find super order
|
|
866
|
+
super_order = DhanHQ::Models::SuperOrder.all.first
|
|
867
|
+
|
|
868
|
+
# Cancel specific leg
|
|
869
|
+
if super_order
|
|
870
|
+
if super_order.cancel("ENTRY_LEG")
|
|
871
|
+
puts "Leg cancelled successfully"
|
|
872
|
+
end
|
|
873
|
+
end
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
### Forever Orders (GTT)
|
|
877
|
+
|
|
878
|
+
#### Get All Forever Orders
|
|
879
|
+
|
|
880
|
+
```ruby
|
|
881
|
+
# Get all forever orders (GTT)
|
|
882
|
+
forever_orders = DhanHQ::Models::ForeverOrder.all
|
|
883
|
+
puts "Total forever orders: #{forever_orders.size}"
|
|
884
|
+
```
|
|
885
|
+
|
|
886
|
+
#### Create Forever Order
|
|
887
|
+
|
|
888
|
+
```ruby
|
|
889
|
+
# Create a forever order (GTT)
|
|
890
|
+
forever_order = DhanHQ::Models::ForeverOrder.create(
|
|
891
|
+
dhan_client_id: "1000000003",
|
|
892
|
+
transaction_type: "BUY",
|
|
893
|
+
exchange_segment: "NSE_EQ",
|
|
894
|
+
product_type: "MARGIN",
|
|
895
|
+
order_type: "LIMIT",
|
|
896
|
+
validity: "GTC",
|
|
897
|
+
security_id: "11536",
|
|
898
|
+
quantity: 1,
|
|
899
|
+
price: 3500.0,
|
|
900
|
+
trigger_price: 3450.0,
|
|
901
|
+
condition: "LTP_LESS_THAN_OR_EQUAL"
|
|
902
|
+
)
|
|
903
|
+
|
|
904
|
+
puts "Forever Order ID: #{forever_order.order_id}"
|
|
905
|
+
```
|
|
906
|
+
|
|
907
|
+
#### Cancel Forever Order
|
|
908
|
+
|
|
909
|
+
```ruby
|
|
910
|
+
# Find forever order
|
|
911
|
+
forever_order = DhanHQ::Models::ForeverOrder.all.first
|
|
912
|
+
|
|
913
|
+
# Cancel forever order
|
|
914
|
+
if forever_order
|
|
915
|
+
if forever_order.cancel
|
|
916
|
+
puts "Forever order cancelled successfully"
|
|
917
|
+
end
|
|
918
|
+
end
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
### EDIS
|
|
922
|
+
|
|
923
|
+
#### Get EDIS Form
|
|
924
|
+
|
|
925
|
+
```ruby
|
|
926
|
+
# Get EDIS form
|
|
927
|
+
edis_form = DhanHQ::Models::Edis.form
|
|
928
|
+
puts "EDIS Form:"
|
|
929
|
+
puts " ISIN: #{edis_form[:isin]}"
|
|
930
|
+
puts " Quantity: #{edis_form[:quantity]}"
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
#### Get Bulk EDIS Form
|
|
934
|
+
|
|
935
|
+
```ruby
|
|
936
|
+
# Get bulk EDIS form
|
|
937
|
+
bulk_form = DhanHQ::Models::Edis.bulk_form
|
|
938
|
+
puts "Bulk Form: #{bulk_form.size} entries"
|
|
939
|
+
```
|
|
940
|
+
|
|
941
|
+
#### Generate TPIN
|
|
942
|
+
|
|
943
|
+
```ruby
|
|
944
|
+
# Generate TPIN
|
|
945
|
+
tpin = DhanHQ::Models::Edis.generate_tpin
|
|
946
|
+
puts "TPIN: #{tpin[:tpin]}"
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
#### Inquire EDIS Status
|
|
950
|
+
|
|
951
|
+
```ruby
|
|
952
|
+
# Inquire EDIS status by ISIN
|
|
953
|
+
isin = "INE467B01029" # Example ISIN
|
|
954
|
+
status = DhanHQ::Models::Edis.inquire(isin: isin)
|
|
955
|
+
puts "EDIS Status: #{status[:status]}"
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
### Kill Switch
|
|
959
|
+
|
|
960
|
+
#### Activate Kill Switch
|
|
961
|
+
|
|
962
|
+
```ruby
|
|
963
|
+
# Activate kill switch
|
|
964
|
+
result = DhanHQ::Models::KillSwitch.update(status: "ACTIVATE")
|
|
965
|
+
if result
|
|
966
|
+
puts "Kill switch activated"
|
|
967
|
+
else
|
|
968
|
+
puts "Failed to activate kill switch"
|
|
969
|
+
end
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
#### Deactivate Kill Switch
|
|
973
|
+
|
|
974
|
+
```ruby
|
|
975
|
+
# Deactivate kill switch
|
|
976
|
+
result = DhanHQ::Models::KillSwitch.update(status: "DEACTIVATE")
|
|
977
|
+
if result
|
|
978
|
+
puts "Kill switch deactivated"
|
|
979
|
+
else
|
|
980
|
+
puts "Failed to deactivate kill switch"
|
|
981
|
+
end
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
### Expired Options Data
|
|
985
|
+
|
|
986
|
+
#### Fetch Expired Options Data
|
|
987
|
+
|
|
988
|
+
```ruby
|
|
989
|
+
# Fetch expired options data
|
|
990
|
+
expired_data = DhanHQ::Models::ExpiredOptionsData.fetch(
|
|
991
|
+
security_id: 12345,
|
|
992
|
+
expiry_code: "20240125",
|
|
993
|
+
strike: 18000,
|
|
994
|
+
interval: "5",
|
|
995
|
+
required_data: ["ohlc", "volume"]
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
puts "Expired Options Data:"
|
|
999
|
+
puts " Total records: #{expired_data.size}"
|
|
1000
|
+
expired_data.first(5).each do |record|
|
|
1001
|
+
puts " #{record[:time]}: O=₹#{record[:open]}, H=₹#{record[:high]}, L=₹#{record[:low]}, C=₹#{record[:close]}"
|
|
1002
|
+
end
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
### Margin Calculator
|
|
1006
|
+
|
|
1007
|
+
#### Calculate Margin
|
|
1008
|
+
|
|
1009
|
+
```ruby
|
|
1010
|
+
# Calculate margin for an order
|
|
1011
|
+
margin = DhanHQ::Models::Margin.calculate(
|
|
1012
|
+
dhan_client_id: "1000000003",
|
|
1013
|
+
transaction_type: "BUY",
|
|
1014
|
+
exchange_segment: "NSE_EQ",
|
|
1015
|
+
product_type: "MARGIN",
|
|
1016
|
+
order_type: "LIMIT",
|
|
1017
|
+
security_id: "11536",
|
|
1018
|
+
quantity: 1,
|
|
1019
|
+
price: 3500.0
|
|
1020
|
+
)
|
|
1021
|
+
|
|
1022
|
+
puts "Margin Required: ₹#{margin.margin_required}"
|
|
1023
|
+
puts "Available Margin: ₹#{margin.available_margin}"
|
|
1024
|
+
puts "Utilized Margin: ₹#{margin.utilized_margin}"
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
### Ledger Entries
|
|
1028
|
+
|
|
1029
|
+
#### Get Ledger Entries
|
|
1030
|
+
|
|
1031
|
+
```ruby
|
|
1032
|
+
# Get ledger entries
|
|
1033
|
+
from_date = Date.today - 7
|
|
1034
|
+
to_date = Date.today
|
|
1035
|
+
|
|
1036
|
+
ledger_entries = DhanHQ::Models::LedgerEntry.all(
|
|
1037
|
+
from_date: from_date,
|
|
1038
|
+
to_date: to_date
|
|
1039
|
+
)
|
|
1040
|
+
|
|
1041
|
+
puts "Total ledger entries: #{ledger_entries.size}"
|
|
1042
|
+
ledger_entries.first(10).each do |entry|
|
|
1043
|
+
puts "#{entry[:date]}: #{entry[:description]} - ₹#{entry[:amount]}"
|
|
1044
|
+
end
|
|
1045
|
+
```
|
|
1046
|
+
|
|
1047
|
+
---
|
|
1048
|
+
|
|
1049
|
+
## Validation Contracts Testing
|
|
1050
|
+
|
|
1051
|
+
### Place Order Contract
|
|
1052
|
+
|
|
1053
|
+
```ruby
|
|
1054
|
+
# Test valid order
|
|
1055
|
+
valid_params = {
|
|
1056
|
+
dhan_client_id: "1000000003",
|
|
1057
|
+
transaction_type: "BUY",
|
|
1058
|
+
exchange_segment: "NSE_EQ",
|
|
1059
|
+
product_type: "INTRADAY",
|
|
1060
|
+
order_type: "LIMIT",
|
|
1061
|
+
validity: "DAY",
|
|
1062
|
+
security_id: "11536",
|
|
1063
|
+
quantity: 1,
|
|
1064
|
+
price: 3500.0
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
contract = DhanHQ::Contracts::PlaceOrderContract.new
|
|
1068
|
+
result = contract.call(valid_params)
|
|
1069
|
+
if result.success?
|
|
1070
|
+
puts "Validation passed"
|
|
1071
|
+
else
|
|
1072
|
+
puts "Validation errors: #{result.errors.to_h}"
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
# Test invalid order (missing required field)
|
|
1076
|
+
invalid_params = {
|
|
1077
|
+
transaction_type: "BUY",
|
|
1078
|
+
exchange_segment: "NSE_EQ"
|
|
1079
|
+
# Missing required fields
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
result = contract.call(invalid_params)
|
|
1083
|
+
if result.failure?
|
|
1084
|
+
puts "Validation failed as expected"
|
|
1085
|
+
puts "Errors: #{result.errors.to_h}"
|
|
1086
|
+
end
|
|
1087
|
+
|
|
1088
|
+
# Test invalid price (NaN)
|
|
1089
|
+
invalid_price_params = valid_params.merge(price: Float::NAN)
|
|
1090
|
+
result = contract.call(invalid_price_params)
|
|
1091
|
+
if result.failure?
|
|
1092
|
+
puts "NaN validation caught: #{result.errors.to_h}"
|
|
1093
|
+
end
|
|
1094
|
+
|
|
1095
|
+
# Test invalid price (Infinity)
|
|
1096
|
+
invalid_inf_params = valid_params.merge(price: Float::INFINITY)
|
|
1097
|
+
result = contract.call(invalid_inf_params)
|
|
1098
|
+
if result.failure?
|
|
1099
|
+
puts "Infinity validation caught: #{result.errors.to_h}"
|
|
1100
|
+
end
|
|
1101
|
+
|
|
1102
|
+
# Test price exceeding upper bound
|
|
1103
|
+
invalid_upper_params = valid_params.merge(price: 2_000_000_000)
|
|
1104
|
+
result = contract.call(invalid_upper_params)
|
|
1105
|
+
if result.failure?
|
|
1106
|
+
puts "Upper bound validation caught: #{result.errors.to_h}"
|
|
1107
|
+
end
|
|
1108
|
+
```
|
|
1109
|
+
|
|
1110
|
+
### Modify Order Contract
|
|
1111
|
+
|
|
1112
|
+
```ruby
|
|
1113
|
+
# Test valid modification
|
|
1114
|
+
valid_params = {
|
|
1115
|
+
dhan_client_id: "1000000003",
|
|
1116
|
+
order_id: "112111182045",
|
|
1117
|
+
price: 3501.0,
|
|
1118
|
+
quantity: 2
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
contract = DhanHQ::Contracts::ModifyOrderContract.new
|
|
1122
|
+
result = contract.call(valid_params)
|
|
1123
|
+
if result.success?
|
|
1124
|
+
puts "Validation passed"
|
|
1125
|
+
else
|
|
1126
|
+
puts "Validation errors: #{result.errors.to_h}"
|
|
1127
|
+
end
|
|
1128
|
+
```
|
|
1129
|
+
|
|
1130
|
+
### Margin Calculator Contract
|
|
1131
|
+
|
|
1132
|
+
```ruby
|
|
1133
|
+
# Test valid margin calculation
|
|
1134
|
+
valid_params = {
|
|
1135
|
+
dhan_client_id: "1000000003",
|
|
1136
|
+
transaction_type: "BUY",
|
|
1137
|
+
exchange_segment: "NSE_EQ",
|
|
1138
|
+
product_type: "MARGIN",
|
|
1139
|
+
order_type: "LIMIT",
|
|
1140
|
+
security_id: "11536",
|
|
1141
|
+
quantity: 1,
|
|
1142
|
+
price: 3500.0
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
contract = DhanHQ::Contracts::MarginCalculatorContract.new
|
|
1146
|
+
result = contract.call(valid_params)
|
|
1147
|
+
if result.success?
|
|
1148
|
+
puts "Validation passed"
|
|
1149
|
+
else
|
|
1150
|
+
puts "Validation errors: #{result.errors.to_h}"
|
|
1151
|
+
end
|
|
1152
|
+
```
|
|
1153
|
+
|
|
1154
|
+
### Option Chain Contract
|
|
1155
|
+
|
|
1156
|
+
```ruby
|
|
1157
|
+
# Test valid option chain request
|
|
1158
|
+
valid_params = {
|
|
1159
|
+
underlying_scrip: "NIFTY",
|
|
1160
|
+
underlying_seg: "IDX_I",
|
|
1161
|
+
expiry: "2024-01-25"
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
contract = DhanHQ::Contracts::OptionChainContract.new
|
|
1165
|
+
result = contract.call(valid_params)
|
|
1166
|
+
if result.success?
|
|
1167
|
+
puts "Validation passed"
|
|
1168
|
+
else
|
|
1169
|
+
puts "Validation errors: #{result.errors.to_h}"
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
# Test invalid expiry format
|
|
1173
|
+
invalid_params = valid_params.merge(expiry: "25-01-2024")
|
|
1174
|
+
result = contract.call(invalid_params)
|
|
1175
|
+
if result.failure?
|
|
1176
|
+
puts "Invalid expiry format caught: #{result.errors.to_h}"
|
|
1177
|
+
end
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
### Historical Data Contract
|
|
1181
|
+
|
|
1182
|
+
```ruby
|
|
1183
|
+
# Test valid historical data request
|
|
1184
|
+
valid_params = {
|
|
1185
|
+
security_id: "11536",
|
|
1186
|
+
exchange_segment: "NSE_EQ",
|
|
1187
|
+
from_date: Date.today - 7,
|
|
1188
|
+
to_date: Date.today,
|
|
1189
|
+
interval: 5
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
contract = DhanHQ::Contracts::HistoricalDataContract.new
|
|
1193
|
+
result = contract.call(valid_params)
|
|
1194
|
+
if result.success?
|
|
1195
|
+
puts "Validation passed"
|
|
1196
|
+
else
|
|
1197
|
+
puts "Validation errors: #{result.errors.to_h}"
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
# Test date range validation (max 31 days)
|
|
1201
|
+
invalid_params = valid_params.merge(
|
|
1202
|
+
from_date: Date.today - 35,
|
|
1203
|
+
to_date: Date.today
|
|
1204
|
+
)
|
|
1205
|
+
result = contract.call(invalid_params)
|
|
1206
|
+
if result.failure?
|
|
1207
|
+
puts "Date range validation caught: #{result.errors.to_h}"
|
|
1208
|
+
end
|
|
1209
|
+
```
|
|
1210
|
+
|
|
1211
|
+
---
|
|
1212
|
+
|
|
1213
|
+
## Error Handling Testing
|
|
1214
|
+
|
|
1215
|
+
### Test Rate Limit Error
|
|
1216
|
+
|
|
1217
|
+
```ruby
|
|
1218
|
+
# Make rapid requests to trigger rate limit
|
|
1219
|
+
10.times do |i|
|
|
1220
|
+
begin
|
|
1221
|
+
DhanHQ::Models::Funds.fetch
|
|
1222
|
+
puts "Request #{i + 1} succeeded"
|
|
1223
|
+
rescue DhanHQ::RateLimitError => e
|
|
1224
|
+
puts "Rate limit error: #{e.message}"
|
|
1225
|
+
break
|
|
1226
|
+
end
|
|
1227
|
+
sleep(0.1)
|
|
1228
|
+
end
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
### Test Authentication Error
|
|
1232
|
+
|
|
1233
|
+
```ruby
|
|
1234
|
+
# Temporarily remove access token
|
|
1235
|
+
original_token = DhanHQ.configuration.access_token
|
|
1236
|
+
DhanHQ.configuration.access_token = nil
|
|
1237
|
+
|
|
1238
|
+
begin
|
|
1239
|
+
DhanHQ::Models::Funds.fetch
|
|
1240
|
+
rescue DhanHQ::InvalidAuthenticationError => e
|
|
1241
|
+
puts "Authentication error caught: #{e.message}"
|
|
1242
|
+
ensure
|
|
1243
|
+
# Restore token
|
|
1244
|
+
DhanHQ.configuration.access_token = original_token
|
|
1245
|
+
end
|
|
1246
|
+
```
|
|
1247
|
+
|
|
1248
|
+
### Test Validation Error
|
|
1249
|
+
|
|
1250
|
+
```ruby
|
|
1251
|
+
# Try to place order with invalid data
|
|
1252
|
+
begin
|
|
1253
|
+
order = DhanHQ::Models::Order.place(
|
|
1254
|
+
transaction_type: "INVALID_TYPE",
|
|
1255
|
+
exchange_segment: "NSE_EQ"
|
|
1256
|
+
)
|
|
1257
|
+
rescue DhanHQ::Error => e
|
|
1258
|
+
puts "Validation error caught: #{e.message}"
|
|
1259
|
+
end
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
### Test Network Error Handling
|
|
1263
|
+
|
|
1264
|
+
```ruby
|
|
1265
|
+
# Test retry logic (will retry on transient errors)
|
|
1266
|
+
begin
|
|
1267
|
+
# This will use retry logic for transient errors
|
|
1268
|
+
funds = DhanHQ::Models::Funds.fetch
|
|
1269
|
+
puts "Success: #{funds.available_margin}"
|
|
1270
|
+
rescue DhanHQ::NetworkError => e
|
|
1271
|
+
puts "Network error after retries: #{e.message}"
|
|
1272
|
+
end
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
---
|
|
1276
|
+
|
|
1277
|
+
## Rate Limiting Testing
|
|
1278
|
+
|
|
1279
|
+
### Test Rate Limiter
|
|
1280
|
+
|
|
1281
|
+
```ruby
|
|
1282
|
+
# Check rate limiter status
|
|
1283
|
+
rate_limiter = DhanHQ::Client.new(api_type: :trading).instance_variable_get(:@rate_limiter)
|
|
1284
|
+
|
|
1285
|
+
# Make multiple requests and observe throttling
|
|
1286
|
+
start_time = Time.now
|
|
1287
|
+
5.times do |i|
|
|
1288
|
+
rate_limiter.throttle!
|
|
1289
|
+
puts "Request #{i + 1} at #{Time.now - start_time}s"
|
|
1290
|
+
end
|
|
1291
|
+
|
|
1292
|
+
# Shutdown rate limiter (cleanup)
|
|
1293
|
+
rate_limiter.shutdown
|
|
1294
|
+
```
|
|
1295
|
+
|
|
1296
|
+
### Test Rate Limit Per Second
|
|
1297
|
+
|
|
1298
|
+
```ruby
|
|
1299
|
+
# Test per-second rate limiting
|
|
1300
|
+
start_time = Time.now
|
|
1301
|
+
10.times do |i|
|
|
1302
|
+
begin
|
|
1303
|
+
DhanHQ::Models::Funds.fetch
|
|
1304
|
+
elapsed = Time.now - start_time
|
|
1305
|
+
puts "Request #{i + 1} completed at #{elapsed.round(2)}s"
|
|
1306
|
+
rescue DhanHQ::RateLimitError => e
|
|
1307
|
+
puts "Rate limited at request #{i + 1}: #{e.message}"
|
|
1308
|
+
end
|
|
1309
|
+
sleep(0.1)
|
|
1310
|
+
end
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
---
|
|
1314
|
+
|
|
1315
|
+
## Advanced Testing Scenarios
|
|
1316
|
+
|
|
1317
|
+
### End-to-End Order Flow
|
|
1318
|
+
|
|
1319
|
+
```ruby
|
|
1320
|
+
# Complete order lifecycle test
|
|
1321
|
+
puts "=== Order Lifecycle Test ==="
|
|
1322
|
+
|
|
1323
|
+
# 1. Check funds
|
|
1324
|
+
funds = DhanHQ::Models::Funds.fetch
|
|
1325
|
+
puts "1. Available Margin: ₹#{funds.available_margin}"
|
|
1326
|
+
|
|
1327
|
+
# 2. Calculate margin
|
|
1328
|
+
margin = DhanHQ::Models::Margin.calculate(
|
|
1329
|
+
dhan_client_id: "1000000003",
|
|
1330
|
+
transaction_type: "BUY",
|
|
1331
|
+
exchange_segment: "NSE_EQ",
|
|
1332
|
+
product_type: "MARGIN",
|
|
1333
|
+
order_type: "LIMIT",
|
|
1334
|
+
security_id: "11536",
|
|
1335
|
+
quantity: 1,
|
|
1336
|
+
price: 3500.0
|
|
1337
|
+
)
|
|
1338
|
+
puts "2. Margin Required: ₹#{margin.margin_required}"
|
|
1339
|
+
|
|
1340
|
+
# 3. Place order
|
|
1341
|
+
order = DhanHQ::Models::Order.place(
|
|
1342
|
+
dhan_client_id: "1000000003",
|
|
1343
|
+
transaction_type: "BUY",
|
|
1344
|
+
exchange_segment: "NSE_EQ",
|
|
1345
|
+
product_type: "MARGIN",
|
|
1346
|
+
order_type: "LIMIT",
|
|
1347
|
+
validity: "DAY",
|
|
1348
|
+
security_id: "11536",
|
|
1349
|
+
quantity: 1,
|
|
1350
|
+
price: 3500.0
|
|
1351
|
+
)
|
|
1352
|
+
puts "3. Order Placed: #{order.order_id}, Status: #{order.order_status}"
|
|
1353
|
+
|
|
1354
|
+
# 4. Monitor order via WebSocket
|
|
1355
|
+
orders_client = DhanHQ::WS::Orders.client
|
|
1356
|
+
orders_client.on(:update) do |update|
|
|
1357
|
+
if update.order_no == order.order_id
|
|
1358
|
+
puts "4. Order Update: #{update.status}"
|
|
1359
|
+
end
|
|
1360
|
+
end
|
|
1361
|
+
orders_client.start
|
|
1362
|
+
|
|
1363
|
+
# 5. Modify order (if pending)
|
|
1364
|
+
sleep(2)
|
|
1365
|
+
order.refresh
|
|
1366
|
+
if order.order_status == "PENDING"
|
|
1367
|
+
if order.modify(price: 3501.0)
|
|
1368
|
+
puts "5. Order Modified"
|
|
1369
|
+
end
|
|
1370
|
+
end
|
|
1371
|
+
|
|
1372
|
+
# 6. Cancel order
|
|
1373
|
+
sleep(2)
|
|
1374
|
+
if order.cancel
|
|
1375
|
+
puts "6. Order Cancelled"
|
|
1376
|
+
end
|
|
1377
|
+
|
|
1378
|
+
# 7. Check trades
|
|
1379
|
+
trades = DhanHQ::Models::Trade.find_by_order_id(order.order_id)
|
|
1380
|
+
puts "7. Trades: #{trades.size}"
|
|
1381
|
+
|
|
1382
|
+
# Cleanup
|
|
1383
|
+
orders_client.stop
|
|
1384
|
+
puts "=== Test Complete ==="
|
|
1385
|
+
```
|
|
1386
|
+
|
|
1387
|
+
### Market Data Analysis
|
|
1388
|
+
|
|
1389
|
+
```ruby
|
|
1390
|
+
# Get historical data and analyze
|
|
1391
|
+
historical_data = DhanHQ::Models::HistoricalData.daily(
|
|
1392
|
+
security_id: "11536",
|
|
1393
|
+
exchange_segment: "NSE_EQ",
|
|
1394
|
+
from_date: Date.today - 30,
|
|
1395
|
+
to_date: Date.today
|
|
1396
|
+
)
|
|
1397
|
+
|
|
1398
|
+
# Calculate simple moving average
|
|
1399
|
+
prices = historical_data.map { |c| c[:close] }
|
|
1400
|
+
sma_20 = prices.last(20).sum / 20.0
|
|
1401
|
+
puts "20-day SMA: ₹#{sma_20.round(2)}"
|
|
1402
|
+
|
|
1403
|
+
# Get current LTP
|
|
1404
|
+
ltp_data = DhanHQ::Models::MarketFeed.ltp("NSE_EQ" => [11536])
|
|
1405
|
+
current_price = ltp_data[:data]["NSE_EQ"]["11536"][:last_price]
|
|
1406
|
+
puts "Current Price: ₹#{current_price}"
|
|
1407
|
+
|
|
1408
|
+
# Compare
|
|
1409
|
+
if current_price > sma_20
|
|
1410
|
+
puts "Price is above 20-day SMA"
|
|
1411
|
+
else
|
|
1412
|
+
puts "Price is below 20-day SMA"
|
|
1413
|
+
end
|
|
1414
|
+
```
|
|
1415
|
+
|
|
1416
|
+
### Option Strategy Testing
|
|
1417
|
+
|
|
1418
|
+
```ruby
|
|
1419
|
+
# Get option chain
|
|
1420
|
+
expiry_list = DhanHQ::Models::OptionChain.fetch_expiry_list(
|
|
1421
|
+
underlying_scrip: "NIFTY",
|
|
1422
|
+
underlying_seg: "IDX_I"
|
|
1423
|
+
)
|
|
1424
|
+
|
|
1425
|
+
expiry = expiry_list.first[:expiry_date]
|
|
1426
|
+
option_chain = DhanHQ::Models::OptionChain.fetch(
|
|
1427
|
+
underlying_scrip: "NIFTY",
|
|
1428
|
+
underlying_seg: "IDX_I",
|
|
1429
|
+
expiry: expiry
|
|
1430
|
+
)
|
|
1431
|
+
|
|
1432
|
+
# Find ATM strike
|
|
1433
|
+
ltp_data = DhanHQ::Models::MarketFeed.ltp("IDX_I" => [13])
|
|
1434
|
+
nifty_ltp = ltp_data[:data]["IDX_I"]["13"][:last_price]
|
|
1435
|
+
atm_strike = (nifty_ltp / 50).round * 50
|
|
1436
|
+
|
|
1437
|
+
# Find ATM options
|
|
1438
|
+
atm_option = option_chain.find { |o| o[:strike_price] == atm_strike }
|
|
1439
|
+
if atm_option
|
|
1440
|
+
puts "ATM Strike: #{atm_strike}"
|
|
1441
|
+
puts "CE Symbol: #{atm_option[:call_option]&.dig(:trading_symbol)}"
|
|
1442
|
+
puts "PE Symbol: #{atm_option[:put_option]&.dig(:trading_symbol)}"
|
|
1443
|
+
end
|
|
1444
|
+
```
|
|
1445
|
+
|
|
1446
|
+
---
|
|
1447
|
+
|
|
1448
|
+
## Tips for Console Testing
|
|
1449
|
+
|
|
1450
|
+
1. **Use Variables**: Store results in variables for reuse
|
|
1451
|
+
```ruby
|
|
1452
|
+
order = DhanHQ::Models::Order.find("112111182045")
|
|
1453
|
+
order.modify(price: 3501.0)
|
|
1454
|
+
```
|
|
1455
|
+
|
|
1456
|
+
2. **Use Helper Methods**: Leverage instrument helper methods
|
|
1457
|
+
```ruby
|
|
1458
|
+
instrument = DhanHQ::Models::Instrument.find("NSE_EQ", "TCS")
|
|
1459
|
+
ltp = instrument.ltp
|
|
1460
|
+
```
|
|
1461
|
+
|
|
1462
|
+
3. **Monitor WebSockets**: Keep WebSocket clients running in background
|
|
1463
|
+
```ruby
|
|
1464
|
+
orders_client = DhanHQ::WS::Orders.client
|
|
1465
|
+
orders_client.start
|
|
1466
|
+
# Continue working, updates will print automatically
|
|
1467
|
+
```
|
|
1468
|
+
|
|
1469
|
+
4. **Error Handling**: Wrap risky operations in begin/rescue
|
|
1470
|
+
```ruby
|
|
1471
|
+
begin
|
|
1472
|
+
order = DhanHQ::Models::Order.place(params)
|
|
1473
|
+
rescue DhanHQ::Error => e
|
|
1474
|
+
puts "Error: #{e.message}"
|
|
1475
|
+
end
|
|
1476
|
+
```
|
|
1477
|
+
|
|
1478
|
+
5. **Cleanup**: Always stop WebSocket connections when done
|
|
1479
|
+
```ruby
|
|
1480
|
+
orders_client.stop
|
|
1481
|
+
market_client.stop
|
|
1482
|
+
```
|
|
1483
|
+
|
|
1484
|
+
---
|
|
1485
|
+
|
|
1486
|
+
## Quick Reference
|
|
1487
|
+
|
|
1488
|
+
### Common Exchange Segments
|
|
1489
|
+
- `NSE_EQ` - NSE Equity
|
|
1490
|
+
- `BSE_EQ` - BSE Equity
|
|
1491
|
+
- `NSE_FNO` - NSE F&O
|
|
1492
|
+
- `BSE_FNO` - BSE F&O
|
|
1493
|
+
- `IDX_I` - Indices (NIFTY, BANKNIFTY, etc.)
|
|
1494
|
+
|
|
1495
|
+
### Common Product Types
|
|
1496
|
+
- `INTRADAY` - Intraday
|
|
1497
|
+
- `MARGIN` - Margin
|
|
1498
|
+
- `CNC` - Cash and Carry
|
|
1499
|
+
- `CO` - Cover Order
|
|
1500
|
+
- `BO` - Bracket Order
|
|
1501
|
+
|
|
1502
|
+
### Common Order Types
|
|
1503
|
+
- `MARKET` - Market Order
|
|
1504
|
+
- `LIMIT` - Limit Order
|
|
1505
|
+
- `STOPLOSS` - Stop Loss Order
|
|
1506
|
+
- `STOPLOSS_MARKET` - Stop Loss Market Order
|
|
1507
|
+
|
|
1508
|
+
### Common Transaction Types
|
|
1509
|
+
- `BUY` - Buy
|
|
1510
|
+
- `SELL` - Sell
|
|
1511
|
+
|
|
1512
|
+
---
|
|
1513
|
+
|
|
1514
|
+
This guide provides comprehensive examples for testing all features of the DhanHQ client gem. Use these examples in `bin/console` to explore and test the gem's functionality.
|