DhanHQ 2.5.0 → 2.6.1
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 +9 -1
- data/CHANGELOG.md +78 -6
- data/GUIDE.md +57 -39
- data/README.md +24 -23
- data/docs/API_DOCS_GAPS.md +128 -0
- data/docs/API_VERIFICATION.md +10 -11
- data/docs/ARCHIVE_README.md +16 -16
- data/docs/AUTHENTICATION.md +1 -1
- data/docs/CONSTANTS_REFERENCE.md +477 -0
- data/docs/DATA_API_PARAMETERS.md +7 -7
- data/docs/{rails_websocket_integration.md → RAILS_WEBSOCKET_INTEGRATION.md} +10 -10
- data/docs/{standalone_ruby_websocket_integration.md → STANDALONE_RUBY_WEBSOCKET_INTEGRATION.md} +32 -32
- data/docs/{technical_analysis.md → TECHNICAL_ANALYSIS.md} +3 -3
- data/docs/TESTING_GUIDE.md +84 -82
- data/docs/{websocket_integration.md → WEBSOCKET_INTEGRATION.md} +19 -19
- data/docs/WEBSOCKET_PROTOCOL.md +2 -2
- data/lib/DhanHQ/constants.rb +456 -151
- data/lib/DhanHQ/contracts/alert_order_contract.rb +37 -10
- data/lib/DhanHQ/contracts/base_contract.rb +22 -0
- data/lib/DhanHQ/contracts/edis_contract.rb +25 -0
- data/lib/DhanHQ/contracts/margin_calculator_contract.rb +27 -4
- data/lib/DhanHQ/contracts/modify_order_contract.rb +65 -12
- data/lib/DhanHQ/contracts/multi_scrip_margin_calc_request_contract.rb +23 -0
- data/lib/DhanHQ/contracts/order_contract.rb +171 -39
- data/lib/DhanHQ/contracts/place_order_contract.rb +14 -141
- data/lib/DhanHQ/contracts/pnl_based_exit_contract.rb +20 -0
- data/lib/DhanHQ/contracts/position_conversion_contract.rb +15 -3
- data/lib/DhanHQ/contracts/slice_order_contract.rb +10 -1
- data/lib/DhanHQ/contracts/user_ip_contract.rb +14 -0
- data/lib/DhanHQ/core/base_model.rb +13 -4
- data/lib/DhanHQ/helpers/response_helper.rb +2 -2
- data/lib/DhanHQ/helpers/validation_helper.rb +1 -1
- data/lib/DhanHQ/models/alert_order.rb +7 -11
- data/lib/DhanHQ/models/concerns/api_response_handler.rb +46 -0
- data/lib/DhanHQ/models/edis.rb +0 -9
- data/lib/DhanHQ/models/expired_options_data.rb +6 -12
- data/lib/DhanHQ/models/forever_order.rb +8 -5
- data/lib/DhanHQ/models/historical_data.rb +0 -8
- data/lib/DhanHQ/models/instrument.rb +1 -7
- data/lib/DhanHQ/models/instrument_helpers.rb +4 -4
- data/lib/DhanHQ/models/kill_switch.rb +1 -11
- data/lib/DhanHQ/models/margin.rb +2 -2
- data/lib/DhanHQ/models/order.rb +107 -126
- data/lib/DhanHQ/models/order_update.rb +7 -13
- data/lib/DhanHQ/models/pnl_exit.rb +1 -9
- data/lib/DhanHQ/models/position.rb +1 -1
- data/lib/DhanHQ/models/postback.rb +4 -13
- data/lib/DhanHQ/models/profile.rb +0 -10
- data/lib/DhanHQ/models/super_order.rb +13 -3
- data/lib/DhanHQ/models/trade.rb +11 -23
- data/lib/DhanHQ/resources/ip_setup.rb +16 -5
- data/lib/DhanHQ/resources/kill_switch.rb +9 -7
- data/lib/DhanHQ/resources/orders.rb +41 -41
- data/lib/DhanHQ/version.rb +1 -1
- data/lib/DhanHQ/ws/cmd_bus.rb +1 -1
- data/lib/DhanHQ/ws/orders/client.rb +6 -6
- data/lib/DhanHQ/ws/singleton_lock.rb +2 -1
- data/lib/dhanhq/analysis/options_buying_advisor.rb +2 -2
- data/lib/rubocop/cop/dhanhq/use_constants.rb +171 -0
- metadata +20 -23
- data/TODO-1.md +0 -14
- data/TODO.md +0 -127
- data/app/services/live/order_update_guard_support.rb +0 -75
- data/app/services/live/order_update_hub.rb +0 -76
- data/app/services/live/order_update_persistence_support.rb +0 -68
- data/docs/PR_2.2.0.md +0 -48
- data/examples/comprehensive_websocket_examples.rb +0 -148
- data/examples/instrument_finder_test.rb +0 -195
- data/examples/live_order_updates.rb +0 -118
- data/examples/market_depth_example.rb +0 -144
- data/examples/market_feed_example.rb +0 -81
- data/examples/order_update_example.rb +0 -105
- data/examples/trading_fields_example.rb +0 -215
- /data/docs/{live_order_updates.md → LIVE_ORDER_UPDATES.md} +0 -0
- /data/docs/{rails_integration.md → RAILS_INTEGRATION.md} +0 -0
|
@@ -1,118 +0,0 @@
|
|
|
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
|
|
@@ -1,144 +0,0 @@
|
|
|
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["DHAN_CLIENT_ID"] || "your_client_id"
|
|
14
|
-
config.access_token = ENV["DHAN_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]&.size&.positive?
|
|
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]&.size&.positive?
|
|
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"
|
|
@@ -1,81 +0,0 @@
|
|
|
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["DHAN_CLIENT_ID"] || "your_client_id"
|
|
14
|
-
config.access_token = ENV["DHAN_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!"
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# Order Update WebSocket Example
|
|
5
|
-
# This script demonstrates how to use the DhanHQ Order Update WebSocket
|
|
6
|
-
# Receives real-time order status updates and execution notifications
|
|
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["DHAN_CLIENT_ID"] || "your_client_id"
|
|
14
|
-
config.access_token = ENV["DHAN_ACCESS_TOKEN"] || "your_access_token"
|
|
15
|
-
config.ws_user_type = ENV["DHAN_WS_USER_TYPE"] || "SELF"
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
puts "DhanHQ Order Update WebSocket Example"
|
|
19
|
-
puts "====================================="
|
|
20
|
-
puts "Receives real-time order updates including:"
|
|
21
|
-
puts "- Order status changes"
|
|
22
|
-
puts "- Execution notifications"
|
|
23
|
-
puts "- Order rejections"
|
|
24
|
-
puts "- Trade confirmations"
|
|
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
|
-
# Order Update WebSocket Connection
|
|
31
|
-
puts "Order Update WebSocket Connection"
|
|
32
|
-
puts "================================="
|
|
33
|
-
|
|
34
|
-
# Create a single order update WebSocket connection
|
|
35
|
-
puts "Creating Order Update WebSocket connection..."
|
|
36
|
-
orders_client = DhanHQ::WS::Orders.connect do |order_update|
|
|
37
|
-
puts "Order Update: #{order_update.order_no} - #{order_update.status}"
|
|
38
|
-
puts " Symbol: #{order_update.symbol}"
|
|
39
|
-
puts " Quantity: #{order_update.quantity}"
|
|
40
|
-
puts " Traded Qty: #{order_update.traded_qty}"
|
|
41
|
-
puts " Price: #{order_update.price}"
|
|
42
|
-
puts " Execution: #{order_update.execution_percentage}%"
|
|
43
|
-
puts " ---"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Add event handlers for different order events
|
|
47
|
-
puts "\nSetting up event handlers..."
|
|
48
|
-
|
|
49
|
-
orders_client.on(:update) do |order_update|
|
|
50
|
-
puts "📝 Order Updated: #{order_update.order_no} - #{order_update.status}"
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
orders_client.on(:status_change) do |change_data|
|
|
54
|
-
puts "🔄 Status Changed: #{change_data[:previous_status]} -> #{change_data[:new_status]}"
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
orders_client.on(:execution) do |execution_data|
|
|
58
|
-
puts "✅ Execution: #{execution_data[:new_traded_qty]} shares executed"
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
orders_client.on(:order_traded) do |order_update|
|
|
62
|
-
puts "💰 Order Traded: #{order_update.order_no} - #{order_update.symbol}"
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
orders_client.on(:order_rejected) do |order_update|
|
|
66
|
-
puts "❌ Order Rejected: #{order_update.order_no} - #{order_update.reason_description}"
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
orders_client.on(:error) do |error|
|
|
70
|
-
puts "⚠️ WebSocket Error: #{error}"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
orders_client.on(:close) do |close_info|
|
|
74
|
-
if close_info.is_a?(Hash)
|
|
75
|
-
puts "🔌 WebSocket Closed: #{close_info[:code]} - #{close_info[:reason]}"
|
|
76
|
-
else
|
|
77
|
-
puts "🔌 WebSocket Closed: #{close_info}"
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
puts "\nOrder Update WebSocket connected successfully!"
|
|
82
|
-
puts "Waiting 30 seconds to receive order updates..."
|
|
83
|
-
puts "Press Ctrl+C to stop early"
|
|
84
|
-
puts ""
|
|
85
|
-
|
|
86
|
-
# Wait for order updates
|
|
87
|
-
begin
|
|
88
|
-
sleep(30)
|
|
89
|
-
rescue Interrupt
|
|
90
|
-
puts "\nStopping early due to user interrupt..."
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# Graceful shutdown
|
|
94
|
-
puts "\nShutting down Order Update WebSocket connection..."
|
|
95
|
-
orders_client.stop
|
|
96
|
-
|
|
97
|
-
puts "Order Update WebSocket connection closed."
|
|
98
|
-
puts "Example completed!"
|
|
99
|
-
puts ""
|
|
100
|
-
puts "Summary:"
|
|
101
|
-
puts "- Successfully demonstrated Order Update WebSocket"
|
|
102
|
-
puts "- Real-time order status tracking"
|
|
103
|
-
puts "- Multiple event handlers for different order events"
|
|
104
|
-
puts "- Used single connection to avoid rate limiting (429 errors)"
|
|
105
|
-
puts "- Proper connection cleanup prevents resource leaks"
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
# DhanHQ Trading Fields Example
|
|
5
|
-
# This script demonstrates how to use the new trading fields in the Instrument model
|
|
6
|
-
# for practical trading operations and risk management
|
|
7
|
-
|
|
8
|
-
require "dhan_hq"
|
|
9
|
-
|
|
10
|
-
# Configure DhanHQ
|
|
11
|
-
DhanHQ.configure do |config|
|
|
12
|
-
config.client_id = ENV["DHAN_CLIENT_ID"] || "your_client_id"
|
|
13
|
-
config.access_token = ENV["DHAN_ACCESS_TOKEN"] || "your_access_token"
|
|
14
|
-
config.ws_user_type = ENV["DHAN_WS_USER_TYPE"] || "SELF"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
puts "DhanHQ Trading Fields Example"
|
|
18
|
-
puts "============================="
|
|
19
|
-
puts "Demonstrating essential trading fields for risk management and order validation"
|
|
20
|
-
puts ""
|
|
21
|
-
|
|
22
|
-
# Helper method to display trading information
|
|
23
|
-
def display_trading_info(instrument, name)
|
|
24
|
-
return unless instrument
|
|
25
|
-
|
|
26
|
-
puts "✅ #{name} Trading Information:"
|
|
27
|
-
puts " Symbol: #{instrument.symbol_name}"
|
|
28
|
-
puts " Underlying Symbol: #{instrument.underlying_symbol}" if instrument.underlying_symbol
|
|
29
|
-
puts " Security ID: #{instrument.security_id}"
|
|
30
|
-
puts " ISIN: #{instrument.isin}"
|
|
31
|
-
puts " Instrument Type: #{instrument.instrument_type}"
|
|
32
|
-
puts " Exchange Segment: #{instrument.exchange_segment}"
|
|
33
|
-
puts " Lot Size: #{instrument.lot_size}"
|
|
34
|
-
puts " Tick Size: #{instrument.tick_size}"
|
|
35
|
-
puts " Expiry Flag: #{instrument.expiry_flag}"
|
|
36
|
-
puts " Bracket Flag: #{instrument.bracket_flag}"
|
|
37
|
-
puts " Cover Flag: #{instrument.cover_flag}"
|
|
38
|
-
puts " ASM/GSM Flag: #{instrument.asm_gsm_flag}"
|
|
39
|
-
puts " ASM/GSM Category: #{instrument.asm_gsm_category}" if instrument.asm_gsm_category != "NA"
|
|
40
|
-
puts " Buy/Sell Indicator: #{instrument.buy_sell_indicator}"
|
|
41
|
-
puts " Buy CO Min Margin %: #{instrument.buy_co_min_margin_per}"
|
|
42
|
-
puts " Sell CO Min Margin %: #{instrument.sell_co_min_margin_per}"
|
|
43
|
-
puts " MTF Leverage: #{instrument.mtf_leverage}"
|
|
44
|
-
puts ""
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
# Helper method to check trading eligibility
|
|
48
|
-
def check_trading_eligibility(instrument, name)
|
|
49
|
-
return unless instrument
|
|
50
|
-
|
|
51
|
-
puts "🔍 #{name} Trading Eligibility Check:"
|
|
52
|
-
|
|
53
|
-
# Check if instrument allows trading
|
|
54
|
-
if instrument.buy_sell_indicator == "A"
|
|
55
|
-
puts " ✅ Trading Allowed"
|
|
56
|
-
else
|
|
57
|
-
puts " ❌ Trading Not Allowed"
|
|
58
|
-
return
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Check bracket orders
|
|
62
|
-
if instrument.bracket_flag == "Y"
|
|
63
|
-
puts " ✅ Bracket Orders Allowed"
|
|
64
|
-
else
|
|
65
|
-
puts " ❌ Bracket Orders Not Allowed"
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Check cover orders
|
|
69
|
-
if instrument.cover_flag == "Y"
|
|
70
|
-
puts " ✅ Cover Orders Allowed"
|
|
71
|
-
else
|
|
72
|
-
puts " ❌ Cover Orders Not Allowed"
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Check ASM/GSM status
|
|
76
|
-
if instrument.asm_gsm_flag == "Y"
|
|
77
|
-
puts " ⚠️ ASM/GSM Applied: #{instrument.asm_gsm_category}"
|
|
78
|
-
else
|
|
79
|
-
puts " ✅ No ASM/GSM Restrictions"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Check expiry
|
|
83
|
-
if instrument.expiry_flag == "Y"
|
|
84
|
-
puts " ⚠️ Instrument Has Expiry: #{instrument.expiry_date}"
|
|
85
|
-
else
|
|
86
|
-
puts " ✅ No Expiry (Perpetual)"
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
puts ""
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Helper method to calculate margin requirements
|
|
93
|
-
def calculate_margin_requirements(instrument, name, quantity, price)
|
|
94
|
-
return unless instrument
|
|
95
|
-
|
|
96
|
-
puts "💰 #{name} Margin Calculation:"
|
|
97
|
-
puts " Quantity: #{quantity}"
|
|
98
|
-
puts " Price: ₹#{price}"
|
|
99
|
-
puts " Lot Size: #{instrument.lot_size}"
|
|
100
|
-
|
|
101
|
-
total_value = quantity * price * instrument.lot_size
|
|
102
|
-
puts " Total Value: ₹#{total_value}"
|
|
103
|
-
|
|
104
|
-
# Calculate margin requirements
|
|
105
|
-
buy_margin = total_value * (instrument.buy_co_min_margin_per / 100.0)
|
|
106
|
-
sell_margin = total_value * (instrument.sell_co_min_margin_per / 100.0)
|
|
107
|
-
|
|
108
|
-
puts " Buy CO Margin Required: ₹#{buy_margin}"
|
|
109
|
-
puts " Sell CO Margin Required: ₹#{sell_margin}"
|
|
110
|
-
|
|
111
|
-
# Calculate MTF leverage
|
|
112
|
-
if instrument.mtf_leverage.positive?
|
|
113
|
-
mtf_value = total_value * instrument.mtf_leverage
|
|
114
|
-
puts " MTF Leverage: #{instrument.mtf_leverage}x"
|
|
115
|
-
puts " MTF Value: ₹#{mtf_value}"
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
puts ""
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
puts "1. Finding Instruments with Trading Fields"
|
|
122
|
-
puts "=" * 50
|
|
123
|
-
|
|
124
|
-
# Find popular trading instruments
|
|
125
|
-
reliance = DhanHQ::Models::Instrument.find("NSE_EQ", "RELIANCE")
|
|
126
|
-
tcs = DhanHQ::Models::Instrument.find("NSE_EQ", "TCS")
|
|
127
|
-
hdfc = DhanHQ::Models::Instrument.find("NSE_EQ", "HDFC")
|
|
128
|
-
nifty = DhanHQ::Models::Instrument.find("IDX_I", "NIFTY")
|
|
129
|
-
banknifty = DhanHQ::Models::Instrument.find("IDX_I", "BANKNIFTY")
|
|
130
|
-
|
|
131
|
-
# Display trading information
|
|
132
|
-
display_trading_info(reliance, "RELIANCE")
|
|
133
|
-
display_trading_info(tcs, "TCS")
|
|
134
|
-
display_trading_info(hdfc, "HDFC")
|
|
135
|
-
display_trading_info(nifty, "NIFTY")
|
|
136
|
-
display_trading_info(banknifty, "BANKNIFTY")
|
|
137
|
-
|
|
138
|
-
puts "2. Trading Eligibility Checks"
|
|
139
|
-
puts "=" * 40
|
|
140
|
-
|
|
141
|
-
# Check trading eligibility
|
|
142
|
-
check_trading_eligibility(reliance, "RELIANCE")
|
|
143
|
-
check_trading_eligibility(tcs, "TCS")
|
|
144
|
-
check_trading_eligibility(nifty, "NIFTY")
|
|
145
|
-
|
|
146
|
-
puts "3. Margin Calculations"
|
|
147
|
-
puts "=" * 25
|
|
148
|
-
|
|
149
|
-
# Calculate margin requirements for different scenarios
|
|
150
|
-
calculate_margin_requirements(reliance, "RELIANCE", 10, 2500)
|
|
151
|
-
calculate_margin_requirements(tcs, "TCS", 5, 3500)
|
|
152
|
-
calculate_margin_requirements(nifty, "NIFTY", 1, 20_000)
|
|
153
|
-
|
|
154
|
-
puts "4. Practical Trading Scenarios"
|
|
155
|
-
puts "=" * 35
|
|
156
|
-
|
|
157
|
-
# Scenario 1: Check if instrument supports bracket orders
|
|
158
|
-
puts "Scenario 1: Bracket Order Support"
|
|
159
|
-
puts "-" * 30
|
|
160
|
-
instruments = [reliance, tcs, hdfc, nifty, banknifty]
|
|
161
|
-
instruments.each do |instrument|
|
|
162
|
-
next unless instrument
|
|
163
|
-
|
|
164
|
-
puts "#{instrument.underlying_symbol || instrument.symbol_name}: #{instrument.bracket_flag == "Y" ? "✅ Supports" : "❌ No Support"}"
|
|
165
|
-
end
|
|
166
|
-
puts ""
|
|
167
|
-
|
|
168
|
-
# Scenario 2: Find instruments with ASM/GSM restrictions
|
|
169
|
-
puts "Scenario 2: ASM/GSM Restricted Instruments"
|
|
170
|
-
puts "-" * 40
|
|
171
|
-
asm_instruments = instruments.select { |i| i&.asm_gsm_flag == "Y" }
|
|
172
|
-
if asm_instruments.any?
|
|
173
|
-
asm_instruments.each do |instrument|
|
|
174
|
-
puts "#{instrument.underlying_symbol || instrument.symbol_name}: #{instrument.asm_gsm_category}"
|
|
175
|
-
end
|
|
176
|
-
else
|
|
177
|
-
puts "No ASM/GSM restricted instruments found in sample"
|
|
178
|
-
end
|
|
179
|
-
puts ""
|
|
180
|
-
|
|
181
|
-
# Scenario 3: Find instruments with high MTF leverage
|
|
182
|
-
puts "Scenario 3: High MTF Leverage Instruments"
|
|
183
|
-
puts "-" * 40
|
|
184
|
-
high_leverage = instruments.select { |i| i&.mtf_leverage && i.mtf_leverage > 3.0 }
|
|
185
|
-
if high_leverage.any?
|
|
186
|
-
high_leverage.each do |instrument|
|
|
187
|
-
puts "#{instrument.underlying_symbol || instrument.symbol_name}: #{instrument.mtf_leverage}x leverage"
|
|
188
|
-
end
|
|
189
|
-
else
|
|
190
|
-
puts "No high leverage instruments found in sample"
|
|
191
|
-
end
|
|
192
|
-
puts ""
|
|
193
|
-
|
|
194
|
-
puts "5. Trading Field Summary"
|
|
195
|
-
puts "=" * 25
|
|
196
|
-
puts "Essential trading fields now available:"
|
|
197
|
-
puts "✅ ISIN - International Securities Identification Number"
|
|
198
|
-
puts "✅ Instrument Type - Classification (ES, INDEX, etc.)"
|
|
199
|
-
puts "✅ Expiry Flag - Whether instrument has expiry"
|
|
200
|
-
puts "✅ Bracket Flag - Bracket order support"
|
|
201
|
-
puts "✅ Cover Flag - Cover order support"
|
|
202
|
-
puts "✅ ASM/GSM Flag - Additional Surveillance Measure status"
|
|
203
|
-
puts "✅ Buy/Sell Indicator - Trading permission"
|
|
204
|
-
puts "✅ Margin Requirements - CO minimum margin percentages"
|
|
205
|
-
puts "✅ MTF Leverage - Margin Trading Facility leverage"
|
|
206
|
-
puts ""
|
|
207
|
-
|
|
208
|
-
puts "Example completed!"
|
|
209
|
-
puts "=================="
|
|
210
|
-
puts "These trading fields enable:"
|
|
211
|
-
puts "- Order validation and eligibility checks"
|
|
212
|
-
puts "- Margin requirement calculations"
|
|
213
|
-
puts "- Risk management and compliance"
|
|
214
|
-
puts "- Trading strategy implementation"
|
|
215
|
-
puts "- Regulatory compliance monitoring"
|
|
File without changes
|
|
File without changes
|