DhanHQ 2.1.0 → 2.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +185 -0
- data/CHANGELOG.md +24 -0
- data/GUIDE.md +44 -44
- data/README.md +40 -14
- data/docs/rails_integration.md +1 -1
- data/docs/technical_analysis.md +144 -0
- data/lib/DhanHQ/config.rb +1 -0
- data/lib/DhanHQ/constants.rb +4 -6
- data/lib/DhanHQ/contracts/instrument_list_contract.rb +12 -0
- data/lib/DhanHQ/contracts/modify_order_contract.rb +1 -0
- data/lib/DhanHQ/contracts/option_chain_contract.rb +11 -1
- data/lib/DhanHQ/helpers/request_helper.rb +5 -1
- data/lib/DhanHQ/models/instrument.rb +56 -0
- data/lib/DhanHQ/models/option_chain.rb +2 -0
- data/lib/DhanHQ/rate_limiter.rb +4 -2
- data/lib/DhanHQ/resources/instruments.rb +28 -0
- data/lib/DhanHQ/version.rb +1 -1
- data/lib/DhanHQ/ws/client.rb +1 -1
- data/lib/DhanHQ/ws/connection.rb +1 -1
- data/lib/DhanHQ/ws/orders/client.rb +3 -0
- data/lib/DhanHQ/ws/orders/connection.rb +5 -6
- data/lib/DhanHQ/ws/orders.rb +3 -2
- data/lib/DhanHQ/ws/registry.rb +1 -0
- data/lib/DhanHQ/ws/segments.rb +4 -4
- data/lib/DhanHQ/ws/sub_state.rb +1 -1
- data/lib/{DhanHQ.rb → dhan_hq.rb} +8 -0
- data/lib/dhanhq/analysis/helpers/bias_aggregator.rb +83 -0
- data/lib/dhanhq/analysis/helpers/moneyness_helper.rb +24 -0
- data/lib/dhanhq/analysis/multi_timeframe_analyzer.rb +232 -0
- data/lib/dhanhq/analysis/options_buying_advisor.rb +251 -0
- data/lib/dhanhq/contracts/options_buying_advisor_contract.rb +24 -0
- data/lib/ta/candles.rb +52 -0
- data/lib/ta/fetcher.rb +70 -0
- data/lib/ta/indicators.rb +169 -0
- data/lib/ta/market_calendar.rb +51 -0
- data/lib/ta/technical_analysis.rb +94 -303
- data/lib/ta.rb +7 -0
- metadata +18 -4
- data/lib/DhanHQ/ws/errors.rb +0 -0
- /data/lib/DhanHQ/contracts/{modify_order_contract copy.rb → modify_order_contract_copy.rb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cff831c4d2dc881c38a4ecc6274ad9ba8601fd6c6910815ab9ec40fde31af564
|
4
|
+
data.tar.gz: 00b892609e077902e1137b789dcd3a6d0e51fa3e042d38b05c39fc92971da157
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f476df43f8f9500515101c85d423b91f713f384e89a01f316ed66265d69502a45b4adf7c2cd06aa6c8d466e65d5548e0337361844305e6f9103df0dd6a7564f3
|
7
|
+
data.tar.gz: aa14913dfa8590e8ba52e2f49a97b4cf475ad6d0058deac7114c1c56cb3817c70a38655afa4b30ef9741ab3da82f53c9d719dec70bef70bb9e242f7081a7392e
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 999`
|
3
|
+
# on 2025-10-12 11:03:03 UTC using RuboCop version 1.80.2.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 4
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
11
|
+
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
|
12
|
+
# URISchemes: http, https
|
13
|
+
Layout/LineLength:
|
14
|
+
Exclude:
|
15
|
+
- 'lib/DhanHQ/ws/decoder.rb'
|
16
|
+
|
17
|
+
# Offense count: 2
|
18
|
+
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
|
19
|
+
Lint/DuplicateBranch:
|
20
|
+
Exclude:
|
21
|
+
- 'bin/ta_strategy.rb'
|
22
|
+
- 'lib/dhanhq/analysis/helpers/bias_aggregator.rb'
|
23
|
+
|
24
|
+
# Offense count: 3
|
25
|
+
# Configuration parameters: AllowComments, AllowNil.
|
26
|
+
Lint/SuppressedException:
|
27
|
+
Exclude:
|
28
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
29
|
+
- 'lib/DhanHQ/ws/registry.rb'
|
30
|
+
|
31
|
+
# Offense count: 42
|
32
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
33
|
+
Metrics/AbcSize:
|
34
|
+
Exclude:
|
35
|
+
- 'bin/ta_strategy.rb'
|
36
|
+
- 'bin/ws_feed_test.rb'
|
37
|
+
- 'lib/DhanHQ/helpers/response_helper.rb'
|
38
|
+
- 'lib/DhanHQ/models/order.rb'
|
39
|
+
- 'lib/DhanHQ/rate_limiter.rb'
|
40
|
+
- 'lib/DhanHQ/ws/client.rb'
|
41
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
42
|
+
- 'lib/DhanHQ/ws/decoder.rb'
|
43
|
+
- 'lib/DhanHQ/ws/orders/connection.rb'
|
44
|
+
- 'lib/DhanHQ/ws/websocket_packet_parser.rb'
|
45
|
+
- 'lib/dhan_hq.rb'
|
46
|
+
- 'lib/dhanhq/analysis/helpers/bias_aggregator.rb'
|
47
|
+
- 'lib/dhanhq/analysis/multi_timeframe_analyzer.rb'
|
48
|
+
- 'lib/dhanhq/analysis/options_buying_advisor.rb'
|
49
|
+
- 'lib/ta/candles.rb'
|
50
|
+
- 'lib/ta/fetcher.rb'
|
51
|
+
- 'lib/ta/indicators.rb'
|
52
|
+
- 'lib/ta/technical_analysis.rb'
|
53
|
+
|
54
|
+
# Offense count: 1
|
55
|
+
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
|
56
|
+
# AllowedMethods: refine
|
57
|
+
Metrics/BlockLength:
|
58
|
+
Exclude:
|
59
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
60
|
+
|
61
|
+
# Offense count: 8
|
62
|
+
# Configuration parameters: CountComments, Max, CountAsOne.
|
63
|
+
Metrics/ClassLength:
|
64
|
+
Exclude:
|
65
|
+
- 'lib/DhanHQ/core/base_model.rb'
|
66
|
+
- 'lib/DhanHQ/models/order.rb'
|
67
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
68
|
+
- 'lib/DhanHQ/ws/orders/connection.rb'
|
69
|
+
- 'lib/DhanHQ/ws/websocket_packet_parser.rb'
|
70
|
+
- 'lib/dhanhq/analysis/multi_timeframe_analyzer.rb'
|
71
|
+
- 'lib/dhanhq/analysis/options_buying_advisor.rb'
|
72
|
+
- 'lib/ta/technical_analysis.rb'
|
73
|
+
|
74
|
+
# Offense count: 25
|
75
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
76
|
+
Metrics/CyclomaticComplexity:
|
77
|
+
Exclude:
|
78
|
+
- 'bin/ta_strategy.rb'
|
79
|
+
- 'bin/ws_feed_test.rb'
|
80
|
+
- 'lib/DhanHQ/helpers/response_helper.rb'
|
81
|
+
- 'lib/DhanHQ/models/order.rb'
|
82
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
83
|
+
- 'lib/DhanHQ/ws/decoder.rb'
|
84
|
+
- 'lib/DhanHQ/ws/orders/connection.rb'
|
85
|
+
- 'lib/DhanHQ/ws/segments.rb'
|
86
|
+
- 'lib/DhanHQ/ws/websocket_packet_parser.rb'
|
87
|
+
- 'lib/dhanhq/analysis/helpers/bias_aggregator.rb'
|
88
|
+
- 'lib/dhanhq/analysis/multi_timeframe_analyzer.rb'
|
89
|
+
- 'lib/dhanhq/analysis/options_buying_advisor.rb'
|
90
|
+
- 'lib/ta/candles.rb'
|
91
|
+
- 'lib/ta/indicators.rb'
|
92
|
+
- 'lib/ta/technical_analysis.rb'
|
93
|
+
|
94
|
+
# Offense count: 52
|
95
|
+
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
96
|
+
Metrics/MethodLength:
|
97
|
+
Exclude:
|
98
|
+
- 'bin/ta_strategy.rb'
|
99
|
+
- 'bin/ws_feed_test.rb'
|
100
|
+
- 'lib/DhanHQ/core/base_model.rb'
|
101
|
+
- 'lib/DhanHQ/helpers/response_helper.rb'
|
102
|
+
- 'lib/DhanHQ/models/holding.rb'
|
103
|
+
- 'lib/DhanHQ/models/instrument.rb'
|
104
|
+
- 'lib/DhanHQ/models/ledger_entry.rb'
|
105
|
+
- 'lib/DhanHQ/models/order.rb'
|
106
|
+
- 'lib/DhanHQ/rate_limiter.rb'
|
107
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
108
|
+
- 'lib/DhanHQ/ws/decoder.rb'
|
109
|
+
- 'lib/DhanHQ/ws/orders/connection.rb'
|
110
|
+
- 'lib/DhanHQ/ws/segments.rb'
|
111
|
+
- 'lib/DhanHQ/ws/singleton_lock.rb'
|
112
|
+
- 'lib/DhanHQ/ws/websocket_packet_parser.rb'
|
113
|
+
- 'lib/dhanhq/analysis/helpers/bias_aggregator.rb'
|
114
|
+
- 'lib/dhanhq/analysis/multi_timeframe_analyzer.rb'
|
115
|
+
- 'lib/dhanhq/analysis/options_buying_advisor.rb'
|
116
|
+
- 'lib/ta/candles.rb'
|
117
|
+
- 'lib/ta/fetcher.rb'
|
118
|
+
- 'lib/ta/indicators.rb'
|
119
|
+
- 'lib/ta/technical_analysis.rb'
|
120
|
+
|
121
|
+
# Offense count: 3
|
122
|
+
# Configuration parameters: CountComments, Max, CountAsOne.
|
123
|
+
Metrics/ModuleLength:
|
124
|
+
Exclude:
|
125
|
+
- 'bin/ta_strategy.rb'
|
126
|
+
- 'lib/DhanHQ/constants.rb'
|
127
|
+
- 'lib/ta/indicators.rb'
|
128
|
+
|
129
|
+
# Offense count: 1
|
130
|
+
# Configuration parameters: Max, CountKeywordArgs, MaxOptionalParameters.
|
131
|
+
Metrics/ParameterLists:
|
132
|
+
Exclude:
|
133
|
+
- 'lib/ta/technical_analysis.rb'
|
134
|
+
|
135
|
+
# Offense count: 21
|
136
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
137
|
+
Metrics/PerceivedComplexity:
|
138
|
+
Exclude:
|
139
|
+
- 'bin/ta_strategy.rb'
|
140
|
+
- 'bin/ws_feed_test.rb'
|
141
|
+
- 'lib/DhanHQ/helpers/response_helper.rb'
|
142
|
+
- 'lib/DhanHQ/models/order.rb'
|
143
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
144
|
+
- 'lib/DhanHQ/ws/decoder.rb'
|
145
|
+
- 'lib/DhanHQ/ws/orders/connection.rb'
|
146
|
+
- 'lib/dhanhq/analysis/helpers/bias_aggregator.rb'
|
147
|
+
- 'lib/dhanhq/analysis/multi_timeframe_analyzer.rb'
|
148
|
+
- 'lib/dhanhq/analysis/options_buying_advisor.rb'
|
149
|
+
- 'lib/ta/candles.rb'
|
150
|
+
- 'lib/ta/indicators.rb'
|
151
|
+
- 'lib/ta/technical_analysis.rb'
|
152
|
+
|
153
|
+
# Offense count: 1
|
154
|
+
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
155
|
+
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
|
156
|
+
Naming/MethodParameterName:
|
157
|
+
Exclude:
|
158
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
159
|
+
|
160
|
+
# Offense count: 7
|
161
|
+
# Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
|
162
|
+
# AllowedMethods: call
|
163
|
+
# WaywardPredicates: nonzero?
|
164
|
+
Naming/PredicateMethod:
|
165
|
+
Exclude:
|
166
|
+
- 'lib/DhanHQ/models/forever_order.rb'
|
167
|
+
- 'lib/DhanHQ/models/order.rb'
|
168
|
+
- 'lib/DhanHQ/models/super_order.rb'
|
169
|
+
- 'lib/DhanHQ/ws/singleton_lock.rb'
|
170
|
+
|
171
|
+
# Offense count: 5
|
172
|
+
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
|
173
|
+
# SupportedStyles: snake_case, normalcase, non_integer
|
174
|
+
# AllowedIdentifiers: TLS1_1, TLS1_2, capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
|
175
|
+
Naming/VariableNumber:
|
176
|
+
Exclude:
|
177
|
+
- 'lib/DhanHQ/ws/connection.rb'
|
178
|
+
- 'lib/DhanHQ/ws/orders/connection.rb'
|
179
|
+
|
180
|
+
# Offense count: 3
|
181
|
+
# Configuration parameters: MinSize.
|
182
|
+
Performance/CollectionLiteralInLoop:
|
183
|
+
Exclude:
|
184
|
+
- 'lib/dhanhq/analysis/multi_timeframe_analyzer.rb'
|
185
|
+
- 'lib/ta/fetcher.rb'
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [2.1.5] - 2025-01-27
|
4
|
+
|
5
|
+
### ⚠️ BREAKING CHANGES
|
6
|
+
- **Changed require statement**: `require 'DhanHQ'` → `require 'dhan_hq'`
|
7
|
+
- This affects all Ruby files that require the gem
|
8
|
+
- Update all `require 'DhanHQ'` statements to `require 'dhan_hq'` in your codebase
|
9
|
+
- The gem name remains `DhanHQ` in your Gemfile, only the require statement changes
|
10
|
+
|
11
|
+
### Added
|
12
|
+
- **OptionChain validation**: Added proper parameter validation for `OptionChain.fetch` and `OptionChain.fetch_expiry_list` methods
|
13
|
+
- `OptionChain.fetch` requires `underlying_scrip`, `underlying_seg`, and `expiry` parameters
|
14
|
+
- `OptionChain.fetch_expiry_list` requires only `underlying_scrip` and `underlying_seg` parameters
|
15
|
+
- Validates exchange segments against `%w[IDX_I NSE_FNO BSE_FNO MCX_FO]`
|
16
|
+
- Validates expiry format as `YYYY-MM-DD` and ensures it's a valid date
|
17
|
+
|
18
|
+
### Fixed
|
19
|
+
- **RuboCop compliance**: Fixed all RuboCop offenses (179 → 0 offenses)
|
20
|
+
- **Documentation**: Updated all documentation examples to use `require 'dhan_hq'`
|
21
|
+
- **Code quality**: Added comprehensive validation tests for OptionChain methods
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
- **File structure**: Renamed main library file from `lib/DhanHQ.rb` to `lib/dhan_hq.rb` for better Ruby conventions
|
25
|
+
- **Require paths**: Updated all internal require statements to use snake_case naming
|
26
|
+
|
3
27
|
## [2.1.0] - 2025-09-20
|
4
28
|
|
5
29
|
- Add REST coverage for EDIS (`/edis/form`, `/edis/bulkform`, `/edis/tpin`, `/edis/inquire/{isin}`) and the account kill-switch endpoint.
|
data/GUIDE.md
CHANGED
@@ -32,7 +32,7 @@ bundle install
|
|
32
32
|
Bootstrap from environment variables:
|
33
33
|
|
34
34
|
```ruby
|
35
|
-
require '
|
35
|
+
require 'dhan_hq'
|
36
36
|
|
37
37
|
DhanHQ.configure_with_env
|
38
38
|
DhanHQ.logger.level = (ENV["DHAN_LOG_LEVEL"] || "INFO").upcase.then { |level| Logger.const_get(level) }
|
@@ -42,9 +42,9 @@ DhanHQ.logger.level = (ENV["DHAN_LOG_LEVEL"] || "INFO").upcase.then { |level| Lo
|
|
42
42
|
|
43
43
|
`configure_with_env` reads from `ENV` and raises unless both variables are set:
|
44
44
|
|
45
|
-
| Variable
|
46
|
-
|
|
47
|
-
| `CLIENT_ID`
|
45
|
+
| Variable | Description |
|
46
|
+
| -------------- | ---------------------------------------------------- |
|
47
|
+
| `CLIENT_ID` | Your Dhan trading client id. |
|
48
48
|
| `ACCESS_TOKEN` | REST/WebSocket access token generated via Dhan APIs. |
|
49
49
|
|
50
50
|
Provide them via `.env`, Rails credentials, or your secret manager of choice
|
@@ -55,14 +55,14 @@ before the initializer runs.
|
|
55
55
|
Set any of the following environment variables _before_ calling
|
56
56
|
`configure_with_env` to customise runtime behaviour:
|
57
57
|
|
58
|
-
| Variable
|
59
|
-
|
|
60
|
-
| `DHAN_LOG_LEVEL`
|
61
|
-
| `DHAN_BASE_URL`
|
62
|
-
| `DHAN_WS_VERSION`
|
63
|
-
| `DHAN_WS_ORDER_URL`
|
64
|
-
| `DHAN_WS_USER_TYPE`
|
65
|
-
| `DHAN_PARTNER_ID` / `DHAN_PARTNER_SECRET` | Required when streaming as a partner.
|
58
|
+
| Variable | Purpose |
|
59
|
+
| ----------------------------------------- | ---------------------------------------------------- |
|
60
|
+
| `DHAN_LOG_LEVEL` | Change logger verbosity (`INFO` default). |
|
61
|
+
| `DHAN_BASE_URL` | Override the REST API host. |
|
62
|
+
| `DHAN_WS_VERSION` | Target a specific WebSocket API version. |
|
63
|
+
| `DHAN_WS_ORDER_URL` | Customise the order update WebSocket endpoint. |
|
64
|
+
| `DHAN_WS_USER_TYPE` | Toggle between `SELF` and `PARTNER` streaming modes. |
|
65
|
+
| `DHAN_PARTNER_ID` / `DHAN_PARTNER_SECRET` | Required when streaming as a partner. |
|
66
66
|
|
67
67
|
---
|
68
68
|
|
@@ -106,32 +106,32 @@ order.refresh
|
|
106
106
|
|
107
107
|
Required fields validated by `DhanHQ::Contracts::PlaceOrderContract`:
|
108
108
|
|
109
|
-
| Key
|
110
|
-
|
|
111
|
-
| `transaction_type
|
112
|
-
| `exchange_segment
|
113
|
-
| `product_type`
|
114
|
-
| `order_type`
|
115
|
-
| `validity`
|
116
|
-
| `security_id`
|
117
|
-
| `quantity`
|
109
|
+
| Key | Type | Allowed Values / Notes |
|
110
|
+
| ------------------ | ------- | -------------------------------------------------- |
|
111
|
+
| `transaction_type` | String | `BUY`, `SELL` |
|
112
|
+
| `exchange_segment` | String | Use `DhanHQ::Constants::EXCHANGE_SEGMENTS` |
|
113
|
+
| `product_type` | String | `CNC`, `INTRADAY`, `MARGIN`, `MTF`, `CO`, `BO` |
|
114
|
+
| `order_type` | String | `LIMIT`, `MARKET`, `STOP_LOSS`, `STOP_LOSS_MARKET` |
|
115
|
+
| `validity` | String | `DAY`, `IOC` |
|
116
|
+
| `security_id` | String | Security identifier from the scrip master |
|
117
|
+
| `quantity` | Integer | Must be > 0 |
|
118
118
|
|
119
119
|
Optional fields and special rules:
|
120
120
|
|
121
|
-
| Key
|
122
|
-
|
|
123
|
-
| `correlation_id`
|
124
|
-
| `disclosed_quantity`
|
125
|
-
| `trading_symbol`
|
126
|
-
| `price`
|
127
|
-
| `trigger_price`
|
128
|
-
| `after_market_order`
|
129
|
-
| `amo_time`
|
130
|
-
| `bo_profit_value`
|
131
|
-
| `bo_stop_loss_value`
|
132
|
-
| `drv_expiry_date`
|
133
|
-
| `drv_option_type`
|
134
|
-
| `drv_strike_price`
|
121
|
+
| Key | Type | Notes |
|
122
|
+
| -------------------- | ------- | --------------------------------------------------------------------------------- |
|
123
|
+
| `correlation_id` | String | ≤ 25 chars; useful for idempotency |
|
124
|
+
| `disclosed_quantity` | Integer | ≥ 0 and ≤ 30% of `quantity` |
|
125
|
+
| `trading_symbol` | String | Optional label |
|
126
|
+
| `price` | Float | Mandatory for `LIMIT` |
|
127
|
+
| `trigger_price` | Float | Mandatory for SL / SLM |
|
128
|
+
| `after_market_order` | Boolean | Require `amo_time` when true |
|
129
|
+
| `amo_time` | String | `OPEN`, `OPEN_30`, `OPEN_60` (check `DhanHQ::Constants::AMO_TIMINGS` for updates) |
|
130
|
+
| `bo_profit_value` | Float | Required with `product_type: "BO"` |
|
131
|
+
| `bo_stop_loss_value` | Float | Required with `product_type: "BO"` |
|
132
|
+
| `drv_expiry_date` | String | Pass ISO `YYYY-MM-DD` for derivatives |
|
133
|
+
| `drv_option_type` | String | `CALL`, `PUT`, `NA` |
|
134
|
+
| `drv_strike_price` | Float | > 0 |
|
135
135
|
|
136
136
|
Example:
|
137
137
|
|
@@ -335,15 +335,15 @@ Both endpoints return arrays and skip validation because they represent historic
|
|
335
335
|
|
336
336
|
`DhanHQ::Models::HistoricalData` enforces `HistoricalDataContract` before delegating to `/v2/charts`.
|
337
337
|
|
338
|
-
| Key | Type
|
339
|
-
| ------------------ |
|
340
|
-
| `security_id` | String
|
341
|
-
| `exchange_segment` | String
|
342
|
-
| `instrument` | String
|
343
|
-
| `from_date` | String
|
344
|
-
| `to_date` | String
|
345
|
-
| `expiry_code` | Integer| Optional (`0`, `1`, `2`)
|
346
|
-
| `interval` | String
|
338
|
+
| Key | Type | Notes |
|
339
|
+
| ------------------ | ------- | -------------------------------------------------- |
|
340
|
+
| `security_id` | String | Required |
|
341
|
+
| `exchange_segment` | String | See `EXCHANGE_SEGMENTS` |
|
342
|
+
| `instrument` | String | Use `DhanHQ::Constants::INSTRUMENTS` |
|
343
|
+
| `from_date` | String | `YYYY-MM-DD` |
|
344
|
+
| `to_date` | String | `YYYY-MM-DD` |
|
345
|
+
| `expiry_code` | Integer | Optional (`0`, `1`, `2`) |
|
346
|
+
| `interval` | String | Optional (`1`, `5`, `15`, `25`, `60`) for intraday |
|
347
347
|
|
348
348
|
```ruby
|
349
349
|
bars = DhanHQ::Models::HistoricalData.intraday(
|
data/README.md
CHANGED
@@ -7,6 +7,26 @@ A clean Ruby client for **Dhan API v2** with ORM-like models (Orders, Positions,
|
|
7
7
|
* REST coverage: Orders, Super Orders, Forever Orders, Trades, Positions, Holdings, Funds/Margin, HistoricalData, OptionChain, MarketFeed
|
8
8
|
* **WebSocket**: subscribe/unsubscribe dynamically, auto-reconnect with backoff, 429 cool-off, idempotent subs, header+payload binary parsing, normalized ticks
|
9
9
|
|
10
|
+
## ⚠️ BREAKING CHANGE NOTICE
|
11
|
+
|
12
|
+
**IMPORTANT**: Starting from version 2.1.5, the require statement has changed:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# OLD (deprecated)
|
16
|
+
require 'DhanHQ'
|
17
|
+
|
18
|
+
# NEW (current)
|
19
|
+
require 'dhan_hq'
|
20
|
+
```
|
21
|
+
|
22
|
+
**Migration**: Update all your `require 'DhanHQ'` statements to `require 'dhan_hq'` in your codebase. This change affects:
|
23
|
+
- All Ruby files that require the gem
|
24
|
+
- Documentation examples
|
25
|
+
- Scripts and automation tools
|
26
|
+
- Rails applications using this gem
|
27
|
+
|
28
|
+
The gem name remains `DhanHQ` in your Gemfile, only the require statement changes.
|
29
|
+
|
10
30
|
---
|
11
31
|
|
12
32
|
## Installation
|
@@ -36,7 +56,7 @@ gem install DhanHQ
|
|
36
56
|
### From ENV / .env
|
37
57
|
|
38
58
|
```ruby
|
39
|
-
require '
|
59
|
+
require 'dhan_hq'
|
40
60
|
|
41
61
|
DhanHQ.configure_with_env
|
42
62
|
DhanHQ.logger.level = (ENV["DHAN_LOG_LEVEL"] || "INFO").upcase.then { |level| Logger.const_get(level) }
|
@@ -44,9 +64,9 @@ DhanHQ.logger.level = (ENV["DHAN_LOG_LEVEL"] || "INFO").upcase.then { |level| Lo
|
|
44
64
|
|
45
65
|
**Minimum environment variables**
|
46
66
|
|
47
|
-
| Variable
|
48
|
-
|
|
49
|
-
| `CLIENT_ID`
|
67
|
+
| Variable | Purpose |
|
68
|
+
| -------------- | ------------------------------------------------- |
|
69
|
+
| `CLIENT_ID` | Trading account client id issued by Dhan. |
|
50
70
|
| `ACCESS_TOKEN` | API access token generated from the Dhan console. |
|
51
71
|
|
52
72
|
`configure_with_env` raises if either value is missing. Load them via `dotenv`,
|
@@ -58,14 +78,14 @@ initialisation.
|
|
58
78
|
Set these variables _before_ calling `configure_with_env` when you need to
|
59
79
|
override defaults supplied by the gem:
|
60
80
|
|
61
|
-
| Variable
|
62
|
-
|
|
63
|
-
| `DHAN_LOG_LEVEL`
|
64
|
-
| `DHAN_BASE_URL`
|
65
|
-
| `DHAN_WS_VERSION`
|
66
|
-
| `DHAN_WS_ORDER_URL`
|
67
|
-
| `DHAN_WS_USER_TYPE`
|
68
|
-
| `DHAN_PARTNER_ID` / `DHAN_PARTNER_SECRET` | Required when `DHAN_WS_USER_TYPE=PARTNER`.
|
81
|
+
| Variable | When to use |
|
82
|
+
| ----------------------------------------- | ---------------------------------------------------- |
|
83
|
+
| `DHAN_LOG_LEVEL` | Adjust logger verbosity (`INFO` by default). |
|
84
|
+
| `DHAN_BASE_URL` | Point REST calls to a different API hostname. |
|
85
|
+
| `DHAN_WS_VERSION` | Pin to a specific WebSocket API version. |
|
86
|
+
| `DHAN_WS_ORDER_URL` | Override the order update WebSocket endpoint. |
|
87
|
+
| `DHAN_WS_USER_TYPE` | Switch between `SELF` and `PARTNER` streaming modes. |
|
88
|
+
| `DHAN_PARTNER_ID` / `DHAN_PARTNER_SECRET` | Required when `DHAN_WS_USER_TYPE=PARTNER`. |
|
69
89
|
|
70
90
|
### Logging
|
71
91
|
|
@@ -155,7 +175,7 @@ initializers, service objects, workers, and ActionCable wiring tailored for the
|
|
155
175
|
### Start, subscribe, stop
|
156
176
|
|
157
177
|
```ruby
|
158
|
-
require '
|
178
|
+
require 'dhan_hq'
|
159
179
|
|
160
180
|
DhanHQ.configure_with_env
|
161
181
|
DhanHQ.logger.level = (ENV["DHAN_LOG_LEVEL"] || "INFO").upcase.then { |level| Logger.const_get(level) }
|
@@ -215,7 +235,7 @@ Receive live updates whenever your orders transition between states (placed →
|
|
215
235
|
### Standalone Ruby script
|
216
236
|
|
217
237
|
```ruby
|
218
|
-
require '
|
238
|
+
require 'dhan_hq'
|
219
239
|
|
220
240
|
DhanHQ.configure_with_env
|
221
241
|
DhanHQ.logger.level = (ENV["DHAN_LOG_LEVEL"] || "INFO").upcase.then { |level| Logger.const_get(level) }
|
@@ -461,3 +481,9 @@ PRs welcome! Please include tests for new packet decoders and WS behaviors (chun
|
|
461
481
|
## License
|
462
482
|
|
463
483
|
MIT.
|
484
|
+
|
485
|
+
## Technical Analysis (Indicators + Multi-Timeframe)
|
486
|
+
|
487
|
+
See the guide for computing indicators and aggregating cross-timeframe bias:
|
488
|
+
|
489
|
+
- docs/technical_analysis.md
|
data/docs/rails_integration.md
CHANGED
@@ -53,7 +53,7 @@ environment variables (Rails credentials can be copied into ENV on boot):
|
|
53
53
|
|
54
54
|
```ruby
|
55
55
|
# config/initializers/dhanhq.rb
|
56
|
-
require '
|
56
|
+
require 'dhan_hq'
|
57
57
|
|
58
58
|
if (creds = Rails.application.credentials.dig(:dhanhq))
|
59
59
|
ENV['CLIENT_ID'] ||= creds[:client_id]
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# Technical Analysis Guide
|
2
|
+
|
3
|
+
This guide explains how to use the technical analysis modules bundled with this gem: fetching historical OHLC, computing indicators, and producing multi-timeframe summaries.
|
4
|
+
|
5
|
+
## Modules Overview
|
6
|
+
|
7
|
+
- `TA::TechnicalAnalysis`: Fetches intraday OHLC (1/5/15/25/60) from Dhan APIs with throttling/backoff, computes RSI/MACD/ADX/ATR, and returns a structured indicators hash.
|
8
|
+
- `TA::Indicators`: Adapters for `ruby-technical-analysis` and `technical-analysis` gems, including safe fallbacks.
|
9
|
+
- `TA::Candles`: Utilities for converting API series to candles and resampling (used for offline data only).
|
10
|
+
- `TA::Fetcher`: Handles API calls, 90-day windowing, throttling, and retries.
|
11
|
+
- `DhanHQ::Analysis::MultiTimeframeAnalyzer`: Consumes the indicator hash and outputs a consolidated bias summary across timeframes.
|
12
|
+
|
13
|
+
## Prerequisites
|
14
|
+
|
15
|
+
- Environment variables set: `CLIENT_ID`, `ACCESS_TOKEN`
|
16
|
+
- Optional indicator gems:
|
17
|
+
- `gem install ruby-technical-analysis technical-analysis`
|
18
|
+
|
19
|
+
## Quick Start: Compute Indicators
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require "dhan_hq"
|
23
|
+
require "ta"
|
24
|
+
|
25
|
+
DhanHQ.configure_with_env
|
26
|
+
|
27
|
+
ta = TA::TechnicalAnalysis.new(throttle_seconds: 2.5, max_retries: 3)
|
28
|
+
indicators = ta.compute(
|
29
|
+
exchange_segment: "NSE_EQ",
|
30
|
+
instrument: "EQUITY",
|
31
|
+
security_id: "1333",
|
32
|
+
intervals: [1, 5, 15, 25, 60] # each fetched directly from API
|
33
|
+
)
|
34
|
+
```
|
35
|
+
|
36
|
+
Output structure:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
{
|
40
|
+
meta: { exchange_segment: "...", instrument: "...", security_id: "...", from_date: "YYYY-MM-DD", to_date: "YYYY-MM-DD" },
|
41
|
+
indicators: {
|
42
|
+
m1: { rsi: Float|nil, adx: Float|nil, atr: Float|nil, macd: { macd: Float|nil, signal: Float|nil, hist: Float|nil } },
|
43
|
+
m5: { ... },
|
44
|
+
m15: { ... },
|
45
|
+
m25: { ... },
|
46
|
+
m60: { ... }
|
47
|
+
}
|
48
|
+
}
|
49
|
+
```
|
50
|
+
|
51
|
+
Notes:
|
52
|
+
- `to_date` defaults to today-or-last-trading-day via `TA::MarketCalendar`.
|
53
|
+
- If `days_back` is not provided, the class auto-selects a sufficient lookback (trading days) per the selected intervals and indicator periods (max of [2×ADX, MACD slow, RSI+1, ATR+1]).
|
54
|
+
- Requests are throttled with jitter; rate-limit errors trigger exponential backoff.
|
55
|
+
|
56
|
+
## Offline Input (JSON OHLC)
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
raw = JSON.parse(File.read("ohlc.json"))
|
60
|
+
indicators = TA::TechnicalAnalysis.new.compute_from_file(
|
61
|
+
path: "ohlc.json", base_interval: 1, intervals: [1,5,15,25,60]
|
62
|
+
)
|
63
|
+
```
|
64
|
+
|
65
|
+
## Analyze Multi-Timeframe Bias
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
require "DhanHQ"
|
69
|
+
|
70
|
+
analyzer = DhanHQ::Analysis::MultiTimeframeAnalyzer.new(data: indicators)
|
71
|
+
summary = analyzer.call
|
72
|
+
```
|
73
|
+
|
74
|
+
Example summary:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
{
|
78
|
+
meta: { security_id: "1333", instrument: "EQUITY", exchange_segment: "NSE_EQ" },
|
79
|
+
summary: {
|
80
|
+
bias: :bullish, # :bullish | :bearish | :neutral
|
81
|
+
setup: :buy_on_dip, # :buy_on_dip | :sell_on_rise | :range_trade
|
82
|
+
confidence: 0.78, # 0.0..1.0 weighted across timeframes
|
83
|
+
rationale: {
|
84
|
+
rsi: "Upward momentum across M5–M60",
|
85
|
+
macd: "MACD bullish signals dominant",
|
86
|
+
adx: "Strong higher timeframe trend",
|
87
|
+
atr: "Volatility expansion"
|
88
|
+
},
|
89
|
+
trend_strength: {
|
90
|
+
short_term: :weak_bullish,
|
91
|
+
medium_term: :neutral_to_bullish,
|
92
|
+
long_term: :strong_bullish
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
```
|
97
|
+
|
98
|
+
## CLI Script
|
99
|
+
|
100
|
+
A convenience script exists at `bin/ta_strategy.rb` to compute indicators and print JSON. Example:
|
101
|
+
|
102
|
+
```bash
|
103
|
+
./bin/ta_strategy.rb --segment NSE_EQ --instrument EQUITY --security-id 1333 \
|
104
|
+
--from 2025-10-06 --to 2025-10-07 --debug
|
105
|
+
```
|
106
|
+
|
107
|
+
Options:
|
108
|
+
- `--print-creds` to verify env
|
109
|
+
- `--data-file` to compute from JSON instead of API
|
110
|
+
- `--interval` (with `--data-file`) to specify base file interval
|
111
|
+
- `--rsi`, `--atr`, `--adx`, `--macd` to tune periods
|
112
|
+
|
113
|
+
## Options Buying Advisor CLI
|
114
|
+
|
115
|
+
Use `bin/options_advisor.rb` to compute indicators, summarize multi-TF bias, and produce a single index options-buying recommendation (CE/PE). If you do not provide `--spot`, the script fetches spot via MarketFeed LTP automatically.
|
116
|
+
|
117
|
+
Examples:
|
118
|
+
|
119
|
+
```bash
|
120
|
+
# Auto-fetch spot via MarketFeed.ltp and chain via OptionChain model
|
121
|
+
./bin/options_advisor.rb --segment IDX_I --instrument INDEX --security-id 13 --symbol NIFTY
|
122
|
+
|
123
|
+
# Provide pre-fetched option chain from file (JSON array of strikes)
|
124
|
+
./bin/options_advisor.rb --segment IDX_I --instrument INDEX --security-id 13 --symbol NIFTY \
|
125
|
+
--chain-file ./chain.json
|
126
|
+
|
127
|
+
# Override spot explicitly
|
128
|
+
./bin/options_advisor.rb --segment IDX_I --instrument INDEX --security-id 13 --symbol NIFTY --spot 24890
|
129
|
+
|
130
|
+
# Verbose debug logging (prints steps to STDERR; JSON output unchanged)
|
131
|
+
./bin/options_advisor.rb --segment IDX_I --instrument INDEX --security-id 13 --symbol NIFTY --debug
|
132
|
+
```
|
133
|
+
|
134
|
+
Behavior:
|
135
|
+
- Spot: when `--spot` is omitted, the script calls `DhanHQ::Models::MarketFeed.ltp({ SEG => [security_id] })` and reads `data[SEG][security_id]["last_price"]`.
|
136
|
+
- Option chain: when `--chain-file` is omitted, the advisor fetches via `DhanHQ::Models::OptionChain` (nearest expiry), transforming OC into an internal array of strikes with CE/PE legs.
|
137
|
+
- Debugging: with `--debug`, the script logs options, spot resolution, indicators meta, missing fields per timeframe, analyzer summary, and advisor output to STDERR.
|
138
|
+
|
139
|
+
## Best Practices & Tips
|
140
|
+
|
141
|
+
- Keep intervals minimal per run to reduce rate limits; increase `throttle_seconds` if needed.
|
142
|
+
- For higher intervals (e.g., 60m), ensure adequate `days_back` (auto-calculation is enabled by default).
|
143
|
+
- The analyzer is heuristic; adjust weights or thresholds as your strategy matures.
|
144
|
+
- See the advisor helpers under `lib/dhanhq/analysis/helpers/` to customize bias and moneyness rules.
|
data/lib/DhanHQ/config.rb
CHANGED
data/lib/DhanHQ/constants.rb
CHANGED
@@ -131,13 +131,11 @@ module DhanHQ
|
|
131
131
|
# Download URL for the detailed instrument master CSV.
|
132
132
|
DETAILED_CSV_URL = "https://images.dhan.co/api-data/api-scrip-master-detailed.csv"
|
133
133
|
|
134
|
-
# API
|
135
|
-
|
136
|
-
/v2/marketfeed/
|
137
|
-
/v2/marketfeed/ohlc
|
138
|
-
/v2/marketfeed/quote
|
134
|
+
# API route prefixes that require a `client-id` header in addition to the access token.
|
135
|
+
DATA_API_PREFIXES = %w[
|
136
|
+
/v2/marketfeed/
|
139
137
|
/v2/optionchain
|
140
|
-
/v2/
|
138
|
+
/v2/instrument/
|
141
139
|
].freeze
|
142
140
|
|
143
141
|
# Mapping of DhanHQ error codes to SDK error classes for consistent exception handling.
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DhanHQ
|
4
|
+
module Contracts
|
5
|
+
# Validates the exchange segment param for instrument list endpoint
|
6
|
+
class InstrumentListContract < BaseContract
|
7
|
+
params do
|
8
|
+
required(:exchange_segment).filled(:string, included_in?: EXCHANGE_SEGMENTS)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|