DhanHQ 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/ARCHITECTURE.md +47 -1
  3. data/CHANGELOG.md +47 -0
  4. data/README.md +241 -3
  5. data/docs/AUTHENTICATION.md +3 -5
  6. data/docs/CONFIGURATION.md +3 -2
  7. data/docs/CONSTANTS_REFERENCE.md +5 -4
  8. data/docs/ENDPOINTS_AND_SANDBOX.md +1 -0
  9. data/docs/LIVE_ORDER_UPDATES.md +5 -10
  10. data/docs/RAILS_INTEGRATION.md +1 -1
  11. data/docs/RELEASE_GUIDE.md +13 -2
  12. data/docs/STANDALONE_RUBY_WEBSOCKET_INTEGRATION.md +2 -2
  13. data/docs/WEBSOCKET_INTEGRATION.md +13 -20
  14. data/docs/WEBSOCKET_PROTOCOL.md +7 -3
  15. data/lib/DhanHQ/agent/key_coercion.rb +36 -0
  16. data/lib/DhanHQ/agent/tool.rb +37 -0
  17. data/lib/DhanHQ/agent/tool_catalogue.rb +180 -0
  18. data/lib/DhanHQ/agent/tool_handlers.rb +116 -0
  19. data/lib/DhanHQ/agent/tool_registry.rb +17 -261
  20. data/lib/DhanHQ/agent/tool_schemas.rb +160 -0
  21. data/lib/DhanHQ/client.rb +58 -2
  22. data/lib/DhanHQ/concerns/order_audit.rb +35 -4
  23. data/lib/DhanHQ/configuration.rb +70 -1
  24. data/lib/DhanHQ/constants.rb +101 -0
  25. data/lib/DhanHQ/contracts/expired_options_data_contract.rb +1 -9
  26. data/lib/DhanHQ/contracts/global_stocks_estimator_contract.rb +28 -0
  27. data/lib/DhanHQ/contracts/global_stocks_modify_order_contract.rb +26 -0
  28. data/lib/DhanHQ/contracts/global_stocks_order_contract.rb +33 -0
  29. data/lib/DhanHQ/contracts/global_stocks_place_order_contract.rb +75 -0
  30. data/lib/DhanHQ/contracts/historical_data_contract.rb +1 -21
  31. data/lib/DhanHQ/contracts/multi_order_contract.rb +74 -0
  32. data/lib/DhanHQ/contracts/trade_history_contract.rb +1 -8
  33. data/lib/DhanHQ/dry_run/ledger.rb +71 -0
  34. data/lib/DhanHQ/dry_run/simulator.rb +140 -0
  35. data/lib/DhanHQ/helpers/attribute_helper.rb +23 -0
  36. data/lib/DhanHQ/models/alert_order.rb +5 -2
  37. data/lib/DhanHQ/models/global_stocks/funds.rb +56 -0
  38. data/lib/DhanHQ/models/global_stocks/holding.rb +101 -0
  39. data/lib/DhanHQ/models/global_stocks/margin.rb +54 -0
  40. data/lib/DhanHQ/models/global_stocks/market_status.rb +63 -0
  41. data/lib/DhanHQ/models/global_stocks/order.rb +189 -0
  42. data/lib/DhanHQ/models/global_stocks/order_estimate.rb +61 -0
  43. data/lib/DhanHQ/models/global_stocks/trade.rb +74 -0
  44. data/lib/DhanHQ/models/margin.rb +5 -1
  45. data/lib/DhanHQ/models/multi_order.rb +130 -0
  46. data/lib/DhanHQ/resources/global_stocks/funds.rb +25 -0
  47. data/lib/DhanHQ/resources/global_stocks/holdings.rb +22 -0
  48. data/lib/DhanHQ/resources/global_stocks/margin_calculator.rb +70 -0
  49. data/lib/DhanHQ/resources/global_stocks/market_status.rb +22 -0
  50. data/lib/DhanHQ/resources/global_stocks/orders.rb +112 -0
  51. data/lib/DhanHQ/resources/global_stocks/trades.rb +31 -0
  52. data/lib/DhanHQ/resources/multi_orders.rb +58 -0
  53. data/lib/DhanHQ/version.rb +1 -1
  54. data/lib/DhanHQ/write_paths.rb +57 -0
  55. data/lib/DhanHQ/ws/client.rb +117 -2
  56. data/lib/DhanHQ/ws/connection.rb +40 -11
  57. data/lib/DhanHQ/ws/sub_state.rb +14 -0
  58. data/lib/dhanhq/analysis/options_buying_advisor.rb +11 -10
  59. metadata +30 -40
  60. data/.rspec +0 -3
  61. data/.rubocop.yml +0 -50
  62. data/.rubocop_todo.yml +0 -217
  63. data/AGENTS.md +0 -23
  64. data/CODE_OF_CONDUCT.md +0 -132
  65. data/Rakefile +0 -14
  66. data/TAGS +0 -10
  67. data/core +0 -0
  68. data/diagram.html +0 -184
  69. data/skills/dhanhq-ruby/SKILL.md +0 -207
  70. data/skills/dhanhq-ruby/examples/fetch_option_chain.rb +0 -54
  71. data/skills/dhanhq-ruby/examples/gtt_forever_order.rb +0 -65
  72. data/skills/dhanhq-ruby/examples/historical_data_analysis.rb +0 -89
  73. data/skills/dhanhq-ruby/examples/iron_condor.rb +0 -137
  74. data/skills/dhanhq-ruby/examples/live_feed_setup.rb +0 -43
  75. data/skills/dhanhq-ruby/examples/margin_check.rb +0 -42
  76. data/skills/dhanhq-ruby/examples/order_management.rb +0 -105
  77. data/skills/dhanhq-ruby/examples/place_equity_order.rb +0 -36
  78. data/skills/dhanhq-ruby/examples/place_fno_order.rb +0 -76
  79. data/skills/dhanhq-ruby/examples/portfolio_summary.rb +0 -74
  80. data/skills/dhanhq-ruby/examples/super_order_with_sl.rb +0 -57
  81. data/skills/dhanhq-ruby/references/backtesting-with-dhan.md +0 -65
  82. data/skills/dhanhq-ruby/references/common-workflows.md +0 -76
  83. data/skills/dhanhq-ruby/references/error-codes.md +0 -50
  84. data/skills/dhanhq-ruby/references/funds.md +0 -67
  85. data/skills/dhanhq-ruby/references/instruments.md +0 -85
  86. data/skills/dhanhq-ruby/references/live-feed.md +0 -83
  87. data/skills/dhanhq-ruby/references/market-data.md +0 -119
  88. data/skills/dhanhq-ruby/references/option-chain.md +0 -71
  89. data/skills/dhanhq-ruby/references/options-analysis-patterns.md +0 -76
  90. data/skills/dhanhq-ruby/references/orders.md +0 -201
  91. data/skills/dhanhq-ruby/references/portfolio.md +0 -93
  92. data/skills/dhanhq-ruby/references/scanx-data.md +0 -62
  93. data/skills/dhanhq-ruby/scripts/dhan_helpers.rb +0 -323
  94. data/skills/dhanhq-ruby/scripts/resolve_security.rb +0 -168
  95. data/skills/dhanhq-ruby/scripts/trade_logger.rb +0 -131
  96. data/skills/dhanhq-ruby/scripts/validate_order.rb +0 -169
  97. data/watchlist.csv +0 -3
@@ -1,105 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
4
- require "dhan_hq"
5
- require_relative "../scripts/dhan_helpers"
6
-
7
- # Initialize credentials
8
- get_client
9
-
10
- security_id = "2885"
11
- price = 2000.0
12
- quantity = 1
13
-
14
- puts preview_order(
15
- security_id: security_id,
16
- exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
17
- transaction_type: DhanHQ::Constants::TransactionType::BUY,
18
- quantity: quantity,
19
- order_type: DhanHQ::Constants::OrderType::LIMIT,
20
- product_type: DhanHQ::Constants::ProductType::CNC,
21
- price: price,
22
- trading_symbol: "RELIANCE"
23
- )
24
-
25
- if ENV["RUN_LIVE_EXAMPLE"] != "1"
26
- puts "Set RUN_LIVE_EXAMPLE=1 to place, modify, and cancel a live demo order."
27
- exit 0
28
- end
29
-
30
- # Step 1: Place a limit order (well below market for demo — won't fill)
31
- puts "Step 1: Placing limit buy order for RELIANCE..."
32
- order = DhanHQ::Models::Order.place(
33
- security_id: security_id,
34
- exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
35
- transaction_type: DhanHQ::Constants::TransactionType::BUY,
36
- quantity: quantity,
37
- order_type: DhanHQ::Constants::OrderType::LIMIT,
38
- product_type: DhanHQ::Constants::ProductType::CNC,
39
- price: price, # Below market — will stay pending
40
- validity: DhanHQ::Constants::Validity::DAY
41
- )
42
-
43
- if order.nil? || order.order_id.to_s.empty?
44
- puts "Order failed to place."
45
- exit 1
46
- end
47
-
48
- order_id = order.order_id
49
- puts "Order placed: #{order_id}"
50
-
51
- # Step 2: Check order status
52
- puts "\nStep 2: Checking order status..."
53
- sleep(1)
54
- order = DhanHQ::Models::Order.find(order_id)
55
- status = order.order_status
56
- puts "Status: #{status}"
57
- puts " Security: #{order.trading_symbol}"
58
- puts " Qty: #{order.quantity}"
59
- puts " Price: ₹#{order.price}"
60
- puts " Filled: #{order.filled_qty || 0}"
61
-
62
- # Step 3: Modify the order (change price)
63
- if status == DhanHQ::Constants::OrderStatus::PENDING
64
- puts "\nStep 3: Modifying order price to ₹2050..."
65
- modified_order = order.modify(
66
- order_type: DhanHQ::Constants::OrderType::LIMIT,
67
- quantity: quantity,
68
- price: 2050.00,
69
- validity: DhanHQ::Constants::Validity::DAY
70
- )
71
- puts "Modify result: #{modified_order ? "Success" : "Failure"}"
72
- end
73
-
74
- # Step 4: Cancel the order
75
- puts "\nStep 4: Cancelling order..."
76
- cancel_success = order.cancel
77
- puts "Cancel result: #{cancel_success ? "Success" : "Failure"}"
78
-
79
- # Step 5: View order book
80
- puts "\nStep 5: Today's order book:"
81
- orders = begin
82
- DhanHQ::Models::Order.all
83
- rescue StandardError
84
- []
85
- end
86
- if orders.any?
87
- orders.last(5).each do |o| # Last 5 orders
88
- printf(" %-12s | %-12s | %-4s | %-12s | ₹%-8.2f\n", o.order_id.to_s[0...12], o.trading_symbol, o.transaction_type, o.order_status, o.price.to_f)
89
- end
90
- end
91
-
92
- # Step 6: View trade book
93
- puts "\nStep 6: Today's trade book:"
94
- trades = begin
95
- DhanHQ::Models::Trade.today
96
- rescue StandardError
97
- []
98
- end
99
- if trades.any?
100
- trades.last(5).each do |t|
101
- printf(" %-12s | %-4s | Qty: %-5d | ₹%-8.2f\n", t.trading_symbol, t.transaction_type, t.traded_quantity, t.traded_price.to_f)
102
- end
103
- else
104
- puts " No trades today"
105
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
4
- require "dhan_hq"
5
- require_relative "../scripts/dhan_helpers"
6
-
7
- # Initialize credentials
8
- get_client
9
-
10
- security_id = "2885" # RELIANCE
11
- price = 2450.0
12
- quantity = 1
13
-
14
- puts preview_order(
15
- security_id: security_id,
16
- exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_EQ,
17
- transaction_type: DhanHQ::Constants::TransactionType::BUY,
18
- quantity: quantity,
19
- order_type: DhanHQ::Constants::OrderType::LIMIT,
20
- product_type: DhanHQ::Constants::ProductType::CNC,
21
- price: price,
22
- trading_symbol: "RELIANCE"
23
- )
24
-
25
- # Uncomment after confirmation:
26
- # order = DhanHQ::Models::Order.place(
27
- # security_id: security_id,
28
- # exchange_segment: "NSE_EQ",
29
- # transaction_type: "BUY",
30
- # quantity: quantity,
31
- # order_type: "LIMIT",
32
- # product_type: "CNC",
33
- # price: price,
34
- # validity: "DAY"
35
- # )
36
- # puts "Placed order ID: #{order.order_id}"
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
4
- require "dhan_hq"
5
- require_relative "../scripts/dhan_helpers"
6
-
7
- # Initialize credentials
8
- get_client
9
-
10
- expiries = DhanHQ::Models::OptionChain.fetch_expiry_list(underlying_scrip: 13, underlying_seg: DhanHQ::Constants::ExchangeSegment::IDX_I)
11
- nearest_expiry = expiries.first
12
-
13
- if nearest_expiry.nil?
14
- puts "Failed to fetch expiries."
15
- exit 1
16
- end
17
-
18
- puts "Nearest expiry: #{nearest_expiry}"
19
-
20
- chain_df, spot = fetch_chain_df(under_security_id: 13, expiry: nearest_expiry)
21
- atm = find_atm_row(chain_df, spot)
22
-
23
- if atm.nil?
24
- puts "Failed to find ATM row."
25
- exit 1
26
- end
27
-
28
- ce_security_id = atm["ce_security_id"]
29
- ce_ltp = atm["ce_ltp"].to_f
30
- lot_size = get_lot_size(underlying: "NIFTY") || 75
31
- quantity = lot_size
32
-
33
- puts "Nifty spot: #{spot}"
34
- puts "ATM strike: #{atm["strike"]}"
35
- puts "CE security ID: #{ce_security_id}, LTP: Rs. #{"%.2f" % ce_ltp}"
36
- puts
37
-
38
- puts preview_order(
39
- security_id: ce_security_id,
40
- exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_FNO,
41
- transaction_type: DhanHQ::Constants::TransactionType::BUY,
42
- quantity: quantity,
43
- order_type: DhanHQ::Constants::OrderType::LIMIT,
44
- product_type: DhanHQ::Constants::ProductType::INTRADAY,
45
- price: ce_ltp,
46
- trading_symbol: "NIFTY #{atm["strike"].to_i} CE"
47
- )
48
-
49
- margin = check_margin(
50
- security_id: ce_security_id,
51
- exchange_segment: DhanHQ::Constants::ExchangeSegment::NSE_FNO,
52
- transaction_type: DhanHQ::Constants::TransactionType::BUY,
53
- quantity: quantity,
54
- product_type: DhanHQ::Constants::ProductType::INTRADAY,
55
- price: ce_ltp
56
- )
57
-
58
- printf(
59
- "Margin check: sufficient=%s required=Rs. %s available=Rs. %s\n",
60
- margin["sufficient"].to_s,
61
- "%.2f" % margin["total_margin"],
62
- "%.2f" % margin["available_balance"]
63
- )
64
-
65
- # Uncomment only after confirmation:
66
- # order = DhanHQ::Models::Order.place(
67
- # security_id: ce_security_id,
68
- # exchange_segment: "NSE_FNO",
69
- # transaction_type: "BUY",
70
- # quantity: quantity,
71
- # order_type: "LIMIT",
72
- # product_type: "INTRADAY",
73
- # price: ce_ltp,
74
- # validity: "DAY"
75
- # )
76
- # puts "Placed order ID: #{order.order_id}"
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
4
- require "dhan_hq"
5
- require_relative "../scripts/dhan_helpers"
6
-
7
- # Initialize credentials
8
- get_client
9
-
10
- holdings = begin
11
- DhanHQ::Models::Holding.all
12
- rescue StandardError
13
- []
14
- end
15
- positions = begin
16
- DhanHQ::Models::Position.all
17
- rescue StandardError
18
- []
19
- end
20
- funds = begin
21
- DhanHQ::Models::Funds.fetch
22
- rescue StandardError
23
- nil
24
- end
25
- trades = begin
26
- DhanHQ::Models::Trade.today
27
- rescue StandardError
28
- []
29
- end
30
-
31
- summary = format_pnl_report(holdings, positions)
32
-
33
- puts "=" * 50
34
- puts " PORTFOLIO SUMMARY"
35
- puts "=" * 50
36
- puts "\nHoldings count: #{summary["holdings_count"]}"
37
- puts "Positions count: #{summary["positions_count"]}"
38
- printf("Current value: Rs. %12.2f\n", summary["current_value"])
39
- printf("Total P&L: Rs. %12.2f\n", summary["total_pnl"])
40
- printf("Day P&L: Rs. %12.2f\n", summary["day_pnl"])
41
-
42
- if funds
43
- available = funds.availabel_balance || funds.available_balance || 0.0
44
- utilized = funds.utilized_amount || 0.0
45
- collateral = funds.collateral_amount || 0.0
46
- withdrawable = funds.withdrawable_balance || 0.0
47
-
48
- puts "\nFUNDS"
49
- printf(" Available: Rs. %12.2f\n", available)
50
- printf(" Utilized: Rs. %12.2f\n", utilized)
51
- printf(" Collateral: Rs. %12.2f\n", collateral)
52
- printf(" Withdrawable: Rs. %12.2f\n", withdrawable)
53
- end
54
-
55
- if holdings.any?
56
- puts "\nTOP HOLDINGS"
57
- # Sort holdings by quantity
58
- sorted_holdings = holdings.sort_by { |h| -(h.total_qty || 0) }
59
- sorted_holdings.first(5).each do |holding|
60
- printf(" %-15s qty=%5d available=%5d\n", holding.trading_symbol, holding.total_qty.to_i, holding.available_qty.to_i)
61
- end
62
- end
63
-
64
- open_positions = positions.reject { |p| p.net_qty.to_i.zero? }
65
- if open_positions.any?
66
- puts "\nOPEN POSITIONS"
67
- open_positions.first(5).each do |position|
68
- pnl = position.realized_profit.to_f + position.unrealized_profit.to_f
69
- printf(" %-20s netQty=%5d pnl=Rs. %8.0f\n", position.trading_symbol, position.net_qty.to_i, pnl)
70
- end
71
- end
72
-
73
- puts "\nTrades today: #{trades.size}"
74
- puts "=" * 50
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
4
- require "dhan_hq"
5
- require_relative "../scripts/dhan_helpers"
6
-
7
- # Initialize credentials
8
- get_client
9
-
10
- # Fetch LTP for Reliance
11
- ltp_response = DhanHQ::Models::MarketFeed.ltp("NSE_EQ" => [2885])
12
- if ltp_response[:status] != "success"
13
- puts "Failed to fetch LTP: #{ltp_response[:remarks]}"
14
- exit 1
15
- end
16
-
17
- reliance_ltp = ltp_response[:data][DhanHQ::Constants::ExchangeSegment::NSE_EQ]["2885"]["last_price"].to_f
18
- puts "Reliance LTP: Rs. #{"%.2f" % reliance_ltp}"
19
-
20
- entry_price = reliance_ltp
21
- target_price = (entry_price * 1.02).round(2)
22
- sl_price = (entry_price * 0.99).round(2)
23
- trailing_jump = 5.0
24
-
25
- puts "\n--- Super Order Preview ---"
26
- puts "Action: BUY 1 share of RELIANCE"
27
- puts "Entry Price: Rs. #{"%.2f" % entry_price}"
28
- puts "Target: Rs. #{"%.2f" % target_price}"
29
- puts "Stop Loss: Rs. #{"%.2f" % sl_price}"
30
- puts "Trailing Jump: Rs. #{"%.2f" % trailing_jump}"
31
- puts "Product: INTRADAY"
32
-
33
- # Uncomment after confirmation:
34
- # order = DhanHQ::Models::SuperOrder.create(
35
- # security_id: "2885",
36
- # exchange_segment: "NSE_EQ",
37
- # transaction_type: "BUY",
38
- # quantity: 1,
39
- # order_type: "LIMIT",
40
- # product_type: "INTRADAY",
41
- # price: entry_price,
42
- # target_price: target_price,
43
- # stop_loss_price: sl_price,
44
- # trailing_jump: trailing_jump
45
- # )
46
- #
47
- # if order
48
- # puts "Super order placed: #{order.order_id} - #{order.order_status}"
49
- #
50
- # # Connect to Order Update websocket to listen for updates
51
- # orders_client = DhanHQ::WS::Orders.connect do |update|
52
- # puts "Order Update -> OrderNo: #{update.order_no}, Status: #{update.status}"
53
- # end
54
- #
55
- # sleep(10)
56
- # orders_client.stop rescue nil
57
- # end
@@ -1,65 +0,0 @@
1
- # Backtesting With Dhan Data (Ruby SDK)
2
-
3
- ## Daily Equity Backtest Skeleton
4
-
5
- ```ruby
6
- # Fetch daily charts via HistoricalData model
7
- candles = DhanHQ::Models::HistoricalData.daily(
8
- security_id: "2885",
9
- exchange_segment: "NSE_EQ",
10
- instrument: "EQUITY",
11
- from_date: "2023-01-01",
12
- to_date: "2024-12-31"
13
- )
14
-
15
- # candles is a normalized array of hashes:
16
- # [{ timestamp: Time, open: Float, high: Float, low: Float, close: Float, volume: Integer }]
17
- ```
18
-
19
- Typical next steps:
20
- - Create signals based on technical calculations.
21
- - Shift positions to avoid look-ahead bias.
22
- - Apply transaction costs.
23
- - Compute CAGR, maximum drawdown, Sharpe ratio, and win rate.
24
-
25
- ## Minute-Level Backtest Skeleton
26
-
27
- ```ruby
28
- candles = DhanHQ::Models::HistoricalData.intraday(
29
- security_id: "2885",
30
- exchange_segment: "NSE_EQ",
31
- instrument: "EQUITY",
32
- from_date: "2024-09-11 09:30:00",
33
- to_date: "2024-09-15 13:00:00",
34
- interval: "5", # 5-minute interval
35
- oi: false
36
- )
37
- ```
38
-
39
- ## Expired Options Backtest Skeleton
40
-
41
- ```ruby
42
- response = DhanHQ::Models::ExpiredOptionsData.fetch(
43
- underlying_scrip: 13,
44
- exchange_segment: "NSE_FNO",
45
- expiry_flag: "MONTH",
46
- expiry_code: 1,
47
- strike: "ATM",
48
- option_type: "CALL",
49
- required_data: ["open", "high", "low", "close", "volume", "oi", "spot"],
50
- from_date: "2021-08-01",
51
- to_date: "2021-08-31",
52
- interval: "1"
53
- )
54
- ```
55
-
56
- ## Cost Model Reminders
57
-
58
- At minimum consider:
59
- - Brokerage charges
60
- - Securities Transaction Tax (STT)
61
- - Exchange transaction charges
62
- - GST (Service Tax)
63
- - Stamp duty
64
- - SEBI turnover charges
65
- - Slippage
@@ -1,76 +0,0 @@
1
- # Common Workflows — Agent Playbooks (Ruby SDK)
2
-
3
- ## Portfolio Rebalance
4
-
5
- Recommended sequence:
6
- 1. Fetch holdings and funds.
7
- 2. Compute target deltas.
8
- 3. Resolve symbols and quantities.
9
- 4. Preview proposed orders.
10
- 5. Confirm with the user.
11
- 6. Place live orders.
12
-
13
- ```ruby
14
- holdings = DhanHQ::Models::Holding.all rescue []
15
- funds = DhanHQ::Models::Funds.fetch rescue nil
16
-
17
- if funds
18
- available_cash = funds.availabel_balance || funds.available_balance || 0.0
19
- end
20
- ```
21
-
22
- ## Delivery Sell With eDIS
23
-
24
- Use this flow for selling demat holdings:
25
- 1. Fetch holdings and identify ISIN.
26
- 2. Generate TPIN: `DhanHQ::Models::EDIS.generate_tpin`
27
- 3. Open authorization form: `DhanHQ::Models::EDIS.open_browser_for_tpin(isin: "...", qty: 5, exchange: "NSE")`
28
- 4. Check inquiry: `DhanHQ::Models::EDIS.inquiry(isin: "...")`
29
- 5. Place the sell order.
30
-
31
- ```ruby
32
- # Generate TPIN
33
- DhanHQ::Models::EDIS.generate_tpin
34
-
35
- # Open authorization portal
36
- DhanHQ::Models::EDIS.open_browser_for_tpin(isin: "INE002A01018", qty: 5, exchange: "NSE")
37
-
38
- # Inquiry
39
- status = DhanHQ::Models::EDIS.inquiry(isin: "INE002A01018")
40
- ```
41
-
42
- ## Single-Leg F&O Execution
43
-
44
- Recommended sequence:
45
- 1. Resolve current contract from option chain or security master.
46
- 2. Resolve lot size.
47
- 3. Validate quantity.
48
- 4. Check margin.
49
- 5. Preview & Confirm.
50
- 6. Place live order.
51
-
52
- ```ruby
53
- require_relative "../scripts/dhan_helpers"
54
-
55
- chain_df, spot = fetch_chain_df(under_security_id: 13, expiry: "2025-03-27")
56
- atm = find_atm_row(chain_df, spot)
57
-
58
- margin = check_margin(
59
- security_id: atm["ce_security_id"],
60
- exchange_segment: "NSE_FNO",
61
- transaction_type: "BUY",
62
- quantity: 75,
63
- product_type: "INTRADAY",
64
- price: atm["ce_ltp"].to_f
65
- )
66
- ```
67
-
68
- ## Daily P&L Summary
69
-
70
- ```ruby
71
- require_relative "../scripts/dhan_helpers"
72
-
73
- holdings = DhanHQ::Models::Holding.all
74
- positions = DhanHQ::Models::Position.all
75
- summary = format_pnl_report(holdings, positions)
76
- ```
@@ -1,50 +0,0 @@
1
- # Error Codes — Complete Reference (Ruby SDK)
2
-
3
- In the Ruby SDK, raw API error codes are automatically mapped in the client layer and raised as structured exceptions.
4
-
5
- ## Exception Mapping
6
-
7
- The Ruby client maps Dhan error codes to specific error classes under the `DhanHQ` module:
8
-
9
- | Error Code | Error Class | Meaning |
10
- |------------|-------------|---------|
11
- | `DH-901` | `DhanHQ::InvalidAuthenticationError` | Client ID or access token is invalid or expired |
12
- | `DH-902` | `DhanHQ::InvalidAccessError` | User does not have required Data API or Trading API access |
13
- | `DH-903` | `DhanHQ::UserAccountError` | Account setup issue or segment activation requirement |
14
- | `DH-904` | `DhanHQ::RateLimitError` | Rate limit exceeded |
15
- | `DH-905` | `DhanHQ::InputExceptionError` | Missing or invalid request fields |
16
- | `DH-906` | `DhanHQ::OrderError` | Order request cannot be processed |
17
- | `DH-907` | `DhanHQ::DataError` | Data unavailable or parameters invalid |
18
- | `DH-908` | `DhanHQ::InternalServerError` | Server-side failure |
19
- | `DH-909` | `DhanHQ::NetworkError` | Backend communication failure |
20
- | `DH-1111` | `DhanHQ::NoHoldingsError` | No holdings present in the account |
21
- | `DH-910` / other | `DhanHQ::OtherError` / `DhanHQ::Error` | Other failure reasons |
22
-
23
- ## Data API Errors
24
-
25
- | Code | Exception | Meaning |
26
- |------|-----------|---------|
27
- | `800` | `DhanHQ::InternalServerError` | Internal Server Error |
28
- | `804` | `DhanHQ::Error` | Requested number of instruments exceeds limit |
29
- | `805` | `DhanHQ::RateLimitError` | Too many requests or connections |
30
- | `806` | `DhanHQ::DataError` | Data APIs not subscribed |
31
- | `807` | `DhanHQ::TokenExpiredError` | Access token is expired |
32
- | `808` | `DhanHQ::AuthenticationFailedError` | Authentication failed - client ID or access token invalid |
33
- | `809` | `DhanHQ::InvalidTokenError` | Access token is invalid |
34
- | `810` | `DhanHQ::InvalidClientIDError` | Client ID is invalid |
35
- | `811` | `DhanHQ::InvalidRequestError` | Invalid expiry date |
36
- | `812` | `DhanHQ::InvalidRequestError` | Invalid date format |
37
- | `813` | `DhanHQ::InvalidRequestError` | Invalid security ID |
38
- | `814` | `DhanHQ::InvalidRequestError` | Invalid request |
39
-
40
- ## User Action Checklist
41
-
42
- ### Invalid Data Subscription (`806` or `DH-902`)
43
- If you receive access errors:
44
- 1. Log in to `web.dhan.co`.
45
- 2. Go to **My Profile** -> **Access DhanHQ APIs**.
46
- 3. Verify that the **Data API** plan is active.
47
- 4. If not active, activate it, generate a fresh access token, and retry.
48
-
49
- ### Static IP Error (`DH-911` or IP issue)
50
- If placing or managing orders fails with IP errors, ensure that the server's public IP is whitelisted in your Dhan console.
@@ -1,67 +0,0 @@
1
- # Funds & Margin — Complete Reference (Ruby SDK)
2
-
3
- The Ruby SDK exposes first-class models `DhanHQ::Models::Funds` and `DhanHQ::Models::Margin` for funds retrieval and pre-flight margin checks (both single-order and multi-leg).
4
-
5
- ## Fund Limits
6
-
7
- Use `DhanHQ::Models::Funds.fetch`:
8
-
9
- ```ruby
10
- funds = DhanHQ::Models::Funds.fetch
11
-
12
- puts "Available Balance: Rs. #{funds.availabel_balance || funds.available_balance}"
13
- puts "Utilized: Rs. #{funds.utilized_amount}"
14
- puts "Collateral: Rs. #{funds.collateral_amount}"
15
- puts "Withdrawable: Rs. #{funds.withdrawable_balance}"
16
- ```
17
-
18
- Normalized model attributes:
19
- - `dhan_client_id`
20
- - `availabel_balance` (or alias `available_balance`)
21
- - `sod_limit`
22
- - `collateral_amount`
23
- - `receiveable_amount`
24
- - `utilized_amount`
25
- - `blocked_payout_amount`
26
- - `withdrawable_balance`
27
-
28
- ---
29
-
30
- ## Margin Calculator — Single Order
31
-
32
- Use `DhanHQ::Models::Margin.calculate(params)`:
33
-
34
- ```ruby
35
- margin = DhanHQ::Models::Margin.calculate(
36
- security_id: "2885",
37
- exchange_segment: "NSE_EQ",
38
- transaction_type: "BUY",
39
- quantity: 10,
40
- product_type: "CNC",
41
- price: 2450.0
42
- )
43
-
44
- puts "Total Margin: Rs. #{margin.total_margin}"
45
- puts "Available Balance: Rs. #{margin.available_balance}"
46
- puts "Brokerage Charges: Rs. #{margin.brokerage}"
47
- puts "Leverage Offered: #{margin.leverage}x"
48
- ```
49
-
50
- ---
51
-
52
- ## Multi-Order Margin
53
-
54
- Unlike the Python SDK, the Ruby SDK has first-class support for multi-leg portfolio margin calculation via `DhanHQ::Models::Margin.calculate_multi(params)`:
55
-
56
- ```ruby
57
- margin = DhanHQ::Models::Margin.calculate_multi(
58
- include_position: true,
59
- include_orders: true,
60
- scripts: [
61
- { exchange_segment: "NSE_EQ", transaction_type: "BUY", quantity: 100, product_type: "CNC", security_id: "1333", price: 1428.0 },
62
- { exchange_segment: "NSE_EQ", transaction_type: "SELL", quantity: 50, product_type: "INTRADAY", security_id: "11536", price: 3000.0 }
63
- ]
64
- )
65
-
66
- puts "Portfolio Total Margin Required: Rs. #{margin.total_margin}"
67
- ```
@@ -1,85 +0,0 @@
1
- # Instruments — Complete Reference (Ruby SDK)
2
-
3
- Use the security master as the primary source for `security_id`, lot size, expiry, strike, tick size, and display symbol.
4
-
5
- ## Preferred SDK Entry Point
6
-
7
- In the Ruby SDK, search and load instruments segment-wise using:
8
-
9
- ```ruby
10
- # Retrieve compact list for a single segment (returns Array of Instrument objects)
11
- instruments = DhanHQ::Models::Instrument.by_segment("NSE_EQ")
12
- ```
13
-
14
- Official instrument sources (managed by the SDK internally):
15
- - Compact CSV: `https://images.dhan.co/api-data/api-scrip-master.csv`
16
- - Detailed CSV: `https://images.dhan.co/api-data/api-scrip-master-detailed.csv`
17
-
18
- ---
19
-
20
- ## Key Columns (Instrument Attributes)
21
-
22
- | Attribute | Meaning |
23
- |-----------|---------|
24
- | `security_id` | Security ID (String) |
25
- | `exchange` | Exchange ID (`NSE`, `BSE`, `MCX`) |
26
- | `instrument` | Instrument Type (`EQUITY`, `OPTIDX`, `OPTSTK`, etc.) |
27
- | `symbol_name` | Exchange trading symbol |
28
- | `display_name` | Dhan custom symbol |
29
- | `lot_size` | Lot size (Integer) |
30
- | `tick_size` | Tick size (Float) |
31
- | `expiry_date` | Expiry date (String) |
32
- | `strike_price` | Strike price (Float) |
33
- | `option_type` | Option Type (`CALL` or `PUT`) |
34
-
35
- ---
36
-
37
- ## Recommended Resolution Flow
38
-
39
- Use the SDK's built-in helper methods on the `Instrument` class:
40
-
41
- ```ruby
42
- # Find specific instrument in a segment (exact match)
43
- inst = DhanHQ::Models::Instrument.find("NSE_EQ", "RELIANCE")
44
-
45
- # Search across multiple segments (finds any match)
46
- inst = DhanHQ::Models::Instrument.find_anywhere("RELIANCE")
47
-
48
- # Fuzzy search across multiple segments
49
- results = DhanHQ::Models::Instrument.search("RELIANCE")
50
- ```
51
-
52
- Or leverage the helper layer in `scripts/dhan_helpers.rb`:
53
-
54
- ```ruby
55
- require_relative "../scripts/dhan_helpers"
56
-
57
- cash = resolve_symbol("RELIANCE", "NSE_EQ")
58
- contract = resolve_derivative("NIFTY", strike: 24000, option_type: "CE", expiry: "2025-03-27")
59
- lot_size = get_lot_size(underlying: "NIFTY")
60
- ```
61
-
62
- ---
63
-
64
- ## Quick-Reference Fallback IDs
65
-
66
- ### Index Underlyings
67
-
68
- | Underlying | security_id | Underlying Segment |
69
- |------------|-------------|-------------------|
70
- | NIFTY 50 | `13` | `IDX_I` |
71
- | BANK NIFTY | `25` | `IDX_I` |
72
- | FINNIFTY | `27` | `IDX_I` |
73
- | MIDCPNIFTY | `442` | `IDX_I` |
74
- | SENSEX | `51` | `IDX_I` |
75
-
76
- ### Common NSE Equities
77
-
78
- | Symbol | security_id |
79
- |--------|-------------|
80
- | RELIANCE | `2885` |
81
- | HDFCBANK | `1333` |
82
- | TCS | `11536` |
83
- | INFY | `1594` |
84
- | ICICIBANK | `4963` |
85
- | SBIN | `3045` |