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
@@ -0,0 +1,148 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Comprehensive WebSocket Examples
5
+ # This script demonstrates all three DhanHQ WebSocket types:
6
+ # 1. Market Feed WebSocket - Real-time market data
7
+ # 2. Order Update WebSocket - Real-time order updates
8
+ # 3. Market Depth WebSocket - Real-time market depth
9
+ # NOTE: Uses sequential connections to avoid rate limiting
10
+
11
+ require "dhan_hq"
12
+
13
+ # Configure DhanHQ
14
+ DhanHQ.configure do |config|
15
+ config.client_id = ENV["CLIENT_ID"] || "your_client_id"
16
+ config.access_token = ENV["ACCESS_TOKEN"] || "your_access_token"
17
+ config.ws_user_type = ENV["DHAN_WS_USER_TYPE"] || "SELF"
18
+ end
19
+
20
+ puts "DhanHQ Comprehensive WebSocket Examples"
21
+ puts "======================================="
22
+ puts "Demonstrates all three WebSocket types:"
23
+ puts "1. Market Feed - Real-time market data for indices"
24
+ puts "2. Order Update - Real-time order status updates"
25
+ puts "3. Market Depth - Real-time bid/ask levels"
26
+ puts ""
27
+ puts "NOTE: Uses sequential connections to avoid rate limiting (429 errors)"
28
+ puts "Dhan allows up to 5 WebSocket connections per user"
29
+ puts ""
30
+
31
+ # Example 1: Market Feed WebSocket
32
+ puts "1. Market Feed WebSocket Example"
33
+ puts "================================"
34
+
35
+ puts "Creating Market Feed WebSocket connection..."
36
+ market_client = DhanHQ::WS.connect(mode: :ticker) do |tick|
37
+ timestamp = tick[:ts] ? Time.at(tick[:ts]) : Time.now
38
+ puts "Market Data: #{tick[:segment]}:#{tick[:security_id]} = #{tick[:ltp]} at #{timestamp}"
39
+ end
40
+
41
+ # Subscribe to major Indian indices
42
+ puts "\nSubscribing to major Indian indices:"
43
+ puts "- Security ID 13: NIFTY (Nifty 50)"
44
+ puts "- Security ID 25: BANKNIFTY (Nifty Bank)"
45
+ puts "- Security ID 29: NIFTYIT (Nifty IT)"
46
+ puts "- Security ID 51: SENSEX (Sensex)"
47
+
48
+ market_client.subscribe_one(segment: "IDX_I", security_id: "13") # NIFTY
49
+ market_client.subscribe_one(segment: "IDX_I", security_id: "25") # BANKNIFTY
50
+ market_client.subscribe_one(segment: "IDX_I", security_id: "29") # NIFTYIT
51
+ market_client.subscribe_one(segment: "IDX_I", security_id: "51") # SENSEX
52
+
53
+ puts "\nMarket Feed WebSocket connected successfully!"
54
+ puts "Waiting 10 seconds to receive market data..."
55
+ sleep(10)
56
+
57
+ puts "Stopping Market Feed WebSocket to prevent rate limiting..."
58
+ market_client.stop
59
+ sleep(2)
60
+
61
+ # Example 2: Order Update WebSocket
62
+ puts "\n2. Order Update WebSocket Example"
63
+ puts "=================================="
64
+
65
+ puts "Creating Order Update WebSocket connection..."
66
+ orders_client = DhanHQ::WS::Orders.connect do |order_update|
67
+ puts "Order Update: #{order_update.order_no} - #{order_update.status}"
68
+ puts " Symbol: #{order_update.symbol}"
69
+ puts " Quantity: #{order_update.quantity}"
70
+ puts " Traded Qty: #{order_update.traded_qty}"
71
+ puts " Price: #{order_update.price}"
72
+ puts " Execution: #{order_update.execution_percentage}%"
73
+ puts " ---"
74
+ end
75
+
76
+ # Add event handlers
77
+ orders_client.on(:update) { |order| puts "📝 Order Updated: #{order.order_no}" }
78
+ orders_client.on(:execution) { |exec| puts "✅ Execution: #{exec[:new_traded_qty]} shares" }
79
+ orders_client.on(:order_rejected) { |order| puts "❌ Order Rejected: #{order.order_no}" }
80
+
81
+ puts "\nOrder Update WebSocket connected successfully!"
82
+ puts "Waiting 10 seconds to receive order updates..."
83
+ sleep(10)
84
+
85
+ puts "Stopping Order Update WebSocket to prevent rate limiting..."
86
+ orders_client.stop
87
+ sleep(2)
88
+
89
+ # Example 3: Market Depth WebSocket
90
+ puts "\n3. Market Depth WebSocket Example"
91
+ puts "=================================="
92
+
93
+ puts "Creating Market Depth WebSocket connection..."
94
+
95
+ # Find instruments using the new .find method (now uses underlying_symbol for equity)
96
+ reliance_instrument = DhanHQ::Models::Instrument.find("NSE_EQ", "RELIANCE")
97
+ tcs_instrument = DhanHQ::Models::Instrument.find("NSE_EQ", "TCS")
98
+
99
+ # Define symbols with correct exchange segments and security IDs
100
+ symbols = []
101
+ if reliance_instrument
102
+ symbols << { symbol: "RELIANCE", exchange_segment: reliance_instrument.exchange_segment,
103
+ security_id: reliance_instrument.security_id }
104
+ puts "✅ Found RELIANCE: #{reliance_instrument.symbol_name} (#{reliance_instrument.exchange_segment}:#{reliance_instrument.security_id})"
105
+ end
106
+
107
+ if tcs_instrument
108
+ symbols << { symbol: "TCS", exchange_segment: tcs_instrument.exchange_segment,
109
+ security_id: tcs_instrument.security_id }
110
+ puts "✅ Found TCS: #{tcs_instrument.symbol_name} (#{tcs_instrument.exchange_segment}:#{tcs_instrument.security_id})"
111
+ end
112
+
113
+ depth_client = DhanHQ::WS::MarketDepth.connect(symbols: symbols) do |depth_data|
114
+ puts "Market Depth: #{depth_data[:symbol]}"
115
+ puts " Best Bid: #{depth_data[:best_bid]}"
116
+ puts " Best Ask: #{depth_data[:best_ask]}"
117
+ puts " Spread: #{depth_data[:spread]}"
118
+ puts " Bid Levels: #{depth_data[:bids].size}"
119
+ puts " Ask Levels: #{depth_data[:asks].size}"
120
+ puts " ---"
121
+ end
122
+
123
+ puts "\nMarket Depth WebSocket connected successfully!"
124
+ puts "Waiting 10 seconds to receive market depth data..."
125
+ sleep(10)
126
+
127
+ puts "Stopping Market Depth WebSocket to prevent rate limiting..."
128
+ depth_client.stop
129
+ sleep(2)
130
+
131
+ # Final cleanup
132
+ puts "\n4. Final Cleanup"
133
+ puts "================"
134
+
135
+ puts "Ensuring all WebSocket connections are closed..."
136
+ DhanHQ::WS.disconnect_all_local!
137
+
138
+ puts "\nAll WebSocket connections closed."
139
+ puts "Comprehensive example completed!"
140
+ puts ""
141
+ puts "Summary:"
142
+ puts "- Successfully demonstrated all three WebSocket types:"
143
+ puts " * Market Feed: Real-time index data (NIFTY, BANKNIFTY, NIFTYIT, SENSEX)"
144
+ puts " * Order Update: Real-time order status tracking"
145
+ puts " * Market Depth: Real-time bid/ask levels (RELIANCE, TCS) - dynamically resolved"
146
+ puts "- Used sequential connections to avoid rate limiting (429 errors)"
147
+ puts "- Proper connection cleanup prevents resource leaks"
148
+ puts "- No multiple connection issues!"
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Test script for the new DhanHQ::Models::Instrument.find method
5
+ # This script demonstrates how to use the new .find and .find_anywhere methods
6
+
7
+ require "dhan_hq"
8
+
9
+ # Configure DhanHQ
10
+ DhanHQ.configure do |config|
11
+ config.client_id = ENV["CLIENT_ID"] || "your_client_id"
12
+ config.access_token = ENV["ACCESS_TOKEN"] || "your_access_token"
13
+ config.ws_user_type = ENV["DHAN_WS_USER_TYPE"] || "SELF"
14
+ end
15
+
16
+ puts "DhanHQ Instrument Finder Test"
17
+ puts "============================="
18
+ puts "Testing the new .find and .find_anywhere methods"
19
+ puts ""
20
+
21
+ # Test 1: Find specific instruments in known segments
22
+ puts "1. Finding instruments in specific segments:"
23
+ puts "-" * 40
24
+
25
+ # Find RELIANCE in NSE_EQ (now uses underlying_symbol for equity)
26
+ reliance = DhanHQ::Models::Instrument.find("NSE_EQ", "RELIANCE")
27
+ if reliance
28
+ puts "✅ RELIANCE:"
29
+ puts " Symbol Name: #{reliance.symbol_name}"
30
+ puts " Underlying Symbol: #{reliance.underlying_symbol}"
31
+ puts " Security ID: #{reliance.security_id}"
32
+ puts " Display Name: #{reliance.display_name}"
33
+ puts " Exchange Segment: #{reliance.exchange_segment}"
34
+ else
35
+ puts "❌ RELIANCE not found"
36
+ end
37
+
38
+ puts
39
+
40
+ # Find TCS in NSE_EQ (now uses underlying_symbol for equity)
41
+ tcs = DhanHQ::Models::Instrument.find("NSE_EQ", "TCS")
42
+ if tcs
43
+ puts "✅ TCS:"
44
+ puts " Symbol Name: #{tcs.symbol_name}"
45
+ puts " Underlying Symbol: #{tcs.underlying_symbol}"
46
+ puts " Security ID: #{tcs.security_id}"
47
+ puts " Display Name: #{tcs.display_name}"
48
+ puts " Exchange Segment: #{tcs.exchange_segment}"
49
+ else
50
+ puts "❌ TCS not found"
51
+ end
52
+
53
+ puts
54
+
55
+ # Find NIFTY in IDX_I
56
+ nifty = DhanHQ::Models::Instrument.find("IDX_I", "NIFTY")
57
+ if nifty
58
+ puts "✅ NIFTY:"
59
+ puts " Security ID: #{nifty.security_id}"
60
+ puts " Display Name: #{nifty.display_name}"
61
+ puts " Exchange Segment: #{nifty.exchange_segment}"
62
+ else
63
+ puts "❌ NIFTY not found"
64
+ end
65
+
66
+ puts
67
+
68
+ # Find BANKNIFTY in IDX_I
69
+ banknifty = DhanHQ::Models::Instrument.find("IDX_I", "BANKNIFTY")
70
+ if banknifty
71
+ puts "✅ BANKNIFTY:"
72
+ puts " Security ID: #{banknifty.security_id}"
73
+ puts " Display Name: #{banknifty.display_name}"
74
+ puts " Exchange Segment: #{banknifty.exchange_segment}"
75
+ else
76
+ puts "❌ BANKNIFTY not found"
77
+ end
78
+
79
+ puts
80
+
81
+ # Test 2: Find instruments anywhere (cross-segment search)
82
+ puts "2. Finding instruments anywhere (cross-segment search):"
83
+ puts "-" * 50
84
+
85
+ # Find RELIANCE anywhere (now uses underlying_symbol for equity)
86
+ reliance_anywhere = DhanHQ::Models::Instrument.find_anywhere("RELIANCE", exact_match: true)
87
+ if reliance_anywhere
88
+ puts "✅ RELIANCE found anywhere:"
89
+ puts " Symbol Name: #{reliance_anywhere.symbol_name}"
90
+ puts " Underlying Symbol: #{reliance_anywhere.underlying_symbol}"
91
+ puts " Security ID: #{reliance_anywhere.security_id}"
92
+ puts " Display Name: #{reliance_anywhere.display_name}"
93
+ puts " Exchange Segment: #{reliance_anywhere.exchange_segment}"
94
+ else
95
+ puts "❌ RELIANCE not found anywhere"
96
+ end
97
+
98
+ puts
99
+
100
+ # Find TCS anywhere (now uses underlying_symbol for equity)
101
+ tcs_anywhere = DhanHQ::Models::Instrument.find_anywhere("TCS", exact_match: true)
102
+ if tcs_anywhere
103
+ puts "✅ TCS found anywhere:"
104
+ puts " Symbol Name: #{tcs_anywhere.symbol_name}"
105
+ puts " Underlying Symbol: #{tcs_anywhere.underlying_symbol}"
106
+ puts " Security ID: #{tcs_anywhere.security_id}"
107
+ puts " Display Name: #{tcs_anywhere.display_name}"
108
+ puts " Exchange Segment: #{tcs_anywhere.exchange_segment}"
109
+ else
110
+ puts "❌ TCS not found anywhere"
111
+ end
112
+
113
+ puts
114
+
115
+ # Find NIFTY anywhere
116
+ nifty_anywhere = DhanHQ::Models::Instrument.find_anywhere("NIFTY", exact_match: true)
117
+ if nifty_anywhere
118
+ puts "✅ NIFTY found anywhere:"
119
+ puts " Security ID: #{nifty_anywhere.security_id}"
120
+ puts " Display Name: #{nifty_anywhere.display_name}"
121
+ puts " Exchange Segment: #{nifty_anywhere.exchange_segment}"
122
+ else
123
+ puts "❌ NIFTY not found anywhere"
124
+ end
125
+
126
+ puts
127
+
128
+ # Test 3: Advanced search options
129
+ puts "3. Testing advanced search options:"
130
+ puts "-" * 35
131
+
132
+ # Test partial match
133
+ reliance_partial = DhanHQ::Models::Instrument.find("NSE_EQ", "RELIANCE")
134
+ if reliance_partial
135
+ puts "✅ RELIANCE (partial match):"
136
+ puts " Symbol: #{reliance_partial.symbol_name}"
137
+ puts " Security ID: #{reliance_partial.security_id}"
138
+ else
139
+ puts "❌ RELIANCE (partial match) not found"
140
+ end
141
+
142
+ puts
143
+
144
+ # Test case insensitive search
145
+ reliance_case = DhanHQ::Models::Instrument.find("NSE_EQ", "reliance industries ltd", case_sensitive: false)
146
+ if reliance_case
147
+ puts "✅ RELIANCE (case insensitive):"
148
+ puts " Symbol: #{reliance_case.symbol_name}"
149
+ puts " Security ID: #{reliance_case.security_id}"
150
+ else
151
+ puts "❌ RELIANCE (case insensitive) not found"
152
+ end
153
+
154
+ puts
155
+
156
+ # Test 4: Practical usage for WebSocket subscriptions
157
+ puts "4. Practical usage for WebSocket subscriptions:"
158
+ puts "-" * 45
159
+
160
+ # Find instruments for Market Depth WebSocket
161
+ puts "Finding instruments for Market Depth WebSocket:"
162
+
163
+ market_depth_symbols = []
164
+ symbols_to_find = [
165
+ { segment: "NSE_EQ", symbol: "RELIANCE", name: "RELIANCE" },
166
+ { segment: "NSE_EQ", symbol: "TCS", name: "TCS" }
167
+ ]
168
+
169
+ symbols_to_find.each do |search|
170
+ instrument = DhanHQ::Models::Instrument.find(search[:segment], search[:symbol])
171
+ if instrument
172
+ market_depth_symbols << {
173
+ symbol: search[:name],
174
+ exchange_segment: instrument.exchange_segment,
175
+ security_id: instrument.security_id
176
+ }
177
+ puts "✅ #{search[:name]}: #{instrument.exchange_segment}:#{instrument.security_id}"
178
+ else
179
+ puts "❌ #{search[:name]}: Not found"
180
+ end
181
+ end
182
+
183
+ puts
184
+ puts "Market Depth WebSocket symbols array:"
185
+ puts market_depth_symbols.inspect
186
+
187
+ puts
188
+ puts "Test completed!"
189
+ puts "==============="
190
+ puts "The new .find and .find_anywhere methods make it easy to:"
191
+ puts "- Find instruments by exchange segment and symbol"
192
+ puts "- Search across multiple segments"
193
+ puts "- Use exact or partial matching"
194
+ puts "- Perform case-sensitive or case-insensitive searches"
195
+ puts "- Dynamically resolve symbols for WebSocket subscriptions"
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Live Order Updates Example
5
+ # Demonstrates comprehensive order state tracking via WebSocket
6
+
7
+ require_relative "lib/dhan_hq"
8
+
9
+ # Configure DhanHQ
10
+ DhanHQ.configure_with_env
11
+
12
+ puts "🚀 DhanHQ Live Order Updates Example"
13
+ puts "====================================="
14
+
15
+ # Create order tracking client
16
+ client = DhanHQ::WS::Orders.client
17
+
18
+ # Track order statistics
19
+ stats = {
20
+ total_orders: 0,
21
+ status_counts: Hash.new(0),
22
+ executions: 0
23
+ }
24
+
25
+ # Set up comprehensive event handling
26
+ client.on(:update) do |order|
27
+ stats[:total_orders] += 1
28
+ stats[:status_counts][order.status] += 1
29
+
30
+ puts "\n📋 Order Update: #{order.order_no}"
31
+ puts " Symbol: #{order.symbol} (#{order.display_name})"
32
+ puts " Status: #{order.status}"
33
+ puts " Type: #{order.txn_type} #{order.order_type}"
34
+ puts " Quantity: #{order.traded_qty}/#{order.quantity} (#{order.execution_percentage}%)"
35
+ puts " Price: #{order.price} | Avg: #{order.avg_traded_price}"
36
+
37
+ puts " Super Order Leg: #{order.leg_no}" if order.super_order?
38
+ end
39
+
40
+ client.on(:status_change) do |data|
41
+ order = data[:order_update]
42
+ puts "\n🔄 Status Change: #{order.order_no}"
43
+ puts " #{data[:previous_status]} -> #{data[:new_status]}"
44
+ end
45
+
46
+ client.on(:execution) do |data|
47
+ order = data[:order_update]
48
+ stats[:executions] += 1
49
+
50
+ puts "\n💰 Execution: #{order.order_no}"
51
+ puts " #{data[:previous_traded_qty]} -> #{data[:new_traded_qty]} shares"
52
+ puts " Execution: #{data[:execution_percentage]}%"
53
+ end
54
+
55
+ client.on(:order_traded) do |order|
56
+ puts "\n✅ Order Fully Executed: #{order.order_no}"
57
+ puts " Symbol: #{order.symbol} | Quantity: #{order.traded_qty}"
58
+ puts " Average Price: #{order.avg_traded_price}"
59
+ end
60
+
61
+ client.on(:order_rejected) do |order|
62
+ puts "\n❌ Order Rejected: #{order.order_no}"
63
+ puts " Reason: #{order.reason_description}"
64
+ end
65
+
66
+ client.on(:order_cancelled) do |order|
67
+ puts "\n🚫 Order Cancelled: #{order.order_no}"
68
+ end
69
+
70
+ client.on(:raw) do |msg|
71
+ # Uncomment for debugging raw messages
72
+ # puts "Raw: #{msg}"
73
+ end
74
+
75
+ # Start monitoring
76
+ puts "\n🔌 Connecting to order updates WebSocket..."
77
+ client.start
78
+
79
+ puts "✅ Connected! Monitoring order updates..."
80
+ puts "Press Ctrl+C to stop\n"
81
+
82
+ # Print periodic summaries
83
+ summary_timer = Thread.new do
84
+ loop do
85
+ sleep 30
86
+
87
+ puts "\n📊 Order Summary (Last 30 seconds):"
88
+ puts " Total Updates: #{stats[:total_orders]}"
89
+ puts " Executions: #{stats[:executions]}"
90
+ puts " Status Distribution:"
91
+ stats[:status_counts].each do |status, count|
92
+ puts " #{status}: #{count}"
93
+ end
94
+
95
+ # Show current order states
96
+ all_orders = client.all_orders
97
+ if all_orders.any?
98
+ puts " Current Orders:"
99
+ all_orders.each do |order_no, order|
100
+ puts " #{order_no}: #{order.symbol} - #{order.status} (#{order.execution_percentage}%)"
101
+ end
102
+ end
103
+
104
+ puts "\n" + ("=" * 50)
105
+ end
106
+ end
107
+
108
+ # Keep running until interrupted
109
+ begin
110
+ loop do
111
+ sleep 1
112
+ end
113
+ rescue Interrupt
114
+ puts "\n\n🛑 Shutting down..."
115
+ client.stop
116
+ summary_timer.kill
117
+ puts "✅ Disconnected. Goodbye!"
118
+ end
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Market Depth WebSocket Example
5
+ # This script demonstrates how to use the DhanHQ Market Depth WebSocket
6
+ # Receives real-time market depth data (bid/ask levels) for specific symbols
7
+ # NOTE: Uses a SINGLE connection to avoid rate limiting
8
+
9
+ require "dhan_hq"
10
+
11
+ # Configure DhanHQ
12
+ DhanHQ.configure do |config|
13
+ config.client_id = ENV["CLIENT_ID"] || "your_client_id"
14
+ config.access_token = ENV["ACCESS_TOKEN"] || "your_access_token"
15
+ config.ws_user_type = ENV["DHAN_WS_USER_TYPE"] || "SELF"
16
+ end
17
+
18
+ puts "DhanHQ Market Depth WebSocket Example"
19
+ puts "===================================="
20
+ puts "Receives real-time market depth data including:"
21
+ puts "- Bid/Ask levels"
22
+ puts "- Order book information"
23
+ puts "- Market depth snapshots"
24
+ puts "- Depth updates"
25
+ puts ""
26
+ puts "Subscribing to popular stocks:"
27
+ puts "- RELIANCE (Reliance Industries) - NSE_EQ:2885"
28
+ puts "- TCS (Tata Consultancy Services) - NSE_EQ:11536"
29
+ puts ""
30
+ puts "NOTE: Using SINGLE connection to avoid rate limiting (429 errors)"
31
+ puts "Dhan allows up to 5 WebSocket connections per user"
32
+ puts ""
33
+
34
+ # Market Depth WebSocket Connection
35
+ puts "Market Depth WebSocket Connection"
36
+ puts "================================="
37
+
38
+ # Create a single market depth WebSocket connection
39
+ puts "Creating Market Depth WebSocket connection..."
40
+
41
+ # Find instruments using the new .find method (now uses underlying_symbol for equity)
42
+ reliance_instrument = DhanHQ::Models::Instrument.find("NSE_EQ", "RELIANCE")
43
+ tcs_instrument = DhanHQ::Models::Instrument.find("NSE_EQ", "TCS")
44
+
45
+ # Define symbols with correct exchange segments and security IDs
46
+ symbols = []
47
+ if reliance_instrument
48
+ symbols << { symbol: "RELIANCE", exchange_segment: reliance_instrument.exchange_segment,
49
+ security_id: reliance_instrument.security_id }
50
+ puts "✅ Found RELIANCE: #{reliance_instrument.symbol_name} (#{reliance_instrument.exchange_segment}:#{reliance_instrument.security_id})"
51
+ else
52
+ puts "❌ Could not find RELIANCE INDUSTRIES LTD"
53
+ end
54
+
55
+ if tcs_instrument
56
+ symbols << { symbol: "TCS", exchange_segment: tcs_instrument.exchange_segment,
57
+ security_id: tcs_instrument.security_id }
58
+ puts "✅ Found TCS: #{tcs_instrument.symbol_name} (#{tcs_instrument.exchange_segment}:#{tcs_instrument.security_id})"
59
+ else
60
+ puts "❌ Could not find TATA CONSULTANCY SERV LT"
61
+ end
62
+
63
+ if symbols.empty?
64
+ puts "❌ No symbols found. Exiting..."
65
+ exit(1)
66
+ end
67
+
68
+ depth_client = DhanHQ::WS::MarketDepth.connect(symbols: symbols) do |depth_data|
69
+ puts "Market Depth: #{depth_data[:symbol]}"
70
+ puts " Best Bid: #{depth_data[:best_bid]}"
71
+ puts " Best Ask: #{depth_data[:best_ask]}"
72
+ puts " Spread: #{depth_data[:spread]}"
73
+ puts " Bid Levels: #{depth_data[:bids].size}"
74
+ puts " Ask Levels: #{depth_data[:asks].size}"
75
+
76
+ # Show top 3 bid/ask levels if available
77
+ if depth_data[:bids] && depth_data[:bids].size > 0
78
+ puts " Top Bids:"
79
+ depth_data[:bids].first(3).each_with_index do |bid, i|
80
+ puts " #{i + 1}. Price: #{bid[:price]}, Qty: #{bid[:quantity]}"
81
+ end
82
+ end
83
+
84
+ if depth_data[:asks] && depth_data[:asks].size > 0
85
+ puts " Top Asks:"
86
+ depth_data[:asks].first(3).each_with_index do |ask, i|
87
+ puts " #{i + 1}. Price: #{ask[:price]}, Qty: #{ask[:quantity]}"
88
+ end
89
+ end
90
+
91
+ puts " ---"
92
+ end
93
+
94
+ # Add event handlers for different depth events
95
+ puts "\nSetting up event handlers..."
96
+
97
+ depth_client.on(:depth_update) do |update_data|
98
+ puts "📊 Depth Update: #{update_data[:symbol]} - #{update_data[:side]} side updated"
99
+ end
100
+
101
+ depth_client.on(:depth_snapshot) do |snapshot_data|
102
+ puts "📸 Depth Snapshot: #{snapshot_data[:symbol]} - Full order book received"
103
+ end
104
+
105
+ depth_client.on(:error) do |error|
106
+ puts "⚠️ WebSocket Error: #{error}"
107
+ end
108
+
109
+ depth_client.on(:close) do |close_info|
110
+ if close_info.is_a?(Hash)
111
+ puts "🔌 WebSocket Closed: #{close_info[:code]} - #{close_info[:reason]}"
112
+ else
113
+ puts "🔌 WebSocket Closed: #{close_info}"
114
+ end
115
+ end
116
+
117
+ puts "\nMarket Depth WebSocket connected successfully!"
118
+ puts "Waiting 30 seconds to receive market depth data..."
119
+ puts "Press Ctrl+C to stop early"
120
+ puts ""
121
+
122
+ # Wait for market depth data
123
+ begin
124
+ sleep(30)
125
+ rescue Interrupt
126
+ puts "\nStopping early due to user interrupt..."
127
+ end
128
+
129
+ # Graceful shutdown
130
+ puts "\nShutting down Market Depth WebSocket connection..."
131
+ depth_client.stop
132
+
133
+ puts "Market Depth WebSocket connection closed."
134
+ puts "Example completed!"
135
+ puts ""
136
+ puts "Summary:"
137
+ puts "- Successfully demonstrated Market Depth WebSocket"
138
+ puts "- Real-time bid/ask level tracking:"
139
+ puts " * RELIANCE (Reliance Industries) - dynamically resolved using .find method"
140
+ puts " * TCS (Tata Consultancy Services) - dynamically resolved using .find method"
141
+ puts "- Order book depth visualization"
142
+ puts "- Used single connection to avoid rate limiting (429 errors)"
143
+ puts "- Proper connection cleanup prevents resource leaks"
144
+ puts "- Dynamic symbol resolution using DhanHQ::Models::Instrument.find"
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Market Feed WebSocket Example
5
+ # This script demonstrates how to use the DhanHQ Market Feed WebSocket
6
+ # Subscribes to major Indian indices (NIFTY, BANKNIFTY, NIFTYIT, SENSEX)
7
+ # NOTE: Uses a SINGLE connection to avoid rate limiting
8
+
9
+ require "dhan_hq"
10
+
11
+ # Configure DhanHQ
12
+ DhanHQ.configure do |config|
13
+ config.client_id = ENV["CLIENT_ID"] || "your_client_id"
14
+ config.access_token = ENV["ACCESS_TOKEN"] || "your_access_token"
15
+ config.ws_user_type = ENV["DHAN_WS_USER_TYPE"] || "SELF"
16
+ end
17
+
18
+ puts "DhanHQ Market Feed WebSocket Example"
19
+ puts "===================================="
20
+ puts "Subscribing to major Indian indices:"
21
+ puts "- NIFTY (Nifty 50)"
22
+ puts "- BANKNIFTY (Nifty Bank)"
23
+ puts "- NIFTYIT (Nifty IT)"
24
+ puts "- SENSEX (Sensex)"
25
+ puts ""
26
+ puts "NOTE: Using SINGLE connection to avoid rate limiting (429 errors)"
27
+ puts "Dhan allows up to 5 WebSocket connections per user"
28
+ puts ""
29
+
30
+ # Market Feed WebSocket Connection
31
+ puts "Market Feed WebSocket Connection"
32
+ puts "================================"
33
+
34
+ # Create a single market feed WebSocket connection
35
+ puts "Creating Market Feed WebSocket connection..."
36
+ market_client = DhanHQ::WS.connect(mode: :ticker) do |tick|
37
+ timestamp = tick[:ts] ? Time.at(tick[:ts]) : Time.now
38
+ puts "Market Data: #{tick[:segment]}:#{tick[:security_id]} = #{tick[:ltp]} at #{timestamp}"
39
+ end
40
+
41
+ # Subscribe to specific IDX_I instruments only
42
+ # Note: IDX_I is the correct segment for index instruments
43
+ puts "\nSubscribing to IDX_I instruments:"
44
+ puts "- Security ID 13: NIFTY (Nifty 50)"
45
+ puts "- Security ID 25: BANKNIFTY (Nifty Bank)"
46
+ puts "- Security ID 29: NIFTYIT (Nifty IT)"
47
+ puts "- Security ID 51: SENSEX (Sensex)"
48
+
49
+ market_client.subscribe_one(segment: "IDX_I", security_id: "13") # NIFTY (Nifty 50)
50
+ market_client.subscribe_one(segment: "IDX_I", security_id: "25") # BANKNIFTY (Nifty Bank)
51
+ market_client.subscribe_one(segment: "IDX_I", security_id: "29") # NIFTYIT (Nifty IT)
52
+ market_client.subscribe_one(segment: "IDX_I", security_id: "51") # SENSEX (Sensex)
53
+
54
+ puts "\nMarket Feed WebSocket connected successfully!"
55
+ puts "Waiting 15 seconds to receive market data..."
56
+ puts "Press Ctrl+C to stop early"
57
+ puts ""
58
+
59
+ # Wait for market data
60
+ begin
61
+ sleep(15)
62
+ rescue Interrupt
63
+ puts "\nStopping early due to user interrupt..."
64
+ end
65
+
66
+ # Graceful shutdown
67
+ puts "\nShutting down WebSocket connection..."
68
+ market_client.stop
69
+
70
+ puts "WebSocket connection closed."
71
+ puts "Example completed!"
72
+ puts ""
73
+ puts "Summary:"
74
+ puts "- Successfully demonstrated IDX_I subscriptions:"
75
+ puts " * Security ID 13: NIFTY (Nifty 50)"
76
+ puts " * Security ID 25: BANKNIFTY (Nifty Bank)"
77
+ puts " * Security ID 29: NIFTYIT (Nifty IT)"
78
+ puts " * Security ID 51: SENSEX (Sensex)"
79
+ puts "- Used single connection to avoid rate limiting (429 errors)"
80
+ puts "- Proper connection cleanup prevents resource leaks"
81
+ puts "- No multiple connection issues!"