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
|
@@ -77,77 +77,64 @@ puts
|
|
|
77
77
|
|
|
78
78
|
# Helper methods (defined before use)
|
|
79
79
|
def perform_technical_analysis(agent, symbol, exchange_segment)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
)
|
|
80
|
+
analysis_result = agent.analysis_agent.analyze_symbol(
|
|
81
|
+
symbol: symbol,
|
|
82
|
+
exchange_segment: exchange_segment
|
|
83
|
+
)
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
puts " ⚠️ Error: #{analysis_result[:error]}"
|
|
88
|
-
return
|
|
89
|
-
end
|
|
85
|
+
return log_analysis_error(analysis_result) if analysis_result[:error]
|
|
90
86
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
puts " 📊 Patterns: #{analysis[:patterns]&.dig(:candlestick)&.length || 0} patterns"
|
|
98
|
-
puts " 📊 Structure Break: #{analysis[:structure_break]&.dig(:broken) ? 'Yes' : 'No'}"
|
|
99
|
-
rescue StandardError => e
|
|
100
|
-
puts " ❌ Error: #{e.message}"
|
|
101
|
-
end
|
|
87
|
+
analysis = analysis_result[:analysis]
|
|
88
|
+
return log_analysis_empty if analysis.nil? || analysis.empty?
|
|
89
|
+
|
|
90
|
+
log_analysis_summary(analysis)
|
|
91
|
+
rescue StandardError => e
|
|
92
|
+
puts " ❌ Error: #{e.message}"
|
|
102
93
|
end
|
|
103
94
|
|
|
104
95
|
def perform_swing_scan(agent, symbol, exchange_segment)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
96
|
+
candidates = agent.swing_scanner.scan_symbols(
|
|
97
|
+
[symbol],
|
|
98
|
+
exchange_segment: exchange_segment,
|
|
99
|
+
min_score: 40,
|
|
100
|
+
verbose: false
|
|
101
|
+
)
|
|
112
102
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
end
|
|
122
|
-
rescue StandardError => e
|
|
123
|
-
puts " ❌ Error: #{e.message}"
|
|
103
|
+
if candidates.empty?
|
|
104
|
+
puts " ⚠️ No swing candidates found (score < 40)"
|
|
105
|
+
else
|
|
106
|
+
candidate = candidates.first
|
|
107
|
+
puts " ✅ Swing Candidate Found"
|
|
108
|
+
puts " 📈 Score: #{candidate[:score]}/100"
|
|
109
|
+
puts " 📊 Trend: #{candidate[:analysis][:trend][:trend]}"
|
|
110
|
+
puts " 💡 #{candidate[:recommendation] || 'Analysis complete'}"
|
|
124
111
|
end
|
|
112
|
+
rescue StandardError => e
|
|
113
|
+
puts " ❌ Error: #{e.message}"
|
|
125
114
|
end
|
|
126
115
|
|
|
127
116
|
def perform_options_scan(agent, symbol, exchange_segment)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
)
|
|
117
|
+
options_setups = agent.options_scanner.scan_for_options_setups(
|
|
118
|
+
symbol,
|
|
119
|
+
exchange_segment: exchange_segment,
|
|
120
|
+
min_score: 40,
|
|
121
|
+
verbose: true
|
|
122
|
+
)
|
|
135
123
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
end
|
|
143
|
-
else
|
|
144
|
-
puts " ⚠️ No options setups found (min_score: 40)"
|
|
145
|
-
puts " Try lowering min_score or check verbose output above for details"
|
|
124
|
+
if options_setups[:error]
|
|
125
|
+
puts " ⚠️ #{options_setups[:error]}"
|
|
126
|
+
elsif options_setups[:setups] && !options_setups[:setups].empty?
|
|
127
|
+
puts " ✅ Found #{options_setups[:setups].length} options setups"
|
|
128
|
+
options_setups[:setups].first(3).each do |setup|
|
|
129
|
+
puts " 📊 #{setup[:type].to_s.upcase} @ #{setup[:strike]}: Score #{setup[:score]}/100"
|
|
146
130
|
end
|
|
147
|
-
|
|
148
|
-
puts "
|
|
149
|
-
puts "
|
|
131
|
+
else
|
|
132
|
+
puts " ⚠️ No options setups found (min_score: 40)"
|
|
133
|
+
puts " Try lowering min_score or check verbose output above for details"
|
|
150
134
|
end
|
|
135
|
+
rescue StandardError => e
|
|
136
|
+
puts " ❌ Error: #{e.message}"
|
|
137
|
+
puts " #{e.backtrace.first(3).join("\n ")}" if e.backtrace
|
|
151
138
|
end
|
|
152
139
|
|
|
153
140
|
# Initialize agent
|
|
@@ -160,11 +147,7 @@ puts "🤔 Letting LLM decide what to analyze..."
|
|
|
160
147
|
puts "─" * 60
|
|
161
148
|
|
|
162
149
|
# Get market context first (can be fetched from real data)
|
|
163
|
-
market_context =
|
|
164
|
-
ARGV[1]
|
|
165
|
-
else
|
|
166
|
-
"Current market: SENSEX, NIFTY and RELIANCE are active. Looking for trading opportunities."
|
|
167
|
-
end
|
|
150
|
+
market_context = ARGV[1] || "Current market: SENSEX, NIFTY and RELIANCE are active. Looking for trading opportunities."
|
|
168
151
|
|
|
169
152
|
user_query = ARGV[0] || "Analyze SENSEX and find swing trading opportunities"
|
|
170
153
|
|
|
@@ -183,7 +166,8 @@ begin
|
|
|
183
166
|
puts " Falling back to default analysis..."
|
|
184
167
|
plan = {
|
|
185
168
|
"analysis_plan" => [
|
|
186
|
-
{ "symbol" => "RELIANCE", "exchange_segment" => "NSE_EQ", "analysis_type" => "technical_analysis",
|
|
169
|
+
{ "symbol" => "RELIANCE", "exchange_segment" => "NSE_EQ", "analysis_type" => "technical_analysis",
|
|
170
|
+
"priority" => 1 },
|
|
187
171
|
{ "symbol" => "TCS", "exchange_segment" => "NSE_EQ", "analysis_type" => "swing_scan", "priority" => 2 },
|
|
188
172
|
{ "symbol" => "NIFTY", "exchange_segment" => "IDX_I", "analysis_type" => "options_scan", "priority" => 3 }
|
|
189
173
|
],
|
|
@@ -208,13 +192,19 @@ begin
|
|
|
208
192
|
puts "Task #{idx + 1}: #{analysis_type} for #{symbol} (#{exchange_segment})"
|
|
209
193
|
puts "─" * 60
|
|
210
194
|
|
|
211
|
-
|
|
212
|
-
when "technical_analysis", "all"
|
|
195
|
+
if analysis_type == "all"
|
|
213
196
|
perform_technical_analysis(agent, symbol, exchange_segment)
|
|
214
|
-
when "swing_scan", "all"
|
|
215
197
|
perform_swing_scan(agent, symbol, exchange_segment)
|
|
216
|
-
when "options_scan", "all"
|
|
217
198
|
perform_options_scan(agent, symbol, exchange_segment)
|
|
199
|
+
else
|
|
200
|
+
case analysis_type
|
|
201
|
+
when "technical_analysis"
|
|
202
|
+
perform_technical_analysis(agent, symbol, exchange_segment)
|
|
203
|
+
when "swing_scan"
|
|
204
|
+
perform_swing_scan(agent, symbol, exchange_segment)
|
|
205
|
+
when "options_scan"
|
|
206
|
+
perform_options_scan(agent, symbol, exchange_segment)
|
|
207
|
+
end
|
|
218
208
|
end
|
|
219
209
|
|
|
220
210
|
puts
|
|
@@ -224,6 +214,70 @@ rescue StandardError => e
|
|
|
224
214
|
puts " #{e.backtrace.first(3).join("\n ")}" if e.backtrace
|
|
225
215
|
end
|
|
226
216
|
|
|
217
|
+
def log_analysis_error(analysis_result)
|
|
218
|
+
puts " ⚠️ Error: #{analysis_result[:error]}"
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def log_analysis_empty
|
|
222
|
+
puts " ⚠️ Error: Analysis returned empty result"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def log_analysis_summary(analysis)
|
|
226
|
+
puts " ✅ Analysis Complete"
|
|
227
|
+
puts trend_summary_text(analysis)
|
|
228
|
+
puts rsi_summary_text(analysis)
|
|
229
|
+
puts macd_summary_text(analysis)
|
|
230
|
+
puts current_price_text(analysis)
|
|
231
|
+
puts patterns_summary_text(analysis)
|
|
232
|
+
puts structure_break_text(analysis)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def trend_summary_text(analysis)
|
|
236
|
+
trend = analysis[:trend] || {}
|
|
237
|
+
trend_name = trend[:trend] || "N/A"
|
|
238
|
+
strength = trend[:strength] || 0
|
|
239
|
+
" 📊 Trend: #{trend_name} (#{strength}% strength)"
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def rsi_summary_text(analysis)
|
|
243
|
+
rsi = analysis[:indicators]&.dig(:rsi)
|
|
244
|
+
rsi_text = rsi ? rsi.round(2) : "N/A"
|
|
245
|
+
" 📊 RSI: #{rsi_text}"
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def macd_summary_text(analysis)
|
|
249
|
+
macd = analysis[:indicators]&.dig(:macd)
|
|
250
|
+
macd_text = macd ? macd.round(2) : "N/A"
|
|
251
|
+
" 📊 MACD: #{macd_text}"
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def current_price_text(analysis)
|
|
255
|
+
current_price = analysis[:current_price] || "N/A"
|
|
256
|
+
" 📊 Current Price: #{current_price}"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def patterns_summary_text(analysis)
|
|
260
|
+
candlestick_patterns = analysis[:patterns]&.dig(:candlestick) || []
|
|
261
|
+
" 📊 Patterns: #{candlestick_patterns.length} patterns"
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def structure_break_text(analysis)
|
|
265
|
+
broken = analysis[:structure_break]&.dig(:broken)
|
|
266
|
+
" 📊 Structure Break: #{broken ? 'Yes' : 'No'}"
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def format_score_breakdown(details)
|
|
270
|
+
"Trend=#{details[:trend]}, RSI=#{details[:rsi]}, MACD=#{details[:macd]}, " \
|
|
271
|
+
"Structure=#{details[:structure]}, Patterns=#{details[:patterns]}"
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def format_option_setup_details(setup)
|
|
275
|
+
iv = setup[:iv]&.round(2) || "N/A"
|
|
276
|
+
oi = setup[:oi] || "N/A"
|
|
277
|
+
volume = setup[:volume] || "N/A"
|
|
278
|
+
"IV: #{iv}% | OI: #{oi} | Volume: #{volume}"
|
|
279
|
+
end
|
|
280
|
+
|
|
227
281
|
# Uncomment below to also run manual examples for comparison
|
|
228
282
|
if ENV["SHOW_MANUAL_EXAMPLES"] == "true"
|
|
229
283
|
puts "=" * 60
|
|
@@ -237,121 +291,121 @@ if ENV["SHOW_MANUAL_EXAMPLES"] == "true"
|
|
|
237
291
|
puts "Example 1: Technical Analysis for RELIANCE"
|
|
238
292
|
puts "─" * 60
|
|
239
293
|
|
|
240
|
-
begin
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
294
|
+
begin
|
|
295
|
+
analysis_result = agent.analysis_agent.analyze_symbol(
|
|
296
|
+
symbol: "RELIANCE",
|
|
297
|
+
exchange_segment: "NSE_EQ"
|
|
298
|
+
)
|
|
245
299
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
300
|
+
if analysis_result[:error]
|
|
301
|
+
puts " ⚠️ Error: #{analysis_result[:error]}"
|
|
302
|
+
elsif analysis_result[:analysis].nil? || analysis_result[:analysis].empty?
|
|
303
|
+
puts " ⚠️ Error: Analysis returned empty result"
|
|
304
|
+
else
|
|
305
|
+
analysis = analysis_result[:analysis]
|
|
306
|
+
puts " ✅ Analysis Complete"
|
|
307
|
+
puts " 📊 Trend: #{analysis[:trend]&.dig(:trend) || 'N/A'} (#{analysis[:trend]&.dig(:strength) || 0}% strength)"
|
|
308
|
+
puts " 📊 RSI: #{analysis[:indicators]&.dig(:rsi)&.round(2) || 'N/A'}"
|
|
309
|
+
puts " 📊 MACD: #{analysis[:indicators]&.dig(:macd)&.round(2) || 'N/A'}"
|
|
310
|
+
puts " 📊 Current Price: #{analysis[:current_price] || 'N/A'}"
|
|
311
|
+
puts " 📊 Patterns Detected: #{analysis[:patterns]&.dig(:candlestick)&.length || 0} candlestick patterns"
|
|
312
|
+
puts " 📊 Structure Break: #{analysis[:structure_break]&.dig(:broken) ? 'Yes' : 'No'}"
|
|
313
|
+
|
|
314
|
+
# Generate swing trading recommendation
|
|
315
|
+
begin
|
|
316
|
+
recommendation = agent.analysis_agent.generate_recommendation(
|
|
317
|
+
analysis_result,
|
|
318
|
+
trading_style: :swing
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
if recommendation && !recommendation[:error] && recommendation.is_a?(Hash)
|
|
322
|
+
puts "\n 💡 Swing Trading Recommendation:"
|
|
323
|
+
puts " Action: #{recommendation['recommendation']&.upcase || 'N/A'}"
|
|
324
|
+
puts " Entry: #{recommendation['entry_price'] || 'N/A'}"
|
|
325
|
+
puts " Stop Loss: #{recommendation['stop_loss'] || 'N/A'}"
|
|
326
|
+
puts " Target: #{recommendation['target_price'] || 'N/A'}"
|
|
327
|
+
puts " Risk/Reward: #{recommendation['risk_reward_ratio']&.round(2) || 'N/A'}"
|
|
328
|
+
puts " Confidence: #{(recommendation['confidence'] * 100).round}%" if recommendation["confidence"]
|
|
329
|
+
end
|
|
330
|
+
rescue StandardError => e
|
|
331
|
+
puts " ⚠️ Could not generate recommendation: #{e.message}"
|
|
275
332
|
end
|
|
276
|
-
rescue StandardError => e
|
|
277
|
-
puts " ⚠️ Could not generate recommendation: #{e.message}"
|
|
278
333
|
end
|
|
334
|
+
rescue StandardError => e
|
|
335
|
+
puts " ❌ Error: #{e.message}"
|
|
336
|
+
puts " #{e.backtrace.first(3).join("\n ")}" if e.backtrace
|
|
279
337
|
end
|
|
280
|
-
rescue StandardError => e
|
|
281
|
-
puts " ❌ Error: #{e.message}"
|
|
282
|
-
puts " #{e.backtrace.first(3).join("\n ")}" if e.backtrace
|
|
283
|
-
end
|
|
284
338
|
|
|
285
|
-
puts
|
|
286
|
-
puts "Example 2: Swing Trading Scanner"
|
|
287
|
-
puts "─" * 60
|
|
339
|
+
puts
|
|
340
|
+
puts "Example 2: Swing Trading Scanner"
|
|
341
|
+
puts "─" * 60
|
|
288
342
|
|
|
289
|
-
begin
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
343
|
+
begin
|
|
344
|
+
# Scan a few symbols for swing opportunities
|
|
345
|
+
symbols_to_scan = ["RELIANCE", "TCS", "INFY"]
|
|
346
|
+
puts " 🔍 Scanning #{symbols_to_scan.length} symbols for swing opportunities..."
|
|
293
347
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
348
|
+
candidates = agent.swing_scanner.scan_symbols(
|
|
349
|
+
symbols_to_scan,
|
|
350
|
+
exchange_segment: "NSE_EQ",
|
|
351
|
+
min_score: 40,
|
|
352
|
+
verbose: true
|
|
353
|
+
)
|
|
300
354
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
355
|
+
if candidates.empty?
|
|
356
|
+
puts " ⚠️ No swing candidates found above minimum score (40/100)"
|
|
357
|
+
puts " Try lowering min_score or check rejected candidates above"
|
|
358
|
+
else
|
|
359
|
+
puts " ✅ Found #{candidates.length} swing candidates:"
|
|
360
|
+
candidates.each do |candidate|
|
|
361
|
+
puts " 📈 #{candidate[:symbol]}: Score #{candidate[:score]}/100"
|
|
362
|
+
if candidate[:score_details]
|
|
363
|
+
details = candidate[:score_details]
|
|
364
|
+
puts " Breakdown: #{format_score_breakdown(details)}"
|
|
365
|
+
end
|
|
366
|
+
trend = candidate[:analysis][:trend]
|
|
367
|
+
puts " Trend: #{trend[:trend]} (#{trend[:strength]}% strength)"
|
|
368
|
+
puts " #{candidate[:interpretation]}"
|
|
311
369
|
end
|
|
312
|
-
trend = candidate[:analysis][:trend]
|
|
313
|
-
puts " Trend: #{trend[:trend]} (#{trend[:strength]}% strength)"
|
|
314
|
-
puts " #{candidate[:interpretation]}"
|
|
315
370
|
end
|
|
371
|
+
rescue StandardError => e
|
|
372
|
+
puts " ❌ Error: #{e.message}"
|
|
373
|
+
puts " #{e.backtrace.first(3).join("\n ")}" if e.backtrace
|
|
316
374
|
end
|
|
317
|
-
rescue StandardError => e
|
|
318
|
-
puts " ❌ Error: #{e.message}"
|
|
319
|
-
puts " #{e.backtrace.first(3).join("\n ")}" if e.backtrace
|
|
320
|
-
end
|
|
321
375
|
|
|
322
|
-
puts
|
|
323
|
-
puts "Example 3: Intraday Options Scanner"
|
|
324
|
-
puts "─" * 60
|
|
376
|
+
puts
|
|
377
|
+
puts "Example 3: Intraday Options Scanner"
|
|
378
|
+
puts "─" * 60
|
|
325
379
|
|
|
326
|
-
begin
|
|
327
|
-
|
|
380
|
+
begin
|
|
381
|
+
puts " 🔍 Scanning NIFTY for intraday options opportunities..."
|
|
328
382
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
383
|
+
options_setups = agent.options_scanner.scan_for_options_setups(
|
|
384
|
+
"NIFTY",
|
|
385
|
+
exchange_segment: "IDX_I",
|
|
386
|
+
min_score: 40,
|
|
387
|
+
verbose: true
|
|
388
|
+
)
|
|
335
389
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
390
|
+
if options_setups[:error]
|
|
391
|
+
puts " ⚠️ #{options_setups[:error]}"
|
|
392
|
+
elsif options_setups[:setups] && !options_setups[:setups].empty?
|
|
393
|
+
puts " ✅ Found #{options_setups[:setups].length} options setups:"
|
|
394
|
+
options_setups[:setups].each do |setup|
|
|
395
|
+
puts " 📊 #{setup[:type].to_s.upcase} @ #{setup[:strike]}"
|
|
396
|
+
puts " #{format_option_setup_details(setup)}"
|
|
397
|
+
puts " Score: #{setup[:score]}/100 | Recommendation: #{setup[:recommendation]}"
|
|
398
|
+
end
|
|
399
|
+
else
|
|
400
|
+
puts " ⚠️ No options setups found above minimum score (40/100)"
|
|
401
|
+
puts " Check rejected setups above or try lowering min_score"
|
|
344
402
|
end
|
|
345
|
-
else
|
|
346
|
-
puts " ⚠️ No options setups found above minimum score (40/100)"
|
|
347
|
-
puts " Check rejected setups above or try lowering min_score"
|
|
348
|
-
end
|
|
349
403
|
rescue StandardError => e
|
|
350
404
|
puts " ❌ Error: #{e.message}"
|
|
351
405
|
puts " #{e.backtrace.first(3).join("\n ")}" if e.backtrace
|
|
352
406
|
end
|
|
353
407
|
|
|
354
|
-
end
|
|
408
|
+
end
|
|
355
409
|
|
|
356
410
|
puts
|
|
357
411
|
puts "=" * 60
|