DhanHQ 2.1.5 → 2.1.6

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/GUIDE.md +215 -73
  4. data/README.md +416 -132
  5. data/README1.md +267 -26
  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 +871 -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/contracts/expired_options_data_contract.rb +103 -0
  19. data/lib/DhanHQ/contracts/trade_contract.rb +70 -0
  20. data/lib/DhanHQ/errors.rb +2 -0
  21. data/lib/DhanHQ/models/expired_options_data.rb +331 -0
  22. data/lib/DhanHQ/models/instrument.rb +96 -2
  23. data/lib/DhanHQ/models/order_update.rb +235 -0
  24. data/lib/DhanHQ/models/trade.rb +118 -31
  25. data/lib/DhanHQ/resources/expired_options_data.rb +22 -0
  26. data/lib/DhanHQ/version.rb +1 -1
  27. data/lib/DhanHQ/ws/base_connection.rb +249 -0
  28. data/lib/DhanHQ/ws/connection.rb +2 -2
  29. data/lib/DhanHQ/ws/decoder.rb +3 -3
  30. data/lib/DhanHQ/ws/market_depth/client.rb +376 -0
  31. data/lib/DhanHQ/ws/market_depth/decoder.rb +131 -0
  32. data/lib/DhanHQ/ws/market_depth.rb +74 -0
  33. data/lib/DhanHQ/ws/orders/client.rb +175 -11
  34. data/lib/DhanHQ/ws/orders/connection.rb +40 -81
  35. data/lib/DhanHQ/ws/orders.rb +28 -0
  36. data/lib/DhanHQ/ws/segments.rb +18 -2
  37. data/lib/DhanHQ/ws.rb +3 -2
  38. data/lib/dhan_hq.rb +5 -0
  39. metadata +35 -1
data/README1.md CHANGED
@@ -423,40 +423,281 @@ end
423
423
 
424
424
  ---
425
425
 
426
- ## Super Orders (example)
426
+ ## Super Orders
427
427
 
428
- ```ruby
429
- intent = {
430
- exchange_segment: "NSE_FNO",
431
- security_id: "12345", # option
432
- transaction_type: "BUY",
433
- quantity: 50,
434
- # derived risk params from ATR/ADX
435
- take_profit: 0.35, # 35% target
436
- stop_loss: 0.18, # 18% SL
437
- trailing_sl: 0.12 # 12% trail
428
+ Super orders are built for smart execution. They bundle entry, target, and stop-loss legs (with optional trailing jump) into one atomic request so the broker manages risk for you.
429
+
430
+ The gem exposes all related REST endpoints so you can create, modify, cancel, and list super orders programmatically across exchanges and segments.
431
+
432
+ ### Endpoints
433
+
434
+ | Method | Path | Description |
435
+ | --- | --- | --- |
436
+ | `POST` | `/super/orders` | Create a new super order |
437
+ | `PUT` | `/super/orders/{order_id}` | Modify a pending super order |
438
+ | `DELETE` | `/super/orders/{order_id}/{order_leg}` | Cancel a pending super order leg |
439
+ | `GET` | `/super/orders` | Retrieve the list of all super orders |
440
+
441
+ ### Place Super Order
442
+
443
+ Use this endpoint to create a new super order consisting of entry, target, stop-loss, and optional trailing jump. It is available for intraday, carry-forward, and MTF across supported exchanges.
444
+
445
+ > ℹ️ Static IP whitelisting with Dhan support is required before invoking this API.
446
+
447
+ ```bash
448
+ curl --request POST \
449
+ --url https://api.dhan.co/v2/super/orders \
450
+ --header 'Content-Type: application/json' \
451
+ --header 'access-token: JWT' \
452
+ --data '{Request JSON}'
453
+ ```
454
+
455
+ #### Request body
456
+
457
+ ```json
458
+ {
459
+ "dhan_client_id": "1000000003",
460
+ "correlation_id": "123abc678",
461
+ "transaction_type": "BUY",
462
+ "exchange_segment": "NSE_EQ",
463
+ "product_type": "CNC",
464
+ "order_type": "LIMIT",
465
+ "security_id": "11536",
466
+ "quantity": 5,
467
+ "price": 1500,
468
+ "target_price": 1600,
469
+ "stop_loss_price": 1400,
470
+ "trailing_jump": 10
438
471
  }
472
+ ```
439
473
 
440
- # If your SuperOrder model exposes create/modify:
441
- o = DhanHQ::Models::SuperOrder.create(intent)
442
- # or fallback:
443
- mkt = DhanHQ::Models::Order.new(
444
- transaction_type: "BUY", exchange_segment: "NSE_FNO",
445
- order_type: "MARKET", validity: "DAY",
446
- security_id: "12345", quantity: 50
447
- ).save
474
+ #### Parameters
475
+
476
+ | Field | Type | Description |
477
+ | --- | --- | --- |
478
+ | `dhan_client_id` | string *(required)* | User specific identification generated by Dhan. When you call via `DhanHQ::Models::SuperOrder`, the gem injects your configured client id so you can omit the key in Ruby. |
479
+ | `correlation_id` | string | Caller supplied identifier for tracking |
480
+ | `transaction_type` | enum string *(required)* | Trading side. `BUY` or `SELL`. |
481
+ | `exchange_segment` | enum string *(required)* | Exchange segment (see appendix). |
482
+ | `product_type` | enum string *(required)* | Product type. `CNC`, `INTRADAY`, `MARGIN`, or `MTF`. |
483
+ | `order_type` | enum string *(required)* | Order type. `LIMIT` or `MARKET`. |
484
+ | `security_id` | string *(required)* | Exchange standard security identifier. |
485
+ | `quantity` | integer *(required)* | Quantity for the entry leg. |
486
+ | `price` | float *(required)* | Entry price. |
487
+ | `target_price` | float *(required)* | Target price for the super order. |
488
+ | `stop_loss_price` | float *(required)* | Stop-loss price for the super order. |
489
+ | `trailing_jump` | float *(required)* | Price jump size for trailing stop-loss. |
490
+
491
+ > 🐍 When you call `DhanHQ::Models::SuperOrder.create`, supply snake_case keys exactly as shown. The client automatically camelizes
492
+ > them before submitting to Dhan's REST API and injects your configured `dhan_client_id`, allowing you to omit the key in Ruby code.
493
+
494
+ #### Response
495
+
496
+ ```json
497
+ {
498
+ "order_id": "112111182198",
499
+ "order_status": "PENDING"
500
+ }
448
501
  ```
449
502
 
450
- If you placed a Super Order and want to trail SL upward using WS ticks:
503
+ | Field | Type | Description |
504
+ | --- | --- | --- |
505
+ | `order_id` | string | Order identifier generated by Dhan |
506
+ | `order_status` | enum string | Latest status. `TRANSIT`, `PENDING`, or `REJECTED`. |
451
507
 
452
- ```ruby
453
- DhanHQ::Models::SuperOrder.modify(
454
- order_id: o.order_id,
455
- stop_loss: new_abs_price, # broker API permitting
456
- trailing_sl: nil
457
- )
508
+ ### Modify Super Order
509
+
510
+ Modify any leg while the order is `PENDING` or `PART_TRADED`. Once the entry leg trades fully, only the target and stop-loss legs (price and trailing jump) remain editable.
511
+
512
+ > ℹ️ Static IP whitelisting with Dhan support is required before invoking this API.
513
+
514
+ ```bash
515
+ curl --request PUT \
516
+ --url https://api.dhan.co/v2/super/orders/{order_id} \
517
+ --header 'Content-Type: application/json' \
518
+ --header 'access-token: JWT' \
519
+ --data '{Request JSON}'
520
+ ```
521
+
522
+ #### Request body
523
+
524
+ ```json
525
+ {
526
+ "dhan_client_id": "1000000009",
527
+ "order_id": "112111182045",
528
+ "order_type": "LIMIT",
529
+ "leg_name": "ENTRY_LEG",
530
+ "quantity": 40,
531
+ "price": 1300,
532
+ "target_price": 1450,
533
+ "stop_loss_price": 1350,
534
+ "trailing_jump": 20
535
+ }
458
536
  ```
459
537
 
538
+ #### Parameters
539
+
540
+ | Field | Type | Description |
541
+ | --- | --- | --- |
542
+ | `dhan_client_id` | string *(required)* | User specific identification generated by Dhan. Automatically merged when using the Ruby model helpers. |
543
+ | `order_id` | string *(required)* | Super order identifier generated by Dhan. |
544
+ | `order_type` | enum string *(conditionally required)* | `LIMIT` or `MARKET`. Required when changing `ENTRY_LEG`. |
545
+ | `leg_name` | enum string *(required)* | `ENTRY_LEG`, `TARGET_LEG`, or `STOP_LOSS_LEG`. Entry edits allowed only while status is `PENDING` or `PART_TRADED`. |
546
+ | `quantity` | integer *(conditionally required)* | Quantity update for `ENTRY_LEG`. |
547
+ | `price` | float *(conditionally required)* | Entry price update for `ENTRY_LEG`. |
548
+ | `target_price` | float *(conditionally required)* | Target price update for `ENTRY_LEG` or `TARGET_LEG`. |
549
+ | `stop_loss_price` | float *(conditionally required)* | Stop-loss price update for `ENTRY_LEG` or `STOP_LOSS_LEG`. |
550
+ | `trailing_jump` | float *(conditionally required)* | Trailing jump update for `ENTRY_LEG` or `STOP_LOSS_LEG`. Omit or set to `0` to cancel trailing. |
551
+
552
+ #### Response
553
+
554
+ ```json
555
+ {
556
+ "order_id": "112111182045",
557
+ "order_status": "TRANSIT"
558
+ }
559
+ ```
560
+
561
+ | Field | Type | Description |
562
+ | --- | --- | --- |
563
+ | `order_id` | string | Order identifier generated by Dhan |
564
+ | `order_status` | enum string | Latest status. `TRANSIT`, `PENDING`, `REJECTED`, or `TRADED`. |
565
+
566
+ ### Cancel Super Order
567
+
568
+ Cancel a pending or active super order leg with the order ID. Cancelling the entry leg removes all legs. Cancelling an individual target or stop-loss leg removes only that leg and it cannot be recreated on the same order.
569
+
570
+ > ℹ️ Static IP whitelisting with Dhan support is required before invoking this API.
571
+
572
+ ```bash
573
+ curl --request DELETE \
574
+ --url https://api.dhan.co/v2/super/orders/{order_id}/{order_leg} \
575
+ --header 'Content-Type: application/json' \
576
+ --header 'access-token: JWT'
577
+ ```
578
+
579
+ #### Path parameters
580
+
581
+ | Field | Description | Example |
582
+ | --- | --- | --- |
583
+ | `order_id` | Super order identifier. | `11211182198` |
584
+ | `order_leg` | Leg to cancel. `ENTRY_LEG`, `TARGET_LEG`, or `STOP_LOSS_LEG`. | `ENTRY_LEG` |
585
+
586
+ #### Response
587
+
588
+ ```json
589
+ {
590
+ "order_id": "112111182045",
591
+ "order_status": "CANCELLED"
592
+ }
593
+ ```
594
+
595
+ | Field | Type | Description |
596
+ | --- | --- | --- |
597
+ | `order_id` | string | Order identifier generated by Dhan |
598
+ | `order_status` | enum string | Latest status. `TRANSIT`, `PENDING`, `REJECTED`, or `CANCELLED`. |
599
+
600
+ ### Super Order List
601
+
602
+ Fetch all super orders placed during the trading day. The response nests leg details under the entry leg, and each leg is also available in the standard order book.
603
+
604
+ ```bash
605
+ curl --request GET \
606
+ --url https://api.dhan.co/v2/super/orders \
607
+ --header 'Content-Type: application/json' \
608
+ --header 'access-token: JWT'
609
+ ```
610
+
611
+ #### Response
612
+
613
+ ```json
614
+ [
615
+ {
616
+ "dhan_client_id": "1100003626",
617
+ "order_id": "5925022734212",
618
+ "correlation_id": "string",
619
+ "order_status": "PENDING",
620
+ "transaction_type": "BUY",
621
+ "exchange_segment": "NSE_EQ",
622
+ "product_type": "CNC",
623
+ "order_type": "LIMIT",
624
+ "validity": "DAY",
625
+ "trading_symbol": "HDFCBANK",
626
+ "security_id": "1333",
627
+ "quantity": 10,
628
+ "remaining_quantity": 10,
629
+ "ltp": 1660.95,
630
+ "price": 1500,
631
+ "after_market_order": false,
632
+ "leg_name": "ENTRY_LEG",
633
+ "exchange_order_id": "11925022734212",
634
+ "create_time": "2025-02-27 19:09:42",
635
+ "update_time": "2025-02-27 19:09:42",
636
+ "exchange_time": "2025-02-27 19:09:42",
637
+ "oms_error_description": "",
638
+ "average_traded_price": 0,
639
+ "filled_qty": 0,
640
+ "leg_details": [
641
+ {
642
+ "order_id": "5925022734212",
643
+ "leg_name": "STOP_LOSS_LEG",
644
+ "transaction_type": "SELL",
645
+ "total_quantity": 0,
646
+ "remaining_quantity": 0,
647
+ "triggered_quantity": 0,
648
+ "price": 1400,
649
+ "order_status": "PENDING",
650
+ "trailing_jump": 10
651
+ },
652
+ {
653
+ "order_id": "5925022734212",
654
+ "leg_name": "TARGET_LEG",
655
+ "transaction_type": "SELL",
656
+ "remaining_quantity": 0,
657
+ "triggered_quantity": 0,
658
+ "price": 1550,
659
+ "order_status": "PENDING",
660
+ "trailing_jump": 0
661
+ }
662
+ ]
663
+ }
664
+ ]
665
+ ```
666
+
667
+ #### Parameters
668
+
669
+ | Field | Type | Description |
670
+ | --- | --- | --- |
671
+ | `dhan_client_id` | string | User specific identification generated by Dhan. |
672
+ | `order_id` | string | Order identifier generated by Dhan. |
673
+ | `correlation_id` | string | Caller supplied correlation identifier. |
674
+ | `order_status` | enum string | Latest status. `TRANSIT`, `PENDING`, `CLOSED`, `REJECTED`, `CANCELLED`, `PART_TRADED`, or `TRADED`. |
675
+ | `transaction_type` | enum string | Trading side. `BUY` or `SELL`. |
676
+ | `exchange_segment` | enum string | Exchange segment. |
677
+ | `product_type` | enum string | Product type. `CNC`, `INTRADAY`, `MARGIN`, or `MTF`. |
678
+ | `order_type` | enum string | Order type. `LIMIT` or `MARKET`. |
679
+ | `validity` | enum string | Order validity. `DAY`. |
680
+ | `trading_symbol` | string | Trading symbol reference. |
681
+ | `security_id` | string | Exchange security identifier. |
682
+ | `quantity` | integer | Ordered quantity. |
683
+ | `remaining_quantity` | integer | Quantity pending execution. |
684
+ | `ltp` | float | Last traded price. |
685
+ | `price` | float | Order price. |
686
+ | `after_market_order` | boolean | Indicates if order was placed after market hours. |
687
+ | `leg_name` | enum string | Leg identifier: `ENTRY_LEG`, `TARGET_LEG`, or `STOP_LOSS_LEG`. |
688
+ | `trailing_jump` | float | Trailing jump for stop-loss. |
689
+ | `exchange_order_id` | string | Exchange generated identifier. |
690
+ | `create_time` | string | Order creation timestamp. |
691
+ | `update_time` | string | Latest update timestamp. |
692
+ | `exchange_time` | string | Exchange timestamp. |
693
+ | `oms_error_description` | string | OMS error description when applicable. |
694
+ | `average_traded_price` | float | Average traded price. |
695
+ | `filled_qty` | integer | Quantity traded on the exchange. |
696
+ | `triggered_quantity` | integer | Quantity triggered for stop-loss or target legs. |
697
+ | `leg_details` | array | Nested leg details for the super order. |
698
+
699
+ > ✅ `CLOSED` indicates the entry leg and either target or stop-loss completed for the full quantity. `TRIGGERED` appears on target and stop-loss legs to highlight which one fired; inspect `triggered_quantity` for executed quantity.
700
+
460
701
  ---
461
702
 
462
703
  ## Packet parsing (for reference)
@@ -0,0 +1,319 @@
1
+ # Live Order Updates - Comprehensive Guide
2
+
3
+ The DhanHQ Ruby client provides comprehensive real-time order update functionality via WebSocket, covering all order states as per the [DhanHQ API documentation](https://dhanhq.co/docs/v2).
4
+
5
+ ## Features
6
+
7
+ ✅ **Complete Order State Tracking** - All order statuses (TRANSIT, PENDING, REJECTED, CANCELLED, TRADED, EXPIRED)
8
+ ✅ **Real-time Execution Updates** - Track partial and full executions
9
+ ✅ **Order State Management** - Query orders by status, symbol, execution state
10
+ ✅ **Event-driven Architecture** - Subscribe to specific order events
11
+ ✅ **Super Order Support** - Track entry, stop-loss, and target legs
12
+ ✅ **Comprehensive Order Data** - All fields from API documentation
13
+
14
+ ## Quick Start
15
+
16
+ ### Basic Usage
17
+
18
+ ```ruby
19
+ require 'dhan_hq'
20
+
21
+ # Configure credentials
22
+ DhanHQ.configure do |config|
23
+ config.client_id = "your_client_id"
24
+ config.access_token = "your_access_token"
25
+ end
26
+
27
+ # Simple order update monitoring
28
+ DhanHQ::WS::Orders.connect do |order_update|
29
+ puts "Order Update: #{order_update.symbol} - #{order_update.status}"
30
+ puts "Quantity: #{order_update.traded_qty}/#{order_update.quantity}"
31
+ end
32
+ ```
33
+
34
+ ### Advanced Usage with Event Handlers
35
+
36
+ ```ruby
37
+ # Create client with multiple event handlers
38
+ client = DhanHQ::WS::Orders.connect_with_handlers({
39
+ :update => ->(order) { puts "Order updated: #{order.order_no}" },
40
+ :status_change => ->(data) {
41
+ puts "Status changed: #{data[:previous_status]} -> #{data[:new_status]}"
42
+ },
43
+ :execution => ->(data) {
44
+ puts "Execution: #{data[:new_traded_qty]} shares at #{data[:order_update].avg_traded_price}"
45
+ },
46
+ :order_traded => ->(order) { puts "Order fully executed: #{order.order_no}" },
47
+ :order_rejected => ->(order) { puts "Order rejected: #{order.reason_description}" }
48
+ })
49
+
50
+ # Keep the connection alive
51
+ sleep
52
+ ```
53
+
54
+ ## Order Update Model
55
+
56
+ The `OrderUpdate` model provides comprehensive access to all order fields:
57
+
58
+ ### Order Information
59
+ ```ruby
60
+ order_update.order_no # Order number
61
+ order_update.exch_order_no # Exchange order number
62
+ order_update.symbol # Trading symbol
63
+ order_update.display_name # Instrument display name
64
+ order_update.security_id # Security ID
65
+ order_update.correlation_id # User correlation ID
66
+ ```
67
+
68
+ ### Order Details
69
+ ```ruby
70
+ order_update.txn_type # "B" for Buy, "S" for Sell
71
+ order_update.order_type # "LMT", "MKT", "SL", "SLM"
72
+ order_update.product # "C", "I", "M", "F", "V", "B"
73
+ order_update.validity # "DAY", "IOC"
74
+ order_update.status # "TRANSIT", "PENDING", "REJECTED", etc.
75
+ ```
76
+
77
+ ### Execution Information
78
+ ```ruby
79
+ order_update.quantity # Total order quantity
80
+ order_update.traded_qty # Executed quantity
81
+ order_update.remaining_quantity # Pending quantity
82
+ order_update.price # Order price
83
+ order_update.traded_price # Last trade price
84
+ order_update.avg_traded_price # Average execution price
85
+ ```
86
+
87
+ ### Helper Methods
88
+
89
+ #### Transaction Type
90
+ ```ruby
91
+ order_update.buy? # true if BUY order
92
+ order_update.sell? # true if SELL order
93
+ ```
94
+
95
+ #### Order Type
96
+ ```ruby
97
+ order_update.limit_order? # true if LIMIT order
98
+ order_update.market_order? # true if MARKET order
99
+ order_update.stop_loss_order? # true if STOP LOSS order
100
+ ```
101
+
102
+ #### Product Type
103
+ ```ruby
104
+ order_update.cnc_product? # true if CNC
105
+ order_update.intraday_product? # true if INTRADAY
106
+ order_update.margin_product? # true if MARGIN
107
+ order_update.mtf_product? # true if MTF
108
+ order_update.cover_order? # true if CO
109
+ order_update.bracket_order? # true if BO
110
+ ```
111
+
112
+ #### Order Status
113
+ ```ruby
114
+ order_update.transit? # true if TRANSIT
115
+ order_update.pending? # true if PENDING
116
+ order_update.rejected? # true if REJECTED
117
+ order_update.cancelled? # true if CANCELLED
118
+ order_update.traded? # true if TRADED
119
+ order_update.expired? # true if EXPIRED
120
+ ```
121
+
122
+ #### Execution State
123
+ ```ruby
124
+ order_update.partially_executed? # true if partially filled
125
+ order_update.fully_executed? # true if fully filled
126
+ order_update.not_executed? # true if not filled
127
+ order_update.execution_percentage # execution percentage (0-100)
128
+ ```
129
+
130
+ #### Super Order Legs
131
+ ```ruby
132
+ order_update.entry_leg? # true if entry leg (leg_no == 1)
133
+ order_update.stop_loss_leg? # true if stop-loss leg (leg_no == 2)
134
+ order_update.target_leg? # true if target leg (leg_no == 3)
135
+ order_update.super_order? # true if part of super order
136
+ ```
137
+
138
+ ## Client Methods
139
+
140
+ ### Order Tracking
141
+ ```ruby
142
+ client = DhanHQ::WS::Orders.client.start
143
+
144
+ # Get specific order state
145
+ order = client.order_state("1124091136546")
146
+
147
+ # Get all tracked orders
148
+ all_orders = client.all_orders
149
+
150
+ # Query orders by status
151
+ pending_orders = client.orders_by_status("PENDING")
152
+ traded_orders = client.orders_by_status("TRADED")
153
+
154
+ # Query orders by symbol
155
+ reliance_orders = client.orders_by_symbol("RELIANCE")
156
+
157
+ # Query by execution state
158
+ partial_orders = client.partially_executed_orders
159
+ full_orders = client.fully_executed_orders
160
+ pending_orders = client.pending_orders
161
+ ```
162
+
163
+ ### Event Handling
164
+ ```ruby
165
+ client = DhanHQ::WS::Orders.client
166
+
167
+ # General events
168
+ client.on(:update) { |order| puts "Order updated: #{order.order_no}" }
169
+ client.on(:raw) { |msg| puts "Raw message: #{msg}" }
170
+ client.on(:close) { puts "Connection closed" }
171
+
172
+ # Status-specific events
173
+ client.on(:order_transit) { |order| puts "Order in transit: #{order.order_no}" }
174
+ client.on(:order_pending) { |order| puts "Order pending: #{order.order_no}" }
175
+ client.on(:order_rejected) { |order| puts "Order rejected: #{order.reason_description}" }
176
+ client.on(:order_cancelled) { |order| puts "Order cancelled: #{order.order_no}" }
177
+ client.on(:order_traded) { |order| puts "Order traded: #{order.order_no}" }
178
+ client.on(:order_expired) { |order| puts "Order expired: #{order.order_no}" }
179
+
180
+ # State change events
181
+ client.on(:status_change) do |data|
182
+ puts "Status: #{data[:previous_status]} -> #{data[:new_status]}"
183
+ end
184
+
185
+ client.on(:execution) do |data|
186
+ puts "Execution: #{data[:new_traded_qty]} shares (#{data[:execution_percentage]}%)"
187
+ end
188
+
189
+ client.start
190
+ ```
191
+
192
+ ## Configuration
193
+
194
+ ### Environment Variables
195
+ ```bash
196
+ # Required
197
+ CLIENT_ID=your_client_id
198
+ ACCESS_TOKEN=your_access_token
199
+
200
+ # Optional WebSocket settings
201
+ DHAN_WS_ORDER_URL=wss://api-order-update.dhan.co
202
+ DHAN_WS_USER_TYPE=SELF # or PARTNER
203
+ DHAN_PARTNER_ID=partner_id # if UserType is PARTNER
204
+ DHAN_PARTNER_SECRET=partner_secret # if UserType is PARTNER
205
+ ```
206
+
207
+ ### Programmatic Configuration
208
+ ```ruby
209
+ DhanHQ.configure do |config|
210
+ config.client_id = "your_client_id"
211
+ config.access_token = "your_access_token"
212
+ config.ws_order_url = "wss://api-order-update.dhan.co"
213
+ config.ws_user_type = "SELF" # or "PARTNER"
214
+
215
+ # For partner mode
216
+ config.partner_id = "partner_id"
217
+ config.partner_secret = "partner_secret"
218
+ end
219
+ ```
220
+
221
+ ## Complete Example
222
+
223
+ ```ruby
224
+ require 'dhan_hq'
225
+
226
+ # Configure
227
+ DhanHQ.configure_with_env
228
+
229
+ # Create order tracking client
230
+ client = DhanHQ::WS::Orders.client
231
+
232
+ # Set up comprehensive event handling
233
+ client.on(:update) do |order|
234
+ puts "\n=== Order Update ==="
235
+ puts "Order: #{order.order_no} | Symbol: #{order.symbol}"
236
+ puts "Status: #{order.status} | Type: #{order.txn_type}"
237
+ puts "Quantity: #{order.traded_qty}/#{order.quantity} (#{order.execution_percentage}%)"
238
+ puts "Price: #{order.price} | Avg Price: #{order.avg_traded_price}"
239
+ puts "Leg: #{order.leg_no} | Super Order: #{order.super_order?}"
240
+ end
241
+
242
+ client.on(:status_change) do |data|
243
+ order = data[:order_update]
244
+ puts "\n🔄 Status Change: #{order.order_no}"
245
+ puts " #{data[:previous_status]} -> #{data[:new_status]}"
246
+ end
247
+
248
+ client.on(:execution) do |data|
249
+ order = data[:order_update]
250
+ puts "\n💰 Execution Update: #{order.order_no}"
251
+ puts " #{data[:previous_traded_qty]} -> #{data[:new_traded_qty]} shares"
252
+ puts " Execution: #{data[:execution_percentage]}%"
253
+ end
254
+
255
+ client.on(:order_traded) do |order|
256
+ puts "\n✅ Order Fully Executed: #{order.order_no}"
257
+ puts " Symbol: #{order.symbol} | Quantity: #{order.traded_qty}"
258
+ puts " Average Price: #{order.avg_traded_price}"
259
+ end
260
+
261
+ client.on(:order_rejected) do |order|
262
+ puts "\n❌ Order Rejected: #{order.order_no}"
263
+ puts " Reason: #{order.reason_description}"
264
+ end
265
+
266
+ # Start monitoring
267
+ puts "Starting order update monitoring..."
268
+ client.start
269
+
270
+ # Keep running
271
+ begin
272
+ loop do
273
+ sleep 1
274
+
275
+ # Print order summary every 30 seconds
276
+ if Time.now.to_i % 30 == 0
277
+ puts "\n📊 Order Summary:"
278
+ puts " Total Orders: #{client.all_orders.size}"
279
+ puts " Pending: #{client.orders_by_status('PENDING').size}"
280
+ puts " Traded: #{client.orders_by_status('TRADED').size}"
281
+ puts " Rejected: #{client.orders_by_status('REJECTED').size}"
282
+ end
283
+ end
284
+ rescue Interrupt
285
+ puts "\nShutting down..."
286
+ client.stop
287
+ end
288
+ ```
289
+
290
+ ## Order States Covered
291
+
292
+ The implementation covers all order states as per DhanHQ API documentation:
293
+
294
+ | Status | Description | Event |
295
+ | ----------- | ---------------------------- | ------------------ |
296
+ | `TRANSIT` | Order in transit to exchange | `:order_transit` |
297
+ | `PENDING` | Order pending at exchange | `:order_pending` |
298
+ | `REJECTED` | Order rejected by exchange | `:order_rejected` |
299
+ | `CANCELLED` | Order cancelled | `:order_cancelled` |
300
+ | `TRADED` | Order fully executed | `:order_traded` |
301
+ | `EXPIRED` | Order expired | `:order_expired` |
302
+
303
+ ## Error Handling
304
+
305
+ The WebSocket client includes comprehensive error handling:
306
+
307
+ - **Automatic Reconnection** with exponential backoff
308
+ - **Rate Limit Handling** with 60-second cool-off for 429 errors
309
+ - **Connection Monitoring** with health checks
310
+ - **Event Handler Protection** - errors in handlers don't crash the client
311
+
312
+ ## Thread Safety
313
+
314
+ All operations are thread-safe using `Concurrent::Map` and `Concurrent::AtomicBoolean` for:
315
+ - Order state tracking
316
+ - Event callback management
317
+ - Connection state management
318
+
319
+ This ensures safe usage in multi-threaded applications.