DhanHQ 2.2.2 → 2.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09510cd95013213714d5ba4878e87dfa6bd5968cb90ea4e0a539ddb0d05bc2b0'
4
- data.tar.gz: 459c316d0f2c68ad8b0556518dfd70762e460e5c68ef063439e73f68ca33ba02
3
+ metadata.gz: 26a3e58a35f27dcc1902c2ec1c6849f0e03f80b5123c6ac310588c8e7a0d3a58
4
+ data.tar.gz: 516cc99f9e3a61f8ec261788babc4309f1b6acc97b1c0ef98f5dbe22b1499217
5
5
  SHA512:
6
- metadata.gz: d54cf0cc58e82d1566f525303ea25fddd051b1c838152da39f12509435a16e4005f55417d5516c52f6222b4ba6286c421202d0a148f743be7ca4127b7ef03bae
7
- data.tar.gz: ea522dfeb54054d8162d00ead357efb4c444c3dd0c4c182c4d688a2bd9a484d44af7b2bab221476c93fded44511bfff7e8cf4b75d6e962fc8191486bee5440b1
6
+ metadata.gz: ce920dd5a3804a4b7ddc41867f742ea187fe38255c1468c4a0f1528641dc144752571591de74812241b2d985c40381604a235032250eb4580d6e3b4ad2ffc0bc
7
+ data.tar.gz: 418f01c9b4bebc8bda9e8d20567dc6d157b60fad7e00eda2522106fd9abfdea607142179e50f2c79c7cfa45a246941be252263354737a8279cb8ab7152d0b9b3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ---
4
+
5
+ ## [2.3.0] - 2026-02-04
6
+
7
+ ### Added
8
+ - **Alert Orders**: `DhanHQ::Resources::AlertOrders` (BaseResource) and `DhanHQ::Models::AlertOrder` with full CRUD. Endpoints: GET/POST `/alerts/orders`, GET/PUT/DELETE `/alerts/orders/{id}` (per API docs). Validation via `DhanHQ::Contracts::AlertOrderContract`.
9
+ - **IP Setup**: `DhanHQ::Resources::IPSetup` (resource-only). Methods: `current` (GET `/ip/getIP`), `set(ip:)` (POST `/ip/setIP`), `update(ip:)` (PUT `/ip/modifyIP`) per API docs.
10
+ - **Trader Control (Kill Switch)**: `DhanHQ::Resources::TraderControl` (resource-only). Methods: `status` (GET `/trader-control`), `enable` (POST action ENABLE), `disable` (POST action DISABLE). `DhanHQ::Resources::KillSwitch` and `DhanHQ::Models::KillSwitch` remain for backward compatibility.
11
+ - **docs/API_VERIFICATION.md**: Documents alignment with [dhanhq.co/docs/v2](https://dhanhq.co/docs/v2/) and [api.dhan.co/v2](https://api.dhan.co/v2/#/) for EDIS, Alert Orders, IP Setup.
12
+
13
+ ### Changed
14
+ - **EDIS**: Resource-only, aligned with [dhanhq.co/docs/v2/edis](https://dhanhq.co/docs/v2/edis/). Use `DhanHQ::Resources::Edis`: `form(params)` (POST `/edis/form`; isin, qty, exchange, segment, bulk), `bulk_form(params)` (POST `/edis/bulkform`), `tpin` (GET `/edis/tpin`), `inquire(isin)` (GET `/edis/inquire/{isin}`).
15
+ - **BaseResource**: Fixed path building: `all`/`find`/`create`/`update`/`delete` now pass relative endpoints (`""`, `"/#{id}"`) so the base path is not doubled.
16
+
17
+ ---
18
+
3
19
  ## [2.2.2] - 2026-01-31
4
20
 
5
21
  ### Contracts (date validation)
data/GUIDE.md CHANGED
@@ -641,33 +641,75 @@ profile.active_segment # => "Equity, Derivative, Currency, Commodity"
641
641
 
642
642
  If the credentials are invalid the helper raises `DhanHQ::InvalidAuthenticationError`.
643
643
 
644
- ### EDIS (Electronic Delivery Instruction Slip)
644
+ ### Alert Orders
645
645
 
646
646
  ```ruby
647
- # Generate a CDSL form for a single ISIN
648
- form = DhanHQ::Models::Edis.form(
649
- isin: "INE0ABCDE123",
650
- qty: 1,
651
- exchange: "NSE",
652
- segment: "EQ",
653
- bulk: false
647
+ # Model (CRUD)
648
+ DhanHQ::Models::AlertOrder.all
649
+ alert = DhanHQ::Models::AlertOrder.find("alert-id")
650
+ alert = DhanHQ::Models::AlertOrder.create(
651
+ exchange_segment: "NSE_EQ",
652
+ security_id: "11536",
653
+ condition: "GTE",
654
+ trigger_price: 100.0,
655
+ transaction_type: "BUY",
656
+ quantity: 10
654
657
  )
658
+ alert.save
659
+ alert.destroy
655
660
 
656
- # Prepare a bulk file
657
- bulk_form = DhanHQ::Models::Edis.bulk_form(
658
- isin: %w[INE0ABCDE123 INE0XYZ89012],
659
- exchange: "NSE",
660
- segment: "EQ"
661
- )
661
+ # Resource only
662
+ DhanHQ::Resources::AlertOrders.new.all
663
+ ```
664
+
665
+ ### EDIS (Electronic Delivery Instruction Slip)
666
+
667
+ EDIS is resource-only (no model). Use `DhanHQ::Resources::Edis` per [dhanhq.co/docs/v2/edis](https://dhanhq.co/docs/v2/edis/):
668
+
669
+ ```ruby
670
+ edis = DhanHQ::Resources::Edis.new
671
+
672
+ # Generate T-PIN (GET /edis/tpin)
673
+ edis.tpin
674
+
675
+ # Retrieve form & enter T-PIN (POST /edis/form): isin, qty, exchange, segment, bulk
676
+ edis.form(isin: "INE733E01010", qty: 1, exchange: "NSE", segment: "EQ", bulk: false)
662
677
 
663
- # Manage T-PIN and status inquiries
664
- DhanHQ::Models::Edis.tpin # => {"status"=>"TPIN sent"}
665
- authorisations = DhanHQ::Models::Edis.inquire("ALL")
678
+ # Bulk form (POST /edis/bulkform)
679
+ edis.bulk_form(exchange: "NSE", segment: "EQ", bulk: true)
680
+
681
+ # Inquire status (GET /edis/inquire/{isin})
682
+ edis.inquire("INE002A01018")
683
+ edis.inquire("ALL")
684
+ ```
685
+
686
+ Params use snake_case; the client camelizes them before calling `/edis/...`.
687
+
688
+ ### IP Setup
689
+
690
+ Resource-only (account configuration) per API docs: GET /ip/getIP, POST /ip/setIP, PUT /ip/modifyIP.
691
+
692
+ ```ruby
693
+ ip = DhanHQ::Resources::IPSetup.new
694
+ ip.current # GET /ip/getIP
695
+ ip.set(ip: "103.21.58.121")
696
+ ip.update(ip: "103.21.58.121")
697
+ ```
698
+
699
+ ### Trader Control (Kill Switch)
700
+
701
+ Resource-only control toggle:
702
+
703
+ ```ruby
704
+ tc = DhanHQ::Resources::TraderControl.new
705
+ tc.status # GET /trader-control
706
+ tc.disable # Kill switch ON — trading blocked
707
+ tc.enable # Trading resumed
666
708
  ```
667
709
 
668
- All helpers accept snake_case keys; the client camelizes them before calling `/v2/edis/...`.
710
+ ### Kill Switch (model)
669
711
 
670
- ### Kill Switch
712
+ Existing model API for backward compatibility:
671
713
 
672
714
  ```ruby
673
715
  activate_payload = DhanHQ::Models::KillSwitch.activate
data/README.md CHANGED
@@ -4,7 +4,7 @@ A clean Ruby client for **Dhan API v2** with ORM-like models (Orders, Positions,
4
4
 
5
5
  * ActiveRecord-style models: `find`, `all`, `where`, `save`, `update`, `cancel`
6
6
  * Validations & errors exposed via ActiveModel-like interfaces
7
- * REST coverage: Orders, Super Orders, Forever Orders, Trades, Positions, Holdings, Funds/Margin, HistoricalData, OptionChain, MarketFeed, ExpiredOptionsData
7
+ * REST coverage: Orders, Alert Orders, Super Orders, Forever Orders, Trades, Positions, Holdings, Funds/Margin, HistoricalData, OptionChain, MarketFeed, ExpiredOptionsData, EDIS, IP Setup, Trader Control (Kill Switch)
8
8
  * **WebSocket**: Orders, Market Feed, Market Depth - subscribe/unsubscribe dynamically, auto-reconnect with backoff, 429 cool-off, idempotent subs, header+payload binary parsing, normalized ticks
9
9
 
10
10
  ## ⚠️ BREAKING CHANGE NOTICE
@@ -0,0 +1,67 @@
1
+ # API Verification (Dhan v2)
2
+
3
+ This document records how the gem’s implementation aligns with the official Dhan API v2 docs.
4
+
5
+ **Sources:**
6
+
7
+ - [dhanhq.co/docs/v2](https://dhanhq.co/docs/v2/) – main docs
8
+ - [dhanhq.co/docs/v2/edis](https://dhanhq.co/docs/v2/edis/) – EDIS
9
+ - [api.dhan.co/v2](https://api.dhan.co/v2/#/) – Developer Kit (when available)
10
+ - In-repo: `CODE_REVIEW_ISSUES.md` (Alert Orders, IP Setup paths)
11
+
12
+ ---
13
+
14
+ ## EDIS
15
+
16
+ **Doc:** [dhanhq.co/docs/v2/edis](https://dhanhq.co/docs/v2/edis/)
17
+
18
+ | Doc endpoint | Method | Gem method | Path / behaviour |
19
+ |---------------------------|--------|--------------|-------------------|
20
+ | Generate T-PIN | GET | `#tpin` | `/edis/tpin` |
21
+ | Retrieve form & enter T-PIN | POST | `#form(params)` | `/edis/form`; body: `isin`, `qty`, `exchange`, `segment`, `bulk` |
22
+ | Bulk form | POST | `#bulk_form(params)` | `/edis/bulkform` (aligned with TODO-1 / legacy) |
23
+ | Inquire status | GET | `#inquire(isin)` | `/edis/inquire/{isin}` |
24
+
25
+ **Request (form):** `isin`, `qty`, `exchange` (NSE/BSE), `segment` (EQ), `bulk` (boolean).
26
+
27
+ ---
28
+
29
+ ## Alert Orders
30
+
31
+ **Doc ref:** `CODE_REVIEW_ISSUES.md` (§31) – Alert Orders endpoints.
32
+
33
+ | Doc path | Gem resource | Path used |
34
+ |---------------------------|---------------------------|------------------|
35
+ | `/alerts/orders` | `Resources::AlertOrders` | `HTTP_PATH = "/alerts/orders"` |
36
+ | GET/POST `/alerts/orders` | `#all`, `#create` | BaseResource |
37
+ | GET/PUT/DELETE `/alerts/orders/{trigger-id}` | `#find`, `#update`, `#delete` | `/{id}` |
38
+
39
+ Model: `Models::AlertOrder`; ID attribute `alert_id` (response field name may be `alertId` or `triggerId` depending on API; adjust if production returns `triggerId`).
40
+
41
+ ---
42
+
43
+ ## IP Setup
44
+
45
+ **Doc ref:** `CODE_REVIEW_ISSUES.md` (§32) – IP Setup endpoints.
46
+
47
+ | Doc path | Gem method | Path used |
48
+ |-----------------|----------------|---------------|
49
+ | GET /ip/getIP | `#current` | `get("/getIP")` |
50
+ | POST /ip/setIP | `#set(ip:)` | `post("/setIP", params: { ip: ip })` |
51
+ | PUT /ip/modifyIP| `#update(ip:)` | `put("/modifyIP", params: { ip: ip })` |
52
+
53
+ ---
54
+
55
+ ## Trader Control / Kill Switch
56
+
57
+ - **Existing:** `Resources::KillSwitch`, `Models::KillSwitch` – path `/v2/killswitch`.
58
+ - **Added:** `Resources::TraderControl` – path `/trader-control`; `#status`, `#enable`, `#disable`.
59
+ Not found on the public docs pages checked; kept for compatibility with design that referenced trader-control.
60
+
61
+ ---
62
+
63
+ ## Base URL and paths
64
+
65
+ - Default base URL: `https://api.dhan.co/v2`.
66
+ - Resource `HTTP_PATH` values are relative to that base (e.g. `/edis`, `/alerts/orders`, `/ip`).
67
+ - Order API resources use `API_TYPE = :order_api`.
@@ -922,65 +922,63 @@ end
922
922
 
923
923
  ### EDIS
924
924
 
925
- #### Get EDIS Form
925
+ EDIS is resource-only per [dhanhq.co/docs/v2/edis](https://dhanhq.co/docs/v2/edis/). Use `DhanHQ::Resources::Edis`.
926
+
927
+ #### Get TPIN (GET /edis/tpin)
926
928
 
927
929
  ```ruby
928
- # Get EDIS form
929
- edis_form = DhanHQ::Models::Edis.form
930
- puts "EDIS Form:"
931
- puts " ISIN: #{edis_form[:isin]}"
932
- puts " Quantity: #{edis_form[:quantity]}"
930
+ edis = DhanHQ::Resources::Edis.new
931
+ tpin_response = edis.tpin
932
+ puts "TPIN: #{tpin_response}"
933
933
  ```
934
934
 
935
- #### Get Bulk EDIS Form
935
+ #### Form (POST /edis/form)
936
936
 
937
937
  ```ruby
938
- # Get bulk EDIS form
939
- bulk_form = DhanHQ::Models::Edis.bulk_form
940
- puts "Bulk Form: #{bulk_form.size} entries"
938
+ edis = DhanHQ::Resources::Edis.new
939
+ response = edis.form(isin: "INE467B01029", qty: 10, exchange: "NSE", segment: "EQ", bulk: false)
940
+ puts "EDIS form: #{response.is_a?(Hash) ? 'OK' : response.class}"
941
941
  ```
942
942
 
943
- #### Generate TPIN
943
+ #### Bulk form (POST /edis/bulkform)
944
944
 
945
945
  ```ruby
946
- # Generate TPIN
947
- tpin = DhanHQ::Models::Edis.generate_tpin
948
- puts "TPIN: #{tpin[:tpin]}"
946
+ edis = DhanHQ::Resources::Edis.new
947
+ response = edis.bulk_form(exchange: "NSE", segment: "EQ", bulk: true)
948
+ puts "EDIS bulk form: #{response.is_a?(Hash) ? 'OK' : response.class}"
949
949
  ```
950
950
 
951
- #### Inquire EDIS Status
951
+ #### Inquire (GET /edis/inquire/{isin})
952
952
 
953
953
  ```ruby
954
- # Inquire EDIS status by ISIN
955
- isin = "INE467B01029" # Example ISIN
956
- status = DhanHQ::Models::Edis.inquire(isin: isin)
957
- puts "EDIS Status: #{status[:status]}"
954
+ edis = DhanHQ::Resources::Edis.new
955
+ status = edis.inquire("INE467B01029")
956
+ puts "EDIS status: #{status}"
957
+ # Or pass "ALL" for all holdings
958
+ all_status = edis.inquire("ALL")
958
959
  ```
959
960
 
960
961
  ### Kill Switch
961
962
 
962
- #### Activate Kill Switch
963
+ #### Trader Control (resource-only)
963
964
 
964
965
  ```ruby
965
- # Activate kill switch
966
- result = DhanHQ::Models::KillSwitch.update(status: "ACTIVATE")
967
- if result
968
- puts "Kill switch activated"
969
- else
970
- puts "Failed to activate kill switch"
971
- end
966
+ tc = DhanHQ::Resources::TraderControl.new
967
+ tc.disable # Kill switch ON
968
+ tc.enable # Trading resumed
969
+ tc.status
972
970
  ```
973
971
 
974
- #### Deactivate Kill Switch
972
+ #### Kill Switch (model, backward compatible)
975
973
 
976
974
  ```ruby
975
+ # Activate kill switch
976
+ result = DhanHQ::Models::KillSwitch.update("ACTIVATE")
977
+ puts result[:kill_switch_status] if result.is_a?(Hash)
978
+
977
979
  # Deactivate kill switch
978
- result = DhanHQ::Models::KillSwitch.update(status: "DEACTIVATE")
979
- if result
980
- puts "Kill switch deactivated"
981
- else
982
- puts "Failed to deactivate kill switch"
983
- end
980
+ result = DhanHQ::Models::KillSwitch.update("DEACTIVATE")
981
+ puts result[:kill_switch_status] if result.is_a?(Hash)
984
982
  ```
985
983
 
986
984
  ### Expired Options Data
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DhanHQ
4
+ module Contracts
5
+ # Validates alert order payloads for create/update (exchange_segment, security_id,
6
+ # condition, trigger_price, transaction_type, quantity; optional price, order_type).
7
+ class AlertOrderContract < BaseContract
8
+ params do
9
+ required(:exchange_segment).filled(:string)
10
+ required(:security_id).filled(:string)
11
+ required(:condition).filled(:string)
12
+ required(:trigger_price).filled(:float)
13
+ required(:transaction_type).filled(:string, included_in?: %w[BUY SELL])
14
+ required(:quantity).filled(:integer, gt?: 0)
15
+ optional(:price).maybe(:float)
16
+ optional(:order_type).maybe(:string)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -11,7 +11,7 @@ module DhanHQ
11
11
  #
12
12
  # @return [Array<Hash>, Hash]
13
13
  def all
14
- get(self.class::HTTP_PATH)
14
+ get("")
15
15
  end
16
16
 
17
17
  # Retrieves a single resource by identifier.
@@ -19,7 +19,7 @@ module DhanHQ
19
19
  # @param id [String, Integer]
20
20
  # @return [Hash]
21
21
  def find(id)
22
- get("#{self.class::HTTP_PATH}/#{id}")
22
+ get("/#{id}")
23
23
  end
24
24
 
25
25
  # Creates a new resource instance.
@@ -27,7 +27,7 @@ module DhanHQ
27
27
  # @param params [Hash]
28
28
  # @return [Hash]
29
29
  def create(params)
30
- post(self.class::HTTP_PATH, params: params)
30
+ post("", params: params)
31
31
  end
32
32
 
33
33
  # Updates an existing resource.
@@ -36,7 +36,7 @@ module DhanHQ
36
36
  # @param params [Hash]
37
37
  # @return [Hash]
38
38
  def update(id, params)
39
- put("#{self.class::HTTP_PATH}/#{id}", params: params)
39
+ put("/#{id}", params: params)
40
40
  end
41
41
 
42
42
  # Deletes a resource by identifier.
@@ -44,7 +44,7 @@ module DhanHQ
44
44
  # @param id [String, Integer]
45
45
  # @return [Hash]
46
46
  def delete(id)
47
- super("#{self.class::HTTP_PATH}/#{id}")
47
+ super("/#{id}")
48
48
  end
49
49
  end
50
50
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../contracts/alert_order_contract"
4
+
5
+ module DhanHQ
6
+ module Models
7
+ # Model for alert/conditional orders. CRUD via AlertOrders resource; validated by AlertOrderContract.
8
+ class AlertOrder < BaseModel
9
+ HTTP_PATH = "/alerts/orders"
10
+
11
+ attributes :alert_id, :exchange_segment, :security_id, :condition,
12
+ :trigger_price, :order_type, :transaction_type, :quantity,
13
+ :price, :status, :created_at
14
+
15
+ class << self
16
+ def api_type
17
+ :order_api
18
+ end
19
+
20
+ def resource
21
+ @resource ||= DhanHQ::Resources::AlertOrders.new
22
+ end
23
+
24
+ def validation_contract
25
+ Contracts::AlertOrderContract
26
+ end
27
+
28
+ def all
29
+ response = resource.all
30
+ return [] unless response.is_a?(Array)
31
+
32
+ response.map { |attrs| new(attrs, skip_validation: true) }
33
+ end
34
+
35
+ def find(alert_id)
36
+ response = resource.find(alert_id)
37
+ return nil unless response.is_a?(Hash) || (response.is_a?(Array) && response.any?)
38
+
39
+ payload = response.is_a?(Array) ? response.first : response
40
+ new(payload, skip_validation: true)
41
+ end
42
+
43
+ def create(params)
44
+ normalized = snake_case(params)
45
+ validate_params!(normalized, DhanHQ::Contracts::AlertOrderContract)
46
+ response = resource.create(camelize_keys(normalized))
47
+ return nil unless response.is_a?(Hash) && response["alertId"]
48
+
49
+ find(response["alertId"])
50
+ end
51
+ end
52
+
53
+ def id
54
+ alert_id&.to_s
55
+ end
56
+
57
+ def save # rubocop:disable Naming/PredicateMethod
58
+ return false unless valid?
59
+
60
+ payload = to_request_params
61
+ response = if new_record?
62
+ self.class.resource.create(camelize_keys(payload))
63
+ else
64
+ self.class.resource.update(id, camelize_keys(payload))
65
+ end
66
+ return false if new_record? && !(response.is_a?(Hash) && response["alertId"])
67
+ return false if !new_record? && !success_response?(response)
68
+
69
+ @attributes.merge!(normalize_keys(response))
70
+ assign_attributes
71
+ true
72
+ end
73
+
74
+ def destroy # rubocop:disable Naming/PredicateMethod
75
+ return false if new_record?
76
+
77
+ response = self.class.resource.delete(id)
78
+ success_response?(response)
79
+ end
80
+ alias delete destroy
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DhanHQ
4
+ module Resources
5
+ # Resource for alert/conditional orders per API docs: /alerts/orders (GET/POST/PUT/DELETE).
6
+ class AlertOrders < BaseResource
7
+ API_TYPE = :order_api
8
+ HTTP_PATH = "/alerts/orders"
9
+ end
10
+ end
11
+ end
@@ -2,40 +2,25 @@
2
2
 
3
3
  module DhanHQ
4
4
  module Resources
5
- # Resource client for electronic DIS flows.
5
+ # Resource for EDIS per https://dhanhq.co/docs/v2/edis/
6
+ # GET /edis/tpin, POST /edis/form (body: isin, qty, exchange, segment, bulk),
7
+ # POST /edis/bulkform, GET /edis/inquire/{isin}.
6
8
  class Edis < BaseAPI
7
- # EDIS endpoints are served from the trading API.
8
- API_TYPE = :order_api
9
- # Base path for EDIS endpoints.
10
- HTTP_PATH = "/v2/edis"
9
+ API_TYPE = :order_api
10
+ HTTP_PATH = "/edis"
11
11
 
12
- # Creates a TPIN request form.
13
- #
14
- # @param params [Hash]
15
- # @return [Hash]
16
12
  def form(params)
17
13
  post("/form", params: params)
18
14
  end
19
15
 
20
- # Bulk EDIS form submission.
21
- #
22
- # @param params [Hash]
23
- # @return [Hash]
24
16
  def bulk_form(params)
25
17
  post("/bulkform", params: params)
26
18
  end
27
19
 
28
- # Generates a TPIN for the client.
29
- #
30
- # @return [Hash]
31
20
  def tpin
32
21
  get("/tpin")
33
22
  end
34
23
 
35
- # Checks the EDIS status for a given ISIN.
36
- #
37
- # @param isin [String]
38
- # @return [Hash]
39
24
  def inquire(isin)
40
25
  get("/inquire/#{isin}")
41
26
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DhanHQ
4
+ module Resources
5
+ # Resource for IP whitelist per API docs: GET /ip/getIP, POST /ip/setIP, PUT /ip/modifyIP.
6
+ class IPSetup < BaseAPI
7
+ API_TYPE = :order_api
8
+ HTTP_PATH = "/ip"
9
+
10
+ def current
11
+ get("/getIP")
12
+ end
13
+
14
+ def set(ip:)
15
+ post("/setIP", params: { ip: ip })
16
+ end
17
+
18
+ def update(ip:)
19
+ put("/modifyIP", params: { ip: ip })
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DhanHQ
4
+ module Resources
5
+ # Resource for trader control (kill switch): status (GET), enable/disable (POST /trader-control).
6
+ class TraderControl < BaseAPI
7
+ API_TYPE = :order_api
8
+ HTTP_PATH = "/trader-control"
9
+
10
+ def status
11
+ get("")
12
+ end
13
+
14
+ def enable
15
+ post("", params: { action: "ENABLE" })
16
+ end
17
+
18
+ def disable
19
+ post("", params: { action: "DISABLE" })
20
+ end
21
+ end
22
+ end
23
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module DhanHQ
4
4
  # Semantic version of the DhanHQ client gem.
5
- VERSION = "2.2.2"
5
+ VERSION = "2.3.0"
6
6
  end
data/lib/dhan_hq.rb CHANGED
@@ -33,6 +33,7 @@ require_relative "DhanHQ/contracts/position_conversion_contract"
33
33
  require_relative "DhanHQ/contracts/slice_order_contract"
34
34
  require_relative "DhanHQ/contracts/trade_contract"
35
35
  require_relative "DhanHQ/contracts/expired_options_data_contract"
36
+ require_relative "DhanHQ/contracts/alert_order_contract"
36
37
 
37
38
  # Resources
38
39
  require_relative "DhanHQ/resources/option_chain"
@@ -48,12 +49,16 @@ require_relative "DhanHQ/resources/historical_data"
48
49
  require_relative "DhanHQ/resources/margin_calculator"
49
50
  require_relative "DhanHQ/resources/market_feed"
50
51
  require_relative "DhanHQ/resources/instruments"
52
+ require_relative "DhanHQ/resources/alert_orders"
51
53
  require_relative "DhanHQ/resources/edis"
54
+ require_relative "DhanHQ/resources/ip_setup"
52
55
  require_relative "DhanHQ/resources/kill_switch"
56
+ require_relative "DhanHQ/resources/trader_control"
53
57
  require_relative "DhanHQ/resources/profile"
54
58
  require_relative "DhanHQ/resources/expired_options_data"
55
59
 
56
60
  # Models
61
+ require_relative "DhanHQ/models/alert_order"
57
62
  require_relative "DhanHQ/models/order"
58
63
  require_relative "DhanHQ/models/funds"
59
64
  require_relative "DhanHQ/models/option_chain"
@@ -67,7 +72,6 @@ require_relative "DhanHQ/models/holding"
67
72
  require_relative "DhanHQ/models/ledger_entry"
68
73
  require_relative "DhanHQ/models/trade"
69
74
  require_relative "DhanHQ/models/margin"
70
- require_relative "DhanHQ/models/edis"
71
75
  require_relative "DhanHQ/models/kill_switch"
72
76
  require_relative "DhanHQ/models/profile"
73
77
  require_relative "DhanHQ/models/order_update"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: DhanHQ
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shubham Taywade
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-31 00:00:00.000000000 Z
11
+ date: 2026-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -183,6 +183,7 @@ files:
183
183
  - core
184
184
  - diagram.html
185
185
  - diagram.md
186
+ - docs/API_VERIFICATION.md
186
187
  - docs/AUTHENTICATION.md
187
188
  - docs/DATA_API_PARAMETERS.md
188
189
  - docs/PR_2.2.0.md
@@ -207,6 +208,7 @@ files:
207
208
  - lib/DhanHQ/config.rb
208
209
  - lib/DhanHQ/configuration.rb
209
210
  - lib/DhanHQ/constants.rb
211
+ - lib/DhanHQ/contracts/alert_order_contract.rb
210
212
  - lib/DhanHQ/contracts/base_contract.rb
211
213
  - lib/DhanHQ/contracts/expired_options_data_contract.rb
212
214
  - lib/DhanHQ/contracts/historical_data_contract.rb
@@ -232,7 +234,7 @@ files:
232
234
  - lib/DhanHQ/helpers/response_helper.rb
233
235
  - lib/DhanHQ/helpers/validation_helper.rb
234
236
  - lib/DhanHQ/json_loader.rb
235
- - lib/DhanHQ/models/edis.rb
237
+ - lib/DhanHQ/models/alert_order.rb
236
238
  - lib/DhanHQ/models/expired_options_data.rb
237
239
  - lib/DhanHQ/models/forever_order.rb
238
240
  - lib/DhanHQ/models/funds.rb
@@ -255,6 +257,7 @@ files:
255
257
  - lib/DhanHQ/requests/optionchain/nifty.json
256
258
  - lib/DhanHQ/requests/optionchain/nifty_expiries.json
257
259
  - lib/DhanHQ/requests/orders/create.json
260
+ - lib/DhanHQ/resources/alert_orders.rb
258
261
  - lib/DhanHQ/resources/edis.rb
259
262
  - lib/DhanHQ/resources/expired_options_data.rb
260
263
  - lib/DhanHQ/resources/forever_orders.rb
@@ -262,6 +265,7 @@ files:
262
265
  - lib/DhanHQ/resources/historical_data.rb
263
266
  - lib/DhanHQ/resources/holdings.rb
264
267
  - lib/DhanHQ/resources/instruments.rb
268
+ - lib/DhanHQ/resources/ip_setup.rb
265
269
  - lib/DhanHQ/resources/kill_switch.rb
266
270
  - lib/DhanHQ/resources/margin_calculator.rb
267
271
  - lib/DhanHQ/resources/market_feed.rb
@@ -271,6 +275,7 @@ files:
271
275
  - lib/DhanHQ/resources/profile.rb
272
276
  - lib/DhanHQ/resources/statements.rb
273
277
  - lib/DhanHQ/resources/super_orders.rb
278
+ - lib/DhanHQ/resources/trader_control.rb
274
279
  - lib/DhanHQ/resources/trades.rb
275
280
  - lib/DhanHQ/version.rb
276
281
  - lib/DhanHQ/ws.rb
@@ -1,194 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DhanHQ
4
- module Models
5
- ##
6
- # Model wrapper for electronic DIS (Delivery Instruction Slip) flows.
7
- #
8
- # To sell holding stocks, one needs to complete the CDSL eDIS flow:
9
- # 1. Generate T-PIN using {tpin}
10
- # 2. Retrieve escaped HTML form using {form} and enter T-PIN to mark stock for EDIS approval
11
- # 3. Check status using {inquire} to verify if stock is approved and marked for sell action
12
- #
13
- # You can get ISIN (International Securities Identification Number) of portfolio stocks
14
- # from the holdings API response.
15
- #
16
- # @example Generate T-PIN
17
- # response = DhanHQ::Models::Edis.tpin
18
- # # Returns 202 Accepted status
19
- #
20
- # @example Generate eDIS form for a single stock
21
- # response = DhanHQ::Models::Edis.form(
22
- # isin: "INE733E01010",
23
- # qty: 1,
24
- # exchange: "NSE",
25
- # segment: "EQ",
26
- # bulk: false
27
- # )
28
- # # => {
29
- # # dhan_client_id: "1000000401",
30
- # # edis_form_html: "<!DOCTYPE html>..."
31
- # # }
32
- #
33
- # @example Check EDIS status for an ISIN
34
- # status = DhanHQ::Models::Edis.inquire("INE00IN01015")
35
- # # => {
36
- # # client_id: "1000000401",
37
- # # isin: "INE00IN01015",
38
- # # total_qty: "10",
39
- # # aprvd_qty: "4",
40
- # # status: "SUCCESS",
41
- # # remarks: "eDIS transaction done successfully"
42
- # # }
43
- #
44
- class Edis < BaseModel
45
- # Base path backing the model operations.
46
- HTTP_PATH = "/v2/edis"
47
-
48
- class << self
49
- ##
50
- # Shared resource client used by the model helpers.
51
- #
52
- # @return [DhanHQ::Resources::Edis] The EDIS resource client instance
53
- def resource
54
- @resource ||= DhanHQ::Resources::Edis.new
55
- end
56
-
57
- ##
58
- # Retrieves escaped HTML form of CDSL and enters T-PIN to mark the stock for EDIS approval.
59
- #
60
- # User has to render this form at their end to unescape. The form contains hidden fields
61
- # that will automatically submit to CDSL's eDIS verification endpoint.
62
- #
63
- # @param params [Hash{Symbol => String, Integer, Boolean}] The EDIS form request parameters
64
- # @option params [String] :isin (required) International Securities Identification Number
65
- # (12-digit alphanumeric code). You can get ISIN from the holdings API response.
66
- # @option params [Integer] :qty (required) Number of shares to mark for EDIS transaction
67
- # @option params [String] :exchange (required) Exchange identifier. Must be either "NSE" or "BSE"
68
- # @option params [String] :segment (required) Segment identifier. Must be "EQ"
69
- # @option params [Boolean] :bulk (optional, default: false) Set to true to mark EDIS for
70
- # all stocks in portfolio. When true, other parameters may be ignored.
71
- #
72
- # @return [Hash{Symbol => String}] The EDIS form response containing escaped HTML form.
73
- # Response keys are normalized to snake_case:
74
- # - **:dhan_client_id** [String] User-specific identification generated by Dhan
75
- # - **:edis_form_html** [String] Escaped HTML form that needs to be rendered and unescaped
76
- #
77
- # @example Generate form for a single stock
78
- # response = DhanHQ::Models::Edis.form(
79
- # isin: "INE733E01010",
80
- # qty: 1,
81
- # exchange: "NSE",
82
- # segment: "EQ",
83
- # bulk: false
84
- # )
85
- # html_form = response[:edis_form_html]
86
- # # Render and unescape the HTML form to complete EDIS approval
87
- #
88
- # @example Generate form for bulk EDIS
89
- # response = DhanHQ::Models::Edis.form(
90
- # isin: "",
91
- # qty: 0,
92
- # exchange: "NSE",
93
- # segment: "EQ",
94
- # bulk: true
95
- # )
96
- def form(params)
97
- resource.form(params)
98
- end
99
-
100
- ##
101
- # Submits a bulk EDIS form request for multiple stocks.
102
- #
103
- # This is an alternative to using {form} with `bulk: true`. The exact parameter
104
- # structure may differ from the single form request.
105
- #
106
- # @param params [Hash{Symbol => String, Integer, Boolean}] The bulk EDIS form request parameters
107
- # @option params [String] :isin (optional) International Securities Identification Number.
108
- # May be ignored for bulk requests
109
- # @option params [Integer] :qty (optional) Number of shares. May be ignored for bulk requests
110
- # @option params [String] :exchange (required) Exchange identifier ("NSE" or "BSE")
111
- # @option params [String] :segment (required) Segment identifier ("EQ")
112
- # @option params [Boolean] :bulk (optional, default: true) Set to true for bulk operations
113
- #
114
- # @return [Hash{Symbol => String}] The bulk EDIS form response containing escaped HTML form.
115
- # Response keys are normalized to snake_case:
116
- # - **:dhan_client_id** [String] User-specific identification generated by Dhan
117
- # - **:edis_form_html** [String] Escaped HTML form that needs to be rendered and unescaped
118
- #
119
- # @example Bulk EDIS form request
120
- # response = DhanHQ::Models::Edis.bulk_form(
121
- # exchange: "NSE",
122
- # segment: "EQ",
123
- # bulk: true
124
- # )
125
- def bulk_form(params)
126
- resource.bulk_form(params)
127
- end
128
-
129
- ##
130
- # Generates a T-PIN (Transaction PIN) for the configured client.
131
- #
132
- # T-PIN is sent to the user's registered mobile number. This T-PIN is required
133
- # when submitting the EDIS form to mark stocks for sell action.
134
- #
135
- # @return [Hash{Symbol => String}] The T-PIN generation response. The T-PIN itself is sent
136
- # to the registered mobile number and not returned in the response. Response typically
137
- # contains a status indicating successful generation (e.g., "202 Accepted").
138
- #
139
- # @example Generate T-PIN
140
- # response = DhanHQ::Models::Edis.tpin
141
- # # T-PIN will be sent to registered mobile number
142
- # # Check your mobile for the T-PIN before submitting the EDIS form
143
- #
144
- # @note This is a GET request with no body parameters required
145
- def tpin
146
- resource.tpin
147
- end
148
-
149
- ##
150
- # Inquires the EDIS status for a specific ISIN to check if stock is approved and marked for sell action.
151
- #
152
- # You can check whether a stock has been approved through the EDIS process and is ready
153
- # for sell action. Alternatively, you can pass "ALL" instead of an ISIN to get EDIS status
154
- # of all holdings in your portfolio.
155
- #
156
- # @param isin [String] International Securities Identification Number (12-digit alphanumeric code).
157
- # You can get ISIN from the holdings API response. Alternatively, pass "ALL" to get status
158
- # for all holdings in your portfolio.
159
- #
160
- # @return [Hash{Symbol => String}] The EDIS inquiry response containing status information.
161
- # Response keys are normalized to snake_case:
162
- # - **:client_id** [String] User-specific identification
163
- # - **:isin** [String] International Securities Identification Number that was queried
164
- # - **:total_qty** [String] Total number of shares for the given stock
165
- # - **:aprvd_qty** [String] Number of approved stocks that are marked for EDIS
166
- # - **:status** [String] Status of the EDIS order (e.g., "SUCCESS", "PENDING", "FAILED")
167
- # - **:remarks** [String] Remarks about the order status (e.g., "eDIS transaction done successfully")
168
- #
169
- # @example Check status for a specific ISIN
170
- # status = DhanHQ::Models::Edis.inquire("INE00IN01015")
171
- # puts status[:status] # => "SUCCESS"
172
- # puts status[:aprvd_qty] # => "4"
173
- # puts status[:total_qty] # => "10"
174
- #
175
- # @example Check status for all holdings
176
- # all_status = DhanHQ::Models::Edis.inquire("ALL")
177
- # # Returns status for all holdings in portfolio
178
- #
179
- # @note This is a GET request with no body parameters. The ISIN is passed in the URL path.
180
- def inquire(isin)
181
- resource.inquire(isin)
182
- end
183
- end
184
-
185
- ##
186
- # EDIS payloads are validated upstream so no contract is applied.
187
- #
188
- # @return [nil] No validation contract is needed for EDIS operations
189
- def validation_contract
190
- nil
191
- end
192
- end
193
- end
194
- end