DhanHQ 2.4.0 → 2.6.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 +4 -4
- data/.rubocop.yml +9 -1
- data/CHANGELOG.md +103 -7
- data/GUIDE.md +57 -39
- data/README.md +198 -755
- data/docs/API_DOCS_GAPS.md +128 -0
- data/docs/API_VERIFICATION.md +10 -11
- data/{README1.md → docs/ARCHIVE_README.md} +16 -16
- data/docs/AUTHENTICATION.md +72 -10
- data/docs/CONFIGURATION.md +109 -0
- 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/SUPER_ORDERS.md +284 -0
- data/docs/{technical_analysis.md → TECHNICAL_ANALYSIS.md} +3 -3
- data/docs/TESTING_GUIDE.md +84 -82
- data/docs/TROUBLESHOOTING.md +117 -0
- data/docs/{websocket_integration.md → WEBSOCKET_INTEGRATION.md} +19 -19
- data/docs/WEBSOCKET_PROTOCOL.md +154 -0
- 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 +29 -11
- data/lib/DhanHQ/models/concerns/api_response_handler.rb +46 -0
- data/lib/DhanHQ/models/edis.rb +101 -0
- 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 +23 -11
- data/lib/DhanHQ/models/margin.rb +51 -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 +122 -0
- data/lib/DhanHQ/models/position.rb +23 -1
- data/lib/DhanHQ/models/postback.rb +114 -0
- 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 +17 -7
- data/lib/DhanHQ/resources/margin_calculator.rb +9 -0
- data/lib/DhanHQ/resources/orders.rb +41 -41
- data/lib/DhanHQ/resources/pnl_exit.rb +37 -0
- data/lib/DhanHQ/resources/positions.rb +8 -0
- 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 +29 -24
- 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/lib/DhanHQ/constants.rb
CHANGED
|
@@ -1,130 +1,412 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "errors"
|
|
4
|
+
|
|
3
5
|
module DhanHQ
|
|
4
6
|
# Enumerations and helper lookups used across the REST and WebSocket clients.
|
|
5
7
|
module Constants
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
MCX_COMM
|
|
18
|
-
IDX_I
|
|
19
|
-
].freeze
|
|
8
|
+
# Exchange segments for different markets and instruments.
|
|
9
|
+
module ExchangeSegment
|
|
10
|
+
IDX_I = "IDX_I"
|
|
11
|
+
NSE_EQ = "NSE_EQ"
|
|
12
|
+
NSE_FNO = "NSE_FNO"
|
|
13
|
+
NSE_CURRENCY = "NSE_CURRENCY"
|
|
14
|
+
NSE_COMM = "NSE_COMM"
|
|
15
|
+
BSE_EQ = "BSE_EQ"
|
|
16
|
+
MCX_COMM = "MCX_COMM"
|
|
17
|
+
BSE_CURRENCY = "BSE_CURRENCY"
|
|
18
|
+
BSE_FNO = "BSE_FNO"
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
INDEX
|
|
24
|
-
FUTIDX
|
|
25
|
-
OPTIDX
|
|
26
|
-
EQUITY
|
|
27
|
-
FUTSTK
|
|
28
|
-
OPTSTK
|
|
29
|
-
FUTCOM
|
|
30
|
-
OPTFUT
|
|
31
|
-
FUTCUR
|
|
32
|
-
OPTCUR
|
|
33
|
-
].freeze
|
|
20
|
+
ALL = [IDX_I, NSE_EQ, NSE_FNO, NSE_CURRENCY, NSE_COMM, BSE_EQ, MCX_COMM, BSE_CURRENCY, BSE_FNO].freeze
|
|
21
|
+
end
|
|
34
22
|
|
|
35
|
-
# Product types
|
|
36
|
-
|
|
37
|
-
CNC
|
|
38
|
-
INTRADAY
|
|
39
|
-
MARGIN
|
|
40
|
-
MTF
|
|
41
|
-
CO
|
|
42
|
-
BO
|
|
43
|
-
].freeze
|
|
23
|
+
# Product types for order placement.
|
|
24
|
+
module ProductType
|
|
25
|
+
CNC = "CNC"
|
|
26
|
+
INTRADAY = "INTRADAY"
|
|
27
|
+
MARGIN = "MARGIN"
|
|
28
|
+
MTF = "MTF"
|
|
29
|
+
CO = "CO"
|
|
30
|
+
BO = "BO"
|
|
44
31
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
LIMIT
|
|
48
|
-
MARKET
|
|
49
|
-
STOP_LOSS
|
|
50
|
-
STOP_LOSS_MARKET
|
|
51
|
-
].freeze
|
|
32
|
+
ALL = [CNC, INTRADAY, MARGIN, MTF, CO, BO].freeze
|
|
33
|
+
end
|
|
52
34
|
|
|
53
|
-
#
|
|
54
|
-
|
|
35
|
+
# Buy/Sell transaction types.
|
|
36
|
+
module TransactionType
|
|
37
|
+
BUY = "BUY"
|
|
38
|
+
SELL = "SELL"
|
|
55
39
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
OPEN
|
|
59
|
-
OPEN_30
|
|
60
|
-
OPEN_60
|
|
61
|
-
PRE_OPEN
|
|
62
|
-
].freeze
|
|
40
|
+
ALL = [BUY, SELL].freeze
|
|
41
|
+
end
|
|
63
42
|
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
43
|
+
# Order types for placement and modification.
|
|
44
|
+
module OrderType
|
|
45
|
+
LIMIT = "LIMIT"
|
|
46
|
+
MARKET = "MARKET"
|
|
47
|
+
STOP_LOSS = "STOP_LOSS"
|
|
48
|
+
STOP_LOSS_MARKET = "STOP_LOSS_MARKET"
|
|
49
|
+
|
|
50
|
+
ALL = [LIMIT, MARKET, STOP_LOSS, STOP_LOSS_MARKET].freeze
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Order validity types.
|
|
54
|
+
module Validity
|
|
55
|
+
DAY = "DAY"
|
|
56
|
+
IOC = "IOC"
|
|
57
|
+
|
|
58
|
+
ALL = [DAY, IOC].freeze
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Order lifecycle status values.
|
|
62
|
+
module OrderStatus
|
|
63
|
+
TRANSIT = "TRANSIT"
|
|
64
|
+
PENDING = "PENDING"
|
|
65
|
+
CLOSED = "CLOSED"
|
|
66
|
+
TRIGGERED = "TRIGGERED"
|
|
67
|
+
REJECTED = "REJECTED"
|
|
68
|
+
CANCELLED = "CANCELLED"
|
|
69
|
+
PART_TRADED = "PART_TRADED"
|
|
70
|
+
TRADED = "TRADED"
|
|
71
|
+
EXPIRED = "EXPIRED"
|
|
72
|
+
MODIFIED = "MODIFIED"
|
|
73
|
+
|
|
74
|
+
ALL = [TRANSIT, PENDING, CLOSED, TRIGGERED, REJECTED, CANCELLED, PART_TRADED, TRADED, EXPIRED, MODIFIED].freeze
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# AMO (after market order) timing options.
|
|
78
|
+
module AmoTime
|
|
79
|
+
PRE_OPEN = "PRE_OPEN"
|
|
80
|
+
OPEN = "OPEN"
|
|
81
|
+
OPEN_30 = "OPEN_30"
|
|
82
|
+
OPEN_60 = "OPEN_60"
|
|
83
|
+
|
|
84
|
+
ALL = [PRE_OPEN, OPEN, OPEN_30, OPEN_60].freeze
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Expiry codes for futures and options.
|
|
88
|
+
module ExpiryCode
|
|
89
|
+
CURRENT = 0
|
|
90
|
+
NEXT = 1
|
|
91
|
+
FAR = 2
|
|
92
|
+
|
|
93
|
+
ALL = [CURRENT, NEXT, FAR].freeze
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Instrument types across exchanges.
|
|
97
|
+
module InstrumentType
|
|
98
|
+
INDEX = "INDEX"
|
|
99
|
+
FUTIDX = "FUTIDX"
|
|
100
|
+
OPTIDX = "OPTIDX"
|
|
101
|
+
EQUITY = "EQUITY"
|
|
102
|
+
FUTSTK = "FUTSTK"
|
|
103
|
+
OPTSTK = "OPTSTK"
|
|
104
|
+
FUTCOM = "FUTCOM"
|
|
105
|
+
OPTFUT = "OPTFUT"
|
|
106
|
+
FUTCUR = "FUTCUR"
|
|
107
|
+
OPTCUR = "OPTCUR"
|
|
108
|
+
|
|
109
|
+
ALL = [INDEX, FUTIDX, OPTIDX, EQUITY, FUTSTK, OPTSTK, FUTCOM, OPTFUT, FUTCUR, OPTCUR].freeze
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Backward-compatible alias kept for existing SDK usage.
|
|
113
|
+
Instrument = InstrumentType
|
|
114
|
+
|
|
115
|
+
# Option types for derivatives trading.
|
|
116
|
+
module OptionType
|
|
117
|
+
CALL = "CALL"
|
|
118
|
+
PUT = "PUT"
|
|
119
|
+
|
|
120
|
+
ALL = [CALL, PUT].freeze
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Leg names used in BO/CO/Super/Forever orders.
|
|
124
|
+
module LegName
|
|
125
|
+
ENTRY_LEG = "ENTRY_LEG"
|
|
126
|
+
TARGET_LEG = "TARGET_LEG"
|
|
127
|
+
STOP_LOSS_LEG = "STOP_LOSS_LEG"
|
|
128
|
+
|
|
129
|
+
ALL = [ENTRY_LEG, TARGET_LEG, STOP_LOSS_LEG].freeze
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Order flags for Forever Orders.
|
|
133
|
+
module OrderFlag
|
|
134
|
+
SINGLE = "SINGLE"
|
|
135
|
+
OCO = "OCO"
|
|
136
|
+
|
|
137
|
+
ALL = [SINGLE, OCO].freeze
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Position types for position conversion.
|
|
141
|
+
module PositionType
|
|
142
|
+
LONG = "LONG"
|
|
143
|
+
SHORT = "SHORT"
|
|
144
|
+
|
|
145
|
+
ALL = [LONG, SHORT].freeze
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Feed request codes for Live Market Feed WebSocket.
|
|
149
|
+
module FeedRequest
|
|
150
|
+
CONNECT = 11
|
|
151
|
+
DISCONNECT = 12
|
|
152
|
+
SUBSCRIBE_TICKER = 15
|
|
153
|
+
UNSUBSCRIBE_TICKER = 16
|
|
154
|
+
SUBSCRIBE_QUOTE = 17
|
|
155
|
+
UNSUBSCRIBE_QUOTE = 18
|
|
156
|
+
SUBSCRIBE_FULL = 21
|
|
157
|
+
UNSUBSCRIBE_FULL = 22
|
|
158
|
+
SUBSCRIBE_DEPTH = 23
|
|
159
|
+
UNSUBSCRIBE_DEPTH = 24
|
|
160
|
+
|
|
161
|
+
ALL = [
|
|
162
|
+
CONNECT,
|
|
163
|
+
DISCONNECT,
|
|
164
|
+
SUBSCRIBE_TICKER,
|
|
165
|
+
UNSUBSCRIBE_TICKER,
|
|
166
|
+
SUBSCRIBE_QUOTE,
|
|
167
|
+
UNSUBSCRIBE_QUOTE,
|
|
168
|
+
SUBSCRIBE_FULL,
|
|
169
|
+
UNSUBSCRIBE_FULL,
|
|
170
|
+
SUBSCRIBE_DEPTH,
|
|
171
|
+
UNSUBSCRIBE_DEPTH
|
|
172
|
+
].freeze
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Feed response codes for Live Market Feed WebSocket.
|
|
176
|
+
module FeedResponse
|
|
177
|
+
INDEX_PACKET = 1
|
|
178
|
+
TICKER_PACKET = 2
|
|
179
|
+
QUOTE_PACKET = 4
|
|
180
|
+
OI_PACKET = 5
|
|
181
|
+
PREV_CLOSE_PACKET = 6
|
|
182
|
+
MARKET_STATUS_PACKET = 7
|
|
183
|
+
FULL_PACKET = 8
|
|
184
|
+
FEED_DISCONNECT = 50
|
|
185
|
+
|
|
186
|
+
ALL = [
|
|
187
|
+
INDEX_PACKET,
|
|
188
|
+
TICKER_PACKET,
|
|
189
|
+
QUOTE_PACKET,
|
|
190
|
+
OI_PACKET,
|
|
191
|
+
PREV_CLOSE_PACKET,
|
|
192
|
+
MARKET_STATUS_PACKET,
|
|
193
|
+
FULL_PACKET,
|
|
194
|
+
FEED_DISCONNECT
|
|
195
|
+
].freeze
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Comparison types for conditional trigger alerts.
|
|
199
|
+
module ComparisonType
|
|
200
|
+
TECHNICAL_WITH_VALUE = "TECHNICAL_WITH_VALUE"
|
|
201
|
+
TECHNICAL_WITH_INDICATOR = "TECHNICAL_WITH_INDICATOR"
|
|
202
|
+
TECHNICAL_WITH_CLOSE = "TECHNICAL_WITH_CLOSE"
|
|
203
|
+
PRICE_WITH_VALUE = "PRICE_WITH_VALUE"
|
|
204
|
+
|
|
205
|
+
ALL = [
|
|
206
|
+
TECHNICAL_WITH_VALUE,
|
|
207
|
+
TECHNICAL_WITH_INDICATOR,
|
|
208
|
+
TECHNICAL_WITH_CLOSE,
|
|
209
|
+
PRICE_WITH_VALUE
|
|
210
|
+
].freeze
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Technical indicators for conditional triggers.
|
|
214
|
+
module IndicatorName
|
|
215
|
+
SMA_5 = "SMA_5"
|
|
216
|
+
SMA_10 = "SMA_10"
|
|
217
|
+
SMA_20 = "SMA_20"
|
|
218
|
+
SMA_50 = "SMA_50"
|
|
219
|
+
SMA_100 = "SMA_100"
|
|
220
|
+
SMA_200 = "SMA_200"
|
|
221
|
+
|
|
222
|
+
EMA_5 = "EMA_5"
|
|
223
|
+
EMA_10 = "EMA_10"
|
|
224
|
+
EMA_20 = "EMA_20"
|
|
225
|
+
EMA_50 = "EMA_50"
|
|
226
|
+
EMA_100 = "EMA_100"
|
|
227
|
+
EMA_200 = "EMA_200"
|
|
228
|
+
|
|
229
|
+
BB_UPPER = "BB_UPPER"
|
|
230
|
+
BB_LOWER = "BB_LOWER"
|
|
231
|
+
RSI_14 = "RSI_14"
|
|
232
|
+
ATR_14 = "ATR_14"
|
|
233
|
+
STOCHASTIC = "STOCHASTIC"
|
|
234
|
+
STOCHRSI_14 = "STOCHRSI_14"
|
|
235
|
+
MACD_26 = "MACD_26"
|
|
236
|
+
MACD_12 = "MACD_12"
|
|
237
|
+
MACD_HIST = "MACD_HIST"
|
|
238
|
+
|
|
239
|
+
ALL = [
|
|
240
|
+
SMA_5,
|
|
241
|
+
SMA_10,
|
|
242
|
+
SMA_20,
|
|
243
|
+
SMA_50,
|
|
244
|
+
SMA_100,
|
|
245
|
+
SMA_200,
|
|
246
|
+
EMA_5,
|
|
247
|
+
EMA_10,
|
|
248
|
+
EMA_20,
|
|
249
|
+
EMA_50,
|
|
250
|
+
EMA_100,
|
|
251
|
+
EMA_200,
|
|
252
|
+
BB_UPPER,
|
|
253
|
+
BB_LOWER,
|
|
254
|
+
RSI_14,
|
|
255
|
+
ATR_14,
|
|
256
|
+
STOCHASTIC,
|
|
257
|
+
STOCHRSI_14,
|
|
258
|
+
MACD_26,
|
|
259
|
+
MACD_12,
|
|
260
|
+
MACD_HIST
|
|
261
|
+
].freeze
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Operators for conditional trigger comparisons.
|
|
265
|
+
module Operator
|
|
266
|
+
CROSSING_UP = "CROSSING_UP"
|
|
267
|
+
CROSSING_DOWN = "CROSSING_DOWN"
|
|
268
|
+
CROSSING_ANY_SIDE = "CROSSING_ANY_SIDE"
|
|
269
|
+
GREATER_THAN = "GREATER_THAN"
|
|
270
|
+
LESS_THAN = "LESS_THAN"
|
|
271
|
+
GREATER_THAN_EQUAL = "GREATER_THAN_EQUAL"
|
|
272
|
+
LESS_THAN_EQUAL = "LESS_THAN_EQUAL"
|
|
273
|
+
EQUAL = "EQUAL"
|
|
274
|
+
NOT_EQUAL = "NOT_EQUAL"
|
|
275
|
+
|
|
276
|
+
ALL = [
|
|
277
|
+
CROSSING_UP,
|
|
278
|
+
CROSSING_DOWN,
|
|
279
|
+
CROSSING_ANY_SIDE,
|
|
280
|
+
GREATER_THAN,
|
|
281
|
+
LESS_THAN,
|
|
282
|
+
GREATER_THAN_EQUAL,
|
|
283
|
+
LESS_THAN_EQUAL,
|
|
284
|
+
EQUAL,
|
|
285
|
+
NOT_EQUAL
|
|
286
|
+
].freeze
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Status values for conditional trigger alerts.
|
|
290
|
+
module TriggerStatus
|
|
291
|
+
ACTIVE = "ACTIVE"
|
|
292
|
+
TRIGGERED = "TRIGGERED"
|
|
293
|
+
EXPIRED = "EXPIRED"
|
|
294
|
+
CANCELLED = "CANCELLED"
|
|
295
|
+
|
|
296
|
+
ALL = [ACTIVE, TRIGGERED, EXPIRED, CANCELLED].freeze
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# Trading API error codes (DH-900 series).
|
|
300
|
+
module TradingErrorCode
|
|
301
|
+
INVALID_AUTHENTICATION = "DH-901"
|
|
302
|
+
INVALID_ACCESS = "DH-902"
|
|
303
|
+
USER_ACCOUNT = "DH-903"
|
|
304
|
+
RATE_LIMIT = "DH-904"
|
|
305
|
+
INPUT_EXCEPTION = "DH-905"
|
|
306
|
+
ORDER_ERROR = "DH-906"
|
|
307
|
+
DATA_ERROR = "DH-907"
|
|
308
|
+
INTERNAL_SERVER_ERROR = "DH-908"
|
|
309
|
+
NETWORK_ERROR = "DH-909"
|
|
310
|
+
OTHERS = "DH-910"
|
|
311
|
+
NO_HOLDINGS = "DH-1111"
|
|
312
|
+
|
|
313
|
+
ALL = [
|
|
314
|
+
INVALID_AUTHENTICATION,
|
|
315
|
+
INVALID_ACCESS,
|
|
316
|
+
USER_ACCOUNT,
|
|
317
|
+
RATE_LIMIT,
|
|
318
|
+
INPUT_EXCEPTION,
|
|
319
|
+
ORDER_ERROR,
|
|
320
|
+
DATA_ERROR,
|
|
321
|
+
INTERNAL_SERVER_ERROR,
|
|
322
|
+
NETWORK_ERROR,
|
|
323
|
+
OTHERS,
|
|
324
|
+
NO_HOLDINGS
|
|
325
|
+
].freeze
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# Data API error codes (800 series).
|
|
329
|
+
module DataErrorCode
|
|
330
|
+
INTERNAL_SERVER_ERROR = 800
|
|
331
|
+
INSTRUMENTS_LIMIT = 804
|
|
332
|
+
TOO_MANY_REQUESTS = 805
|
|
333
|
+
NOT_SUBSCRIBED = 806
|
|
334
|
+
TOKEN_EXPIRED = 807
|
|
335
|
+
AUTH_FAILED = 808
|
|
336
|
+
INVALID_TOKEN = 809
|
|
337
|
+
INVALID_CLIENT_ID = 810
|
|
338
|
+
INVALID_EXPIRY_DATE = 811
|
|
339
|
+
INVALID_DATE_FORMAT = 812
|
|
340
|
+
INVALID_SECURITY_ID = 813
|
|
341
|
+
INVALID_REQUEST = 814
|
|
342
|
+
|
|
343
|
+
ALL = [
|
|
344
|
+
INTERNAL_SERVER_ERROR,
|
|
345
|
+
INSTRUMENTS_LIMIT,
|
|
346
|
+
TOO_MANY_REQUESTS,
|
|
347
|
+
NOT_SUBSCRIBED,
|
|
348
|
+
TOKEN_EXPIRED,
|
|
349
|
+
AUTH_FAILED,
|
|
350
|
+
INVALID_TOKEN,
|
|
351
|
+
INVALID_CLIENT_ID,
|
|
352
|
+
INVALID_EXPIRY_DATE,
|
|
353
|
+
INVALID_DATE_FORMAT,
|
|
354
|
+
INVALID_SECURITY_ID,
|
|
355
|
+
INVALID_REQUEST
|
|
356
|
+
].freeze
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Public rate limits published in DhanHQ API documentation.
|
|
360
|
+
module RateLimit
|
|
361
|
+
ORDER_API = { per_second: 10, per_minute: 250, per_hour: 1000, per_day: 7000 }.freeze
|
|
362
|
+
DATA_API = { per_second: 5, per_day: 100_000 }.freeze
|
|
363
|
+
QUOTE_API = { per_second: 1 }.freeze
|
|
364
|
+
NON_TRADING_API = { per_second: 20 }.freeze
|
|
365
|
+
ORDER_MODIFICATIONS_PER_ORDER = 25
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Backward-compatible arrays used across existing validations.
|
|
369
|
+
TRANSACTION_TYPES = TransactionType::ALL
|
|
370
|
+
EXCHANGE_SEGMENTS = ExchangeSegment::ALL
|
|
371
|
+
INSTRUMENTS = InstrumentType::ALL
|
|
372
|
+
PRODUCT_TYPES = ProductType::ALL
|
|
373
|
+
ORDER_TYPES = OrderType::ALL
|
|
374
|
+
VALIDITY_TYPES = Validity::ALL
|
|
375
|
+
AMO_TIMINGS = AmoTime::ALL
|
|
376
|
+
ORDER_STATUSES = OrderStatus::ALL
|
|
377
|
+
COMPARISON_TYPES = ComparisonType::ALL
|
|
378
|
+
OPERATORS = Operator::ALL
|
|
76
379
|
|
|
77
380
|
# Exchange aliases used when building subscription payloads.
|
|
78
|
-
NSE =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# National Stock Exchange futures & options segment alias.
|
|
88
|
-
NSE_FNO = "NSE_FNO"
|
|
89
|
-
# Bombay Stock Exchange futures & options segment alias.
|
|
90
|
-
BSE_FNO = "BSE_FNO"
|
|
91
|
-
# Broad index segment alias.
|
|
92
|
-
INDEX = "IDX_I"
|
|
93
|
-
|
|
94
|
-
# Segments that support option instruments.
|
|
381
|
+
NSE = ExchangeSegment::NSE_EQ
|
|
382
|
+
BSE = ExchangeSegment::BSE_EQ
|
|
383
|
+
CUR = ExchangeSegment::NSE_CURRENCY
|
|
384
|
+
MCX = ExchangeSegment::MCX_COMM
|
|
385
|
+
FNO = ExchangeSegment::NSE_FNO
|
|
386
|
+
NSE_FNO = ExchangeSegment::NSE_FNO
|
|
387
|
+
BSE_FNO = ExchangeSegment::BSE_FNO
|
|
388
|
+
INDEX = ExchangeSegment::IDX_I
|
|
389
|
+
|
|
95
390
|
OPTION_SEGMENTS = [NSE, BSE, CUR, MCX, FNO, NSE_FNO, BSE_FNO, INDEX].freeze
|
|
96
391
|
|
|
97
|
-
# Canonical
|
|
98
|
-
BUY =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
# Limit price order type.
|
|
116
|
-
LIMIT = "LIMIT"
|
|
117
|
-
# Market order type.
|
|
118
|
-
MARKET = "MARKET"
|
|
119
|
-
# Stop-loss limit order type.
|
|
120
|
-
SL = "STOP_LOSS"
|
|
121
|
-
# Stop-loss market order type.
|
|
122
|
-
SLM = "STOP_LOSS_MARKET"
|
|
123
|
-
|
|
124
|
-
# Good-for-day validity flag.
|
|
125
|
-
DAY = "DAY"
|
|
126
|
-
# Immediate-or-cancel validity flag.
|
|
127
|
-
IOC = "IOC"
|
|
392
|
+
# Canonical labels kept for compatibility with previous SDK versions.
|
|
393
|
+
BUY = TransactionType::BUY
|
|
394
|
+
SELL = TransactionType::SELL
|
|
395
|
+
|
|
396
|
+
CNC = ProductType::CNC
|
|
397
|
+
INTRA = ProductType::INTRADAY
|
|
398
|
+
MARGIN = ProductType::MARGIN
|
|
399
|
+
CO = ProductType::CO
|
|
400
|
+
BO = ProductType::BO
|
|
401
|
+
MTF = ProductType::MTF
|
|
402
|
+
|
|
403
|
+
LIMIT = OrderType::LIMIT
|
|
404
|
+
MARKET = OrderType::MARKET
|
|
405
|
+
SL = OrderType::STOP_LOSS
|
|
406
|
+
SLM = OrderType::STOP_LOSS_MARKET
|
|
407
|
+
|
|
408
|
+
DAY = Validity::DAY
|
|
409
|
+
IOC = Validity::IOC
|
|
128
410
|
|
|
129
411
|
# Download URL for the compact instrument master CSV.
|
|
130
412
|
COMPACT_CSV_URL = "https://images.dhan.co/api-data/api-scrip-master.csv"
|
|
@@ -132,53 +414,76 @@ module DhanHQ
|
|
|
132
414
|
DETAILED_CSV_URL = "https://images.dhan.co/api-data/api-scrip-master-detailed.csv"
|
|
133
415
|
|
|
134
416
|
# API route prefixes that require a `client-id` header in addition to the access token.
|
|
135
|
-
DATA_API_PREFIXES =
|
|
136
|
-
/v2/marketfeed/
|
|
137
|
-
/v2/optionchain
|
|
138
|
-
/v2/instrument/
|
|
417
|
+
DATA_API_PREFIXES = [
|
|
418
|
+
"/v2/marketfeed/",
|
|
419
|
+
"/v2/optionchain",
|
|
420
|
+
"/v2/instrument/"
|
|
139
421
|
].freeze
|
|
140
422
|
|
|
141
423
|
# Mapping of exchange and segment combinations to canonical exchange segment names.
|
|
142
|
-
# Used for translating between CSV column values (EXCH_ID, SEGMENT) and API segment names.
|
|
143
|
-
# Key format: [exchange, segment] => exchange_segment
|
|
144
|
-
# Example: ["NSE", "E"] => "NSE_EQ"
|
|
145
424
|
SEGMENT_MAP = {
|
|
146
|
-
%w[NSE E] =>
|
|
147
|
-
%w[BSE E] =>
|
|
148
|
-
%w[NSE D] =>
|
|
149
|
-
%w[BSE D] =>
|
|
150
|
-
%w[NSE C] =>
|
|
151
|
-
%w[BSE C] =>
|
|
152
|
-
%w[MCX M] =>
|
|
153
|
-
%w[NSE I] =>
|
|
154
|
-
%w[BSE I] =>
|
|
425
|
+
%w[NSE E] => ExchangeSegment::NSE_EQ,
|
|
426
|
+
%w[BSE E] => ExchangeSegment::BSE_EQ,
|
|
427
|
+
%w[NSE D] => ExchangeSegment::NSE_FNO,
|
|
428
|
+
%w[BSE D] => ExchangeSegment::BSE_FNO,
|
|
429
|
+
%w[NSE C] => ExchangeSegment::NSE_CURRENCY,
|
|
430
|
+
%w[BSE C] => ExchangeSegment::BSE_CURRENCY,
|
|
431
|
+
%w[MCX M] => ExchangeSegment::MCX_COMM,
|
|
432
|
+
%w[NSE I] => ExchangeSegment::IDX_I,
|
|
433
|
+
%w[BSE I] => ExchangeSegment::IDX_I
|
|
155
434
|
}.freeze
|
|
156
435
|
|
|
157
436
|
# Mapping of DhanHQ error codes to SDK error classes for consistent exception handling.
|
|
158
437
|
DHAN_ERROR_MAPPING = {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
438
|
+
TradingErrorCode::INVALID_AUTHENTICATION => DhanHQ::InvalidAuthenticationError,
|
|
439
|
+
TradingErrorCode::INVALID_ACCESS => DhanHQ::InvalidAccessError,
|
|
440
|
+
TradingErrorCode::USER_ACCOUNT => DhanHQ::UserAccountError,
|
|
441
|
+
TradingErrorCode::RATE_LIMIT => DhanHQ::RateLimitError,
|
|
442
|
+
TradingErrorCode::INPUT_EXCEPTION => DhanHQ::InputExceptionError,
|
|
443
|
+
TradingErrorCode::ORDER_ERROR => DhanHQ::OrderError,
|
|
444
|
+
TradingErrorCode::DATA_ERROR => DhanHQ::DataError,
|
|
445
|
+
TradingErrorCode::INTERNAL_SERVER_ERROR => DhanHQ::InternalServerError,
|
|
446
|
+
TradingErrorCode::NO_HOLDINGS => DhanHQ::NoHoldingsError,
|
|
447
|
+
TradingErrorCode::NETWORK_ERROR => DhanHQ::NetworkError,
|
|
448
|
+
TradingErrorCode::OTHERS => DhanHQ::OtherError,
|
|
449
|
+
DataErrorCode::INTERNAL_SERVER_ERROR.to_s => DhanHQ::InternalServerError,
|
|
450
|
+
DataErrorCode::INSTRUMENTS_LIMIT.to_s => DhanHQ::Error,
|
|
451
|
+
DataErrorCode::TOO_MANY_REQUESTS.to_s => DhanHQ::RateLimitError,
|
|
452
|
+
DataErrorCode::NOT_SUBSCRIBED.to_s => DhanHQ::DataError,
|
|
453
|
+
DataErrorCode::TOKEN_EXPIRED.to_s => DhanHQ::TokenExpiredError,
|
|
454
|
+
DataErrorCode::AUTH_FAILED.to_s => DhanHQ::AuthenticationFailedError,
|
|
455
|
+
DataErrorCode::INVALID_TOKEN.to_s => DhanHQ::InvalidTokenError,
|
|
456
|
+
DataErrorCode::INVALID_CLIENT_ID.to_s => DhanHQ::InvalidClientIDError,
|
|
457
|
+
DataErrorCode::INVALID_EXPIRY_DATE.to_s => DhanHQ::InvalidRequestError,
|
|
458
|
+
DataErrorCode::INVALID_DATE_FORMAT.to_s => DhanHQ::InvalidRequestError,
|
|
459
|
+
DataErrorCode::INVALID_SECURITY_ID.to_s => DhanHQ::InvalidRequestError,
|
|
460
|
+
DataErrorCode::INVALID_REQUEST.to_s => DhanHQ::InvalidRequestError
|
|
182
461
|
}.freeze
|
|
462
|
+
|
|
463
|
+
# Validate if a value belongs to a constants module that exposes ALL.
|
|
464
|
+
def self.valid?(module_name, value)
|
|
465
|
+
mod = resolve_module(module_name)
|
|
466
|
+
mod.const_defined?(:ALL) && mod::ALL.include?(value)
|
|
467
|
+
rescue NameError
|
|
468
|
+
false
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# Get all values for a constants module that exposes ALL.
|
|
472
|
+
def self.all_for(module_name)
|
|
473
|
+
mod = resolve_module(module_name)
|
|
474
|
+
return [] unless mod.const_defined?(:ALL)
|
|
475
|
+
|
|
476
|
+
mod::ALL
|
|
477
|
+
rescue NameError
|
|
478
|
+
[]
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
# Resolve symbols, strings, or direct modules under DhanHQ::Constants.
|
|
482
|
+
def self.resolve_module(module_name)
|
|
483
|
+
return module_name if module_name.is_a?(Module)
|
|
484
|
+
|
|
485
|
+
const_get(module_name.to_s)
|
|
486
|
+
end
|
|
487
|
+
private_class_method :resolve_module
|
|
183
488
|
end
|
|
184
489
|
end
|