DhanHQ 2.1.5 → 2.1.7

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/GUIDE.md +221 -31
  4. data/README.md +453 -126
  5. data/README1.md +293 -30
  6. data/docs/live_order_updates.md +319 -0
  7. data/docs/rails_websocket_integration.md +847 -0
  8. data/docs/standalone_ruby_websocket_integration.md +1588 -0
  9. data/docs/websocket_integration.md +918 -0
  10. data/examples/comprehensive_websocket_examples.rb +148 -0
  11. data/examples/instrument_finder_test.rb +195 -0
  12. data/examples/live_order_updates.rb +118 -0
  13. data/examples/market_depth_example.rb +144 -0
  14. data/examples/market_feed_example.rb +81 -0
  15. data/examples/order_update_example.rb +105 -0
  16. data/examples/trading_fields_example.rb +215 -0
  17. data/lib/DhanHQ/configuration.rb +16 -1
  18. data/lib/DhanHQ/constants.rb +16 -0
  19. data/lib/DhanHQ/contracts/expired_options_data_contract.rb +103 -0
  20. data/lib/DhanHQ/contracts/trade_contract.rb +70 -0
  21. data/lib/DhanHQ/errors.rb +2 -0
  22. data/lib/DhanHQ/models/expired_options_data.rb +331 -0
  23. data/lib/DhanHQ/models/instrument.rb +114 -4
  24. data/lib/DhanHQ/models/instrument_helpers.rb +141 -0
  25. data/lib/DhanHQ/models/order_update.rb +235 -0
  26. data/lib/DhanHQ/models/trade.rb +118 -31
  27. data/lib/DhanHQ/resources/expired_options_data.rb +22 -0
  28. data/lib/DhanHQ/version.rb +1 -1
  29. data/lib/DhanHQ/ws/base_connection.rb +249 -0
  30. data/lib/DhanHQ/ws/connection.rb +2 -2
  31. data/lib/DhanHQ/ws/decoder.rb +3 -3
  32. data/lib/DhanHQ/ws/market_depth/client.rb +376 -0
  33. data/lib/DhanHQ/ws/market_depth/decoder.rb +131 -0
  34. data/lib/DhanHQ/ws/market_depth.rb +74 -0
  35. data/lib/DhanHQ/ws/orders/client.rb +175 -11
  36. data/lib/DhanHQ/ws/orders/connection.rb +40 -81
  37. data/lib/DhanHQ/ws/orders.rb +28 -0
  38. data/lib/DhanHQ/ws/segments.rb +18 -2
  39. data/lib/DhanHQ/ws.rb +3 -2
  40. data/lib/dhan_hq.rb +5 -0
  41. metadata +36 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cff831c4d2dc881c38a4ecc6274ad9ba8601fd6c6910815ab9ec40fde31af564
4
- data.tar.gz: 00b892609e077902e1137b789dcd3a6d0e51fa3e042d38b05c39fc92971da157
3
+ metadata.gz: 1ffcb72b2997f7841ef6c872ad71748c36f4305f9e746a5d4d8f2a3b9429c8da
4
+ data.tar.gz: 5a72519746d9ca58f6cb295855f9065ccc3b9059c2684347b58c3e998ad8668b
5
5
  SHA512:
6
- metadata.gz: f476df43f8f9500515101c85d423b91f713f384e89a01f316ed66265d69502a45b4adf7c2cd06aa6c8d466e65d5548e0337361844305e6f9103df0dd6a7564f3
7
- data.tar.gz: aa14913dfa8590e8ba52e2f49a97b4cf475ad6d0058deac7114c1c56cb3817c70a38655afa4b30ef9741ab3da82f53c9d719dec70bef70bb9e242f7081a7392e
6
+ metadata.gz: 397d51627f7049470332e23926ca7d00d78aad94d88eb0939d25164dc74330d68014a5ad6593453dfedb2da51c4f2a810ecc7e971d5f1735b3b21e96d3d068df
7
+ data.tar.gz: 2092c00ab1903f18d7718bd27125236251d2129cd536a071b506c3a53d2826a66eb5c9ba737ab89eff52b125e864138b507e577616ffc9e0a034da0a4eb8e37a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.1.7] - 2025-01-28
4
+
5
+ ### Added
6
+ - **Instrument instance methods**: Added convenience methods to Instrument model for accessing market feed, historical data, and option chain data
7
+ - `instrument.ltp` - Fetches last traded price using `DhanHQ::Models::MarketFeed.ltp`
8
+ - `instrument.ohlc` - Fetches OHLC data using `DhanHQ::Models::MarketFeed.ohlc`
9
+ - `instrument.quote` - Fetches full quote depth using `DhanHQ::Models::MarketFeed.quote`
10
+ - `instrument.daily(from_date:, to_date:, **options)` - Fetches daily historical data using `DhanHQ::Models::HistoricalData.daily`
11
+ - `instrument.intraday(from_date:, to_date:, interval:, **options)` - Fetches intraday historical data using `DhanHQ::Models::HistoricalData.intraday`
12
+ - `instrument.expiry_list` - Fetches expiry list using `DhanHQ::Models::OptionChain.fetch_expiry_list`
13
+ - `instrument.option_chain(expiry:)` - Fetches option chain using `DhanHQ::Models::OptionChain.fetch`
14
+ - All methods automatically use the instrument's `security_id`, `exchange_segment`, and `instrument` attributes
15
+ - **InstrumentHelpers module**: Created reusable module to provide these convenience methods
16
+
17
+ ### Changed
18
+ - Align Super Order documentation across README, README1, and GUIDE with the latest API contract (place, modify, cancel, list).
19
+ - Normalise remaining documentation examples to snake_case, including order update WebSocket callbacks and kill switch response guidance.
20
+
3
21
  ## [2.1.5] - 2025-01-27
4
22
 
5
23
  ### ⚠️ BREAKING CHANGES
@@ -18,6 +36,9 @@
18
36
  ### Fixed
19
37
  - **RuboCop compliance**: Fixed all RuboCop offenses (179 → 0 offenses)
20
38
  - **Documentation**: Updated all documentation examples to use `require 'dhan_hq'`
39
+ - **Documentation**: Correct Super Order examples to use snake_case parameters for `DhanHQ::Models` helpers
40
+ - **Documentation**: Normalise Super Order path placeholders and response fields to snake_case for consistency
41
+ - **Documentation**: Clarified that model helpers auto-inject `dhan_client_id`, removing the need to add it manually in Ruby payloads
21
42
  - **Code quality**: Added comprehensive validation tests for OptionChain methods
22
43
 
23
44
  ### Changed
data/GUIDE.md CHANGED
@@ -156,9 +156,9 @@ puts order.order_status # => "TRADED" / "PENDING" / ...
156
156
 
157
157
  `Order#modify` merges the existing attributes with the supplied overrides and validates against `ModifyOrderContract`.
158
158
 
159
- - Required: the instance must have an `order_id` and `dhan_client_id`.
159
+ - Required: the instance must have an `order_id`; the model reuses the saved `dhan_client_id` when building the payload.
160
160
  - At least one of `order_type`, `quantity`, `price`, `trigger_price`, `disclosed_quantity`, `validity` must change.
161
- - Payload is camelised automatically before hitting `/v2/orders/{orderId}`.
161
+ - Payload is camelised automatically before hitting `/v2/orders/{order_id}`.
162
162
 
163
163
  ```ruby
164
164
  order.modify(price: 154.2, trigger_price: 149.5)
@@ -208,42 +208,174 @@ DhanHQ::Models::Order.resource.slicing(payload)
208
208
 
209
209
  ### Super Orders
210
210
 
211
- `DhanHQ::Models::SuperOrder` wraps `/v2/super/orders`.
211
+ `DhanHQ::Models::SuperOrder` wraps the `/v2/super/orders` family. A super order combines entry, target, and stop-loss legs into one atomic instruction and supports an optional trailing jump so risk is managed server-side immediately after entry.
212
212
 
213
- ```ruby
214
- legs = {
215
- transactionType: "BUY",
216
- exchangeSegment: "NSE_FNO",
217
- productType: "CO",
218
- orderType: "LIMIT",
219
- validity: "DAY",
220
- securityId: "43492",
221
- quantity: 50,
222
- price: 100.0,
223
- stopLossPrice: 95.0,
224
- targetPrice: 110.0
213
+ #### Endpoints
214
+
215
+ | Method | Path | Description |
216
+ | -------- | -------------------------------------- | ------------------------------------- |
217
+ | `POST` | `/super/orders` | Create a new super order |
218
+ | `PUT` | `/super/orders/{order_id}` | Modify a pending super order |
219
+ | `DELETE` | `/super/orders/{order_id}/{order_leg}` | Cancel a pending super order leg |
220
+ | `GET` | `/super/orders` | Retrieve the list of all super orders |
221
+
222
+ #### Place Super Order
223
+
224
+ > ℹ️ Static IP whitelisting with Dhan support is required before invoking these APIs.
225
+
226
+ ```bash
227
+ curl --request POST \
228
+ --url https://api.dhan.co/v2/super/orders \
229
+ --header 'Content-Type: application/json' \
230
+ --header 'access-token: JWT' \
231
+ --data '{Request JSON}'
232
+ ```
233
+
234
+ Request body:
235
+
236
+ ```json
237
+ {
238
+ "dhan_client_id": "1000000003",
239
+ "correlation_id": "123abc678",
240
+ "transaction_type": "BUY",
241
+ "exchange_segment": "NSE_EQ",
242
+ "product_type": "CNC",
243
+ "order_type": "LIMIT",
244
+ "security_id": "11536",
245
+ "quantity": 5,
246
+ "price": 1500,
247
+ "target_price": 1600,
248
+ "stop_loss_price": 1400,
249
+ "trailing_jump": 10
250
+ }
251
+ ```
252
+
253
+ Key parameters:
254
+
255
+ | Field | Type | Notes |
256
+ | ------------------ | ------------------------ | -------------------------------------------------------------------------------------------------------------- |
257
+ | `dhan_client_id` | string *(required)* | User specific identifier generated by Dhan. Automatically merged when you call through the Ruby model helpers. |
258
+ | `correlation_id` | string | Optional caller supplied correlation id. |
259
+ | `transaction_type` | enum string *(required)* | `BUY` or `SELL`. |
260
+ | `exchange_segment` | enum string *(required)* | Exchange segment. |
261
+ | `product_type` | enum string *(required)* | `CNC`, `INTRADAY`, `MARGIN`, or `MTF`. |
262
+ | `order_type` | enum string *(required)* | `LIMIT` or `MARKET`. |
263
+ | `security_id` | string *(required)* | Exchange security identifier. |
264
+ | `quantity` | integer *(required)* | Entry quantity. |
265
+ | `price` | float *(required)* | Entry price. |
266
+ | `target_price` | float *(required)* | Target price for the super order. |
267
+ | `stop_loss_price` | float *(required)* | Stop-loss price for the super order. |
268
+ | `trailing_jump` | float *(required)* | Trailing jump size. |
269
+
270
+ > 🐍 Pass snake_case keys when invoking `DhanHQ::Models::SuperOrder.create`—the client camelizes internally before calling the REST API and injects your configured `dhan_client_id`, so the key is optional in Ruby payloads.
271
+
272
+ Response:
273
+
274
+ ```json
275
+ {
276
+ "order_id": "112111182198",
277
+ "order_status": "PENDING"
225
278
  }
279
+ ```
280
+
281
+ #### Modify Super Order
226
282
 
227
- super_order = DhanHQ::Models::SuperOrder.create(legs)
228
- super_order.modify(trailingJump: 2.5)
229
- super_order.cancel("ENTRY_LEG")
283
+ Modify while the order is `PENDING` or `PART_TRADED`. Entry leg updates adjust the entire super order until the entry trades; afterwards only target and stop-loss legs (price, trailing) remain editable.
284
+
285
+ ```bash
286
+ curl --request PUT \
287
+ --url https://api.dhan.co/v2/super/orders/{order_id} \
288
+ --header 'Content-Type: application/json' \
289
+ --header 'access-token: JWT' \
290
+ --data '{Request JSON}'
230
291
  ```
231
292
 
293
+ Example payload:
294
+
295
+ ```json
296
+ {
297
+ "dhan_client_id": "1000000009",
298
+ "order_id": "112111182045",
299
+ "order_type": "LIMIT",
300
+ "leg_name": "ENTRY_LEG",
301
+ "quantity": 40,
302
+ "price": 1300,
303
+ "target_price": 1450,
304
+ "stop_loss_price": 1350,
305
+ "trailing_jump": 20
306
+ }
307
+ ```
308
+
309
+ Conditional fields:
310
+
311
+ | Field | Required when | Notes |
312
+ | ----------------- | --------------------------------------- | ------------------------------------ |
313
+ | `order_type` | Updating `ENTRY_LEG` | `LIMIT` or `MARKET`. |
314
+ | `quantity` | Updating `ENTRY_LEG` | Adjusts entry quantity. |
315
+ | `price` | Updating `ENTRY_LEG` | Adjusts entry price. |
316
+ | `target_price` | Updating `ENTRY_LEG` or `TARGET_LEG` | Adjusts target price. |
317
+ | `stop_loss_price` | Updating `ENTRY_LEG` or `STOP_LOSS_LEG` | Adjusts stop-loss price. |
318
+ | `trailing_jump` | Updating `ENTRY_LEG` or `STOP_LOSS_LEG` | Pass `0` or omit to cancel trailing. |
319
+
320
+ Response:
321
+
322
+ ```json
323
+ {
324
+ "order_id": "112111182045",
325
+ "order_status": "TRANSIT"
326
+ }
327
+ ```
328
+
329
+ #### Cancel Super Order
330
+
331
+ ```bash
332
+ curl --request DELETE \
333
+ --url https://api.dhan.co/v2/super/orders/{order_id}/{order_leg} \
334
+ --header 'Content-Type: application/json' \
335
+ --header 'access-token: JWT'
336
+ ```
337
+
338
+ Path parameters:
339
+
340
+ | Field | Description | Example |
341
+ | ----------- | -------------------------------------------------------------- | ------------- |
342
+ | `order_id` | Super order identifier. | `11211182198` |
343
+ | `order_leg` | Leg to cancel (`ENTRY_LEG`, `TARGET_LEG`, or `STOP_LOSS_LEG`). | `ENTRY_LEG` |
344
+
345
+ Response:
346
+
347
+ ```json
348
+ {
349
+ "order_id": "112111182045",
350
+ "order_status": "CANCELLED"
351
+ }
352
+ ```
353
+
354
+ #### Super Order List
355
+
356
+ ```bash
357
+ curl --request GET \
358
+ --url https://api.dhan.co/v2/super/orders \
359
+ --header 'Content-Type: application/json' \
360
+ --header 'access-token: JWT'
361
+ ```
362
+
363
+ The response returns one object per super order with nested `leg_details`. Key attributes include `order_status`, `filled_qty`, `remaining_quantity`, `average_traded_price`, and leg-level trailing configuration. `CLOSED` indicates the entry plus either target or stop-loss filled the entire quantity; `TRIGGERED` surfaces on the target or stop-loss leg that fired.
364
+
232
365
  ### Forever Orders (GTT)
233
366
 
234
367
  `DhanHQ::Models::ForeverOrder` maps to `/v2/forever/orders`.
235
368
 
236
369
  ```ruby
237
370
  params = {
238
- dhanClientId: "123456",
239
- transactionType: "SELL",
240
- exchangeSegment: "NSE_EQ",
241
- productType: "CNC",
242
- orderType: "LIMIT",
371
+ transaction_type: "SELL",
372
+ exchange_segment: "NSE_EQ",
373
+ product_type: "CNC",
374
+ order_type: "LIMIT",
243
375
  validity: "DAY",
244
- securityId: "1333",
376
+ security_id: "1333",
245
377
  price: 200.0,
246
- triggerPrice: 198.0
378
+ trigger_price: 198.0
247
379
  }
248
380
 
249
381
  forever_order = DhanHQ::Models::ForeverOrder.create(params)
@@ -251,6 +383,8 @@ forever_order.modify(price: 205.0)
251
383
  forever_order.cancel
252
384
  ```
253
385
 
386
+ > 🪄 Model helpers merge the configured `dhan_client_id` automatically, so you can omit it when constructing Ruby hashes like the example above.
387
+
254
388
  The forever order helpers accept snake_case parameters and camelize them internally; only the low-level resource requires raw API casing.
255
389
 
256
390
  ---
@@ -268,7 +402,6 @@ Convert an intraday position to delivery (or vice versa):
268
402
 
269
403
  ```ruby
270
404
  convert_payload = {
271
- dhan_client_id: "123456",
272
405
  security_id: "1333",
273
406
  from_product_type: "INTRADAY",
274
407
  to_product_type: "CNC",
@@ -281,6 +414,8 @@ response = DhanHQ::Models::Position.convert(convert_payload)
281
414
  raise response.errors.to_s if response.is_a?(DhanHQ::ErrorObject)
282
415
  ```
283
416
 
417
+ > 🪄 No need to merge `dhan_client_id`; the helper adds it from your configuration before calling `/v2/positions/convert`.
418
+
284
419
  The conversion helper validates the payload with `PositionConversionContract`; missing or invalid fields raise `DhanHQ::Error` before the request is sent.
285
420
 
286
421
  ### Holdings
@@ -379,7 +514,6 @@ The model filters strikes where both CE and PE have zero `last_price`, keeping t
379
514
 
380
515
  ```ruby
381
516
  params = {
382
- dhan_client_id: "123456",
383
517
  exchange_segment: "NSE_EQ",
384
518
  transaction_type: "BUY",
385
519
  quantity: 10,
@@ -392,6 +526,8 @@ margin = DhanHQ::Models::Margin.calculate(params)
392
526
  puts margin.total_margin
393
527
  ```
394
528
 
529
+ > 🪄 The margin helper appends `dhan_client_id` from your credentials before calling `/v2/margincalculator`.
530
+
395
531
  If a required field is missing (for example `transaction_type`), the contract raises `DhanHQ::Error` before any API call is issued.
396
532
 
397
533
  ### REST Market Feed (Batch LTP/OHLC/Quote)
@@ -407,7 +543,55 @@ ohlc = DhanHQ::Models::MarketFeed.ohlc(payload)
407
543
  quote = DhanHQ::Models::MarketFeed.quote(payload)
408
544
  ```
409
545
 
410
- These endpoints are rate-limited by Dhan. The clients internal `RateLimiter` throttles calls—consider batching symbols sensibly.
546
+ These endpoints are rate-limited by Dhan. The client's internal `RateLimiter` throttles calls—consider batching symbols sensibly.
547
+
548
+ ### Instrument Convenience Methods
549
+
550
+ The Instrument model provides convenient instance methods that automatically use the instrument's attributes (`security_id`, `exchange_segment`, `instrument`) to fetch market data. This eliminates the need to manually construct parameters for each API call.
551
+
552
+ ```ruby
553
+ # Find an instrument first
554
+ instrument = DhanHQ::Models::Instrument.find("IDX_I", "NIFTY")
555
+ # or
556
+ reliance = DhanHQ::Models::Instrument.find("NSE_EQ", "RELIANCE")
557
+
558
+ # Market Feed Methods - automatically uses instrument's attributes
559
+ ltp_data = instrument.ltp # Last traded price
560
+ ohlc_data = instrument.ohlc # OHLC data
561
+ quote_data = instrument.quote # Full quote depth
562
+
563
+ # Historical Data Methods
564
+ daily_data = instrument.daily(
565
+ from_date: "2024-01-01",
566
+ to_date: "2024-01-31",
567
+ expiry_code: 0 # Optional, only for derivatives
568
+ )
569
+
570
+ intraday_data = instrument.intraday(
571
+ from_date: "2024-09-11",
572
+ to_date: "2024-09-15",
573
+ interval: "15" # 1, 5, 15, 25, or 60 minutes
574
+ )
575
+
576
+ # Option Chain Methods (for F&O instruments)
577
+ fn_instrument = DhanHQ::Models::Instrument.find("IDX_I", "NIFTY")
578
+ expiries = fn_instrument.expiry_list # Get all available expiries
579
+ chain = fn_instrument.option_chain(expiry: "2024-02-29") # Get option chain for specific expiry
580
+ ```
581
+
582
+ **Available Instance Methods:**
583
+
584
+ | Method | Description | Underlying API |
585
+ | ----------------------------------------------------------------- | -------------------------------- | ----------------------------------------------- |
586
+ | `instrument.ltp` | Fetches last traded price | `DhanHQ::Models::MarketFeed.ltp` |
587
+ | `instrument.ohlc` | Fetches OHLC data | `DhanHQ::Models::MarketFeed.ohlc` |
588
+ | `instrument.quote` | Fetches full quote depth | `DhanHQ::Models::MarketFeed.quote` |
589
+ | `instrument.daily(from_date:, to_date:, **options)` | Fetches daily historical data | `DhanHQ::Models::HistoricalData.daily` |
590
+ | `instrument.intraday(from_date:, to_date:, interval:, **options)` | Fetches intraday historical data | `DhanHQ::Models::HistoricalData.intraday` |
591
+ | `instrument.expiry_list` | Fetches expiry list | `DhanHQ::Models::OptionChain.fetch_expiry_list` |
592
+ | `instrument.option_chain(expiry:)` | Fetches option chain | `DhanHQ::Models::OptionChain.fetch` |
593
+
594
+ All methods automatically extract `security_id`, `exchange_segment`, and `instrument` from the instrument instance, making it easier to work with market data without manually managing these parameters.
411
595
 
412
596
  ### WebSocket Market Feed
413
597
 
@@ -473,14 +657,20 @@ All helpers accept snake_case keys; the client camelizes them before calling `/v
473
657
  ### Kill Switch
474
658
 
475
659
  ```ruby
476
- DhanHQ::Models::KillSwitch.activate # => {"killSwitchStatus"=>"ACTIVATE"}
477
- DhanHQ::Models::KillSwitch.deactivate # => {"killSwitchStatus"=>"DEACTIVATE"}
660
+ activate_payload = DhanHQ::Models::KillSwitch.activate
661
+ deactivate_payload = DhanHQ::Models::KillSwitch.deactivate
662
+
663
+ DhanHQ::Models::KillSwitch.snake_case(activate_payload)
664
+ # => { kill_switch_status: "ACTIVATE" }
665
+
666
+ DhanHQ::Models::KillSwitch.snake_case(deactivate_payload)
667
+ # => { kill_switch_status: "DEACTIVATE" }
478
668
 
479
669
  # Explicit status update
480
670
  DhanHQ::Models::KillSwitch.update("ACTIVATE")
481
671
  ```
482
672
 
483
- Only `"ACTIVATE"` and `"DEACTIVATE"` are accepted—any other value raises `DhanHQ::Error`.
673
+ Only `"ACTIVATE"` and `"DEACTIVATE"` are accepted—any other value raises `DhanHQ::Error`. Use the `snake_case` helper to normalise API responses when you prefer underscore keys.
484
674
 
485
675
  ---
486
676