DhanHQ 2.1.3 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +185 -0
- data/CHANGELOG.md +31 -0
- data/GUIDE.md +173 -31
- data/README.md +437 -133
- data/README1.md +267 -26
- data/docs/live_order_updates.md +319 -0
- data/docs/rails_integration.md +1 -1
- data/docs/rails_websocket_integration.md +847 -0
- data/docs/standalone_ruby_websocket_integration.md +1588 -0
- data/docs/technical_analysis.md +1 -0
- data/docs/websocket_integration.md +871 -0
- data/examples/comprehensive_websocket_examples.rb +148 -0
- data/examples/instrument_finder_test.rb +195 -0
- data/examples/live_order_updates.rb +118 -0
- data/examples/market_depth_example.rb +144 -0
- data/examples/market_feed_example.rb +81 -0
- data/examples/order_update_example.rb +105 -0
- data/examples/trading_fields_example.rb +215 -0
- data/lib/DhanHQ/config.rb +1 -0
- data/lib/DhanHQ/configuration.rb +16 -1
- data/lib/DhanHQ/contracts/expired_options_data_contract.rb +103 -0
- data/lib/DhanHQ/contracts/modify_order_contract.rb +1 -0
- data/lib/DhanHQ/contracts/option_chain_contract.rb +11 -1
- data/lib/DhanHQ/contracts/trade_contract.rb +70 -0
- data/lib/DhanHQ/errors.rb +2 -0
- data/lib/DhanHQ/models/expired_options_data.rb +331 -0
- data/lib/DhanHQ/models/instrument.rb +96 -2
- data/lib/DhanHQ/models/option_chain.rb +2 -0
- data/lib/DhanHQ/models/order_update.rb +235 -0
- data/lib/DhanHQ/models/trade.rb +118 -31
- data/lib/DhanHQ/rate_limiter.rb +4 -2
- data/lib/DhanHQ/resources/expired_options_data.rb +22 -0
- data/lib/DhanHQ/version.rb +1 -1
- data/lib/DhanHQ/ws/base_connection.rb +249 -0
- data/lib/DhanHQ/ws/client.rb +1 -1
- data/lib/DhanHQ/ws/connection.rb +3 -3
- data/lib/DhanHQ/ws/decoder.rb +3 -3
- data/lib/DhanHQ/ws/market_depth/client.rb +376 -0
- data/lib/DhanHQ/ws/market_depth/decoder.rb +131 -0
- data/lib/DhanHQ/ws/market_depth.rb +74 -0
- data/lib/DhanHQ/ws/orders/client.rb +177 -10
- data/lib/DhanHQ/ws/orders/connection.rb +41 -83
- data/lib/DhanHQ/ws/orders.rb +31 -2
- data/lib/DhanHQ/ws/registry.rb +1 -0
- data/lib/DhanHQ/ws/segments.rb +21 -5
- data/lib/DhanHQ/ws/sub_state.rb +1 -1
- data/lib/DhanHQ/ws.rb +3 -2
- data/lib/{DhanHQ.rb → dhan_hq.rb} +5 -0
- data/lib/dhanhq/analysis/helpers/bias_aggregator.rb +18 -18
- data/lib/dhanhq/analysis/helpers/moneyness_helper.rb +1 -0
- data/lib/dhanhq/analysis/multi_timeframe_analyzer.rb +2 -0
- data/lib/dhanhq/analysis/options_buying_advisor.rb +4 -3
- data/lib/dhanhq/contracts/options_buying_advisor_contract.rb +1 -0
- data/lib/ta/candles.rb +1 -0
- data/lib/ta/fetcher.rb +1 -0
- data/lib/ta/indicators.rb +2 -1
- data/lib/ta/market_calendar.rb +4 -3
- data/lib/ta/technical_analysis.rb +3 -2
- metadata +38 -4
- data/lib/DhanHQ/ws/errors.rb +0 -0
- /data/lib/DhanHQ/contracts/{modify_order_contract copy.rb → modify_order_contract_copy.rb} +0 -0
@@ -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!"
|