prab-cli 1.2.1 → 1.2.4

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.
@@ -0,0 +1,559 @@
1
+ "use strict";
2
+ /**
3
+ * Trading Signal Generator with AI Reasoning
4
+ * Combines technical analysis with AI-powered insights
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.generateTradingSignal = generateTradingSignal;
11
+ exports.displaySignal = displaySignal;
12
+ exports.quickSignal = quickSignal;
13
+ exports.fullSignal = fullSignal;
14
+ exports.displayComprehensiveAnalysis = displayComprehensiveAnalysis;
15
+ exports.comprehensiveAnalysis = comprehensiveAnalysis;
16
+ const chalk_1 = __importDefault(require("chalk"));
17
+ const ora_1 = __importDefault(require("ora"));
18
+ const data_fetcher_1 = require("./data-fetcher");
19
+ const analyzer_1 = require("./analyzer");
20
+ const market_analyzer_1 = require("./market-analyzer");
21
+ const config_1 = require("../config");
22
+ const groq_provider_1 = require("../models/groq-provider");
23
+ /**
24
+ * Generate AI reasoning for the trading signal
25
+ */
26
+ async function generateAIReasoning(symbol, signal, price, priceChange24h) {
27
+ const apiKey = (0, config_1.getApiKey)();
28
+ if (!apiKey) {
29
+ return "AI reasoning unavailable (no API key configured)";
30
+ }
31
+ const modelConfig = (0, config_1.getModelConfig)();
32
+ const provider = new groq_provider_1.GroqProvider(modelConfig.modelId, 0.7);
33
+ provider.initialize(apiKey, modelConfig.modelId);
34
+ const prompt = `You are a crypto trading analyst. Based on the following technical analysis, provide a brief (2-3 sentences) trading insight and recommendation.
35
+
36
+ Symbol: ${symbol}
37
+ Current Price: $${price.toLocaleString()}
38
+ 24h Change: ${priceChange24h.toFixed(2)}%
39
+
40
+ Technical Analysis:
41
+ - Signal: ${signal.signal}
42
+ - Confidence: ${signal.confidence}%
43
+ - Trend: ${signal.indicators.trend}
44
+ - EMA Crossover: ${signal.indicators.emaCrossover}
45
+ - Price vs EMAs: ${signal.indicators.priceVsEMA}
46
+ - Suggested Stop-Loss: ${signal.stopLoss}%
47
+ - Suggested Take-Profit: ${signal.takeProfit}%
48
+
49
+ Key Observations:
50
+ ${signal.reasoning.map((r) => `- ${r}`).join("\n")}
51
+
52
+ Provide a concise trading insight (2-3 sentences) explaining the signal and any cautions. Be direct and actionable.`;
53
+ try {
54
+ const stream = provider.streamChat([{ role: "user", content: prompt }], [] // No tools needed
55
+ );
56
+ let response = "";
57
+ for await (const chunk of stream) {
58
+ if (chunk.content && typeof chunk.content === "string") {
59
+ response += chunk.content;
60
+ }
61
+ }
62
+ return response.trim();
63
+ }
64
+ catch (error) {
65
+ return `AI reasoning unavailable: ${error.message}`;
66
+ }
67
+ }
68
+ /**
69
+ * Main function to generate trading signal with AI reasoning
70
+ */
71
+ async function generateTradingSignal(symbol, interval = "1h", includeAI = true) {
72
+ const spinner = (0, ora_1.default)(`Fetching ${symbol.toUpperCase()} data...`).start();
73
+ try {
74
+ // Fetch crypto data
75
+ const data = await (0, data_fetcher_1.fetchCryptoData)(symbol, interval, 250); // Get 250 candles for EMA200
76
+ spinner.text = "Analyzing chart data...";
77
+ // Generate technical signal
78
+ const signal = (0, analyzer_1.generateSignal)(data);
79
+ spinner.text = "Generating trading signal...";
80
+ let aiReasoning;
81
+ // Generate AI reasoning if requested
82
+ if (includeAI) {
83
+ spinner.text = "Getting AI insights...";
84
+ aiReasoning = await generateAIReasoning(data.symbol, signal, data.currentPrice, data.priceChangePercent24h);
85
+ }
86
+ spinner.succeed(`Analysis complete for ${data.symbol}`);
87
+ return {
88
+ success: true,
89
+ symbol: data.symbol,
90
+ signal,
91
+ aiReasoning,
92
+ price: data.currentPrice,
93
+ priceChange24h: data.priceChangePercent24h,
94
+ };
95
+ }
96
+ catch (error) {
97
+ spinner.fail(`Failed to analyze ${symbol}`);
98
+ return {
99
+ success: false,
100
+ symbol: (0, data_fetcher_1.normalizeSymbol)(symbol),
101
+ error: error.message,
102
+ };
103
+ }
104
+ }
105
+ /**
106
+ * Display trading signal in terminal
107
+ */
108
+ function displaySignal(result) {
109
+ if (!result.success || !result.signal) {
110
+ console.log(chalk_1.default.red(`\nError: ${result.error}`));
111
+ return;
112
+ }
113
+ const { signal, symbol, price, priceChange24h, aiReasoning } = result;
114
+ // Signal colors
115
+ const signalColor = signal.signal === "BUY"
116
+ ? chalk_1.default.green.bold
117
+ : signal.signal === "SELL"
118
+ ? chalk_1.default.red.bold
119
+ : chalk_1.default.yellow.bold;
120
+ const signalIcon = signal.signal === "BUY" ? "\u{1F7E2}" : signal.signal === "SELL" ? "\u{1F534}" : "\u{1F7E1}";
121
+ const trendIcon = signal.indicators.trend === "bullish"
122
+ ? chalk_1.default.green("\u{2191}")
123
+ : signal.indicators.trend === "bearish"
124
+ ? chalk_1.default.red("\u{2193}")
125
+ : chalk_1.default.yellow("\u{2192}");
126
+ const changeColor = priceChange24h >= 0 ? chalk_1.default.green : chalk_1.default.red;
127
+ const changeSign = priceChange24h >= 0 ? "+" : "";
128
+ // Format price for display
129
+ const formattedPrice = price < 1
130
+ ? `$${price.toFixed(4)}`
131
+ : price < 100
132
+ ? `$${price.toFixed(2)}`
133
+ : `$${price.toLocaleString(undefined, { maximumFractionDigits: 2 })}`;
134
+ // Header with current price
135
+ console.log("");
136
+ console.log(chalk_1.default.cyan("\u{250C}" + "\u{2500}".repeat(45) + "\u{2510}"));
137
+ console.log(chalk_1.default.cyan("\u{2502}") +
138
+ chalk_1.default.bold.white(` \u{1F4CA} ${symbol}`.padEnd(44)) +
139
+ chalk_1.default.cyan("\u{2502}"));
140
+ console.log(chalk_1.default.cyan("\u{2502}") +
141
+ chalk_1.default.bold.yellow(` Current Price: ${formattedPrice}`).padEnd(44) +
142
+ chalk_1.default.cyan("\u{2502}"));
143
+ console.log(chalk_1.default.cyan("\u{2502}") +
144
+ ` 24h: ${changeColor(changeSign + priceChange24h.toFixed(2) + "%")}`.padEnd(52) +
145
+ chalk_1.default.cyan("\u{2502}"));
146
+ console.log(chalk_1.default.cyan("\u{251C}" + "\u{2500}".repeat(45) + "\u{2524}"));
147
+ // Signal
148
+ console.log(chalk_1.default.cyan("\u{2502}") +
149
+ ` Signal: ${signalIcon} ${signalColor(signal.signal)}`.padEnd(53) +
150
+ chalk_1.default.cyan("\u{2502}"));
151
+ console.log(chalk_1.default.cyan("\u{2502}") +
152
+ ` Confidence: ${chalk_1.default.white(signal.confidence + "%")}`.padEnd(53) +
153
+ chalk_1.default.cyan("\u{2502}"));
154
+ console.log(chalk_1.default.cyan("\u{2502}") +
155
+ ` Stop-Loss: ${chalk_1.default.red("-" + signal.stopLoss + "%")}`.padEnd(53) +
156
+ chalk_1.default.cyan("\u{2502}"));
157
+ console.log(chalk_1.default.cyan("\u{2502}") +
158
+ ` Take-Profit: ${chalk_1.default.green("+" + signal.takeProfit + "%")}`.padEnd(53) +
159
+ chalk_1.default.cyan("\u{2502}"));
160
+ // Trend info
161
+ console.log(chalk_1.default.cyan("\u{251C}" + "\u{2500}".repeat(45) + "\u{2524}"));
162
+ console.log(chalk_1.default.cyan("\u{2502}") +
163
+ ` Trend: ${trendIcon} ${chalk_1.default.white(signal.indicators.trend)}`.padEnd(53) +
164
+ chalk_1.default.cyan("\u{2502}"));
165
+ // EMA Values
166
+ console.log(chalk_1.default.cyan("\u{251C}" + "\u{2500}".repeat(45) + "\u{2524}"));
167
+ console.log(chalk_1.default.cyan("\u{2502}") + chalk_1.default.gray(" EMA Indicators:").padEnd(53) + chalk_1.default.cyan("\u{2502}"));
168
+ console.log(chalk_1.default.cyan("\u{2502}") +
169
+ chalk_1.default.gray(` EMA9: $${signal.indicators.currentEMA9.toFixed(2)}`).padEnd(44) +
170
+ chalk_1.default.cyan("\u{2502}"));
171
+ console.log(chalk_1.default.cyan("\u{2502}") +
172
+ chalk_1.default.gray(` EMA21: $${signal.indicators.currentEMA21.toFixed(2)}`).padEnd(44) +
173
+ chalk_1.default.cyan("\u{2502}"));
174
+ console.log(chalk_1.default.cyan("\u{2502}") +
175
+ chalk_1.default.gray(` EMA50: $${signal.indicators.currentEMA50.toFixed(2)}`).padEnd(44) +
176
+ chalk_1.default.cyan("\u{2502}"));
177
+ if (signal.indicators.currentEMA200 > 0) {
178
+ console.log(chalk_1.default.cyan("\u{2502}") +
179
+ chalk_1.default.gray(` EMA200: $${signal.indicators.currentEMA200.toFixed(2)}`).padEnd(44) +
180
+ chalk_1.default.cyan("\u{2502}"));
181
+ }
182
+ // Technical observations
183
+ console.log(chalk_1.default.cyan("\u{251C}" + "\u{2500}".repeat(45) + "\u{2524}"));
184
+ console.log(chalk_1.default.cyan("\u{2502}") + chalk_1.default.gray(" Technical Analysis:").padEnd(53) + chalk_1.default.cyan("\u{2502}"));
185
+ for (const reason of signal.reasoning.slice(0, 4)) {
186
+ const truncated = reason.length > 40 ? reason.substring(0, 37) + "..." : reason;
187
+ console.log(chalk_1.default.cyan("\u{2502}") +
188
+ chalk_1.default.gray(` \u{2022} ${truncated}`).padEnd(44) +
189
+ chalk_1.default.cyan("\u{2502}"));
190
+ }
191
+ // AI Reasoning
192
+ if (aiReasoning) {
193
+ console.log(chalk_1.default.cyan("\u{251C}" + "\u{2500}".repeat(45) + "\u{2524}"));
194
+ console.log(chalk_1.default.cyan("\u{2502}") +
195
+ chalk_1.default.magenta.bold(" \u{1F916} AI Insight:").padEnd(53) +
196
+ chalk_1.default.cyan("\u{2502}"));
197
+ // Word wrap AI reasoning
198
+ const words = aiReasoning.split(" ");
199
+ let line = " ";
200
+ for (const word of words) {
201
+ if (line.length + word.length > 40) {
202
+ console.log(chalk_1.default.cyan("\u{2502}") + chalk_1.default.white(line.padEnd(44)) + chalk_1.default.cyan("\u{2502}"));
203
+ line = " " + word + " ";
204
+ }
205
+ else {
206
+ line += word + " ";
207
+ }
208
+ }
209
+ if (line.trim()) {
210
+ console.log(chalk_1.default.cyan("\u{2502}") + chalk_1.default.white(line.padEnd(44)) + chalk_1.default.cyan("\u{2502}"));
211
+ }
212
+ }
213
+ // Footer
214
+ console.log(chalk_1.default.cyan("\u{2514}" + "\u{2500}".repeat(45) + "\u{2518}"));
215
+ // Disclaimer
216
+ console.log("");
217
+ console.log(chalk_1.default.gray.italic(" \u{26A0}\u{FE0F} This is not financial advice. Always do your own research."));
218
+ console.log("");
219
+ }
220
+ /**
221
+ * Quick signal check (no AI)
222
+ */
223
+ async function quickSignal(symbol) {
224
+ const result = await generateTradingSignal(symbol, "1h", false);
225
+ displaySignal(result);
226
+ }
227
+ /**
228
+ * Full signal with AI reasoning
229
+ */
230
+ async function fullSignal(symbol, interval = "1h") {
231
+ const result = await generateTradingSignal(symbol, interval, true);
232
+ displaySignal(result);
233
+ }
234
+ // ============================================
235
+ // COMPREHENSIVE ANALYSIS
236
+ // ============================================
237
+ /**
238
+ * Generate AI analysis for comprehensive market data
239
+ */
240
+ async function generateComprehensiveAIAnalysis(analysis) {
241
+ const apiKey = (0, config_1.getApiKey)();
242
+ if (!apiKey) {
243
+ return "AI analysis unavailable (no API key configured)";
244
+ }
245
+ const modelConfig = (0, config_1.getModelConfig)();
246
+ const provider = new groq_provider_1.GroqProvider(modelConfig.modelId, 0.7);
247
+ provider.initialize(apiKey, modelConfig.modelId);
248
+ const prompt = `You are an expert crypto trading analyst. Provide a detailed but concise analysis (4-6 sentences) based on the following comprehensive market data.
249
+
250
+ Symbol: ${analysis.symbol}
251
+ Current Price: $${analysis.currentPrice.toLocaleString()}
252
+ 24h Change: ${analysis.priceChange24h.toFixed(2)}%
253
+
254
+ RECOMMENDATION: ${analysis.recommendation}
255
+ Confidence: ${analysis.confidence}%
256
+ Risk Level: ${analysis.riskLevel}
257
+
258
+ MULTI-TIMEFRAME ANALYSIS:
259
+ - 1H Trend: ${analysis.timeframes.short.signal} (${analysis.timeframes.short.trend.direction})
260
+ - 4H Trend: ${analysis.timeframes.medium.signal} (${analysis.timeframes.medium.trend.direction})
261
+ - 1D Trend: ${analysis.timeframes.long.signal} (${analysis.timeframes.long.trend.direction})
262
+ - Timeframe Alignment: ${analysis.timeframeAlignment}
263
+
264
+ INDICATORS:
265
+ - RSI(14): ${analysis.indicators.rsi.current.toFixed(1)} (${analysis.indicators.rsi.condition})
266
+ - MACD: ${analysis.indicators.macd.crossover} crossover, momentum ${analysis.indicators.macd.momentum}
267
+ - Bollinger: Price ${analysis.indicators.bollinger.pricePosition}, ${analysis.indicators.bollinger.squeeze ? "SQUEEZE detected" : "normal bandwidth"}
268
+ - Volume: ${analysis.indicators.volume.volumeRatio.toFixed(1)}x average, ${analysis.indicators.volume.trend} trend
269
+ - ATR Volatility: ${analysis.indicators.atr.volatility} (${analysis.indicators.atr.percentOfPrice.toFixed(1)}% of price)
270
+
271
+ KEY LEVELS:
272
+ - Support: $${analysis.indicators.supportResistance.nearestSupport.toFixed(2)} (${analysis.indicators.supportResistance.distanceToSupport.toFixed(1)}% away)
273
+ - Resistance: $${analysis.indicators.supportResistance.nearestResistance.toFixed(2)} (${analysis.indicators.supportResistance.distanceToResistance.toFixed(1)}% away)
274
+
275
+ TIMING:
276
+ - Action: ${analysis.timing.action}
277
+ - Entry Zone: $${analysis.timing.entryZone.low.toFixed(2)} - $${analysis.timing.entryZone.high.toFixed(2)}
278
+
279
+ TRADE SETUP:
280
+ - Entry: $${analysis.tradeSetup.entry.toFixed(2)}
281
+ - Stop Loss: $${analysis.tradeSetup.stopLoss.toFixed(2)}
282
+ - Target 1: $${analysis.tradeSetup.target1.toFixed(2)}
283
+ - Target 2: $${analysis.tradeSetup.target2.toFixed(2)}
284
+ - Risk/Reward: ${analysis.tradeSetup.riskRewardRatio}:1
285
+
286
+ MARKET CONDITION: ${analysis.marketCondition.type}
287
+ ${analysis.marketCondition.description}
288
+
289
+ Bullish Factors:
290
+ ${analysis.reasoning.bullishFactors
291
+ .slice(0, 3)
292
+ .map((f) => `- ${f}`)
293
+ .join("\n")}
294
+
295
+ Bearish Factors:
296
+ ${analysis.reasoning.bearishFactors
297
+ .slice(0, 3)
298
+ .map((f) => `- ${f}`)
299
+ .join("\n")}
300
+
301
+ Warnings:
302
+ ${analysis.reasoning.warnings.map((w) => `- ${w}`).join("\n")}
303
+
304
+ Provide a detailed trading analysis (4-6 sentences) that:
305
+ 1. Explains the current market structure and why the recommendation makes sense
306
+ 2. Specifies WHEN to enter (now, wait for pullback, wait for breakout, etc.)
307
+ 3. Mentions specific price levels to watch
308
+ 4. Highlights any risks or cautions
309
+ Be specific with prices and actionable advice.`;
310
+ try {
311
+ const stream = provider.streamChat([{ role: "user", content: prompt }], []);
312
+ let response = "";
313
+ for await (const chunk of stream) {
314
+ if (chunk.content && typeof chunk.content === "string") {
315
+ response += chunk.content;
316
+ }
317
+ }
318
+ return response.trim();
319
+ }
320
+ catch (error) {
321
+ return `AI analysis unavailable: ${error.message}`;
322
+ }
323
+ }
324
+ /**
325
+ * Format price for display
326
+ */
327
+ function formatPrice(price) {
328
+ if (price < 0.01)
329
+ return `$${price.toFixed(6)}`;
330
+ if (price < 1)
331
+ return `$${price.toFixed(4)}`;
332
+ if (price < 100)
333
+ return `$${price.toFixed(2)}`;
334
+ return `$${price.toLocaleString(undefined, { maximumFractionDigits: 2 })}`;
335
+ }
336
+ /**
337
+ * Word wrap text for terminal display
338
+ */
339
+ function wordWrap(text, maxWidth) {
340
+ const words = text.split(" ");
341
+ const lines = [];
342
+ let currentLine = "";
343
+ for (const word of words) {
344
+ if (currentLine.length + word.length + 1 > maxWidth) {
345
+ lines.push(currentLine.trim());
346
+ currentLine = word + " ";
347
+ }
348
+ else {
349
+ currentLine += word + " ";
350
+ }
351
+ }
352
+ if (currentLine.trim()) {
353
+ lines.push(currentLine.trim());
354
+ }
355
+ return lines;
356
+ }
357
+ /**
358
+ * Display comprehensive analysis in terminal
359
+ */
360
+ function displayComprehensiveAnalysis(analysis, aiAnalysis) {
361
+ const boxWidth = 55;
362
+ const contentWidth = boxWidth - 4;
363
+ const border = {
364
+ top: chalk_1.default.cyan("\u{250C}" + "\u{2500}".repeat(boxWidth) + "\u{2510}"),
365
+ mid: chalk_1.default.cyan("\u{251C}" + "\u{2500}".repeat(boxWidth) + "\u{2524}"),
366
+ bot: chalk_1.default.cyan("\u{2514}" + "\u{2500}".repeat(boxWidth) + "\u{2518}"),
367
+ left: chalk_1.default.cyan("\u{2502}"),
368
+ right: chalk_1.default.cyan("\u{2502}"),
369
+ };
370
+ const line = (content, padEnd = contentWidth) => {
371
+ console.log(border.left + " " + content.padEnd(padEnd) + " " + border.right);
372
+ };
373
+ // Recommendation colors and icons
374
+ const recColors = {
375
+ STRONG_BUY: chalk_1.default.green.bold,
376
+ BUY: chalk_1.default.green,
377
+ WAIT_TO_BUY: chalk_1.default.greenBright,
378
+ HOLD: chalk_1.default.yellow,
379
+ WAIT_TO_SELL: chalk_1.default.redBright,
380
+ SELL: chalk_1.default.red,
381
+ STRONG_SELL: chalk_1.default.red.bold,
382
+ };
383
+ const recIcons = {
384
+ STRONG_BUY: "\u{1F7E2}\u{1F7E2}",
385
+ BUY: "\u{1F7E2}",
386
+ WAIT_TO_BUY: "\u{1F7E1}\u{2197}",
387
+ HOLD: "\u{1F7E1}",
388
+ WAIT_TO_SELL: "\u{1F7E1}\u{2198}",
389
+ SELL: "\u{1F534}",
390
+ STRONG_SELL: "\u{1F534}\u{1F534}",
391
+ };
392
+ const changeColor = analysis.priceChange24h >= 0 ? chalk_1.default.green : chalk_1.default.red;
393
+ const changeSign = analysis.priceChange24h >= 0 ? "+" : "";
394
+ console.log("");
395
+ // Header
396
+ console.log(border.top);
397
+ line(chalk_1.default.bold.white(`\u{1F4CA} ${analysis.symbol} - Comprehensive Analysis`));
398
+ line(chalk_1.default.bold.yellow(`Current Price: ${formatPrice(analysis.currentPrice)}`) +
399
+ ` ${changeColor(changeSign + analysis.priceChange24h.toFixed(2) + "%")}`);
400
+ console.log(border.mid);
401
+ // Main Recommendation
402
+ const recColor = recColors[analysis.recommendation] || chalk_1.default.white;
403
+ const recIcon = recIcons[analysis.recommendation] || "";
404
+ line(chalk_1.default.bold(`\u{1F3AF} RECOMMENDATION: ${recIcon} ${recColor(analysis.recommendation)}`));
405
+ line(` Confidence: ${chalk_1.default.white(analysis.confidence + "%")} | Risk: ${analysis.riskLevel === "low"
406
+ ? chalk_1.default.green(analysis.riskLevel)
407
+ : analysis.riskLevel === "medium"
408
+ ? chalk_1.default.yellow(analysis.riskLevel)
409
+ : chalk_1.default.red(analysis.riskLevel)}`);
410
+ // Timing
411
+ console.log(border.mid);
412
+ line(chalk_1.default.bold("\u{23F0} TIMING"));
413
+ const timingAction = analysis.timing.action.replace(/_/g, " ").toUpperCase();
414
+ line(` ${chalk_1.default.cyan(timingAction)}`);
415
+ line(` Entry Zone: ${chalk_1.default.white(formatPrice(analysis.timing.entryZone.low))} - ${chalk_1.default.white(formatPrice(analysis.timing.entryZone.high))}`);
416
+ const timingLines = wordWrap(analysis.timing.reason, contentWidth - 3);
417
+ timingLines.forEach((l) => line(chalk_1.default.gray(` ${l}`)));
418
+ // Trade Setup
419
+ console.log(border.mid);
420
+ line(chalk_1.default.bold("\u{1F4B0} TRADE SETUP"));
421
+ line(` Entry: ${chalk_1.default.white(formatPrice(analysis.tradeSetup.entry))}`);
422
+ line(` Stop Loss: ${chalk_1.default.red(formatPrice(analysis.tradeSetup.stopLoss))} (${chalk_1.default.red("-" +
423
+ (((analysis.tradeSetup.entry - analysis.tradeSetup.stopLoss) / analysis.tradeSetup.entry) *
424
+ 100).toFixed(1) +
425
+ "%")})`);
426
+ line(` Target 1: ${chalk_1.default.green(formatPrice(analysis.tradeSetup.target1))} (${chalk_1.default.green("+" +
427
+ (((analysis.tradeSetup.target1 - analysis.tradeSetup.entry) / analysis.tradeSetup.entry) *
428
+ 100).toFixed(1) +
429
+ "%")})`);
430
+ line(` Target 2: ${chalk_1.default.green(formatPrice(analysis.tradeSetup.target2))} (${chalk_1.default.green("+" +
431
+ (((analysis.tradeSetup.target2 - analysis.tradeSetup.entry) / analysis.tradeSetup.entry) *
432
+ 100).toFixed(1) +
433
+ "%")})`);
434
+ line(` R/R Ratio: ${chalk_1.default.cyan(analysis.tradeSetup.riskRewardRatio + ":1")}`);
435
+ // Multi-Timeframe
436
+ console.log(border.mid);
437
+ line(chalk_1.default.bold("\u{1F4C8} MULTI-TIMEFRAME ANALYSIS"));
438
+ const tfIcon = (signal) => signal === "bullish"
439
+ ? chalk_1.default.green("\u{2191}")
440
+ : signal === "bearish"
441
+ ? chalk_1.default.red("\u{2193}")
442
+ : chalk_1.default.yellow("\u{2192}");
443
+ line(` 1H: ${tfIcon(analysis.timeframes.short.signal)} ${analysis.timeframes.short.signal.padEnd(8)} | RSI: ${analysis.timeframes.short.rsi.current.toFixed(0)}`);
444
+ line(` 4H: ${tfIcon(analysis.timeframes.medium.signal)} ${analysis.timeframes.medium.signal.padEnd(8)} | RSI: ${analysis.timeframes.medium.rsi.current.toFixed(0)}`);
445
+ line(` 1D: ${tfIcon(analysis.timeframes.long.signal)} ${analysis.timeframes.long.signal.padEnd(8)} | RSI: ${analysis.timeframes.long.rsi.current.toFixed(0)}`);
446
+ const alignmentColor = analysis.timeframeAlignment === "aligned_bullish"
447
+ ? chalk_1.default.green
448
+ : analysis.timeframeAlignment === "aligned_bearish"
449
+ ? chalk_1.default.red
450
+ : chalk_1.default.yellow;
451
+ line(` Alignment: ${alignmentColor(analysis.timeframeAlignment.replace(/_/g, " "))}`);
452
+ // Indicators
453
+ console.log(border.mid);
454
+ line(chalk_1.default.bold("\u{1F4CA} INDICATORS"));
455
+ // RSI
456
+ const rsiColor = analysis.indicators.rsi.condition === "overbought"
457
+ ? chalk_1.default.red
458
+ : analysis.indicators.rsi.condition === "oversold"
459
+ ? chalk_1.default.green
460
+ : chalk_1.default.white;
461
+ line(` RSI(14): ${rsiColor(analysis.indicators.rsi.current.toFixed(1))} (${analysis.indicators.rsi.condition})${analysis.indicators.rsi.divergence !== "none"
462
+ ? chalk_1.default.magenta(` - ${analysis.indicators.rsi.divergence} div`)
463
+ : ""}`);
464
+ // MACD
465
+ const macdColor = analysis.indicators.macd.crossover === "bullish"
466
+ ? chalk_1.default.green
467
+ : analysis.indicators.macd.crossover === "bearish"
468
+ ? chalk_1.default.red
469
+ : chalk_1.default.gray;
470
+ line(` MACD: ${macdColor(analysis.indicators.macd.crossover)} | momentum ${analysis.indicators.macd.momentum}`);
471
+ // Bollinger
472
+ const bbPosition = analysis.indicators.bollinger.pricePosition.replace(/_/g, " ");
473
+ line(` Bollinger: ${bbPosition}${analysis.indicators.bollinger.squeeze ? chalk_1.default.yellow(" [SQUEEZE]") : ""}`);
474
+ // Volume
475
+ const volColor = analysis.indicators.volume.volumeRatio > 1.2
476
+ ? chalk_1.default.green
477
+ : analysis.indicators.volume.volumeRatio < 0.8
478
+ ? chalk_1.default.red
479
+ : chalk_1.default.white;
480
+ line(` Volume: ${volColor(analysis.indicators.volume.volumeRatio.toFixed(1) + "x")} avg | ${analysis.indicators.volume.trend}`);
481
+ // ATR
482
+ const atrColor = analysis.indicators.atr.volatility === "high"
483
+ ? chalk_1.default.red
484
+ : analysis.indicators.atr.volatility === "low"
485
+ ? chalk_1.default.green
486
+ : chalk_1.default.yellow;
487
+ line(` Volatility: ${atrColor(analysis.indicators.atr.volatility)} (ATR: ${analysis.indicators.atr.percentOfPrice.toFixed(1)}%)`);
488
+ // Key Levels
489
+ console.log(border.mid);
490
+ line(chalk_1.default.bold("\u{1F511} KEY LEVELS"));
491
+ line(` Support: ${chalk_1.default.green(formatPrice(analysis.indicators.supportResistance.nearestSupport))} (${analysis.indicators.supportResistance.distanceToSupport.toFixed(1)}% away)`);
492
+ line(` Resistance: ${chalk_1.default.red(formatPrice(analysis.indicators.supportResistance.nearestResistance))} (${analysis.indicators.supportResistance.distanceToResistance.toFixed(1)}% away)`);
493
+ line(` EMA21: ${chalk_1.default.gray(formatPrice(analysis.timeframes.medium.ema.ema21))}`);
494
+ line(` EMA50: ${chalk_1.default.gray(formatPrice(analysis.timeframes.medium.ema.ema50))}`);
495
+ line(` EMA200: ${chalk_1.default.gray(formatPrice(analysis.timeframes.medium.ema.ema200))}`);
496
+ // Market Condition
497
+ console.log(border.mid);
498
+ line(chalk_1.default.bold(`\u{1F30A} MARKET: ${analysis.marketCondition.type.toUpperCase()}`));
499
+ const conditionLines = wordWrap(analysis.marketCondition.tradingAdvice, contentWidth - 3);
500
+ conditionLines.forEach((l) => line(chalk_1.default.gray(` ${l}`)));
501
+ // Bullish/Bearish Factors
502
+ if (analysis.reasoning.bullishFactors.length > 0 ||
503
+ analysis.reasoning.bearishFactors.length > 0) {
504
+ console.log(border.mid);
505
+ if (analysis.reasoning.bullishFactors.length > 0) {
506
+ line(chalk_1.default.green.bold("\u{2705} BULLISH FACTORS"));
507
+ analysis.reasoning.bullishFactors.slice(0, 3).forEach((f) => {
508
+ const lines = wordWrap(f, contentWidth - 5);
509
+ lines.forEach((l, i) => line(chalk_1.default.green(` ${i === 0 ? "\u{2022}" : " "} ${l}`)));
510
+ });
511
+ }
512
+ if (analysis.reasoning.bearishFactors.length > 0) {
513
+ line(chalk_1.default.red.bold("\u{274C} BEARISH FACTORS"));
514
+ analysis.reasoning.bearishFactors.slice(0, 3).forEach((f) => {
515
+ const lines = wordWrap(f, contentWidth - 5);
516
+ lines.forEach((l, i) => line(chalk_1.default.red(` ${i === 0 ? "\u{2022}" : " "} ${l}`)));
517
+ });
518
+ }
519
+ }
520
+ // Warnings
521
+ if (analysis.reasoning.warnings.length > 0) {
522
+ console.log(border.mid);
523
+ line(chalk_1.default.yellow.bold("\u{26A0}\u{FE0F} WARNINGS"));
524
+ analysis.reasoning.warnings.forEach((w) => {
525
+ const lines = wordWrap(w, contentWidth - 5);
526
+ lines.forEach((l, i) => line(chalk_1.default.yellow(` ${i === 0 ? "\u{2022}" : " "} ${l}`)));
527
+ });
528
+ }
529
+ // AI Analysis
530
+ if (aiAnalysis) {
531
+ console.log(border.mid);
532
+ line(chalk_1.default.magenta.bold("\u{1F916} AI ANALYSIS"));
533
+ const aiLines = wordWrap(aiAnalysis, contentWidth - 3);
534
+ aiLines.forEach((l) => line(chalk_1.default.white(` ${l}`)));
535
+ }
536
+ // Footer
537
+ console.log(border.bot);
538
+ console.log("");
539
+ console.log(chalk_1.default.gray.italic(" \u{26A0}\u{FE0F} This is not financial advice. Always do your own research."));
540
+ console.log("");
541
+ }
542
+ /**
543
+ * Perform and display comprehensive market analysis
544
+ */
545
+ async function comprehensiveAnalysis(symbol) {
546
+ const spinner = (0, ora_1.default)(`Analyzing ${symbol.toUpperCase()} across multiple timeframes...`).start();
547
+ try {
548
+ spinner.text = "Fetching 1H, 4H, and 1D data...";
549
+ const analysis = await (0, market_analyzer_1.analyzeMarket)(symbol);
550
+ spinner.text = "Generating AI insights...";
551
+ const aiAnalysis = await generateComprehensiveAIAnalysis(analysis);
552
+ spinner.succeed(`Comprehensive analysis complete for ${analysis.symbol}`);
553
+ displayComprehensiveAnalysis(analysis, aiAnalysis);
554
+ }
555
+ catch (error) {
556
+ spinner.fail(`Failed to analyze ${symbol}`);
557
+ console.log(chalk_1.default.red(`\nError: ${error.message}`));
558
+ }
559
+ }