prab-cli 1.2.0 → 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,418 @@
1
+ "use strict";
2
+ /**
3
+ * SMC (Smart Money Concepts) Analyzer
4
+ * Combines SMC with traditional analysis for comprehensive trading signals
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.displaySMCAnalysis = displaySMCAnalysis;
11
+ exports.runSMCAnalysis = runSMCAnalysis;
12
+ const chalk_1 = __importDefault(require("chalk"));
13
+ const ora_1 = __importDefault(require("ora"));
14
+ const data_fetcher_1 = require("./data-fetcher");
15
+ const smc_indicators_1 = require("./smc-indicators");
16
+ const config_1 = require("../config");
17
+ const groq_provider_1 = require("../models/groq-provider");
18
+ const chart_visual_1 = require("./chart-visual");
19
+ // ============================================
20
+ // TRADE SETUP GENERATION
21
+ // ============================================
22
+ function generateSMCTradeSetup(smc, currentPrice) {
23
+ const { marketStructure, orderBlocks, fairValueGaps, liquidity, premiumDiscount, bias } = smc;
24
+ const setup = {
25
+ bias: bias.direction === "bullish" ? "long" : bias.direction === "bearish" ? "short" : "neutral",
26
+ confidence: bias.confidence,
27
+ entry: {
28
+ type: "structure_break",
29
+ zone: { low: currentPrice * 0.99, high: currentPrice * 1.01 },
30
+ trigger: "Wait for confirmation",
31
+ },
32
+ stopLoss: currentPrice * (bias.direction === "bullish" ? 0.97 : 1.03),
33
+ targets: [],
34
+ riskReward: 0,
35
+ invalidation: "",
36
+ };
37
+ // Determine best entry based on SMC confluence
38
+ if (bias.direction === "bullish") {
39
+ // Look for bullish entry
40
+ if (orderBlocks.nearest?.type === "bullish" && !orderBlocks.nearest.mitigated) {
41
+ const ob = orderBlocks.nearest;
42
+ setup.entry = {
43
+ type: "order_block",
44
+ zone: { low: ob.bottom, high: ob.top },
45
+ trigger: `Enter on bullish reaction from OB zone`,
46
+ };
47
+ setup.stopLoss = ob.bottom * 0.99;
48
+ }
49
+ else if (fairValueGaps.unfilled.some((f) => f.type === "bullish")) {
50
+ const fvg = fairValueGaps.unfilled.find((f) => f.type === "bullish");
51
+ setup.entry = {
52
+ type: "fvg",
53
+ zone: { low: fvg.bottom, high: fvg.top },
54
+ trigger: `Enter on fill of bullish FVG`,
55
+ };
56
+ setup.stopLoss = fvg.bottom * 0.99;
57
+ }
58
+ else if (premiumDiscount.zone === "discount") {
59
+ setup.entry = {
60
+ type: "liquidity_sweep",
61
+ zone: { low: premiumDiscount.rangeLow, high: premiumDiscount.equilibrium },
62
+ trigger: `Enter in discount zone after sweep of lows`,
63
+ };
64
+ setup.stopLoss = premiumDiscount.rangeLow * 0.99;
65
+ }
66
+ // Set targets based on liquidity
67
+ if (liquidity.buySide.length > 0) {
68
+ setup.targets = liquidity.buySide.slice(0, 3).map((l) => l.level);
69
+ }
70
+ else {
71
+ setup.targets = [currentPrice * 1.02, currentPrice * 1.04, premiumDiscount.rangeHigh];
72
+ }
73
+ setup.invalidation = `Break below ${marketStructure.swingLows[marketStructure.swingLows.length - 1]?.price.toFixed(2) || "recent low"}`;
74
+ }
75
+ else if (bias.direction === "bearish") {
76
+ // Look for bearish entry
77
+ if (orderBlocks.nearest?.type === "bearish" && !orderBlocks.nearest.mitigated) {
78
+ const ob = orderBlocks.nearest;
79
+ setup.entry = {
80
+ type: "order_block",
81
+ zone: { low: ob.bottom, high: ob.top },
82
+ trigger: `Enter on bearish rejection from OB zone`,
83
+ };
84
+ setup.stopLoss = ob.top * 1.01;
85
+ }
86
+ else if (fairValueGaps.unfilled.some((f) => f.type === "bearish")) {
87
+ const fvg = fairValueGaps.unfilled.find((f) => f.type === "bearish");
88
+ setup.entry = {
89
+ type: "fvg",
90
+ zone: { low: fvg.bottom, high: fvg.top },
91
+ trigger: `Enter on fill of bearish FVG`,
92
+ };
93
+ setup.stopLoss = fvg.top * 1.01;
94
+ }
95
+ else if (premiumDiscount.zone === "premium") {
96
+ setup.entry = {
97
+ type: "liquidity_sweep",
98
+ zone: { low: premiumDiscount.equilibrium, high: premiumDiscount.rangeHigh },
99
+ trigger: `Enter in premium zone after sweep of highs`,
100
+ };
101
+ setup.stopLoss = premiumDiscount.rangeHigh * 1.01;
102
+ }
103
+ // Set targets based on liquidity
104
+ if (liquidity.sellSide.length > 0) {
105
+ setup.targets = liquidity.sellSide.slice(0, 3).map((l) => l.level);
106
+ }
107
+ else {
108
+ setup.targets = [currentPrice * 0.98, currentPrice * 0.96, premiumDiscount.rangeLow];
109
+ }
110
+ setup.invalidation = `Break above ${marketStructure.swingHighs[marketStructure.swingHighs.length - 1]?.price.toFixed(2) || "recent high"}`;
111
+ }
112
+ // Calculate R:R
113
+ const entryPrice = (setup.entry.zone.low + setup.entry.zone.high) / 2;
114
+ const risk = Math.abs(entryPrice - setup.stopLoss);
115
+ const reward = setup.targets.length > 1 ? Math.abs(setup.targets[1] - entryPrice) : risk * 2;
116
+ setup.riskReward = Math.round((reward / risk) * 10) / 10;
117
+ return setup;
118
+ }
119
+ // ============================================
120
+ // AI ANALYSIS
121
+ // ============================================
122
+ async function generateSMCAIAnalysis(analysis) {
123
+ const apiKey = (0, config_1.getApiKey)();
124
+ if (!apiKey)
125
+ return "AI analysis unavailable (no API key configured)";
126
+ const modelConfig = (0, config_1.getModelConfig)();
127
+ const provider = new groq_provider_1.GroqProvider(modelConfig.modelId, 0.7);
128
+ provider.initialize(apiKey, modelConfig.modelId);
129
+ const { smc, tradeSetup, currentPrice } = analysis;
130
+ const prompt = `You are an expert Smart Money Concepts (SMC) trader. Analyze this setup and provide actionable advice (4-5 sentences).
131
+
132
+ Symbol: ${analysis.symbol}
133
+ Current Price: $${currentPrice.toFixed(2)}
134
+ 24h Change: ${analysis.priceChange24h.toFixed(2)}%
135
+
136
+ MARKET STRUCTURE:
137
+ - Trend: ${smc.marketStructure.trend}
138
+ - Last BOS: ${smc.marketStructure.lastBOS ? `${smc.marketStructure.lastBOS.direction} at $${smc.marketStructure.lastBOS.level.toFixed(2)}` : "None"}
139
+ - Last CHoCH: ${smc.marketStructure.lastCHoCH ? `${smc.marketStructure.lastCHoCH.direction} at $${smc.marketStructure.lastCHoCH.level.toFixed(2)}` : "None"}
140
+
141
+ ORDER BLOCKS:
142
+ - Bullish OBs: ${smc.orderBlocks.bullish.length} (Nearest: ${smc.orderBlocks.nearest?.type === "bullish" ? `$${smc.orderBlocks.nearest.bottom.toFixed(2)}-$${smc.orderBlocks.nearest.top.toFixed(2)}` : "N/A"})
143
+ - Bearish OBs: ${smc.orderBlocks.bearish.length} (Nearest: ${smc.orderBlocks.nearest?.type === "bearish" ? `$${smc.orderBlocks.nearest.bottom.toFixed(2)}-$${smc.orderBlocks.nearest.top.toFixed(2)}` : "N/A"})
144
+
145
+ FAIR VALUE GAPS:
146
+ - Unfilled: ${smc.fairValueGaps.unfilled.length}
147
+ - Bullish FVGs above: ${smc.fairValueGaps.bullish.filter((f) => !f.filled && f.bottom > currentPrice).length}
148
+ - Bearish FVGs below: ${smc.fairValueGaps.bearish.filter((f) => !f.filled && f.top < currentPrice).length}
149
+
150
+ LIQUIDITY:
151
+ - Buy-side (above): ${smc.liquidity.buySide.map((l) => `$${l.level.toFixed(2)}`).join(", ") || "None"}
152
+ - Sell-side (below): ${smc.liquidity.sellSide.map((l) => `$${l.level.toFixed(2)}`).join(", ") || "None"}
153
+
154
+ PREMIUM/DISCOUNT:
155
+ - Zone: ${smc.premiumDiscount.zone} (${smc.premiumDiscount.fibLevel.toFixed(0)}% of range)
156
+ - Range: $${smc.premiumDiscount.rangeLow.toFixed(2)} - $${smc.premiumDiscount.rangeHigh.toFixed(2)}
157
+ - Equilibrium: $${smc.premiumDiscount.equilibrium.toFixed(2)}
158
+
159
+ TRADE SETUP:
160
+ - Bias: ${tradeSetup.bias.toUpperCase()}
161
+ - Entry Type: ${tradeSetup.entry.type}
162
+ - Entry Zone: $${tradeSetup.entry.zone.low.toFixed(2)} - $${tradeSetup.entry.zone.high.toFixed(2)}
163
+ - Stop Loss: $${tradeSetup.stopLoss.toFixed(2)}
164
+ - Targets: ${tradeSetup.targets.map((t) => `$${t.toFixed(2)}`).join(", ")}
165
+ - R:R: ${tradeSetup.riskReward}:1
166
+
167
+ SMC BIAS REASONING:
168
+ ${smc.bias.reasoning.map((r) => `- ${r}`).join("\n")}
169
+
170
+ Provide SMC-focused analysis explaining:
171
+ 1. Current market structure and institutional order flow
172
+ 2. Where smart money is likely positioned
173
+ 3. Best entry strategy (order block, FVG, or liquidity sweep)
174
+ 4. Key levels to watch and when to enter
175
+ Be specific with prices and SMC terminology.`;
176
+ try {
177
+ const stream = provider.streamChat([{ role: "user", content: prompt }], []);
178
+ let response = "";
179
+ for await (const chunk of stream) {
180
+ if (chunk.content && typeof chunk.content === "string") {
181
+ response += chunk.content;
182
+ }
183
+ }
184
+ return response.trim();
185
+ }
186
+ catch (error) {
187
+ return `AI analysis unavailable: ${error.message}`;
188
+ }
189
+ }
190
+ // ============================================
191
+ // DISPLAY
192
+ // ============================================
193
+ function formatPrice(price) {
194
+ if (price < 0.01)
195
+ return `$${price.toFixed(6)}`;
196
+ if (price < 1)
197
+ return `$${price.toFixed(4)}`;
198
+ if (price < 100)
199
+ return `$${price.toFixed(2)}`;
200
+ return `$${price.toLocaleString(undefined, { maximumFractionDigits: 2 })}`;
201
+ }
202
+ function wordWrap(text, maxWidth) {
203
+ const words = text.split(" ");
204
+ const lines = [];
205
+ let currentLine = "";
206
+ for (const word of words) {
207
+ if (currentLine.length + word.length + 1 > maxWidth) {
208
+ lines.push(currentLine.trim());
209
+ currentLine = word + " ";
210
+ }
211
+ else {
212
+ currentLine += word + " ";
213
+ }
214
+ }
215
+ if (currentLine.trim())
216
+ lines.push(currentLine.trim());
217
+ return lines;
218
+ }
219
+ function displaySMCAnalysis(analysis, aiAnalysis) {
220
+ const boxWidth = 58;
221
+ const contentWidth = boxWidth - 4;
222
+ const border = {
223
+ top: chalk_1.default.magenta("\u{250C}" + "\u{2500}".repeat(boxWidth) + "\u{2510}"),
224
+ mid: chalk_1.default.magenta("\u{251C}" + "\u{2500}".repeat(boxWidth) + "\u{2524}"),
225
+ bot: chalk_1.default.magenta("\u{2514}" + "\u{2500}".repeat(boxWidth) + "\u{2518}"),
226
+ left: chalk_1.default.magenta("\u{2502}"),
227
+ right: chalk_1.default.magenta("\u{2502}"),
228
+ };
229
+ const line = (content, pad = contentWidth) => {
230
+ console.log(border.left + " " + content.padEnd(pad) + " " + border.right);
231
+ };
232
+ const { smc, tradeSetup, currentPrice, priceChange24h } = analysis;
233
+ const changeColor = priceChange24h >= 0 ? chalk_1.default.green : chalk_1.default.red;
234
+ const changeSign = priceChange24h >= 0 ? "+" : "";
235
+ console.log("");
236
+ console.log(border.top);
237
+ // Header
238
+ line(chalk_1.default.bold.white(`\u{1F3E6} ${analysis.symbol} - Smart Money Analysis`));
239
+ line(chalk_1.default.bold.yellow(`Price: ${formatPrice(currentPrice)}`) +
240
+ ` ${changeColor(changeSign + priceChange24h.toFixed(2) + "%")}`);
241
+ // Market Structure
242
+ console.log(border.mid);
243
+ line(chalk_1.default.bold("\u{1F4CA} MARKET STRUCTURE"));
244
+ const trendColor = smc.marketStructure.trend === "bullish"
245
+ ? chalk_1.default.green
246
+ : smc.marketStructure.trend === "bearish"
247
+ ? chalk_1.default.red
248
+ : chalk_1.default.yellow;
249
+ line(` Trend: ${trendColor(smc.marketStructure.trend.toUpperCase())}`);
250
+ if (smc.marketStructure.lastBOS) {
251
+ const bosColor = smc.marketStructure.lastBOS.direction === "bullish" ? chalk_1.default.green : chalk_1.default.red;
252
+ line(` Last BOS: ${bosColor(smc.marketStructure.lastBOS.direction)} @ ${formatPrice(smc.marketStructure.lastBOS.level)}`);
253
+ }
254
+ if (smc.marketStructure.lastCHoCH) {
255
+ const chochColor = smc.marketStructure.lastCHoCH.direction === "bullish" ? chalk_1.default.green : chalk_1.default.red;
256
+ line(` Last CHoCH: ${chochColor(smc.marketStructure.lastCHoCH.direction)} @ ${formatPrice(smc.marketStructure.lastCHoCH.level)}`);
257
+ }
258
+ // Order Blocks
259
+ console.log(border.mid);
260
+ line(chalk_1.default.bold("\u{1F4E6} ORDER BLOCKS"));
261
+ line(` Bullish OBs: ${chalk_1.default.green(smc.orderBlocks.bullish.length.toString())}`);
262
+ line(` Bearish OBs: ${chalk_1.default.red(smc.orderBlocks.bearish.length.toString())}`);
263
+ if (smc.orderBlocks.nearest) {
264
+ const ob = smc.orderBlocks.nearest;
265
+ const obColor = ob.type === "bullish" ? chalk_1.default.green : chalk_1.default.red;
266
+ line(` Nearest: ${obColor(ob.type)} ${formatPrice(ob.bottom)} - ${formatPrice(ob.top)}`);
267
+ line(` Strength: ${ob.strength} | Mitigated: ${ob.mitigated ? "Yes" : "No"}`);
268
+ }
269
+ // Fair Value Gaps
270
+ console.log(border.mid);
271
+ line(chalk_1.default.bold("\u{26A1} FAIR VALUE GAPS"));
272
+ line(` Unfilled FVGs: ${chalk_1.default.yellow(smc.fairValueGaps.unfilled.length.toString())}`);
273
+ smc.fairValueGaps.unfilled.slice(0, 2).forEach((fvg) => {
274
+ const fvgColor = fvg.type === "bullish" ? chalk_1.default.green : chalk_1.default.red;
275
+ line(` ${fvgColor(fvg.type)}: ${formatPrice(fvg.bottom)} - ${formatPrice(fvg.top)}`);
276
+ });
277
+ // Liquidity
278
+ console.log(border.mid);
279
+ line(chalk_1.default.bold("\u{1F4B0} LIQUIDITY POOLS"));
280
+ if (smc.liquidity.buySide.length > 0) {
281
+ line(chalk_1.default.cyan(" Buy-side (stops above):"));
282
+ smc.liquidity.buySide.slice(0, 2).forEach((l) => {
283
+ line(` ${formatPrice(l.level)} (${l.strength} touch${l.strength > 1 ? "es" : ""})`);
284
+ });
285
+ }
286
+ if (smc.liquidity.sellSide.length > 0) {
287
+ line(chalk_1.default.cyan(" Sell-side (stops below):"));
288
+ smc.liquidity.sellSide.slice(0, 2).forEach((l) => {
289
+ line(` ${formatPrice(l.level)} (${l.strength} touch${l.strength > 1 ? "es" : ""})`);
290
+ });
291
+ }
292
+ // Premium/Discount
293
+ console.log(border.mid);
294
+ line(chalk_1.default.bold("\u{1F3AF} PREMIUM/DISCOUNT"));
295
+ const zoneColor = smc.premiumDiscount.zone === "discount"
296
+ ? chalk_1.default.green
297
+ : smc.premiumDiscount.zone === "premium"
298
+ ? chalk_1.default.red
299
+ : chalk_1.default.yellow;
300
+ line(` Zone: ${zoneColor(smc.premiumDiscount.zone.toUpperCase())} (${smc.premiumDiscount.fibLevel.toFixed(0)}%)`);
301
+ line(` Range: ${formatPrice(smc.premiumDiscount.rangeLow)} - ${formatPrice(smc.premiumDiscount.rangeHigh)}`);
302
+ line(` Equilibrium: ${formatPrice(smc.premiumDiscount.equilibrium)}`);
303
+ // Trade Setup
304
+ console.log(border.mid);
305
+ const biasColor = tradeSetup.bias === "long"
306
+ ? chalk_1.default.green.bold
307
+ : tradeSetup.bias === "short"
308
+ ? chalk_1.default.red.bold
309
+ : chalk_1.default.yellow.bold;
310
+ const biasIcon = tradeSetup.bias === "long"
311
+ ? "\u{1F7E2}"
312
+ : tradeSetup.bias === "short"
313
+ ? "\u{1F534}"
314
+ : "\u{1F7E1}";
315
+ line(chalk_1.default.bold(`\u{1F4DD} TRADE SETUP: ${biasIcon} ${biasColor(tradeSetup.bias.toUpperCase())}`));
316
+ line(` Confidence: ${chalk_1.default.white(tradeSetup.confidence + "%")}`);
317
+ line(` Entry Type: ${chalk_1.default.cyan(tradeSetup.entry.type.replace(/_/g, " "))}`);
318
+ line(` Entry Zone: ${chalk_1.default.white(formatPrice(tradeSetup.entry.zone.low))} - ${chalk_1.default.white(formatPrice(tradeSetup.entry.zone.high))}`);
319
+ line(` Stop Loss: ${chalk_1.default.red(formatPrice(tradeSetup.stopLoss))}`);
320
+ line(` Targets:`);
321
+ tradeSetup.targets.slice(0, 3).forEach((t, i) => {
322
+ const pct = ((t - currentPrice) / currentPrice) * 100;
323
+ const pctStr = pct >= 0 ? `+${pct.toFixed(1)}%` : `${pct.toFixed(1)}%`;
324
+ line(` T${i + 1}: ${chalk_1.default.green(formatPrice(t))} (${chalk_1.default.green(pctStr)})`);
325
+ });
326
+ line(` R:R Ratio: ${chalk_1.default.cyan(tradeSetup.riskReward + ":1")}`);
327
+ // SMC Bias Reasoning
328
+ console.log(border.mid);
329
+ line(chalk_1.default.bold("\u{1F9E0} SMC REASONING"));
330
+ smc.bias.reasoning.slice(0, 4).forEach((r) => {
331
+ const lines = wordWrap(r, contentWidth - 5);
332
+ lines.forEach((l, i) => line(chalk_1.default.gray(` ${i === 0 ? "\u{2022}" : " "} ${l}`)));
333
+ });
334
+ // AI Analysis
335
+ if (aiAnalysis) {
336
+ console.log(border.mid);
337
+ line(chalk_1.default.bold.magenta("\u{1F916} AI SMC ANALYSIS"));
338
+ const aiLines = wordWrap(aiAnalysis, contentWidth - 3);
339
+ aiLines.forEach((l) => line(chalk_1.default.white(` ${l}`)));
340
+ }
341
+ console.log(border.bot);
342
+ // ============================================
343
+ // VISUAL CHARTS SECTION
344
+ // ============================================
345
+ console.log("");
346
+ console.log(chalk_1.default.bold.cyan(" ═══════════════════════════════════════════════════════"));
347
+ console.log(chalk_1.default.bold.cyan(" 📊 VISUAL ANALYSIS "));
348
+ console.log(chalk_1.default.bold.cyan(" ═══════════════════════════════════════════════════════"));
349
+ // Market Structure Visual
350
+ (0, chart_visual_1.createMarketStructureVisual)(smc).forEach((l) => console.log(l));
351
+ // Price Candlestick Chart (if candles available)
352
+ if (analysis.candles && analysis.candles.length > 0) {
353
+ console.log(chalk_1.default.bold.white(" ┌─────────────────────────────────────────────┐"));
354
+ console.log(chalk_1.default.bold.white(" │") +
355
+ chalk_1.default.bold.yellow(" PRICE ACTION (Last 50 Candles) ") +
356
+ chalk_1.default.bold.white("│"));
357
+ console.log(chalk_1.default.bold.white(" └─────────────────────────────────────────────┘"));
358
+ console.log("");
359
+ const candleChart = (0, chart_visual_1.createCandlestickChart)(analysis.candles, 45, 12);
360
+ candleChart.forEach((l) => console.log(" " + l));
361
+ console.log(chalk_1.default.gray(" └" + "─".repeat(45) + "┘"));
362
+ console.log(chalk_1.default.gray(" " +
363
+ chalk_1.default.green("█ Bullish") +
364
+ " " +
365
+ chalk_1.default.red("░ Bearish") +
366
+ " " +
367
+ chalk_1.default.gray("│ Wick")));
368
+ console.log("");
369
+ }
370
+ // Order Block Visual
371
+ (0, chart_visual_1.createOrderBlockVisual)(smc.orderBlocks, currentPrice).forEach((l) => console.log(l));
372
+ // FVG Visual
373
+ (0, chart_visual_1.createFVGVisual)(smc.fairValueGaps, currentPrice).forEach((l) => console.log(l));
374
+ // Liquidity Visual
375
+ (0, chart_visual_1.createLiquidityVisual)(smc.liquidity, currentPrice).forEach((l) => console.log(l));
376
+ // Trade Setup Visual
377
+ const entryMid = (tradeSetup.entry.zone.low + tradeSetup.entry.zone.high) / 2;
378
+ (0, chart_visual_1.createTradeSetupVisual)(currentPrice, entryMid, tradeSetup.stopLoss, tradeSetup.targets, tradeSetup.bias).forEach((l) => console.log(l));
379
+ // SMC Price Level Chart
380
+ console.log("");
381
+ const smcChart = (0, chart_visual_1.createSMCVisualChart)(currentPrice, smc, tradeSetup);
382
+ smcChart.forEach((l) => console.log(l));
383
+ console.log("");
384
+ console.log(chalk_1.default.gray.italic(" \u{26A0}\u{FE0F} This is not financial advice. Always do your own research."));
385
+ console.log("");
386
+ }
387
+ // ============================================
388
+ // MAIN FUNCTION
389
+ // ============================================
390
+ async function runSMCAnalysis(symbol) {
391
+ const spinner = (0, ora_1.default)(`Analyzing ${symbol.toUpperCase()} with Smart Money Concepts...`).start();
392
+ try {
393
+ spinner.text = "Fetching market data...";
394
+ const data = await (0, data_fetcher_1.fetchCryptoData)(symbol, "4h", 200);
395
+ spinner.text = "Identifying order blocks & FVGs...";
396
+ const smc = (0, smc_indicators_1.analyzeSMC)(data.candles);
397
+ spinner.text = "Generating trade setup...";
398
+ const tradeSetup = generateSMCTradeSetup(smc, data.currentPrice);
399
+ const analysis = {
400
+ symbol: data.symbol,
401
+ currentPrice: data.currentPrice,
402
+ priceChange24h: data.priceChangePercent24h,
403
+ smc,
404
+ tradeSetup,
405
+ confluence: smc.bias.reasoning,
406
+ warnings: [],
407
+ candles: data.candles,
408
+ };
409
+ spinner.text = "Getting AI insights...";
410
+ const aiAnalysis = await generateSMCAIAnalysis(analysis);
411
+ spinner.succeed(`SMC analysis complete for ${data.symbol}`);
412
+ displaySMCAnalysis(analysis, aiAnalysis);
413
+ }
414
+ catch (error) {
415
+ spinner.fail(`Failed to analyze ${symbol}`);
416
+ console.log(chalk_1.default.red(`\nError: ${error.message}`));
417
+ }
418
+ }