ollama-client 0.2.5 → 0.2.6
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/CHANGELOG.md +13 -0
- data/README.md +138 -76
- data/docs/EXAMPLE_REORGANIZATION.md +412 -0
- data/docs/GETTING_STARTED.md +361 -0
- data/docs/INTEGRATION_TESTING.md +170 -0
- data/docs/NEXT_STEPS_SUMMARY.md +114 -0
- data/docs/PERSONAS.md +383 -0
- data/docs/QUICK_START.md +195 -0
- data/docs/TESTING.md +392 -170
- data/docs/TEST_CHECKLIST.md +450 -0
- data/examples/README.md +51 -66
- data/examples/basic_chat.rb +33 -0
- data/examples/basic_generate.rb +29 -0
- data/examples/tool_calling_parsing.rb +59 -0
- data/exe/ollama-client +128 -1
- data/lib/ollama/agent/planner.rb +7 -2
- data/lib/ollama/chat_session.rb +101 -0
- data/lib/ollama/client.rb +41 -35
- data/lib/ollama/config.rb +4 -1
- data/lib/ollama/document_loader.rb +1 -1
- data/lib/ollama/embeddings.rb +41 -26
- data/lib/ollama/errors.rb +1 -0
- data/lib/ollama/personas.rb +287 -0
- data/lib/ollama/version.rb +1 -1
- data/lib/ollama_client.rb +7 -0
- metadata +14 -48
- data/examples/advanced_complex_schemas.rb +0 -366
- data/examples/advanced_edge_cases.rb +0 -241
- data/examples/advanced_error_handling.rb +0 -200
- data/examples/advanced_multi_step_agent.rb +0 -341
- data/examples/advanced_performance_testing.rb +0 -186
- data/examples/chat_console.rb +0 -143
- data/examples/complete_workflow.rb +0 -245
- data/examples/dhan_console.rb +0 -843
- data/examples/dhanhq/README.md +0 -236
- data/examples/dhanhq/agents/base_agent.rb +0 -74
- data/examples/dhanhq/agents/data_agent.rb +0 -66
- data/examples/dhanhq/agents/orchestrator_agent.rb +0 -120
- data/examples/dhanhq/agents/technical_analysis_agent.rb +0 -252
- data/examples/dhanhq/agents/trading_agent.rb +0 -81
- data/examples/dhanhq/analysis/market_structure.rb +0 -138
- data/examples/dhanhq/analysis/pattern_recognizer.rb +0 -192
- data/examples/dhanhq/analysis/trend_analyzer.rb +0 -88
- data/examples/dhanhq/builders/market_context_builder.rb +0 -67
- data/examples/dhanhq/dhanhq_agent.rb +0 -829
- data/examples/dhanhq/indicators/technical_indicators.rb +0 -158
- data/examples/dhanhq/scanners/intraday_options_scanner.rb +0 -492
- data/examples/dhanhq/scanners/swing_scanner.rb +0 -247
- data/examples/dhanhq/schemas/agent_schemas.rb +0 -61
- data/examples/dhanhq/services/base_service.rb +0 -46
- data/examples/dhanhq/services/data_service.rb +0 -118
- data/examples/dhanhq/services/trading_service.rb +0 -59
- data/examples/dhanhq/technical_analysis_agentic_runner.rb +0 -411
- data/examples/dhanhq/technical_analysis_runner.rb +0 -420
- data/examples/dhanhq/test_tool_calling.rb +0 -538
- data/examples/dhanhq/test_tool_calling_verbose.rb +0 -251
- data/examples/dhanhq/utils/instrument_helper.rb +0 -32
- data/examples/dhanhq/utils/parameter_cleaner.rb +0 -28
- data/examples/dhanhq/utils/parameter_normalizer.rb +0 -45
- data/examples/dhanhq/utils/rate_limiter.rb +0 -23
- data/examples/dhanhq/utils/trading_parameter_normalizer.rb +0 -72
- data/examples/dhanhq_agent.rb +0 -964
- data/examples/dhanhq_tools.rb +0 -1663
- data/examples/multi_step_agent_with_external_data.rb +0 -368
- data/examples/structured_outputs_chat.rb +0 -72
- data/examples/structured_tools.rb +0 -89
- data/examples/test_dhanhq_tool_calling.rb +0 -375
- data/examples/test_tool_calling.rb +0 -160
- data/examples/tool_calling_direct.rb +0 -124
- data/examples/tool_calling_pattern.rb +0 -269
- data/exe/dhan_console +0 -4
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../analysis/trend_analyzer"
|
|
4
|
-
require_relative "../services/data_service"
|
|
5
|
-
|
|
6
|
-
module DhanHQ
|
|
7
|
-
module Scanners
|
|
8
|
-
# Scanner for swing trading candidates
|
|
9
|
-
class SwingScanner
|
|
10
|
-
def initialize
|
|
11
|
-
@data_service = Services::DataService.new
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def scan_symbols(symbols, exchange_segment: "NSE_EQ", min_score: 40, verbose: false)
|
|
15
|
-
candidates = []
|
|
16
|
-
rejected = []
|
|
17
|
-
|
|
18
|
-
symbols.each do |symbol|
|
|
19
|
-
analysis = analyze_symbol(symbol, exchange_segment)
|
|
20
|
-
|
|
21
|
-
if analysis[:error]
|
|
22
|
-
rejected << { symbol: symbol, reason: analysis[:error] }
|
|
23
|
-
next
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
score = calculate_swing_score(analysis[:analysis])
|
|
27
|
-
score_details = calculate_swing_score_details(analysis[:analysis])
|
|
28
|
-
|
|
29
|
-
if score < min_score
|
|
30
|
-
rejected << {
|
|
31
|
-
symbol: symbol,
|
|
32
|
-
score: score,
|
|
33
|
-
reason: "Below minimum score (#{min_score})",
|
|
34
|
-
details: score_details
|
|
35
|
-
}
|
|
36
|
-
next
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
candidates << {
|
|
40
|
-
symbol: symbol,
|
|
41
|
-
score: score,
|
|
42
|
-
analysis: analysis[:analysis],
|
|
43
|
-
recommendation: analysis[:interpretation],
|
|
44
|
-
score_details: score_details
|
|
45
|
-
}
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
if verbose && !rejected.empty?
|
|
49
|
-
puts " 📋 Rejected candidates:"
|
|
50
|
-
rejected.each do |r|
|
|
51
|
-
puts " ❌ #{r[:symbol]}: Score #{r[:score]}/100 - #{r[:reason]}"
|
|
52
|
-
puts " Breakdown: #{format_score_breakdown(r[:details])}" if r[:details]
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
candidates.sort_by { |c| -c[:score] }
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def scan_by_criteria(_criteria = {})
|
|
60
|
-
# This would typically fetch a list of symbols from an API
|
|
61
|
-
# For now, return empty - would need symbol list source
|
|
62
|
-
[]
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
private
|
|
66
|
-
|
|
67
|
-
def analyze_symbol(symbol, exchange_segment)
|
|
68
|
-
result = @data_service.execute(
|
|
69
|
-
action: "get_historical_data",
|
|
70
|
-
params: {
|
|
71
|
-
"symbol" => symbol,
|
|
72
|
-
"exchange_segment" => exchange_segment,
|
|
73
|
-
"from_date" => (Date.today - 90).strftime("%Y-%m-%d"),
|
|
74
|
-
"to_date" => Date.today.strftime("%Y-%m-%d")
|
|
75
|
-
}
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
return { error: "Failed to fetch data: #{result[:error] || 'Unknown error'}" } if result[:error]
|
|
79
|
-
return { error: "No result data returned" } unless result[:result]
|
|
80
|
-
|
|
81
|
-
ohlc_data = convert_to_ohlc(result)
|
|
82
|
-
return { error: "Failed to convert data to OHLC format" } if ohlc_data.nil? || ohlc_data.empty?
|
|
83
|
-
|
|
84
|
-
analysis = Analysis::TrendAnalyzer.analyze(ohlc_data)
|
|
85
|
-
return { error: "Analysis returned empty result" } if analysis.nil? || analysis.empty?
|
|
86
|
-
|
|
87
|
-
{
|
|
88
|
-
symbol: symbol,
|
|
89
|
-
analysis: analysis,
|
|
90
|
-
interpretation: interpret_for_swing(analysis)
|
|
91
|
-
}
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def calculate_swing_score(analysis)
|
|
95
|
-
details = calculate_swing_score_details(analysis)
|
|
96
|
-
details.values.sum
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def calculate_swing_score_details(analysis)
|
|
100
|
-
return empty_score_details if analysis.nil? || analysis.empty?
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
trend: trend_points(analysis),
|
|
104
|
-
rsi: rsi_points(analysis),
|
|
105
|
-
macd: macd_points(analysis),
|
|
106
|
-
structure: structure_points(analysis),
|
|
107
|
-
patterns: pattern_points(analysis)
|
|
108
|
-
}
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def interpret_for_swing(analysis)
|
|
112
|
-
return "Unable to analyze" if analysis.nil? || analysis.empty?
|
|
113
|
-
|
|
114
|
-
trend = analysis[:trend]&.dig(:trend)
|
|
115
|
-
rsi = analysis[:indicators]&.dig(:rsi)
|
|
116
|
-
structure_break = analysis[:structure_break]
|
|
117
|
-
|
|
118
|
-
if trend == :uptrend && rsi && rsi < 70 && structure_break && structure_break[:broken]
|
|
119
|
-
"Strong swing candidate - uptrend with bullish structure break"
|
|
120
|
-
elsif trend == :uptrend && rsi&.between?(40, 60)
|
|
121
|
-
"Good swing candidate - healthy uptrend, RSI in good zone"
|
|
122
|
-
else
|
|
123
|
-
"Moderate candidate - review individual factors"
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def convert_to_ohlc(historical_data)
|
|
128
|
-
return [] unless historical_data.is_a?(Hash)
|
|
129
|
-
|
|
130
|
-
data = extract_data_payload(historical_data)
|
|
131
|
-
return [] unless data
|
|
132
|
-
|
|
133
|
-
return ohlc_from_hash(data) if data.is_a?(Hash)
|
|
134
|
-
return ohlc_from_array(data) if data.is_a?(Array)
|
|
135
|
-
|
|
136
|
-
[]
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def format_score_breakdown(details)
|
|
140
|
-
"Trend=#{details[:trend]}, RSI=#{details[:rsi]}, MACD=#{details[:macd]}, " \
|
|
141
|
-
"Structure=#{details[:structure]}, Patterns=#{details[:patterns]}"
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def empty_score_details
|
|
145
|
-
{ trend: 0, rsi: 0, macd: 0, structure: 0, patterns: 0 }
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def trend_points(analysis)
|
|
149
|
-
trend = analysis[:trend]
|
|
150
|
-
return 0 unless trend && trend[:trend] == :uptrend
|
|
151
|
-
|
|
152
|
-
(trend[:strength] || 0).clamp(0, 30)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def rsi_points(analysis)
|
|
156
|
-
rsi = analysis[:indicators]&.dig(:rsi)
|
|
157
|
-
return 0 unless rsi
|
|
158
|
-
return 20 if rsi.between?(40, 60)
|
|
159
|
-
return 10 if rsi.between?(30, 70)
|
|
160
|
-
|
|
161
|
-
0
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def macd_points(analysis)
|
|
165
|
-
macd = analysis[:indicators]&.dig(:macd)
|
|
166
|
-
signal = analysis[:indicators]&.dig(:macd_signal)
|
|
167
|
-
return 0 unless macd && signal
|
|
168
|
-
|
|
169
|
-
return 20 if macd > signal
|
|
170
|
-
return 10 if macd > signal * 0.9
|
|
171
|
-
|
|
172
|
-
0
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def structure_points(analysis)
|
|
176
|
-
structure_break = analysis[:structure_break]
|
|
177
|
-
return 0 unless structure_break && structure_break[:broken]
|
|
178
|
-
return 0 unless structure_break[:direction] == :bullish_break
|
|
179
|
-
|
|
180
|
-
15
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
def pattern_points(analysis)
|
|
184
|
-
patterns = analysis[:patterns]&.dig(:candlestick) || []
|
|
185
|
-
bullish_patterns = patterns.count { |pattern| pattern.is_a?(Hash) && pattern[:type].to_s.include?("bullish") }
|
|
186
|
-
[bullish_patterns * 5, 15].min
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def extract_data_payload(historical_data)
|
|
190
|
-
outer_result = historical_data[:result] || historical_data["result"]
|
|
191
|
-
return nil unless outer_result.is_a?(Hash)
|
|
192
|
-
|
|
193
|
-
outer_result[:data] || outer_result["data"]
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def ohlc_from_hash(data)
|
|
197
|
-
series = extract_series(data)
|
|
198
|
-
return [] if series[:closes].empty?
|
|
199
|
-
|
|
200
|
-
max_length = series_lengths(series).max
|
|
201
|
-
build_ohlc_rows(series, max_length)
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def extract_series(data)
|
|
205
|
-
{
|
|
206
|
-
opens: data[:open] || data["open"] || [],
|
|
207
|
-
highs: data[:high] || data["high"] || [],
|
|
208
|
-
lows: data[:low] || data["low"] || [],
|
|
209
|
-
closes: data[:close] || data["close"] || [],
|
|
210
|
-
volumes: data[:volume] || data["volume"] || []
|
|
211
|
-
}
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
def series_lengths(series)
|
|
215
|
-
[series[:opens].length, series[:highs].length, series[:lows].length, series[:closes].length]
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def build_ohlc_rows(series, max_length)
|
|
219
|
-
(0...max_length).map do |index|
|
|
220
|
-
{
|
|
221
|
-
open: series[:opens][index],
|
|
222
|
-
high: series[:highs][index],
|
|
223
|
-
low: series[:lows][index],
|
|
224
|
-
close: series[:closes][index],
|
|
225
|
-
volume: series[:volumes][index] || 0
|
|
226
|
-
}
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
def ohlc_from_array(data)
|
|
231
|
-
data.filter_map { |bar| normalize_bar(bar) }
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
def normalize_bar(bar)
|
|
235
|
-
return nil unless bar.is_a?(Hash)
|
|
236
|
-
|
|
237
|
-
{
|
|
238
|
-
open: bar["open"] || bar[:open],
|
|
239
|
-
high: bar["high"] || bar[:high],
|
|
240
|
-
low: bar["low"] || bar[:low],
|
|
241
|
-
close: bar["close"] || bar[:close],
|
|
242
|
-
volume: bar["volume"] || bar[:volume]
|
|
243
|
-
}
|
|
244
|
-
end
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
end
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module DhanHQ
|
|
4
|
-
module Schemas
|
|
5
|
-
# JSON schemas for agent decision-making
|
|
6
|
-
class AgentSchemas
|
|
7
|
-
DATA_AGENT_SCHEMA = {
|
|
8
|
-
"type" => "object",
|
|
9
|
-
"required" => ["action", "reasoning", "confidence"],
|
|
10
|
-
"properties" => {
|
|
11
|
-
"action" => {
|
|
12
|
-
"type" => "string",
|
|
13
|
-
"enum" => ["get_market_quote", "get_live_ltp", "get_market_depth", "get_historical_data",
|
|
14
|
-
"get_expired_options_data", "get_option_chain", "no_action"]
|
|
15
|
-
},
|
|
16
|
-
"reasoning" => {
|
|
17
|
-
"type" => "string",
|
|
18
|
-
"description" => "Why this action was chosen"
|
|
19
|
-
},
|
|
20
|
-
"confidence" => {
|
|
21
|
-
"type" => "number",
|
|
22
|
-
"minimum" => 0,
|
|
23
|
-
"maximum" => 1,
|
|
24
|
-
"description" => "Confidence in this decision (0.0 to 1.0, where 1.0 is 100% confident)"
|
|
25
|
-
},
|
|
26
|
-
"parameters" => {
|
|
27
|
-
"type" => "object",
|
|
28
|
-
"additionalProperties" => true,
|
|
29
|
-
"description" => "Parameters for the action (symbol, exchange_segment, etc.)"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}.freeze
|
|
33
|
-
|
|
34
|
-
TRADING_AGENT_SCHEMA = {
|
|
35
|
-
"type" => "object",
|
|
36
|
-
"required" => ["action", "reasoning", "confidence"],
|
|
37
|
-
"properties" => {
|
|
38
|
-
"action" => {
|
|
39
|
-
"type" => "string",
|
|
40
|
-
"enum" => ["place_order", "place_super_order", "cancel_order", "no_action"]
|
|
41
|
-
},
|
|
42
|
-
"reasoning" => {
|
|
43
|
-
"type" => "string",
|
|
44
|
-
"description" => "Why this action was chosen"
|
|
45
|
-
},
|
|
46
|
-
"confidence" => {
|
|
47
|
-
"type" => "number",
|
|
48
|
-
"minimum" => 0,
|
|
49
|
-
"maximum" => 1,
|
|
50
|
-
"description" => "Confidence in this decision (0.0 to 1.0, where 1.0 is 100% confident)"
|
|
51
|
-
},
|
|
52
|
-
"parameters" => {
|
|
53
|
-
"type" => "object",
|
|
54
|
-
"additionalProperties" => true,
|
|
55
|
-
"description" => "Parameters for the action (security_id, quantity, price, etc.)"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}.freeze
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "../utils/instrument_helper"
|
|
4
|
-
require_relative "../utils/rate_limiter"
|
|
5
|
-
|
|
6
|
-
module DhanHQ
|
|
7
|
-
module Services
|
|
8
|
-
# Base service class with common functionality
|
|
9
|
-
class BaseService
|
|
10
|
-
protected
|
|
11
|
-
|
|
12
|
-
def find_instrument(exchange_segment, symbol)
|
|
13
|
-
DhanHQ::Models::Instrument.find(exchange_segment, symbol)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def safe_attr(instrument, attr_name)
|
|
17
|
-
DhanHQ::Utils::InstrumentHelper.safe_attr(instrument, attr_name)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def extract_value(data, keys)
|
|
21
|
-
DhanHQ::Utils::InstrumentHelper.extract_value(data, keys)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def rate_limit_marketfeed
|
|
25
|
-
DhanHQ::Utils::RateLimiter.marketfeed
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def resolve_security_id(security_id, symbol, exchange_segment)
|
|
29
|
-
return security_id.to_s if security_id
|
|
30
|
-
|
|
31
|
-
instrument = find_instrument(exchange_segment, symbol.to_s)
|
|
32
|
-
return nil unless instrument
|
|
33
|
-
|
|
34
|
-
safe_attr(instrument, :security_id)&.to_s
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def error_response(action, error, params = {})
|
|
38
|
-
{ action: action, error: error, params: params }
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def success_response(action, result, params = {})
|
|
42
|
-
{ action: action, params: params, result: result }
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "base_service"
|
|
4
|
-
require_relative "../../dhanhq_tools"
|
|
5
|
-
|
|
6
|
-
module DhanHQ
|
|
7
|
-
module Services
|
|
8
|
-
# Service for executing data retrieval actions
|
|
9
|
-
class DataService < BaseService
|
|
10
|
-
def execute(action:, params:)
|
|
11
|
-
case action
|
|
12
|
-
when "get_market_quote"
|
|
13
|
-
execute_market_quote(params)
|
|
14
|
-
when "get_live_ltp"
|
|
15
|
-
execute_live_ltp(params)
|
|
16
|
-
when "get_market_depth"
|
|
17
|
-
execute_market_depth(params)
|
|
18
|
-
when "get_historical_data"
|
|
19
|
-
execute_historical_data(params)
|
|
20
|
-
when "get_option_chain"
|
|
21
|
-
execute_option_chain(params)
|
|
22
|
-
when "get_expired_options_data"
|
|
23
|
-
execute_expired_options_data(params)
|
|
24
|
-
when "no_action"
|
|
25
|
-
{ action: "no_action", message: "No action taken" }
|
|
26
|
-
else
|
|
27
|
-
{ action: "unknown", error: "Unknown action: #{action}" }
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
private
|
|
32
|
-
|
|
33
|
-
def execute_market_quote(params)
|
|
34
|
-
validate_symbol_or_id(params, "get_market_quote") ||
|
|
35
|
-
DhanHQDataTools.get_market_quote(
|
|
36
|
-
symbol: params["symbol"],
|
|
37
|
-
security_id: params["security_id"],
|
|
38
|
-
exchange_segment: params["exchange_segment"] || "NSE_EQ"
|
|
39
|
-
)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def execute_live_ltp(params)
|
|
43
|
-
validate_symbol_or_id(params, "get_live_ltp") ||
|
|
44
|
-
DhanHQDataTools.get_live_ltp(
|
|
45
|
-
symbol: params["symbol"],
|
|
46
|
-
security_id: params["security_id"],
|
|
47
|
-
exchange_segment: params["exchange_segment"] || "NSE_EQ"
|
|
48
|
-
)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def execute_market_depth(params)
|
|
52
|
-
validate_symbol_or_id(params, "get_market_depth") ||
|
|
53
|
-
DhanHQDataTools.get_market_depth(
|
|
54
|
-
symbol: params["symbol"],
|
|
55
|
-
security_id: params["security_id"],
|
|
56
|
-
exchange_segment: params["exchange_segment"] || "NSE_EQ"
|
|
57
|
-
)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def execute_historical_data(params)
|
|
61
|
-
validate_symbol_or_id(params, "get_historical_data") ||
|
|
62
|
-
DhanHQDataTools.get_historical_data(
|
|
63
|
-
symbol: params["symbol"],
|
|
64
|
-
security_id: params["security_id"],
|
|
65
|
-
exchange_segment: params["exchange_segment"] || "NSE_EQ",
|
|
66
|
-
from_date: params["from_date"],
|
|
67
|
-
to_date: params["to_date"],
|
|
68
|
-
interval: params["interval"],
|
|
69
|
-
expiry_code: params["expiry_code"]
|
|
70
|
-
)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def execute_option_chain(params)
|
|
74
|
-
validate_symbol_or_id(params, "get_option_chain") ||
|
|
75
|
-
DhanHQDataTools.get_option_chain(
|
|
76
|
-
symbol: params["symbol"],
|
|
77
|
-
security_id: params["security_id"],
|
|
78
|
-
exchange_segment: params["exchange_segment"] || "NSE_EQ",
|
|
79
|
-
expiry: params["expiry"]
|
|
80
|
-
)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def execute_expired_options_data(params)
|
|
84
|
-
if missing_expired_options_params?(params)
|
|
85
|
-
return error_response("get_expired_options_data",
|
|
86
|
-
"Either symbol or security_id, and expiry_date are required",
|
|
87
|
-
params)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
DhanHQDataTools.get_expired_options_data(
|
|
91
|
-
symbol: params["symbol"],
|
|
92
|
-
security_id: params["security_id"],
|
|
93
|
-
exchange_segment: params["exchange_segment"] || "NSE_FNO",
|
|
94
|
-
expiry_date: params["expiry_date"],
|
|
95
|
-
expiry_code: params["expiry_code"],
|
|
96
|
-
interval: params["interval"] || "1",
|
|
97
|
-
instrument: params["instrument"],
|
|
98
|
-
expiry_flag: params["expiry_flag"] || "MONTH",
|
|
99
|
-
strike: params["strike"] || "ATM",
|
|
100
|
-
drv_option_type: params["drv_option_type"] || "CALL",
|
|
101
|
-
required_data: params["required_data"]
|
|
102
|
-
)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def validate_symbol_or_id(params, action)
|
|
106
|
-
return nil unless params["symbol"].nil? && (params["security_id"].nil? || params["security_id"].to_s.empty?)
|
|
107
|
-
|
|
108
|
-
error_response(action, "Either symbol or security_id is required", params)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def missing_expired_options_params?(params)
|
|
112
|
-
symbol_or_id_missing = params["symbol"].nil? &&
|
|
113
|
-
(params["security_id"].nil? || params["security_id"].to_s.empty?)
|
|
114
|
-
symbol_or_id_missing || params["expiry_date"].nil?
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "base_service"
|
|
4
|
-
require_relative "../../dhanhq_tools"
|
|
5
|
-
|
|
6
|
-
module DhanHQ
|
|
7
|
-
module Services
|
|
8
|
-
# Service for executing trading order actions
|
|
9
|
-
class TradingService < BaseService
|
|
10
|
-
def execute(action:, params:)
|
|
11
|
-
case action
|
|
12
|
-
when "place_order"
|
|
13
|
-
execute_place_order(params)
|
|
14
|
-
when "place_super_order"
|
|
15
|
-
execute_place_super_order(params)
|
|
16
|
-
when "cancel_order"
|
|
17
|
-
execute_cancel_order(params)
|
|
18
|
-
when "no_action"
|
|
19
|
-
{ action: "no_action", message: "No action taken" }
|
|
20
|
-
else
|
|
21
|
-
{ action: "unknown", error: "Unknown action: #{action}" }
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
private
|
|
26
|
-
|
|
27
|
-
def execute_place_order(params)
|
|
28
|
-
DhanHQTradingTools.build_order_params(
|
|
29
|
-
transaction_type: params["transaction_type"] || "BUY",
|
|
30
|
-
exchange_segment: params["exchange_segment"] || "NSE_EQ",
|
|
31
|
-
product_type: params["product_type"] || "MARGIN",
|
|
32
|
-
order_type: params["order_type"] || "LIMIT",
|
|
33
|
-
security_id: params["security_id"],
|
|
34
|
-
quantity: params["quantity"] || 1,
|
|
35
|
-
price: params["price"]
|
|
36
|
-
)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def execute_place_super_order(params)
|
|
40
|
-
DhanHQTradingTools.build_super_order_params(
|
|
41
|
-
transaction_type: params["transaction_type"] || "BUY",
|
|
42
|
-
exchange_segment: params["exchange_segment"] || "NSE_EQ",
|
|
43
|
-
product_type: params["product_type"] || "MARGIN",
|
|
44
|
-
order_type: params["order_type"] || "LIMIT",
|
|
45
|
-
security_id: params["security_id"],
|
|
46
|
-
quantity: params["quantity"] || 1,
|
|
47
|
-
price: params["price"],
|
|
48
|
-
target_price: params["target_price"],
|
|
49
|
-
stop_loss_price: params["stop_loss_price"],
|
|
50
|
-
trailing_jump: params["trailing_jump"] || 10
|
|
51
|
-
)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def execute_cancel_order(params)
|
|
55
|
-
DhanHQTradingTools.build_cancel_params(order_id: params["order_id"])
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|