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
data/docs/{standalone_ruby_websocket_integration.md → STANDALONE_RUBY_WEBSOCKET_INTEGRATION.md}
RENAMED
|
@@ -43,10 +43,10 @@ market_client = DhanHQ::WS.connect(mode: :ticker) do |tick|
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# Subscribe to major indices
|
|
46
|
-
market_client.subscribe_one(segment:
|
|
47
|
-
market_client.subscribe_one(segment:
|
|
48
|
-
market_client.subscribe_one(segment:
|
|
49
|
-
market_client.subscribe_one(segment:
|
|
46
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13") # NIFTY
|
|
47
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25") # BANKNIFTY
|
|
48
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29") # NIFTYIT
|
|
49
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51") # SENSEX
|
|
50
50
|
|
|
51
51
|
# Wait for data
|
|
52
52
|
sleep(30)
|
|
@@ -179,10 +179,10 @@ class MarketFeedScript
|
|
|
179
179
|
|
|
180
180
|
def subscribe_to_indices
|
|
181
181
|
indices = [
|
|
182
|
-
{ segment:
|
|
183
|
-
{ segment:
|
|
184
|
-
{ segment:
|
|
185
|
-
{ segment:
|
|
182
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13", name: "NIFTY" },
|
|
183
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25", name: "BANKNIFTY" },
|
|
184
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29", name: "NIFTYIT" },
|
|
185
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51", name: "SENSEX" }
|
|
186
186
|
]
|
|
187
187
|
|
|
188
188
|
indices.each do |index|
|
|
@@ -411,8 +411,8 @@ class MarketDepthScript
|
|
|
411
411
|
|
|
412
412
|
# Define symbols with correct exchange segments and security IDs
|
|
413
413
|
symbols = [
|
|
414
|
-
{ symbol: "RELIANCE", exchange_segment:
|
|
415
|
-
{ symbol: "TCS", exchange_segment:
|
|
414
|
+
{ symbol: "RELIANCE", exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "2885" },
|
|
415
|
+
{ symbol: "TCS", exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "11536" }
|
|
416
416
|
]
|
|
417
417
|
|
|
418
418
|
@depth_client = DhanHQ::WS::MarketDepth.connect(symbols: symbols) do |depth_data|
|
|
@@ -664,10 +664,10 @@ class MarketFeedDaemon
|
|
|
664
664
|
|
|
665
665
|
def subscribe_to_indices
|
|
666
666
|
indices = [
|
|
667
|
-
{ segment:
|
|
668
|
-
{ segment:
|
|
669
|
-
{ segment:
|
|
670
|
-
{ segment:
|
|
667
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13", name: "NIFTY" },
|
|
668
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25", name: "BANKNIFTY" },
|
|
669
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29", name: "NIFTYIT" },
|
|
670
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51", name: "SENSEX" }
|
|
671
671
|
]
|
|
672
672
|
|
|
673
673
|
indices.each do |index|
|
|
@@ -906,10 +906,10 @@ class MarketDataCLI
|
|
|
906
906
|
|
|
907
907
|
def subscribe_to_default_indices(client)
|
|
908
908
|
indices = [
|
|
909
|
-
{ segment:
|
|
910
|
-
{ segment:
|
|
911
|
-
{ segment:
|
|
912
|
-
{ segment:
|
|
909
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13", name: "NIFTY" },
|
|
910
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25", name: "BANKNIFTY" },
|
|
911
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29", name: "NIFTYIT" },
|
|
912
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51", name: "SENSEX" }
|
|
913
913
|
]
|
|
914
914
|
|
|
915
915
|
indices.each do |index|
|
|
@@ -1128,10 +1128,10 @@ class RobustWebSocketClient
|
|
|
1128
1128
|
|
|
1129
1129
|
def subscribe_to_indices
|
|
1130
1130
|
indices = [
|
|
1131
|
-
{ segment:
|
|
1132
|
-
{ segment:
|
|
1133
|
-
{ segment:
|
|
1134
|
-
{ segment:
|
|
1131
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13", name: "NIFTY" },
|
|
1132
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25", name: "BANKNIFTY" },
|
|
1133
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29", name: "NIFTYIT" },
|
|
1134
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51", name: "SENSEX" }
|
|
1135
1135
|
]
|
|
1136
1136
|
|
|
1137
1137
|
indices.each do |index|
|
|
@@ -1311,10 +1311,10 @@ class ProductionWebSocketClient
|
|
|
1311
1311
|
|
|
1312
1312
|
def subscribe_to_indices
|
|
1313
1313
|
indices = [
|
|
1314
|
-
{ segment:
|
|
1315
|
-
{ segment:
|
|
1316
|
-
{ segment:
|
|
1317
|
-
{ segment:
|
|
1314
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13", name: "NIFTY" },
|
|
1315
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25", name: "BANKNIFTY" },
|
|
1316
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29", name: "NIFTYIT" },
|
|
1317
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51", name: "SENSEX" }
|
|
1318
1318
|
]
|
|
1319
1319
|
|
|
1320
1320
|
indices.each do |index|
|
|
@@ -1461,8 +1461,8 @@ class WebSocketMonitor
|
|
|
1461
1461
|
|
|
1462
1462
|
def start_market_depth_client
|
|
1463
1463
|
symbols = [
|
|
1464
|
-
{ symbol: "RELIANCE", exchange_segment:
|
|
1465
|
-
{ symbol: "TCS", exchange_segment:
|
|
1464
|
+
{ symbol: "RELIANCE", exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "2885" },
|
|
1465
|
+
{ symbol: "TCS", exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "11536" }
|
|
1466
1466
|
]
|
|
1467
1467
|
|
|
1468
1468
|
@clients[:market_depth] = DhanHQ::WS::MarketDepth.connect(symbols: symbols) do |depth_data|
|
|
@@ -1483,10 +1483,10 @@ class WebSocketMonitor
|
|
|
1483
1483
|
|
|
1484
1484
|
def subscribe_to_indices(client)
|
|
1485
1485
|
indices = [
|
|
1486
|
-
{ segment:
|
|
1487
|
-
{ segment:
|
|
1488
|
-
{ segment:
|
|
1489
|
-
{ segment:
|
|
1486
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13", name: "NIFTY" },
|
|
1487
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25", name: "BANKNIFTY" },
|
|
1488
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29", name: "NIFTYIT" },
|
|
1489
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51", name: "SENSEX" }
|
|
1490
1490
|
]
|
|
1491
1491
|
|
|
1492
1492
|
indices.each do |index|
|
|
@@ -26,8 +26,8 @@ DhanHQ.configure_with_env
|
|
|
26
26
|
|
|
27
27
|
ta = TA::TechnicalAnalysis.new(throttle_seconds: 2.5, max_retries: 3)
|
|
28
28
|
indicators = ta.compute(
|
|
29
|
-
exchange_segment:
|
|
30
|
-
instrument:
|
|
29
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
30
|
+
instrument: DhanHQ::Constants::InstrumentType::EQUITY,
|
|
31
31
|
security_id: "1333",
|
|
32
32
|
intervals: [1, 5, 15, 25, 60] # each fetched directly from API
|
|
33
33
|
)
|
|
@@ -75,7 +75,7 @@ Example summary:
|
|
|
75
75
|
|
|
76
76
|
```ruby
|
|
77
77
|
{
|
|
78
|
-
meta: { security_id: "1333", instrument:
|
|
78
|
+
meta: { security_id: "1333", instrument: DhanHQ::Constants::InstrumentType::EQUITY, exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ },
|
|
79
79
|
summary: {
|
|
80
80
|
bias: :bullish, # :bullish | :bearish | :neutral
|
|
81
81
|
setup: :buy_on_dip, # :buy_on_dip | :sell_on_rise | :range_trade
|
data/docs/TESTING_GUIDE.md
CHANGED
|
@@ -95,10 +95,10 @@ market_client = DhanHQ::WS.connect(mode: :ticker) do |tick|
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
# Subscribe to NIFTY (Security ID: 13, Segment: IDX_I)
|
|
98
|
-
market_client.subscribe_one(segment:
|
|
98
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13")
|
|
99
99
|
|
|
100
100
|
# Subscribe to BANKNIFTY (Security ID: 25, Segment: IDX_I)
|
|
101
|
-
market_client.subscribe_one(segment:
|
|
101
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25")
|
|
102
102
|
|
|
103
103
|
# Wait for data (in console, you can continue working)
|
|
104
104
|
sleep(10)
|
|
@@ -117,7 +117,7 @@ ohlc_client = DhanHQ::WS.connect(mode: :ohlc) do |data|
|
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
# Subscribe to NIFTY
|
|
120
|
-
ohlc_client.subscribe_one(segment:
|
|
120
|
+
ohlc_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13")
|
|
121
121
|
|
|
122
122
|
sleep(10)
|
|
123
123
|
ohlc_client.stop
|
|
@@ -135,7 +135,7 @@ quote_client = DhanHQ::WS.connect(mode: :quote) do |data|
|
|
|
135
135
|
end
|
|
136
136
|
|
|
137
137
|
# Subscribe to NIFTY
|
|
138
|
-
quote_client.subscribe_one(segment:
|
|
138
|
+
quote_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13")
|
|
139
139
|
|
|
140
140
|
sleep(10)
|
|
141
141
|
quote_client.stop
|
|
@@ -151,10 +151,10 @@ end
|
|
|
151
151
|
|
|
152
152
|
# Subscribe to multiple indices
|
|
153
153
|
indices = [
|
|
154
|
-
{ segment:
|
|
155
|
-
{ segment:
|
|
156
|
-
{ segment:
|
|
157
|
-
{ segment:
|
|
154
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13" }, # NIFTY
|
|
155
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25" }, # BANKNIFTY
|
|
156
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29" }, # NIFTYIT
|
|
157
|
+
{ segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51" } # SENSEX
|
|
158
158
|
]
|
|
159
159
|
|
|
160
160
|
indices.each do |idx|
|
|
@@ -169,7 +169,7 @@ market_client.stop
|
|
|
169
169
|
|
|
170
170
|
```ruby
|
|
171
171
|
market_client = DhanHQ::WS.connect(mode: :ticker) { |tick| puts tick[:ltp] }
|
|
172
|
-
market_client.subscribe_one(segment:
|
|
172
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13")
|
|
173
173
|
|
|
174
174
|
# Check connection state
|
|
175
175
|
puts "Connected: #{market_client.connected?}"
|
|
@@ -326,11 +326,11 @@ depth_client.stop
|
|
|
326
326
|
# Place a market order
|
|
327
327
|
order = DhanHQ::Models::Order.place(
|
|
328
328
|
dhan_client_id: "1000000003",
|
|
329
|
-
transaction_type:
|
|
330
|
-
exchange_segment:
|
|
331
|
-
product_type:
|
|
332
|
-
order_type:
|
|
333
|
-
validity:
|
|
329
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
330
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
331
|
+
product_type: DhanHQ::Constants::ProductType::INTRADAY,
|
|
332
|
+
order_type: DhanHQ::Constants::OrderType::MARKET,
|
|
333
|
+
validity: DhanHQ::Constants::Validity::DAY,
|
|
334
334
|
security_id: "11536", # TCS
|
|
335
335
|
quantity: 1
|
|
336
336
|
)
|
|
@@ -345,11 +345,11 @@ puts "Status: #{order.order_status}"
|
|
|
345
345
|
# Place a limit order
|
|
346
346
|
order = DhanHQ::Models::Order.place(
|
|
347
347
|
dhan_client_id: "1000000003",
|
|
348
|
-
transaction_type:
|
|
349
|
-
exchange_segment:
|
|
350
|
-
product_type:
|
|
351
|
-
order_type:
|
|
352
|
-
validity:
|
|
348
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
349
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
350
|
+
product_type: DhanHQ::Constants::ProductType::INTRADAY,
|
|
351
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
352
|
+
validity: DhanHQ::Constants::Validity::DAY,
|
|
353
353
|
security_id: "11536",
|
|
354
354
|
quantity: 1,
|
|
355
355
|
price: 3500.0
|
|
@@ -364,11 +364,11 @@ puts "Order ID: #{order.order_id}"
|
|
|
364
364
|
# Place stop loss order
|
|
365
365
|
order = DhanHQ::Models::Order.place(
|
|
366
366
|
dhan_client_id: "1000000003",
|
|
367
|
-
transaction_type:
|
|
368
|
-
exchange_segment:
|
|
369
|
-
product_type:
|
|
367
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
368
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
369
|
+
product_type: DhanHQ::Constants::ProductType::INTRADAY,
|
|
370
370
|
order_type: "STOPLOSS",
|
|
371
|
-
validity:
|
|
371
|
+
validity: DhanHQ::Constants::Validity::DAY,
|
|
372
372
|
security_id: "11536",
|
|
373
373
|
quantity: 1,
|
|
374
374
|
price: 3500.0,
|
|
@@ -410,11 +410,11 @@ orders = DhanHQ::Models::Order.all
|
|
|
410
410
|
puts "Total orders: #{orders.size}"
|
|
411
411
|
|
|
412
412
|
# Filter pending orders
|
|
413
|
-
pending = orders.select { |o| o.order_status ==
|
|
413
|
+
pending = orders.select { |o| o.order_status == DhanHQ::Constants::OrderStatus::PENDING }
|
|
414
414
|
puts "Pending orders: #{pending.size}"
|
|
415
415
|
|
|
416
416
|
# Filter executed orders
|
|
417
|
-
executed = orders.select { |o| o.order_status ==
|
|
417
|
+
executed = orders.select { |o| o.order_status == DhanHQ::Constants::OrderStatus::TRADED }
|
|
418
418
|
puts "Executed orders: #{executed.size}"
|
|
419
419
|
```
|
|
420
420
|
|
|
@@ -472,11 +472,11 @@ end
|
|
|
472
472
|
# Create order instance
|
|
473
473
|
order = DhanHQ::Models::Order.new(
|
|
474
474
|
dhan_client_id: "1000000003",
|
|
475
|
-
transaction_type:
|
|
476
|
-
exchange_segment:
|
|
477
|
-
product_type:
|
|
478
|
-
order_type:
|
|
479
|
-
validity:
|
|
475
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
476
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
477
|
+
product_type: DhanHQ::Constants::ProductType::INTRADAY,
|
|
478
|
+
order_type: DhanHQ::Constants::OrderType::MARKET,
|
|
479
|
+
validity: DhanHQ::Constants::Validity::DAY,
|
|
480
480
|
security_id: "11536",
|
|
481
481
|
quantity: 1
|
|
482
482
|
)
|
|
@@ -499,7 +499,7 @@ positions = DhanHQ::Models::Position.all
|
|
|
499
499
|
puts "Total positions: #{positions.size}"
|
|
500
500
|
|
|
501
501
|
# Filter by exchange
|
|
502
|
-
nse_positions = positions.select { |p| p.exchange_segment ==
|
|
502
|
+
nse_positions = positions.select { |p| p.exchange_segment == DhanHQ::Constants::ExchangeSegment::NSE_EQ }
|
|
503
503
|
puts "NSE positions: #{nse_positions.size}"
|
|
504
504
|
|
|
505
505
|
# Filter long positions
|
|
@@ -517,8 +517,8 @@ position = DhanHQ::Models::Position.all.first
|
|
|
517
517
|
if position
|
|
518
518
|
result = position.convert(
|
|
519
519
|
dhan_client_id: "1000000003",
|
|
520
|
-
from_product_type:
|
|
521
|
-
to_product_type:
|
|
520
|
+
from_product_type: DhanHQ::Constants::ProductType::INTRADAY,
|
|
521
|
+
to_product_type: DhanHQ::Constants::ProductType::MARGIN,
|
|
522
522
|
quantity: position.net_qty.abs
|
|
523
523
|
)
|
|
524
524
|
|
|
@@ -677,7 +677,7 @@ puts " Ask Price: ₹#{quote_data[:ask_price]}"
|
|
|
677
677
|
# Get daily candles
|
|
678
678
|
historical_data = DhanHQ::Models::HistoricalData.daily(
|
|
679
679
|
security_id: "11536",
|
|
680
|
-
exchange_segment:
|
|
680
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
681
681
|
from_date: Date.today - 30,
|
|
682
682
|
to_date: Date.today
|
|
683
683
|
)
|
|
@@ -694,7 +694,7 @@ end
|
|
|
694
694
|
# Get intraday candles (5-minute interval)
|
|
695
695
|
historical_data = DhanHQ::Models::HistoricalData.intraday(
|
|
696
696
|
security_id: "11536",
|
|
697
|
-
exchange_segment:
|
|
697
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
698
698
|
from_date: Date.today,
|
|
699
699
|
to_date: Date.today,
|
|
700
700
|
interval: 5
|
|
@@ -714,7 +714,7 @@ end
|
|
|
714
714
|
# Get expiry list for NIFTY
|
|
715
715
|
expiry_list = DhanHQ::Models::OptionChain.fetch_expiry_list(
|
|
716
716
|
underlying_scrip: "NIFTY",
|
|
717
|
-
underlying_seg:
|
|
717
|
+
underlying_seg: DhanHQ::Constants::ExchangeSegment::IDX_I
|
|
718
718
|
)
|
|
719
719
|
|
|
720
720
|
puts "Available expiries:"
|
|
@@ -731,7 +731,7 @@ expiry_date = expiry_list.first[:expiry_date] # Use first expiry from above
|
|
|
731
731
|
|
|
732
732
|
option_chain = DhanHQ::Models::OptionChain.fetch(
|
|
733
733
|
underlying_scrip: "NIFTY",
|
|
734
|
-
underlying_seg:
|
|
734
|
+
underlying_seg: DhanHQ::Constants::ExchangeSegment::IDX_I,
|
|
735
735
|
expiry: expiry_date
|
|
736
736
|
)
|
|
737
737
|
|
|
@@ -835,22 +835,22 @@ super_order = DhanHQ::Models::SuperOrder.create(
|
|
|
835
835
|
legs: [
|
|
836
836
|
{
|
|
837
837
|
leg_name: "ENTRY_LEG",
|
|
838
|
-
transaction_type:
|
|
839
|
-
exchange_segment:
|
|
840
|
-
product_type:
|
|
841
|
-
order_type:
|
|
842
|
-
validity:
|
|
838
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
839
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_FNO,
|
|
840
|
+
product_type: DhanHQ::Constants::ProductType::MARGIN,
|
|
841
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
842
|
+
validity: DhanHQ::Constants::Validity::DAY,
|
|
843
843
|
security_id: "49081",
|
|
844
844
|
quantity: 50,
|
|
845
845
|
price: 18000.0
|
|
846
846
|
},
|
|
847
847
|
{
|
|
848
848
|
leg_name: "EXIT_LEG",
|
|
849
|
-
transaction_type:
|
|
850
|
-
exchange_segment:
|
|
851
|
-
product_type:
|
|
852
|
-
order_type:
|
|
853
|
-
validity:
|
|
849
|
+
transaction_type: DhanHQ::Constants::TransactionType::SELL,
|
|
850
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_FNO,
|
|
851
|
+
product_type: DhanHQ::Constants::ProductType::MARGIN,
|
|
852
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
853
|
+
validity: DhanHQ::Constants::Validity::DAY,
|
|
854
854
|
security_id: "49081",
|
|
855
855
|
quantity: 50,
|
|
856
856
|
price: 18100.0
|
|
@@ -891,10 +891,10 @@ puts "Total forever orders: #{forever_orders.size}"
|
|
|
891
891
|
# Create a forever order (GTT)
|
|
892
892
|
forever_order = DhanHQ::Models::ForeverOrder.create(
|
|
893
893
|
dhan_client_id: "1000000003",
|
|
894
|
-
transaction_type:
|
|
895
|
-
exchange_segment:
|
|
896
|
-
product_type:
|
|
897
|
-
order_type:
|
|
894
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
895
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
896
|
+
product_type: DhanHQ::Constants::ProductType::MARGIN,
|
|
897
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
898
898
|
validity: "GTC",
|
|
899
899
|
security_id: "11536",
|
|
900
900
|
quantity: 1,
|
|
@@ -971,6 +971,8 @@ tc.status
|
|
|
971
971
|
|
|
972
972
|
#### Kill Switch (model, backward compatible)
|
|
973
973
|
|
|
974
|
+
Uses query param per API doc: `POST /v2/killswitch?killSwitchStatus=ACTIVATE` (no body).
|
|
975
|
+
|
|
974
976
|
```ruby
|
|
975
977
|
# Activate kill switch
|
|
976
978
|
result = DhanHQ::Models::KillSwitch.update("ACTIVATE")
|
|
@@ -1010,10 +1012,10 @@ end
|
|
|
1010
1012
|
# Calculate margin for an order
|
|
1011
1013
|
margin = DhanHQ::Models::Margin.calculate(
|
|
1012
1014
|
dhan_client_id: "1000000003",
|
|
1013
|
-
transaction_type:
|
|
1014
|
-
exchange_segment:
|
|
1015
|
-
product_type:
|
|
1016
|
-
order_type:
|
|
1015
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
1016
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
1017
|
+
product_type: DhanHQ::Constants::ProductType::MARGIN,
|
|
1018
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
1017
1019
|
security_id: "11536",
|
|
1018
1020
|
quantity: 1,
|
|
1019
1021
|
price: 3500.0
|
|
@@ -1054,11 +1056,11 @@ end
|
|
|
1054
1056
|
# Test valid order
|
|
1055
1057
|
valid_params = {
|
|
1056
1058
|
dhan_client_id: "1000000003",
|
|
1057
|
-
transaction_type:
|
|
1058
|
-
exchange_segment:
|
|
1059
|
-
product_type:
|
|
1060
|
-
order_type:
|
|
1061
|
-
validity:
|
|
1059
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
1060
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
1061
|
+
product_type: DhanHQ::Constants::ProductType::INTRADAY,
|
|
1062
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
1063
|
+
validity: DhanHQ::Constants::Validity::DAY,
|
|
1062
1064
|
security_id: "11536",
|
|
1063
1065
|
quantity: 1,
|
|
1064
1066
|
price: 3500.0
|
|
@@ -1074,8 +1076,8 @@ end
|
|
|
1074
1076
|
|
|
1075
1077
|
# Test invalid order (missing required field)
|
|
1076
1078
|
invalid_params = {
|
|
1077
|
-
transaction_type:
|
|
1078
|
-
exchange_segment:
|
|
1079
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
1080
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ
|
|
1079
1081
|
# Missing required fields
|
|
1080
1082
|
}
|
|
1081
1083
|
|
|
@@ -1133,10 +1135,10 @@ end
|
|
|
1133
1135
|
# Test valid margin calculation
|
|
1134
1136
|
valid_params = {
|
|
1135
1137
|
dhan_client_id: "1000000003",
|
|
1136
|
-
transaction_type:
|
|
1137
|
-
exchange_segment:
|
|
1138
|
-
product_type:
|
|
1139
|
-
order_type:
|
|
1138
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
1139
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
1140
|
+
product_type: DhanHQ::Constants::ProductType::MARGIN,
|
|
1141
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
1140
1142
|
security_id: "11536",
|
|
1141
1143
|
quantity: 1,
|
|
1142
1144
|
price: 3500.0
|
|
@@ -1157,7 +1159,7 @@ end
|
|
|
1157
1159
|
# Test valid option chain request
|
|
1158
1160
|
valid_params = {
|
|
1159
1161
|
underlying_scrip: "NIFTY",
|
|
1160
|
-
underlying_seg:
|
|
1162
|
+
underlying_seg: DhanHQ::Constants::ExchangeSegment::IDX_I,
|
|
1161
1163
|
expiry: "2024-01-25"
|
|
1162
1164
|
}
|
|
1163
1165
|
|
|
@@ -1183,7 +1185,7 @@ end
|
|
|
1183
1185
|
# Test valid historical data request
|
|
1184
1186
|
valid_params = {
|
|
1185
1187
|
security_id: "11536",
|
|
1186
|
-
exchange_segment:
|
|
1188
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
1187
1189
|
from_date: Date.today - 7,
|
|
1188
1190
|
to_date: Date.today,
|
|
1189
1191
|
interval: 5
|
|
@@ -1252,7 +1254,7 @@ end
|
|
|
1252
1254
|
begin
|
|
1253
1255
|
order = DhanHQ::Models::Order.place(
|
|
1254
1256
|
transaction_type: "INVALID_TYPE",
|
|
1255
|
-
exchange_segment:
|
|
1257
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ
|
|
1256
1258
|
)
|
|
1257
1259
|
rescue DhanHQ::Error => e
|
|
1258
1260
|
puts "Validation error caught: #{e.message}"
|
|
@@ -1327,10 +1329,10 @@ puts "1. Available Margin: ₹#{funds.available_margin}"
|
|
|
1327
1329
|
# 2. Calculate margin
|
|
1328
1330
|
margin = DhanHQ::Models::Margin.calculate(
|
|
1329
1331
|
dhan_client_id: "1000000003",
|
|
1330
|
-
transaction_type:
|
|
1331
|
-
exchange_segment:
|
|
1332
|
-
product_type:
|
|
1333
|
-
order_type:
|
|
1332
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
1333
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
1334
|
+
product_type: DhanHQ::Constants::ProductType::MARGIN,
|
|
1335
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
1334
1336
|
security_id: "11536",
|
|
1335
1337
|
quantity: 1,
|
|
1336
1338
|
price: 3500.0
|
|
@@ -1340,11 +1342,11 @@ puts "2. Margin Required: ₹#{margin.margin_required}"
|
|
|
1340
1342
|
# 3. Place order
|
|
1341
1343
|
order = DhanHQ::Models::Order.place(
|
|
1342
1344
|
dhan_client_id: "1000000003",
|
|
1343
|
-
transaction_type:
|
|
1344
|
-
exchange_segment:
|
|
1345
|
-
product_type:
|
|
1346
|
-
order_type:
|
|
1347
|
-
validity:
|
|
1345
|
+
transaction_type: DhanHQ::Constants::TransactionType::BUY,
|
|
1346
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
1347
|
+
product_type: DhanHQ::Constants::ProductType::MARGIN,
|
|
1348
|
+
order_type: DhanHQ::Constants::OrderType::LIMIT,
|
|
1349
|
+
validity: DhanHQ::Constants::Validity::DAY,
|
|
1348
1350
|
security_id: "11536",
|
|
1349
1351
|
quantity: 1,
|
|
1350
1352
|
price: 3500.0
|
|
@@ -1363,7 +1365,7 @@ orders_client.start
|
|
|
1363
1365
|
# 5. Modify order (if pending)
|
|
1364
1366
|
sleep(2)
|
|
1365
1367
|
order.refresh
|
|
1366
|
-
if order.order_status ==
|
|
1368
|
+
if order.order_status == DhanHQ::Constants::OrderStatus::PENDING
|
|
1367
1369
|
if order.modify(price: 3501.0)
|
|
1368
1370
|
puts "5. Order Modified"
|
|
1369
1371
|
end
|
|
@@ -1390,7 +1392,7 @@ puts "=== Test Complete ==="
|
|
|
1390
1392
|
# Get historical data and analyze
|
|
1391
1393
|
historical_data = DhanHQ::Models::HistoricalData.daily(
|
|
1392
1394
|
security_id: "11536",
|
|
1393
|
-
exchange_segment:
|
|
1395
|
+
exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
|
|
1394
1396
|
from_date: Date.today - 30,
|
|
1395
1397
|
to_date: Date.today
|
|
1396
1398
|
)
|
|
@@ -1419,13 +1421,13 @@ end
|
|
|
1419
1421
|
# Get option chain
|
|
1420
1422
|
expiry_list = DhanHQ::Models::OptionChain.fetch_expiry_list(
|
|
1421
1423
|
underlying_scrip: "NIFTY",
|
|
1422
|
-
underlying_seg:
|
|
1424
|
+
underlying_seg: DhanHQ::Constants::ExchangeSegment::IDX_I
|
|
1423
1425
|
)
|
|
1424
1426
|
|
|
1425
1427
|
expiry = expiry_list.first[:expiry_date]
|
|
1426
1428
|
option_chain = DhanHQ::Models::OptionChain.fetch(
|
|
1427
1429
|
underlying_scrip: "NIFTY",
|
|
1428
|
-
underlying_seg:
|
|
1430
|
+
underlying_seg: DhanHQ::Constants::ExchangeSegment::IDX_I,
|
|
1429
1431
|
expiry: expiry
|
|
1430
1432
|
)
|
|
1431
1433
|
|
|
@@ -45,10 +45,10 @@ market_client = DhanHQ::WS.connect(mode: :ticker) do |tick|
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
# Subscribe to specific indices
|
|
48
|
-
market_client.subscribe_one(segment:
|
|
49
|
-
market_client.subscribe_one(segment:
|
|
50
|
-
market_client.subscribe_one(segment:
|
|
51
|
-
market_client.subscribe_one(segment:
|
|
48
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13") # NIFTY
|
|
49
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25") # BANKNIFTY
|
|
50
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29") # NIFTYIT
|
|
51
|
+
market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51") # SENSEX
|
|
52
52
|
|
|
53
53
|
# Clean shutdown
|
|
54
54
|
market_client.stop
|
|
@@ -136,20 +136,20 @@ end
|
|
|
136
136
|
client = DhanHQ::WS.connect(mode: :ticker) { |tick| puts tick[:ltp] }
|
|
137
137
|
|
|
138
138
|
# Subscribe to individual instruments
|
|
139
|
-
client.subscribe_one(segment:
|
|
140
|
-
client.subscribe_one(segment:
|
|
141
|
-
client.subscribe_one(segment:
|
|
139
|
+
client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13") # NIFTY
|
|
140
|
+
client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25") # BANKNIFTY
|
|
141
|
+
client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "2885") # RELIANCE
|
|
142
142
|
|
|
143
143
|
# Subscribe to multiple instruments
|
|
144
144
|
instruments = [
|
|
145
|
-
{ ExchangeSegment:
|
|
146
|
-
{ ExchangeSegment:
|
|
147
|
-
{ ExchangeSegment:
|
|
145
|
+
{ ExchangeSegment: DhanHQ::Constants::ExchangeSegment::IDX_I, SecurityId: "13" },
|
|
146
|
+
{ ExchangeSegment: DhanHQ::Constants::ExchangeSegment::IDX_I, SecurityId: "25" },
|
|
147
|
+
{ ExchangeSegment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, SecurityId: "2885" }
|
|
148
148
|
]
|
|
149
149
|
client.subscribe_many(instruments)
|
|
150
150
|
|
|
151
151
|
# Unsubscribe
|
|
152
|
-
client.unsubscribe_one(segment:
|
|
152
|
+
client.unsubscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13")
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
#### Finding Correct Security IDs
|
|
@@ -297,8 +297,8 @@ end
|
|
|
297
297
|
|
|
298
298
|
# Method 2: Direct specification (legacy)
|
|
299
299
|
symbols_direct = [
|
|
300
|
-
{ symbol: "RELIANCE", exchange_segment:
|
|
301
|
-
{ symbol: "TCS", exchange_segment:
|
|
300
|
+
{ symbol: "RELIANCE", exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "2885" },
|
|
301
|
+
{ symbol: "TCS", exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "11536" }
|
|
302
302
|
]
|
|
303
303
|
|
|
304
304
|
depth_client = DhanHQ::WS::MarketDepth.connect(symbols: symbols_direct) do |depth_data|
|
|
@@ -333,8 +333,8 @@ client.start
|
|
|
333
333
|
|
|
334
334
|
# Subscribe to symbols
|
|
335
335
|
symbols = [
|
|
336
|
-
{ symbol: "RELIANCE", exchange_segment:
|
|
337
|
-
{ symbol: "TCS", exchange_segment:
|
|
336
|
+
{ symbol: "RELIANCE", exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "2885" },
|
|
337
|
+
{ symbol: "TCS", exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ, security_id: "11536" }
|
|
338
338
|
]
|
|
339
339
|
client.subscribe(symbols)
|
|
340
340
|
```
|
|
@@ -587,10 +587,10 @@ class MarketDataService
|
|
|
587
587
|
end
|
|
588
588
|
|
|
589
589
|
# Subscribe to indices
|
|
590
|
-
@market_client.subscribe_one(segment:
|
|
591
|
-
@market_client.subscribe_one(segment:
|
|
592
|
-
@market_client.subscribe_one(segment:
|
|
593
|
-
@market_client.subscribe_one(segment:
|
|
590
|
+
@market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "13") # NIFTY
|
|
591
|
+
@market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "25") # BANKNIFTY
|
|
592
|
+
@market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "29") # NIFTYIT
|
|
593
|
+
@market_client.subscribe_one(segment: DhanHQ::Constants::ExchangeSegment::IDX_I, security_id: "51") # SENSEX
|
|
594
594
|
end
|
|
595
595
|
|
|
596
596
|
def stop_market_feed
|
data/docs/WEBSOCKET_PROTOCOL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# WebSocket Protocol Reference
|
|
2
2
|
|
|
3
|
-
Low-level protocol details for the DhanHQ WebSocket market feed. For high-level usage, see the [WebSocket Integration Guide](
|
|
3
|
+
Low-level protocol details for the DhanHQ WebSocket market feed. For high-level usage, see the [WebSocket Integration Guide](WEBSOCKET_INTEGRATION.md).
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -59,7 +59,7 @@ All ticks are delivered as a Ruby Hash with consistent keys:
|
|
|
59
59
|
```ruby
|
|
60
60
|
{
|
|
61
61
|
kind: :quote, # :ticker | :quote | :full | :oi | :prev_close | :misc
|
|
62
|
-
segment:
|
|
62
|
+
segment: DhanHQ::Constants::ExchangeSegment::NSE_FNO, # string enum
|
|
63
63
|
security_id: "12345",
|
|
64
64
|
ltp: 101.5,
|
|
65
65
|
ts: 1723791300, # LTT epoch (sec) if present
|