prab-cli 1.2.1 → 1.2.5

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