DhanHQ 2.4.0 → 2.6.0

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -1
  3. data/CHANGELOG.md +103 -7
  4. data/GUIDE.md +57 -39
  5. data/README.md +198 -755
  6. data/docs/API_DOCS_GAPS.md +128 -0
  7. data/docs/API_VERIFICATION.md +10 -11
  8. data/{README1.md → docs/ARCHIVE_README.md} +16 -16
  9. data/docs/AUTHENTICATION.md +72 -10
  10. data/docs/CONFIGURATION.md +109 -0
  11. data/docs/CONSTANTS_REFERENCE.md +477 -0
  12. data/docs/DATA_API_PARAMETERS.md +7 -7
  13. data/docs/{rails_websocket_integration.md → RAILS_WEBSOCKET_INTEGRATION.md} +10 -10
  14. data/docs/{standalone_ruby_websocket_integration.md → STANDALONE_RUBY_WEBSOCKET_INTEGRATION.md} +32 -32
  15. data/docs/SUPER_ORDERS.md +284 -0
  16. data/docs/{technical_analysis.md → TECHNICAL_ANALYSIS.md} +3 -3
  17. data/docs/TESTING_GUIDE.md +84 -82
  18. data/docs/TROUBLESHOOTING.md +117 -0
  19. data/docs/{websocket_integration.md → WEBSOCKET_INTEGRATION.md} +19 -19
  20. data/docs/WEBSOCKET_PROTOCOL.md +154 -0
  21. data/lib/DhanHQ/constants.rb +456 -151
  22. data/lib/DhanHQ/contracts/alert_order_contract.rb +37 -10
  23. data/lib/DhanHQ/contracts/base_contract.rb +22 -0
  24. data/lib/DhanHQ/contracts/edis_contract.rb +25 -0
  25. data/lib/DhanHQ/contracts/margin_calculator_contract.rb +27 -4
  26. data/lib/DhanHQ/contracts/modify_order_contract.rb +65 -12
  27. data/lib/DhanHQ/contracts/multi_scrip_margin_calc_request_contract.rb +23 -0
  28. data/lib/DhanHQ/contracts/order_contract.rb +171 -39
  29. data/lib/DhanHQ/contracts/place_order_contract.rb +14 -141
  30. data/lib/DhanHQ/contracts/pnl_based_exit_contract.rb +20 -0
  31. data/lib/DhanHQ/contracts/position_conversion_contract.rb +15 -3
  32. data/lib/DhanHQ/contracts/slice_order_contract.rb +10 -1
  33. data/lib/DhanHQ/contracts/user_ip_contract.rb +14 -0
  34. data/lib/DhanHQ/core/base_model.rb +13 -4
  35. data/lib/DhanHQ/helpers/response_helper.rb +2 -2
  36. data/lib/DhanHQ/helpers/validation_helper.rb +1 -1
  37. data/lib/DhanHQ/models/alert_order.rb +29 -11
  38. data/lib/DhanHQ/models/concerns/api_response_handler.rb +46 -0
  39. data/lib/DhanHQ/models/edis.rb +101 -0
  40. data/lib/DhanHQ/models/expired_options_data.rb +6 -12
  41. data/lib/DhanHQ/models/forever_order.rb +8 -5
  42. data/lib/DhanHQ/models/historical_data.rb +0 -8
  43. data/lib/DhanHQ/models/instrument.rb +1 -7
  44. data/lib/DhanHQ/models/instrument_helpers.rb +4 -4
  45. data/lib/DhanHQ/models/kill_switch.rb +23 -11
  46. data/lib/DhanHQ/models/margin.rb +51 -2
  47. data/lib/DhanHQ/models/order.rb +107 -126
  48. data/lib/DhanHQ/models/order_update.rb +7 -13
  49. data/lib/DhanHQ/models/pnl_exit.rb +122 -0
  50. data/lib/DhanHQ/models/position.rb +23 -1
  51. data/lib/DhanHQ/models/postback.rb +114 -0
  52. data/lib/DhanHQ/models/profile.rb +0 -10
  53. data/lib/DhanHQ/models/super_order.rb +13 -3
  54. data/lib/DhanHQ/models/trade.rb +11 -23
  55. data/lib/DhanHQ/resources/ip_setup.rb +16 -5
  56. data/lib/DhanHQ/resources/kill_switch.rb +17 -7
  57. data/lib/DhanHQ/resources/margin_calculator.rb +9 -0
  58. data/lib/DhanHQ/resources/orders.rb +41 -41
  59. data/lib/DhanHQ/resources/pnl_exit.rb +37 -0
  60. data/lib/DhanHQ/resources/positions.rb +8 -0
  61. data/lib/DhanHQ/version.rb +1 -1
  62. data/lib/DhanHQ/ws/cmd_bus.rb +1 -1
  63. data/lib/DhanHQ/ws/orders/client.rb +6 -6
  64. data/lib/DhanHQ/ws/singleton_lock.rb +2 -1
  65. data/lib/dhanhq/analysis/options_buying_advisor.rb +2 -2
  66. data/lib/rubocop/cop/dhanhq/use_constants.rb +171 -0
  67. metadata +29 -24
  68. data/TODO-1.md +0 -14
  69. data/TODO.md +0 -127
  70. data/app/services/live/order_update_guard_support.rb +0 -75
  71. data/app/services/live/order_update_hub.rb +0 -76
  72. data/app/services/live/order_update_persistence_support.rb +0 -68
  73. data/docs/PR_2.2.0.md +0 -48
  74. data/examples/comprehensive_websocket_examples.rb +0 -148
  75. data/examples/instrument_finder_test.rb +0 -195
  76. data/examples/live_order_updates.rb +0 -118
  77. data/examples/market_depth_example.rb +0 -144
  78. data/examples/market_feed_example.rb +0 -81
  79. data/examples/order_update_example.rb +0 -105
  80. data/examples/trading_fields_example.rb +0 -215
  81. /data/docs/{live_order_updates.md → LIVE_ORDER_UPDATES.md} +0 -0
  82. /data/docs/{rails_integration.md → RAILS_INTEGRATION.md} +0 -0
@@ -0,0 +1,154 @@
1
+ # WebSocket Protocol Reference
2
+
3
+ Low-level protocol details for the DhanHQ WebSocket market feed. For high-level usage, see the [WebSocket Integration Guide](WEBSOCKET_INTEGRATION.md).
4
+
5
+ ---
6
+
7
+ ## Subscription Modes
8
+
9
+ | Mode | What you get | Best for |
10
+ | --------- | ----------------------------------------- | ------------------------------- |
11
+ | `:ticker` | LTP + LTT | Lightweight price monitoring |
12
+ | `:quote` | LTP + LTT + OHLCV + totals | Most trading strategies |
13
+ | `:full` | Quote + OI + best-5 depth (bid/ask) | Order book analysis, depth-based strategies |
14
+
15
+ ---
16
+
17
+ ## Request Codes
18
+
19
+ Per Dhan documentation:
20
+
21
+ | Action | Ticker | Quote | Full |
22
+ | ------------ | ------ | ----- | ---- |
23
+ | Subscribe | 15 | 17 | 21 |
24
+ | Unsubscribe | 16 | 18 | 22 |
25
+ | Disconnect | 12 | 12 | 12 |
26
+
27
+ ---
28
+
29
+ ## Packet Parsing
30
+
31
+ ### Response Header (8 bytes)
32
+
33
+ | Field | Size | Encoding | Description |
34
+ | -------------------- | ------ | -------- | ----------------------------- |
35
+ | `feed_response_code` | 1 byte | u8, BE | Identifies the packet type |
36
+ | `message_length` | 2 bytes| u16, BE | Total message length in bytes |
37
+ | `exchange_segment` | 1 byte | u8, BE | Exchange segment identifier |
38
+ | `security_id` | 4 bytes| i32, LE | Security identifier |
39
+
40
+ ### Packet Types
41
+
42
+ | Code | Type | Fields |
43
+ | ---- | ------------- | ------------------------------------------------------------- |
44
+ | 1 | Index | Surfaced as raw/misc unless documented |
45
+ | 2 | Ticker | `ltp`, `ltt` |
46
+ | 4 | Quote | `ltp`, `ltt`, `atp`, `volume`, totals, `day_*` |
47
+ | 5 | OI | `open_interest` |
48
+ | 6 | Prev Close | `prev_close`, `oi_prev` |
49
+ | 7 | Market Status | Raw/misc unless documented |
50
+ | 8 | Full | Quote fields + `open_interest` + 5× depth (bid/ask) |
51
+ | 50 | Disconnect | Reason code |
52
+
53
+ ---
54
+
55
+ ## Normalized Tick Schema
56
+
57
+ All ticks are delivered as a Ruby Hash with consistent keys:
58
+
59
+ ```ruby
60
+ {
61
+ kind: :quote, # :ticker | :quote | :full | :oi | :prev_close | :misc
62
+ segment: DhanHQ::Constants::ExchangeSegment::NSE_FNO, # string enum
63
+ security_id: "12345",
64
+ ltp: 101.5,
65
+ ts: 1723791300, # LTT epoch (sec) if present
66
+ vol: 123456, # quote/full only
67
+ atp: 100.9, # quote/full only
68
+ day_open: 100.1,
69
+ day_high: 102.4,
70
+ day_low: 99.5,
71
+ day_close: nil,
72
+ oi: 987654, # full or OI packet
73
+ bid: 101.45, # from depth (mode :full)
74
+ ask: 101.55 # from depth (mode :full)
75
+ }
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Connection Limits & Behavior
81
+
82
+ ### Limits
83
+
84
+ - **100 instruments** per subscribe/unsubscribe frame (auto-chunked by the client)
85
+ - **5 WebSocket connections** per user (per Dhan)
86
+
87
+ ### Backoff & 429 Cool-Off
88
+
89
+ - Exponential backoff with jitter on connection failure
90
+ - Handshake **429** triggers a **60-second cool-off** before retry
91
+ - The client handles this automatically — avoid manual rapid reconnect loops
92
+
93
+ ### Reconnect & Resubscribe
94
+
95
+ - On reconnect, the client resends the **current subscription snapshot** (idempotent)
96
+ - No manual re-subscribe needed after automatic reconnection
97
+
98
+ ### Graceful Shutdown
99
+
100
+ - `ws.disconnect!` — sends broker disconnect code 12, prevents reconnects
101
+ - `ws.stop` — hard stop (no broker message, just closes and halts loop)
102
+ - `DhanHQ::WS.disconnect_all_local!` — kills all registered WS clients
103
+ - An `at_exit` hook stops all registered clients to avoid leaked sockets
104
+
105
+ ---
106
+
107
+ ## Exchange Segment Enums
108
+
109
+ Use these string enums in WebSocket `subscribe_*` calls and REST parameters:
110
+
111
+ | Enum | Exchange | Segment |
112
+ | -------------- | -------- | ----------------- |
113
+ | `IDX_I` | Index | Index Value |
114
+ | `NSE_EQ` | NSE | Equity Cash |
115
+ | `NSE_FNO` | NSE | Futures & Options |
116
+ | `NSE_CURRENCY` | NSE | Currency |
117
+ | `BSE_EQ` | BSE | Equity Cash |
118
+ | `BSE_FNO` | BSE | Futures & Options |
119
+ | `BSE_CURRENCY` | BSE | Currency |
120
+ | `MCX_COMM` | MCX | Commodity |
121
+
122
+ ---
123
+
124
+ ## Tick Access Patterns
125
+
126
+ ### Direct Handler
127
+
128
+ ```ruby
129
+ ws.on(:tick) { |t| do_something_fast(t) } # avoid heavy work here
130
+ ```
131
+
132
+ ### Shared TickCache (Recommended)
133
+
134
+ ```ruby
135
+ # app/services/live/tick_cache.rb
136
+ class TickCache
137
+ MAP = Concurrent::Map.new
138
+ def self.put(t) = MAP["#{t[:segment]}:#{t[:security_id]}"] = t
139
+ def self.get(seg, sid) = MAP["#{seg}:#{sid}"]
140
+ def self.ltp(seg, sid) = get(seg, sid)&.dig(:ltp)
141
+ end
142
+
143
+ ws.on(:tick) { |t| TickCache.put(t) }
144
+ ltp = TickCache.ltp("NSE_FNO", "12345")
145
+ ```
146
+
147
+ ### Filtered Callback
148
+
149
+ ```ruby
150
+ def on_tick_for(ws, segment:, security_id:, &blk)
151
+ key = "#{segment}:#{security_id}"
152
+ ws.on(:tick) { |t| blk.call(t) if "#{t[:segment]}:#{t[:security_id]}" == key }
153
+ end
154
+ ```