ollama-client 0.2.1 → 0.2.3
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 +8 -0
- data/README.md +220 -12
- data/docs/CLOUD.md +29 -0
- data/docs/CONSOLE_IMPROVEMENTS.md +256 -0
- data/docs/FEATURES_ADDED.md +145 -0
- data/docs/HANDLERS_ANALYSIS.md +190 -0
- data/docs/README.md +37 -0
- data/docs/SCHEMA_FIXES.md +147 -0
- data/docs/TEST_UPDATES.md +107 -0
- data/examples/README.md +92 -0
- data/examples/advanced_complex_schemas.rb +6 -3
- data/examples/advanced_multi_step_agent.rb +13 -7
- data/examples/chat_console.rb +143 -0
- data/examples/complete_workflow.rb +14 -4
- data/examples/dhan_console.rb +843 -0
- data/examples/dhanhq/agents/base_agent.rb +0 -2
- data/examples/dhanhq/agents/orchestrator_agent.rb +1 -2
- data/examples/dhanhq/agents/technical_analysis_agent.rb +67 -49
- data/examples/dhanhq/analysis/market_structure.rb +44 -28
- data/examples/dhanhq/analysis/pattern_recognizer.rb +64 -47
- data/examples/dhanhq/analysis/trend_analyzer.rb +6 -8
- data/examples/dhanhq/dhanhq_agent.rb +296 -99
- data/examples/dhanhq/indicators/technical_indicators.rb +3 -5
- data/examples/dhanhq/scanners/intraday_options_scanner.rb +360 -255
- data/examples/dhanhq/scanners/swing_scanner.rb +118 -84
- data/examples/dhanhq/schemas/agent_schemas.rb +2 -2
- data/examples/dhanhq/services/data_service.rb +5 -7
- data/examples/dhanhq/services/trading_service.rb +0 -3
- data/examples/dhanhq/technical_analysis_agentic_runner.rb +217 -84
- data/examples/dhanhq/technical_analysis_runner.rb +216 -162
- data/examples/dhanhq/test_tool_calling.rb +538 -0
- data/examples/dhanhq/test_tool_calling_verbose.rb +251 -0
- data/examples/dhanhq/utils/trading_parameter_normalizer.rb +12 -17
- data/examples/dhanhq_agent.rb +159 -116
- data/examples/dhanhq_tools.rb +1158 -251
- data/examples/multi_step_agent_with_external_data.rb +368 -0
- data/examples/structured_tools.rb +89 -0
- data/examples/test_dhanhq_tool_calling.rb +375 -0
- data/examples/test_tool_calling.rb +160 -0
- data/examples/tool_calling_direct.rb +124 -0
- data/examples/tool_dto_example.rb +94 -0
- data/exe/dhan_console +4 -0
- data/exe/ollama-client +1 -1
- data/lib/ollama/agent/executor.rb +116 -15
- data/lib/ollama/client.rb +118 -55
- data/lib/ollama/config.rb +36 -0
- data/lib/ollama/dto.rb +187 -0
- data/lib/ollama/embeddings.rb +77 -0
- data/lib/ollama/options.rb +104 -0
- data/lib/ollama/response.rb +121 -0
- data/lib/ollama/tool/function/parameters/property.rb +72 -0
- data/lib/ollama/tool/function/parameters.rb +101 -0
- data/lib/ollama/tool/function.rb +78 -0
- data/lib/ollama/tool.rb +60 -0
- data/lib/ollama/version.rb +1 -1
- data/lib/ollama_client.rb +3 -0
- metadata +31 -3
- /data/{PRODUCTION_FIXES.md → docs/PRODUCTION_FIXES.md} +0 -0
- /data/{TESTING.md → docs/TESTING.md} +0 -0
|
@@ -69,8 +69,7 @@ module DhanHQ
|
|
|
69
69
|
|
|
70
70
|
protected
|
|
71
71
|
|
|
72
|
-
def build_analysis_prompt(
|
|
73
|
-
# Not used in this agent, but required by base class
|
|
72
|
+
def build_analysis_prompt(*)
|
|
74
73
|
""
|
|
75
74
|
end
|
|
76
75
|
|
|
@@ -79,58 +78,72 @@ module DhanHQ
|
|
|
79
78
|
def convert_to_ohlc(historical_data)
|
|
80
79
|
return [] unless historical_data.is_a?(Hash)
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
data = extract_data_payload(historical_data)
|
|
82
|
+
return [] unless data
|
|
83
|
+
|
|
84
|
+
return ohlc_from_hash(data) if data.is_a?(Hash)
|
|
85
|
+
return ohlc_from_array(data) if data.is_a?(Array)
|
|
86
|
+
|
|
87
|
+
[]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def extract_data_payload(historical_data)
|
|
83
91
|
outer_result = historical_data[:result] || historical_data["result"]
|
|
84
|
-
return
|
|
92
|
+
return nil unless outer_result.is_a?(Hash)
|
|
85
93
|
|
|
86
|
-
|
|
87
|
-
|
|
94
|
+
outer_result[:data] || outer_result["data"]
|
|
95
|
+
end
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
highs = data[:high] || data["high"] || []
|
|
93
|
-
lows = data[:low] || data["low"] || []
|
|
94
|
-
closes = data[:close] || data["close"] || []
|
|
95
|
-
volumes = data[:volume] || data["volume"] || []
|
|
96
|
-
|
|
97
|
-
return [] if closes.nil? || closes.empty?
|
|
98
|
-
|
|
99
|
-
# Convert parallel arrays to array of hashes
|
|
100
|
-
max_length = [opens.length, highs.length, lows.length, closes.length].max
|
|
101
|
-
return [] if max_length.zero?
|
|
102
|
-
|
|
103
|
-
ohlc_data = []
|
|
104
|
-
|
|
105
|
-
(0...max_length).each do |i|
|
|
106
|
-
ohlc_data << {
|
|
107
|
-
open: opens[i] || closes[i] || 0,
|
|
108
|
-
high: highs[i] || closes[i] || 0,
|
|
109
|
-
low: lows[i] || closes[i] || 0,
|
|
110
|
-
close: closes[i] || 0,
|
|
111
|
-
volume: volumes[i] || 0
|
|
112
|
-
}
|
|
113
|
-
end
|
|
97
|
+
def ohlc_from_hash(data)
|
|
98
|
+
series = extract_series(data)
|
|
99
|
+
return [] if series[:closes].nil? || series[:closes].empty?
|
|
114
100
|
|
|
115
|
-
|
|
116
|
-
|
|
101
|
+
max_length = series_lengths(series).max
|
|
102
|
+
return [] if max_length.zero?
|
|
117
103
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
104
|
+
build_ohlc_rows(series, max_length)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def extract_series(data)
|
|
108
|
+
{
|
|
109
|
+
opens: data[:open] || data["open"] || [],
|
|
110
|
+
highs: data[:high] || data["high"] || [],
|
|
111
|
+
lows: data[:low] || data["low"] || [],
|
|
112
|
+
closes: data[:close] || data["close"] || [],
|
|
113
|
+
volumes: data[:volume] || data["volume"] || []
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def series_lengths(series)
|
|
118
|
+
[series[:opens].length, series[:highs].length, series[:lows].length, series[:closes].length]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def build_ohlc_rows(series, max_length)
|
|
122
|
+
(0...max_length).map do |index|
|
|
123
|
+
{
|
|
124
|
+
open: series[:opens][index] || series[:closes][index] || 0,
|
|
125
|
+
high: series[:highs][index] || series[:closes][index] || 0,
|
|
126
|
+
low: series[:lows][index] || series[:closes][index] || 0,
|
|
127
|
+
close: series[:closes][index] || 0,
|
|
128
|
+
volume: series[:volumes][index] || 0
|
|
129
|
+
}
|
|
131
130
|
end
|
|
131
|
+
end
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
def ohlc_from_array(data)
|
|
134
|
+
data.filter_map { |bar| normalize_bar(bar) }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def normalize_bar(bar)
|
|
138
|
+
return nil unless bar.is_a?(Hash)
|
|
139
|
+
|
|
140
|
+
{
|
|
141
|
+
open: bar["open"] || bar[:open],
|
|
142
|
+
high: bar["high"] || bar[:high],
|
|
143
|
+
low: bar["low"] || bar[:low],
|
|
144
|
+
close: bar["close"] || bar[:close],
|
|
145
|
+
volume: bar["volume"] || bar[:volume]
|
|
146
|
+
}
|
|
134
147
|
end
|
|
135
148
|
|
|
136
149
|
def interpret_analysis(symbol, analysis)
|
|
@@ -214,7 +227,7 @@ module DhanHQ
|
|
|
214
227
|
}
|
|
215
228
|
end
|
|
216
229
|
|
|
217
|
-
def build_recommendation_schema(
|
|
230
|
+
def build_recommendation_schema(_trading_style)
|
|
218
231
|
{
|
|
219
232
|
"type" => "object",
|
|
220
233
|
"properties" => {
|
|
@@ -223,7 +236,12 @@ module DhanHQ
|
|
|
223
236
|
"stop_loss" => { "type" => "number" },
|
|
224
237
|
"target_price" => { "type" => "number" },
|
|
225
238
|
"risk_reward_ratio" => { "type" => "number" },
|
|
226
|
-
"confidence" => {
|
|
239
|
+
"confidence" => {
|
|
240
|
+
"type" => "number",
|
|
241
|
+
"minimum" => 0,
|
|
242
|
+
"maximum" => 1,
|
|
243
|
+
"description" => "Confidence (0.0 to 1.0)"
|
|
244
|
+
},
|
|
227
245
|
"reasoning" => { "type" => "string" },
|
|
228
246
|
"timeframe" => { "type" => "string" }
|
|
229
247
|
}
|
|
@@ -9,34 +9,8 @@ module DhanHQ
|
|
|
9
9
|
def self.analyze_trend(highs, lows, closes)
|
|
10
10
|
return { trend: :unknown, strength: 0 } if closes.nil? || closes.length < 3
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
recent_highs = highs.last(10) if highs
|
|
15
|
-
recent_lows = lows.last(10) if lows
|
|
16
|
-
recent_closes = closes.last(10)
|
|
17
|
-
|
|
18
|
-
higher_highs = recent_highs ? recent_highs.each_cons(2).all? { |a, b| b >= a } : false
|
|
19
|
-
higher_lows = recent_lows ? recent_lows.each_cons(2).all? { |a, b| b >= a } : false
|
|
20
|
-
lower_highs = recent_highs ? recent_highs.each_cons(2).all? { |a, b| b <= a } : false
|
|
21
|
-
lower_lows = recent_lows ? recent_lows.each_cons(2).all? { |a, b| b <= a } : false
|
|
22
|
-
|
|
23
|
-
trend = if higher_highs && higher_lows
|
|
24
|
-
:uptrend
|
|
25
|
-
elsif lower_highs && lower_lows
|
|
26
|
-
:downtrend
|
|
27
|
-
else
|
|
28
|
-
:sideways
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Calculate trend strength using moving averages
|
|
32
|
-
sma_20 = DhanHQ::Indicators::TechnicalIndicators.sma(closes, 20)
|
|
33
|
-
sma_50 = DhanHQ::Indicators::TechnicalIndicators.sma(closes, 50)
|
|
34
|
-
|
|
35
|
-
strength = if sma_20.last && sma_50.last
|
|
36
|
-
((sma_20.last - sma_50.last) / sma_50.last * 100).abs
|
|
37
|
-
else
|
|
38
|
-
0
|
|
39
|
-
end
|
|
12
|
+
trend = infer_trend(highs, lows)
|
|
13
|
+
strength = moving_average_strength(closes)
|
|
40
14
|
|
|
41
15
|
{ trend: trend, strength: strength.round(2) }
|
|
42
16
|
end
|
|
@@ -117,6 +91,48 @@ module DhanHQ
|
|
|
117
91
|
|
|
118
92
|
{ broken: broken, direction: direction, current_trend: trend[:trend] }
|
|
119
93
|
end
|
|
94
|
+
|
|
95
|
+
def self.infer_trend(highs, lows)
|
|
96
|
+
recent_highs = extract_recent(highs)
|
|
97
|
+
recent_lows = extract_recent(lows)
|
|
98
|
+
|
|
99
|
+
higher_highs = non_decreasing?(recent_highs)
|
|
100
|
+
higher_lows = non_decreasing?(recent_lows)
|
|
101
|
+
lower_highs = non_increasing?(recent_highs)
|
|
102
|
+
lower_lows = non_increasing?(recent_lows)
|
|
103
|
+
|
|
104
|
+
return :uptrend if higher_highs && higher_lows
|
|
105
|
+
return :downtrend if lower_highs && lower_lows
|
|
106
|
+
|
|
107
|
+
:sideways
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def self.moving_average_strength(closes)
|
|
111
|
+
short_average = DhanHQ::Indicators::TechnicalIndicators.sma(closes, 20)
|
|
112
|
+
long_average = DhanHQ::Indicators::TechnicalIndicators.sma(closes, 50)
|
|
113
|
+
|
|
114
|
+
return 0 unless short_average.last && long_average.last
|
|
115
|
+
|
|
116
|
+
((short_average.last - long_average.last) / long_average.last * 100).abs
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def self.extract_recent(series, lookback = 10)
|
|
120
|
+
return nil unless series
|
|
121
|
+
|
|
122
|
+
series.last(lookback)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def self.non_decreasing?(series)
|
|
126
|
+
return false unless series
|
|
127
|
+
|
|
128
|
+
series.each_cons(2).all? { |first, second| second >= first }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def self.non_increasing?(series)
|
|
132
|
+
return false unless series
|
|
133
|
+
|
|
134
|
+
series.each_cons(2).all? { |first, second| second <= first }
|
|
135
|
+
end
|
|
120
136
|
end
|
|
121
137
|
end
|
|
122
138
|
end
|
|
@@ -11,35 +11,31 @@ module DhanHQ
|
|
|
11
11
|
patterns = []
|
|
12
12
|
|
|
13
13
|
(2...closes.length).each do |i|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
first_candle = build_candle(opens, highs, lows, closes, i - 2)
|
|
15
|
+
second_candle = build_candle(opens, highs, lows, closes, i - 1)
|
|
16
|
+
third_candle = build_candle(opens, highs, lows, closes, i)
|
|
17
17
|
|
|
18
18
|
# Engulfing patterns
|
|
19
|
-
if bullish_engulfing?(
|
|
19
|
+
if bullish_engulfing?(first_candle, second_candle)
|
|
20
20
|
patterns << { type: :bullish_engulfing, index: i, strength: :medium }
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
if bearish_engulfing?(
|
|
23
|
+
if bearish_engulfing?(first_candle, second_candle)
|
|
24
24
|
patterns << { type: :bearish_engulfing, index: i, strength: :medium }
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# Hammer pattern
|
|
28
|
-
|
|
29
|
-
patterns << { type: :hammer, index: i - 1, strength: :medium }
|
|
30
|
-
end
|
|
28
|
+
patterns << { type: :hammer, index: i - 1, strength: :medium } if hammer?(second_candle)
|
|
31
29
|
|
|
32
30
|
# Shooting star
|
|
33
|
-
|
|
34
|
-
patterns << { type: :shooting_star, index: i - 1, strength: :medium }
|
|
35
|
-
end
|
|
31
|
+
patterns << { type: :shooting_star, index: i - 1, strength: :medium } if shooting_star?(second_candle)
|
|
36
32
|
|
|
37
33
|
# Three white soldiers / three black crows
|
|
38
|
-
if three_white_soldiers?(
|
|
34
|
+
if three_white_soldiers?([first_candle, second_candle, third_candle])
|
|
39
35
|
patterns << { type: :three_white_soldiers, index: i, strength: :strong }
|
|
40
36
|
end
|
|
41
37
|
|
|
42
|
-
if three_black_crows?(
|
|
38
|
+
if three_black_crows?([first_candle, second_candle, third_candle])
|
|
43
39
|
patterns << { type: :three_black_crows, index: i, strength: :strong }
|
|
44
40
|
end
|
|
45
41
|
end
|
|
@@ -65,46 +61,62 @@ module DhanHQ
|
|
|
65
61
|
patterns
|
|
66
62
|
end
|
|
67
63
|
|
|
68
|
-
|
|
64
|
+
def self.bullish_engulfing?(first_candle, second_candle)
|
|
65
|
+
first_open = first_candle[:open]
|
|
66
|
+
first_close = first_candle[:close]
|
|
67
|
+
second_open = second_candle[:open]
|
|
68
|
+
second_close = second_candle[:close]
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
c2 > o1 # Second closes above first open
|
|
70
|
+
first_close < first_open && # First candle is bearish
|
|
71
|
+
second_close > second_open && # Second candle is bullish
|
|
72
|
+
second_open < first_close && # Second opens below first close
|
|
73
|
+
second_close > first_open # Second closes above first open
|
|
75
74
|
end
|
|
76
75
|
|
|
77
|
-
def self.bearish_engulfing?(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
76
|
+
def self.bearish_engulfing?(first_candle, second_candle)
|
|
77
|
+
first_open = first_candle[:open]
|
|
78
|
+
first_close = first_candle[:close]
|
|
79
|
+
second_open = second_candle[:open]
|
|
80
|
+
second_close = second_candle[:close]
|
|
81
|
+
|
|
82
|
+
first_close > first_open && # First candle is bullish
|
|
83
|
+
second_close < second_open && # Second candle is bearish
|
|
84
|
+
second_open > first_close && # Second opens above first close
|
|
85
|
+
second_close < first_open # Second closes below first open
|
|
82
86
|
end
|
|
83
87
|
|
|
84
|
-
def self.hammer?(
|
|
85
|
-
body = (close - open).abs
|
|
86
|
-
lower_shadow = [open, close].min - low
|
|
87
|
-
upper_shadow = high - [open, close].max
|
|
88
|
+
def self.hammer?(candle)
|
|
89
|
+
body = (candle[:close] - candle[:open]).abs
|
|
90
|
+
lower_shadow = [candle[:open], candle[:close]].min - candle[:low]
|
|
91
|
+
upper_shadow = candle[:high] - [candle[:open], candle[:close]].max
|
|
88
92
|
|
|
89
93
|
lower_shadow > body * 2 && upper_shadow < body * 0.5
|
|
90
94
|
end
|
|
91
95
|
|
|
92
|
-
def self.shooting_star?(
|
|
93
|
-
body = (close - open).abs
|
|
94
|
-
upper_shadow = high - [open, close].max
|
|
95
|
-
lower_shadow = [open, close].min - low
|
|
96
|
+
def self.shooting_star?(candle)
|
|
97
|
+
body = (candle[:close] - candle[:open]).abs
|
|
98
|
+
upper_shadow = candle[:high] - [candle[:open], candle[:close]].max
|
|
99
|
+
lower_shadow = [candle[:open], candle[:close]].min - candle[:low]
|
|
96
100
|
|
|
97
101
|
upper_shadow > body * 2 && lower_shadow < body * 0.5
|
|
98
102
|
end
|
|
99
103
|
|
|
100
|
-
def self.three_white_soldiers?(
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
def self.three_white_soldiers?(candles)
|
|
105
|
+
first, second, third = candles
|
|
106
|
+
first[:close] > first[:open] &&
|
|
107
|
+
second[:close] > second[:open] &&
|
|
108
|
+
third[:close] > third[:open] && # All bullish
|
|
109
|
+
second[:close] > first[:close] &&
|
|
110
|
+
third[:close] > second[:close] # Each closes higher
|
|
103
111
|
end
|
|
104
112
|
|
|
105
|
-
def self.three_black_crows?(
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
def self.three_black_crows?(candles)
|
|
114
|
+
first, second, third = candles
|
|
115
|
+
first[:close] < first[:open] &&
|
|
116
|
+
second[:close] < second[:open] &&
|
|
117
|
+
third[:close] < third[:open] && # All bearish
|
|
118
|
+
second[:close] < first[:close] &&
|
|
119
|
+
third[:close] < second[:close] # Each closes lower
|
|
108
120
|
end
|
|
109
121
|
|
|
110
122
|
def self.head_and_shoulders?(highs, _lows)
|
|
@@ -123,8 +135,8 @@ module DhanHQ
|
|
|
123
135
|
head[:value] > left_shoulder[:value] && head[:value] > right_shoulder[:value]
|
|
124
136
|
end
|
|
125
137
|
|
|
126
|
-
def self.double_top_bottom?(highs, lows,
|
|
127
|
-
return
|
|
138
|
+
def self.double_top_bottom?(highs, lows, _closes)
|
|
139
|
+
return false if highs.length < 20
|
|
128
140
|
|
|
129
141
|
# Double top: two similar highs with dip in between
|
|
130
142
|
peaks = find_peaks(highs)
|
|
@@ -148,15 +160,13 @@ module DhanHQ
|
|
|
148
160
|
end
|
|
149
161
|
end
|
|
150
162
|
|
|
151
|
-
|
|
163
|
+
false
|
|
152
164
|
end
|
|
153
165
|
|
|
154
166
|
def self.find_peaks(values)
|
|
155
167
|
peaks = []
|
|
156
168
|
(1...(values.length - 1)).each do |i|
|
|
157
|
-
if values[i] > values[i - 1] && values[i] > values[i + 1]
|
|
158
|
-
peaks << { index: i, value: values[i] }
|
|
159
|
-
end
|
|
169
|
+
peaks << { index: i, value: values[i] } if values[i] > values[i - 1] && values[i] > values[i + 1]
|
|
160
170
|
end
|
|
161
171
|
peaks
|
|
162
172
|
end
|
|
@@ -164,12 +174,19 @@ module DhanHQ
|
|
|
164
174
|
def self.find_troughs(values)
|
|
165
175
|
troughs = []
|
|
166
176
|
(1...(values.length - 1)).each do |i|
|
|
167
|
-
if values[i] < values[i - 1] && values[i] < values[i + 1]
|
|
168
|
-
troughs << { index: i, value: values[i] }
|
|
169
|
-
end
|
|
177
|
+
troughs << { index: i, value: values[i] } if values[i] < values[i - 1] && values[i] < values[i + 1]
|
|
170
178
|
end
|
|
171
179
|
troughs
|
|
172
180
|
end
|
|
181
|
+
|
|
182
|
+
def self.build_candle(opens, highs, lows, closes, index)
|
|
183
|
+
{
|
|
184
|
+
open: opens[index],
|
|
185
|
+
high: highs[index],
|
|
186
|
+
low: lows[index],
|
|
187
|
+
close: closes[index]
|
|
188
|
+
}
|
|
189
|
+
end
|
|
173
190
|
end
|
|
174
191
|
end
|
|
175
192
|
end
|
|
@@ -20,9 +20,9 @@ module DhanHQ
|
|
|
20
20
|
return {} if closes.nil? || closes.empty?
|
|
21
21
|
|
|
22
22
|
# Technical indicators
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
sma20 = DhanHQ::Indicators::TechnicalIndicators.sma(closes, 20)
|
|
24
|
+
sma50 = DhanHQ::Indicators::TechnicalIndicators.sma(closes, 50)
|
|
25
|
+
ema12 = DhanHQ::Indicators::TechnicalIndicators.ema(closes, 12)
|
|
26
26
|
rsi = DhanHQ::Indicators::TechnicalIndicators.rsi(closes, 14)
|
|
27
27
|
macd = DhanHQ::Indicators::TechnicalIndicators.macd(closes)
|
|
28
28
|
|
|
@@ -43,9 +43,9 @@ module DhanHQ
|
|
|
43
43
|
trend: trend,
|
|
44
44
|
structure_break: structure_break,
|
|
45
45
|
indicators: {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
sma20: sma20.last,
|
|
47
|
+
sma50: sma50.last,
|
|
48
|
+
ema12: ema12.last,
|
|
49
49
|
rsi: rsi.last,
|
|
50
50
|
macd: macd[:macd].last,
|
|
51
51
|
macd_signal: macd[:signal].last,
|
|
@@ -64,8 +64,6 @@ module DhanHQ
|
|
|
64
64
|
}
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
private
|
|
68
|
-
|
|
69
67
|
def self.extract_closes(data)
|
|
70
68
|
data.map { |d| d[:close] || d["close"] || d["c"] || d[:c] }.compact
|
|
71
69
|
end
|