prab-cli 1.2.4 → 1.2.6
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.
- package/dist/index.js +218 -2
- package/dist/lib/chat-handler.js +39 -5
- package/dist/lib/crypto/data-fetcher.js +86 -0
- package/dist/lib/crypto/ict-strategy.js +955 -0
- package/dist/lib/crypto/index.js +23 -1
- package/dist/lib/crypto/market-scanner.js +569 -0
- package/dist/lib/crypto/news-fetcher.js +394 -0
- package/dist/lib/crypto/orderblock-strategy.js +445 -0
- package/dist/lib/crypto/signal-generator.js +144 -17
- package/dist/lib/crypto/smc-analyzer.js +39 -7
- package/dist/lib/crypto/strategy-engine.js +803 -0
- package/dist/lib/crypto/whale-tracker.js +508 -0
- package/dist/lib/slash-commands.js +36 -0
- package/dist/lib/ui.js +45 -1
- package/dist/server/index.js +501 -0
- package/package.json +7 -1
|
@@ -0,0 +1,955 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ICT (Inner Circle Trader) Strategy Module
|
|
4
|
+
* Complete implementation of ICT trading concepts
|
|
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.generateICTSignal = generateICTSignal;
|
|
11
|
+
exports.displayICTSignal = displayICTSignal;
|
|
12
|
+
exports.runICTStrategy = runICTStrategy;
|
|
13
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
14
|
+
const ora_1 = __importDefault(require("ora"));
|
|
15
|
+
const data_fetcher_1 = require("./data-fetcher");
|
|
16
|
+
const smc_indicators_1 = require("./smc-indicators");
|
|
17
|
+
const indicators_1 = require("./indicators");
|
|
18
|
+
// ============================================
|
|
19
|
+
// KILLZONE DETECTION
|
|
20
|
+
// ============================================
|
|
21
|
+
const KILLZONES = [
|
|
22
|
+
{
|
|
23
|
+
name: "Asian Session",
|
|
24
|
+
type: "asian",
|
|
25
|
+
startHourUTC: 0, // 00:00 UTC (8 PM EST)
|
|
26
|
+
endHourUTC: 6, // 06:00 UTC
|
|
27
|
+
description: "Range forming session - identify highs/lows",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "London Open",
|
|
31
|
+
type: "london",
|
|
32
|
+
startHourUTC: 7, // 07:00 UTC (2 AM EST)
|
|
33
|
+
endHourUTC: 10, // 10:00 UTC (5 AM EST)
|
|
34
|
+
description: "High volatility - trend continuation or reversal",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "New York AM",
|
|
38
|
+
type: "new_york_am",
|
|
39
|
+
startHourUTC: 13, // 13:00 UTC (8 AM EST)
|
|
40
|
+
endHourUTC: 16, // 16:00 UTC (11 AM EST)
|
|
41
|
+
description: "Highest volatility - major moves",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "New York PM",
|
|
45
|
+
type: "new_york_pm",
|
|
46
|
+
startHourUTC: 18, // 18:00 UTC (1 PM EST)
|
|
47
|
+
endHourUTC: 21, // 21:00 UTC (4 PM EST)
|
|
48
|
+
description: "Profit taking and reversals",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "Silver Bullet AM",
|
|
52
|
+
type: "silver_bullet_am",
|
|
53
|
+
startHourUTC: 14, // 14:00 UTC (10 AM EST)
|
|
54
|
+
endHourUTC: 15, // 15:00 UTC (11 AM EST)
|
|
55
|
+
description: "ICT Silver Bullet - high probability entry window",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "Silver Bullet PM",
|
|
59
|
+
type: "silver_bullet_pm",
|
|
60
|
+
startHourUTC: 19, // 19:00 UTC (2 PM EST)
|
|
61
|
+
endHourUTC: 20, // 20:00 UTC (3 PM EST)
|
|
62
|
+
description: "ICT Silver Bullet - afternoon entry window",
|
|
63
|
+
},
|
|
64
|
+
];
|
|
65
|
+
function getCurrentKillzone() {
|
|
66
|
+
const now = new Date();
|
|
67
|
+
const hourUTC = now.getUTCHours();
|
|
68
|
+
for (const kz of KILLZONES) {
|
|
69
|
+
if (hourUTC >= kz.startHourUTC && hourUTC < kz.endHourUTC) {
|
|
70
|
+
return {
|
|
71
|
+
...kz,
|
|
72
|
+
active: true,
|
|
73
|
+
bias: "neutral",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
name: "No Active Killzone",
|
|
79
|
+
type: "none",
|
|
80
|
+
active: false,
|
|
81
|
+
startHourUTC: 0,
|
|
82
|
+
endHourUTC: 0,
|
|
83
|
+
bias: "neutral",
|
|
84
|
+
description: "Outside of main trading sessions",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// ============================================
|
|
88
|
+
// OTE (OPTIMAL TRADE ENTRY)
|
|
89
|
+
// ============================================
|
|
90
|
+
function calculateOTE(candles, swingPoints, currentPrice) {
|
|
91
|
+
const recentHighs = swingPoints.filter((p) => p.type === "high").slice(-5);
|
|
92
|
+
const recentLows = swingPoints.filter((p) => p.type === "low").slice(-5);
|
|
93
|
+
if (recentHighs.length < 2 || recentLows.length < 2) {
|
|
94
|
+
return {
|
|
95
|
+
isValid: false,
|
|
96
|
+
fibLevel: 0,
|
|
97
|
+
zone: { low: currentPrice, high: currentPrice },
|
|
98
|
+
swingHigh: currentPrice,
|
|
99
|
+
swingLow: currentPrice,
|
|
100
|
+
direction: "bullish",
|
|
101
|
+
quality: "suboptimal",
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// Get most recent swing high and low
|
|
105
|
+
const swingHigh = Math.max(...recentHighs.map((h) => h.price));
|
|
106
|
+
const swingLow = Math.min(...recentLows.map((l) => l.price));
|
|
107
|
+
const range = swingHigh - swingLow;
|
|
108
|
+
// Calculate current position as Fib level
|
|
109
|
+
const fibLevel = (currentPrice - swingLow) / range;
|
|
110
|
+
// Determine direction based on recent price action
|
|
111
|
+
const lastCandles = candles.slice(-10);
|
|
112
|
+
const avgClose = lastCandles.reduce((sum, c) => sum + c.close, 0) / lastCandles.length;
|
|
113
|
+
const direction = currentPrice > avgClose ? "bullish" : "bearish";
|
|
114
|
+
// OTE Zone is 62% - 79% retracement
|
|
115
|
+
let oteZone;
|
|
116
|
+
if (direction === "bullish") {
|
|
117
|
+
// For bullish OTE, we want price to retrace into discount
|
|
118
|
+
oteZone = {
|
|
119
|
+
low: swingLow + range * 0.62,
|
|
120
|
+
high: swingLow + range * 0.79,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
// For bearish OTE, we want price to retrace into premium
|
|
125
|
+
oteZone = {
|
|
126
|
+
low: swingHigh - range * 0.79,
|
|
127
|
+
high: swingHigh - range * 0.62,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
// Determine quality based on fib level
|
|
131
|
+
let quality;
|
|
132
|
+
if (direction === "bullish") {
|
|
133
|
+
if (fibLevel >= 0.62 && fibLevel <= 0.79)
|
|
134
|
+
quality = "premium";
|
|
135
|
+
else if (fibLevel >= 0.5 && fibLevel <= 0.85)
|
|
136
|
+
quality = "standard";
|
|
137
|
+
else
|
|
138
|
+
quality = "suboptimal";
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (fibLevel >= 0.21 && fibLevel <= 0.38)
|
|
142
|
+
quality = "premium";
|
|
143
|
+
else if (fibLevel >= 0.15 && fibLevel <= 0.5)
|
|
144
|
+
quality = "standard";
|
|
145
|
+
else
|
|
146
|
+
quality = "suboptimal";
|
|
147
|
+
}
|
|
148
|
+
const isValid = quality !== "suboptimal";
|
|
149
|
+
return {
|
|
150
|
+
isValid,
|
|
151
|
+
fibLevel,
|
|
152
|
+
zone: oteZone,
|
|
153
|
+
swingHigh,
|
|
154
|
+
swingLow,
|
|
155
|
+
direction,
|
|
156
|
+
quality,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
// ============================================
|
|
160
|
+
// BREAKER BLOCKS
|
|
161
|
+
// ============================================
|
|
162
|
+
function findBreakerBlocks(candles, orderBlocks) {
|
|
163
|
+
const breakerBlocks = [];
|
|
164
|
+
const currentPrice = candles[candles.length - 1].close;
|
|
165
|
+
for (const ob of orderBlocks) {
|
|
166
|
+
// Check if this order block was broken (mitigated) and then price returned
|
|
167
|
+
if (ob.mitigated) {
|
|
168
|
+
// Find where it was broken
|
|
169
|
+
let breakIndex = -1;
|
|
170
|
+
let breakPrice = 0;
|
|
171
|
+
for (let i = ob.index + 1; i < candles.length; i++) {
|
|
172
|
+
if (ob.type === "bullish" && candles[i].close < ob.bottom) {
|
|
173
|
+
breakIndex = i;
|
|
174
|
+
breakPrice = candles[i].close;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (ob.type === "bearish" && candles[i].close > ob.top) {
|
|
178
|
+
breakIndex = i;
|
|
179
|
+
breakPrice = candles[i].close;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (breakIndex > 0) {
|
|
184
|
+
// A broken bullish OB becomes a bearish breaker
|
|
185
|
+
// A broken bearish OB becomes a bullish breaker
|
|
186
|
+
const breakerType = ob.type === "bullish" ? "bearish" : "bullish";
|
|
187
|
+
// Check if price has returned to this level
|
|
188
|
+
const priceNearBreaker = (breakerType === "bullish" &&
|
|
189
|
+
currentPrice >= ob.bottom * 0.99 &&
|
|
190
|
+
currentPrice <= ob.top * 1.01) ||
|
|
191
|
+
(breakerType === "bearish" &&
|
|
192
|
+
currentPrice >= ob.bottom * 0.99 &&
|
|
193
|
+
currentPrice <= ob.top * 1.01);
|
|
194
|
+
if (priceNearBreaker || breakerBlocks.length < 5) {
|
|
195
|
+
breakerBlocks.push({
|
|
196
|
+
type: breakerType,
|
|
197
|
+
top: ob.top,
|
|
198
|
+
bottom: ob.bottom,
|
|
199
|
+
originalOB: ob,
|
|
200
|
+
breakPrice,
|
|
201
|
+
strength: ob.strength,
|
|
202
|
+
index: ob.index,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return breakerBlocks.slice(0, 5);
|
|
209
|
+
}
|
|
210
|
+
// ============================================
|
|
211
|
+
// INDUCEMENT DETECTION
|
|
212
|
+
// ============================================
|
|
213
|
+
function findInducements(candles, swingPoints) {
|
|
214
|
+
const inducements = [];
|
|
215
|
+
const currentPrice = candles[candles.length - 1].close;
|
|
216
|
+
// Find equal highs (buy-side liquidity)
|
|
217
|
+
const highs = swingPoints.filter((p) => p.type === "high");
|
|
218
|
+
for (let i = 1; i < highs.length; i++) {
|
|
219
|
+
const diff = Math.abs(highs[i].price - highs[i - 1].price) / highs[i].price;
|
|
220
|
+
if (diff < 0.003) {
|
|
221
|
+
// Within 0.3% = equal highs
|
|
222
|
+
const level = (highs[i].price + highs[i - 1].price) / 2;
|
|
223
|
+
// Check if swept
|
|
224
|
+
let swept = false;
|
|
225
|
+
let sweepCandle = null;
|
|
226
|
+
for (let j = highs[i].index + 1; j < candles.length; j++) {
|
|
227
|
+
if (candles[j].high > level * 1.001) {
|
|
228
|
+
swept = true;
|
|
229
|
+
sweepCandle = j;
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
inducements.push({
|
|
234
|
+
type: "buy_side",
|
|
235
|
+
level,
|
|
236
|
+
swept,
|
|
237
|
+
sweepCandle,
|
|
238
|
+
trapType: "equal_highs",
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// Find equal lows (sell-side liquidity)
|
|
243
|
+
const lows = swingPoints.filter((p) => p.type === "low");
|
|
244
|
+
for (let i = 1; i < lows.length; i++) {
|
|
245
|
+
const diff = Math.abs(lows[i].price - lows[i - 1].price) / lows[i].price;
|
|
246
|
+
if (diff < 0.003) {
|
|
247
|
+
const level = (lows[i].price + lows[i - 1].price) / 2;
|
|
248
|
+
let swept = false;
|
|
249
|
+
let sweepCandle = null;
|
|
250
|
+
for (let j = lows[i].index + 1; j < candles.length; j++) {
|
|
251
|
+
if (candles[j].low < level * 0.999) {
|
|
252
|
+
swept = true;
|
|
253
|
+
sweepCandle = j;
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
inducements.push({
|
|
258
|
+
type: "sell_side",
|
|
259
|
+
level,
|
|
260
|
+
swept,
|
|
261
|
+
sweepCandle,
|
|
262
|
+
trapType: "equal_lows",
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return inducements.slice(0, 10);
|
|
267
|
+
}
|
|
268
|
+
// ============================================
|
|
269
|
+
// DISPLACEMENT DETECTION
|
|
270
|
+
// ============================================
|
|
271
|
+
function detectDisplacement(candles, atrValue) {
|
|
272
|
+
const recentCandles = candles.slice(-10);
|
|
273
|
+
for (let i = 0; i < recentCandles.length - 1; i++) {
|
|
274
|
+
const candle = recentCandles[i];
|
|
275
|
+
const body = Math.abs(candle.close - candle.open);
|
|
276
|
+
// Displacement = candle body > 2x ATR
|
|
277
|
+
if (body > atrValue * 2) {
|
|
278
|
+
const direction = candle.close > candle.open ? "bullish" : "bearish";
|
|
279
|
+
// Check if FVG was created
|
|
280
|
+
let fvgCreated = false;
|
|
281
|
+
if (i > 0 && i < recentCandles.length - 1) {
|
|
282
|
+
const prev = recentCandles[i - 1];
|
|
283
|
+
const next = recentCandles[i + 1];
|
|
284
|
+
if (direction === "bullish" && next.low > prev.high)
|
|
285
|
+
fvgCreated = true;
|
|
286
|
+
if (direction === "bearish" && next.high < prev.low)
|
|
287
|
+
fvgCreated = true;
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
detected: true,
|
|
291
|
+
direction,
|
|
292
|
+
strength: body / atrValue,
|
|
293
|
+
startIndex: candles.length - 10 + i,
|
|
294
|
+
fvgCreated,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
detected: false,
|
|
300
|
+
direction: "bullish",
|
|
301
|
+
strength: 0,
|
|
302
|
+
startIndex: 0,
|
|
303
|
+
fvgCreated: false,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
// ============================================
|
|
307
|
+
// POWER OF 3 (AMD MODEL)
|
|
308
|
+
// ============================================
|
|
309
|
+
function analyzePowerOf3(candles) {
|
|
310
|
+
// Need at least 24 hourly candles for daily analysis
|
|
311
|
+
if (candles.length < 24) {
|
|
312
|
+
return {
|
|
313
|
+
phase: "unknown",
|
|
314
|
+
asianRangeHigh: 0,
|
|
315
|
+
asianRangeLow: 0,
|
|
316
|
+
manipulation: "none",
|
|
317
|
+
expectedMove: "unclear",
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
const now = new Date();
|
|
321
|
+
const hourUTC = now.getUTCHours();
|
|
322
|
+
// Get approximate Asian session candles (last 6-12 candles depending on timeframe)
|
|
323
|
+
const asianCandles = candles.slice(-12, -6);
|
|
324
|
+
if (asianCandles.length === 0) {
|
|
325
|
+
return {
|
|
326
|
+
phase: "unknown",
|
|
327
|
+
asianRangeHigh: 0,
|
|
328
|
+
asianRangeLow: 0,
|
|
329
|
+
manipulation: "none",
|
|
330
|
+
expectedMove: "unclear",
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
const asianRangeHigh = Math.max(...asianCandles.map((c) => c.high));
|
|
334
|
+
const asianRangeLow = Math.min(...asianCandles.map((c) => c.low));
|
|
335
|
+
// Get recent candles (London/NY session)
|
|
336
|
+
const recentCandles = candles.slice(-6);
|
|
337
|
+
const currentPrice = candles[candles.length - 1].close;
|
|
338
|
+
const recentHigh = Math.max(...recentCandles.map((c) => c.high));
|
|
339
|
+
const recentLow = Math.min(...recentCandles.map((c) => c.low));
|
|
340
|
+
// Determine manipulation
|
|
341
|
+
let manipulation = "none";
|
|
342
|
+
if (recentHigh > asianRangeHigh * 1.001)
|
|
343
|
+
manipulation = "above";
|
|
344
|
+
else if (recentLow < asianRangeLow * 0.999)
|
|
345
|
+
manipulation = "below";
|
|
346
|
+
// Determine phase
|
|
347
|
+
let phase;
|
|
348
|
+
if (hourUTC >= 0 && hourUTC < 7) {
|
|
349
|
+
phase = "accumulation";
|
|
350
|
+
}
|
|
351
|
+
else if (hourUTC >= 7 && hourUTC < 14) {
|
|
352
|
+
phase = "manipulation";
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
phase = "distribution";
|
|
356
|
+
}
|
|
357
|
+
// Expected move based on manipulation
|
|
358
|
+
let expectedMove = "unclear";
|
|
359
|
+
if (manipulation === "above") {
|
|
360
|
+
// Swept buy-side liquidity, expect bearish move
|
|
361
|
+
expectedMove = "bearish";
|
|
362
|
+
}
|
|
363
|
+
else if (manipulation === "below") {
|
|
364
|
+
// Swept sell-side liquidity, expect bullish move
|
|
365
|
+
expectedMove = "bullish";
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
phase,
|
|
369
|
+
asianRangeHigh,
|
|
370
|
+
asianRangeLow,
|
|
371
|
+
manipulation,
|
|
372
|
+
expectedMove,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
// ============================================
|
|
376
|
+
// MAIN ICT ANALYSIS
|
|
377
|
+
// ============================================
|
|
378
|
+
async function generateICTSignal(symbol, interval = "1h") {
|
|
379
|
+
const spinner = (0, ora_1.default)(`Analyzing ${symbol} with ICT methodology...`).start();
|
|
380
|
+
try {
|
|
381
|
+
// Fetch data
|
|
382
|
+
spinner.text = "Fetching market data...";
|
|
383
|
+
const data = await (0, data_fetcher_1.fetchCryptoData)(symbol, interval, 200);
|
|
384
|
+
const candles = data.candles;
|
|
385
|
+
const currentPrice = data.currentPrice;
|
|
386
|
+
// Get current killzone
|
|
387
|
+
spinner.text = "Checking killzones...";
|
|
388
|
+
const killzone = getCurrentKillzone();
|
|
389
|
+
// Find swing points
|
|
390
|
+
spinner.text = "Analyzing market structure...";
|
|
391
|
+
const swingPoints = (0, smc_indicators_1.findSwingPoints)(candles, 3);
|
|
392
|
+
// Detect structure breaks
|
|
393
|
+
const structureBreaks = (0, smc_indicators_1.detectStructureBreaks)(candles, swingPoints);
|
|
394
|
+
const lastBOS = structureBreaks.filter((b) => b.type === "BOS").pop() || null;
|
|
395
|
+
const lastCHoCH = structureBreaks.filter((b) => b.type === "CHoCH").pop() || null;
|
|
396
|
+
// Determine trend
|
|
397
|
+
let trend = "ranging";
|
|
398
|
+
if (lastBOS)
|
|
399
|
+
trend = lastBOS.direction;
|
|
400
|
+
if (lastCHoCH && (!lastBOS || lastCHoCH.index > lastBOS.index)) {
|
|
401
|
+
trend = lastCHoCH.direction;
|
|
402
|
+
}
|
|
403
|
+
// Check for MSS (Market Structure Shift)
|
|
404
|
+
const mss = lastCHoCH !== null && lastCHoCH.index > candles.length - 20;
|
|
405
|
+
// Calculate indicators
|
|
406
|
+
spinner.text = "Calculating ICT concepts...";
|
|
407
|
+
const closes = candles.map((c) => c.close);
|
|
408
|
+
const rsi = (0, indicators_1.calculateRSI)(closes, 14);
|
|
409
|
+
const atr = (0, indicators_1.calculateATR)(candles, 14);
|
|
410
|
+
// Find order blocks and FVGs
|
|
411
|
+
const orderBlocks = (0, smc_indicators_1.findOrderBlocks)(candles, 100);
|
|
412
|
+
const fvgs = (0, smc_indicators_1.findFairValueGaps)(candles, 50);
|
|
413
|
+
// Calculate OTE
|
|
414
|
+
const ote = calculateOTE(candles, swingPoints, currentPrice);
|
|
415
|
+
// Find breaker blocks
|
|
416
|
+
const breakerBlocks = findBreakerBlocks(candles, orderBlocks);
|
|
417
|
+
// Find inducements
|
|
418
|
+
const inducements = findInducements(candles, swingPoints);
|
|
419
|
+
// Detect displacement
|
|
420
|
+
const displacement = detectDisplacement(candles, atr.current);
|
|
421
|
+
// Analyze Power of 3
|
|
422
|
+
const powerOf3 = analyzePowerOf3(candles);
|
|
423
|
+
// Premium/Discount
|
|
424
|
+
const premiumDiscount = (0, smc_indicators_1.calculatePremiumDiscount)(candles, 50);
|
|
425
|
+
// ============================================
|
|
426
|
+
// SIGNAL GENERATION
|
|
427
|
+
// ============================================
|
|
428
|
+
spinner.text = "Generating ICT signal...";
|
|
429
|
+
let signal = "WAIT";
|
|
430
|
+
let confidence = 30;
|
|
431
|
+
let modelType = "standard";
|
|
432
|
+
let entry = {
|
|
433
|
+
price: currentPrice,
|
|
434
|
+
zone: { low: currentPrice * 0.99, high: currentPrice * 1.01 },
|
|
435
|
+
type: "Wait for Setup",
|
|
436
|
+
reason: "No valid ICT setup detected",
|
|
437
|
+
};
|
|
438
|
+
let stopLoss = currentPrice;
|
|
439
|
+
let tp1 = currentPrice, tp2 = currentPrice, tp3 = currentPrice;
|
|
440
|
+
const reasoning = [];
|
|
441
|
+
const confluenceFactors = [];
|
|
442
|
+
const warnings = [];
|
|
443
|
+
// Check for active breaker block
|
|
444
|
+
const activeBreaker = breakerBlocks.find((bb) => {
|
|
445
|
+
return currentPrice >= bb.bottom * 0.995 && currentPrice <= bb.top * 1.005;
|
|
446
|
+
}) || null;
|
|
447
|
+
// Recent sweep detection
|
|
448
|
+
const recentSweep = inducements.find((ind) => {
|
|
449
|
+
if (!ind.swept || ind.sweepCandle === null)
|
|
450
|
+
return false;
|
|
451
|
+
return ind.sweepCandle >= candles.length - 5;
|
|
452
|
+
}) || null;
|
|
453
|
+
// ============================================
|
|
454
|
+
// SILVER BULLET MODEL
|
|
455
|
+
// ============================================
|
|
456
|
+
if (killzone.type === "silver_bullet_am" || killzone.type === "silver_bullet_pm") {
|
|
457
|
+
modelType = "silver_bullet";
|
|
458
|
+
confluenceFactors.push("In Silver Bullet window");
|
|
459
|
+
// Look for FVG in direction of trend
|
|
460
|
+
const unfilledFVGs = fvgs.filter((f) => !f.filled);
|
|
461
|
+
const trendFVG = unfilledFVGs.find((f) => f.type === (trend === "bullish" ? "bullish" : "bearish"));
|
|
462
|
+
if (trendFVG && displacement.detected && displacement.direction === trend) {
|
|
463
|
+
if (trend === "bullish") {
|
|
464
|
+
signal = "BUY";
|
|
465
|
+
confidence = 75;
|
|
466
|
+
entry = {
|
|
467
|
+
price: (trendFVG.top + trendFVG.bottom) / 2,
|
|
468
|
+
zone: { low: trendFVG.bottom, high: trendFVG.top },
|
|
469
|
+
type: "Silver Bullet FVG Entry",
|
|
470
|
+
reason: "FVG fill in bullish trend during Silver Bullet",
|
|
471
|
+
};
|
|
472
|
+
stopLoss = trendFVG.bottom * 0.995;
|
|
473
|
+
const risk = entry.price - stopLoss;
|
|
474
|
+
tp1 = entry.price + risk * 2;
|
|
475
|
+
tp2 = entry.price + risk * 3;
|
|
476
|
+
tp3 = entry.price + risk * 5;
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
signal = "SELL";
|
|
480
|
+
confidence = 75;
|
|
481
|
+
entry = {
|
|
482
|
+
price: (trendFVG.top + trendFVG.bottom) / 2,
|
|
483
|
+
zone: { low: trendFVG.bottom, high: trendFVG.top },
|
|
484
|
+
type: "Silver Bullet FVG Entry",
|
|
485
|
+
reason: "FVG fill in bearish trend during Silver Bullet",
|
|
486
|
+
};
|
|
487
|
+
stopLoss = trendFVG.top * 1.005;
|
|
488
|
+
const risk = stopLoss - entry.price;
|
|
489
|
+
tp1 = entry.price - risk * 2;
|
|
490
|
+
tp2 = entry.price - risk * 3;
|
|
491
|
+
tp3 = entry.price - risk * 5;
|
|
492
|
+
}
|
|
493
|
+
reasoning.push("Silver Bullet setup detected with FVG and displacement");
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
// ============================================
|
|
497
|
+
// OTE MODEL
|
|
498
|
+
// ============================================
|
|
499
|
+
if (signal === "WAIT" && ote.isValid && ote.quality === "premium") {
|
|
500
|
+
modelType = "ote";
|
|
501
|
+
// Check if price is in OTE zone
|
|
502
|
+
const inOTEZone = currentPrice >= ote.zone.low && currentPrice <= ote.zone.high;
|
|
503
|
+
if (inOTEZone) {
|
|
504
|
+
confluenceFactors.push("Price in OTE zone (62-79% retracement)");
|
|
505
|
+
if (ote.direction === "bullish" && premiumDiscount.zone === "discount") {
|
|
506
|
+
signal = "BUY";
|
|
507
|
+
confidence = 70;
|
|
508
|
+
entry = {
|
|
509
|
+
price: currentPrice,
|
|
510
|
+
zone: ote.zone,
|
|
511
|
+
type: "OTE Long Entry",
|
|
512
|
+
reason: "Bullish OTE in discount zone",
|
|
513
|
+
};
|
|
514
|
+
stopLoss = ote.swingLow * 0.995;
|
|
515
|
+
const risk = entry.price - stopLoss;
|
|
516
|
+
tp1 = entry.price + risk * 1.5;
|
|
517
|
+
tp2 = ote.swingHigh;
|
|
518
|
+
tp3 = ote.swingHigh + risk;
|
|
519
|
+
reasoning.push(`OTE at ${(ote.fibLevel * 100).toFixed(0)}% retracement`);
|
|
520
|
+
}
|
|
521
|
+
else if (ote.direction === "bearish" && premiumDiscount.zone === "premium") {
|
|
522
|
+
signal = "SELL";
|
|
523
|
+
confidence = 70;
|
|
524
|
+
entry = {
|
|
525
|
+
price: currentPrice,
|
|
526
|
+
zone: ote.zone,
|
|
527
|
+
type: "OTE Short Entry",
|
|
528
|
+
reason: "Bearish OTE in premium zone",
|
|
529
|
+
};
|
|
530
|
+
stopLoss = ote.swingHigh * 1.005;
|
|
531
|
+
const risk = stopLoss - entry.price;
|
|
532
|
+
tp1 = entry.price - risk * 1.5;
|
|
533
|
+
tp2 = ote.swingLow;
|
|
534
|
+
tp3 = ote.swingLow - risk;
|
|
535
|
+
reasoning.push(`OTE at ${(ote.fibLevel * 100).toFixed(0)}% retracement`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// ============================================
|
|
540
|
+
// BREAKER BLOCK MODEL
|
|
541
|
+
// ============================================
|
|
542
|
+
if (signal === "WAIT" && activeBreaker) {
|
|
543
|
+
modelType = "breaker";
|
|
544
|
+
confluenceFactors.push("Price at Breaker Block");
|
|
545
|
+
if (activeBreaker.type === "bullish") {
|
|
546
|
+
signal = "BUY";
|
|
547
|
+
confidence = 65;
|
|
548
|
+
entry = {
|
|
549
|
+
price: (activeBreaker.top + activeBreaker.bottom) / 2,
|
|
550
|
+
zone: { low: activeBreaker.bottom, high: activeBreaker.top },
|
|
551
|
+
type: "Bullish Breaker Entry",
|
|
552
|
+
reason: "Price retesting bullish breaker block",
|
|
553
|
+
};
|
|
554
|
+
stopLoss = activeBreaker.bottom * 0.99;
|
|
555
|
+
const risk = entry.price - stopLoss;
|
|
556
|
+
tp1 = entry.price + risk * 2;
|
|
557
|
+
tp2 = entry.price + risk * 3;
|
|
558
|
+
tp3 = entry.price + risk * 5;
|
|
559
|
+
reasoning.push("Bullish breaker block retest");
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
signal = "SELL";
|
|
563
|
+
confidence = 65;
|
|
564
|
+
entry = {
|
|
565
|
+
price: (activeBreaker.top + activeBreaker.bottom) / 2,
|
|
566
|
+
zone: { low: activeBreaker.bottom, high: activeBreaker.top },
|
|
567
|
+
type: "Bearish Breaker Entry",
|
|
568
|
+
reason: "Price retesting bearish breaker block",
|
|
569
|
+
};
|
|
570
|
+
stopLoss = activeBreaker.top * 1.01;
|
|
571
|
+
const risk = stopLoss - entry.price;
|
|
572
|
+
tp1 = entry.price - risk * 2;
|
|
573
|
+
tp2 = entry.price - risk * 3;
|
|
574
|
+
tp3 = entry.price - risk * 5;
|
|
575
|
+
reasoning.push("Bearish breaker block retest");
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
// ============================================
|
|
579
|
+
// DISPLACEMENT MODEL
|
|
580
|
+
// ============================================
|
|
581
|
+
if (signal === "WAIT" && displacement.detected && displacement.fvgCreated) {
|
|
582
|
+
modelType = "displacement";
|
|
583
|
+
confluenceFactors.push(`${displacement.direction} displacement detected`);
|
|
584
|
+
// Find the FVG created by displacement
|
|
585
|
+
const displacementFVG = fvgs.find((f) => f.type === displacement.direction && !f.filled && f.index >= displacement.startIndex - 2);
|
|
586
|
+
if (displacementFVG) {
|
|
587
|
+
const distToFVG = displacement.direction === "bullish"
|
|
588
|
+
? ((displacementFVG.bottom - currentPrice) / currentPrice) * 100
|
|
589
|
+
: ((currentPrice - displacementFVG.top) / currentPrice) * 100;
|
|
590
|
+
if (distToFVG < 2) {
|
|
591
|
+
if (displacement.direction === "bullish") {
|
|
592
|
+
signal = "BUY";
|
|
593
|
+
confidence = 60;
|
|
594
|
+
entry = {
|
|
595
|
+
price: displacementFVG.top,
|
|
596
|
+
zone: { low: displacementFVG.bottom, high: displacementFVG.top },
|
|
597
|
+
type: "Displacement FVG Entry",
|
|
598
|
+
reason: "Bullish displacement with FVG fill opportunity",
|
|
599
|
+
};
|
|
600
|
+
stopLoss = displacementFVG.bottom * 0.99;
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
signal = "SELL";
|
|
604
|
+
confidence = 60;
|
|
605
|
+
entry = {
|
|
606
|
+
price: displacementFVG.bottom,
|
|
607
|
+
zone: { low: displacementFVG.bottom, high: displacementFVG.top },
|
|
608
|
+
type: "Displacement FVG Entry",
|
|
609
|
+
reason: "Bearish displacement with FVG fill opportunity",
|
|
610
|
+
};
|
|
611
|
+
stopLoss = displacementFVG.top * 1.01;
|
|
612
|
+
}
|
|
613
|
+
const risk = Math.abs(entry.price - stopLoss);
|
|
614
|
+
tp1 =
|
|
615
|
+
displacement.direction === "bullish" ? entry.price + risk * 2 : entry.price - risk * 2;
|
|
616
|
+
tp2 =
|
|
617
|
+
displacement.direction === "bullish" ? entry.price + risk * 3 : entry.price - risk * 3;
|
|
618
|
+
tp3 =
|
|
619
|
+
displacement.direction === "bullish" ? entry.price + risk * 5 : entry.price - risk * 5;
|
|
620
|
+
reasoning.push(`Displacement strength: ${displacement.strength.toFixed(1)}x ATR`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
// ============================================
|
|
625
|
+
// ADD CONFLUENCE FACTORS
|
|
626
|
+
// ============================================
|
|
627
|
+
if (killzone.active)
|
|
628
|
+
confluenceFactors.push(`Active Killzone: ${killzone.name}`);
|
|
629
|
+
if (mss)
|
|
630
|
+
confluenceFactors.push("Recent Market Structure Shift");
|
|
631
|
+
if (recentSweep)
|
|
632
|
+
confluenceFactors.push(`${recentSweep.type} liquidity swept`);
|
|
633
|
+
if (powerOf3.manipulation !== "none") {
|
|
634
|
+
confluenceFactors.push(`AMD: ${powerOf3.manipulation} manipulation detected`);
|
|
635
|
+
}
|
|
636
|
+
// Adjust confidence based on confluence
|
|
637
|
+
confidence += Math.min(confluenceFactors.length * 5, 20);
|
|
638
|
+
confidence = Math.min(confidence, 95);
|
|
639
|
+
// ============================================
|
|
640
|
+
// WARNINGS
|
|
641
|
+
// ============================================
|
|
642
|
+
if (!killzone.active) {
|
|
643
|
+
warnings.push("Outside of major killzones - lower probability");
|
|
644
|
+
}
|
|
645
|
+
if (signal !== "WAIT" && trend !== (signal === "BUY" ? "bullish" : "bearish")) {
|
|
646
|
+
warnings.push("Counter-trend trade - manage risk carefully");
|
|
647
|
+
}
|
|
648
|
+
if (rsi.current > 75 && signal === "BUY") {
|
|
649
|
+
warnings.push("RSI overbought - consider waiting for pullback");
|
|
650
|
+
}
|
|
651
|
+
if (rsi.current < 25 && signal === "SELL") {
|
|
652
|
+
warnings.push("RSI oversold - consider waiting for bounce");
|
|
653
|
+
}
|
|
654
|
+
// Add general context
|
|
655
|
+
reasoning.push(`Trend: ${trend} | RSI: ${rsi.current.toFixed(1)}`);
|
|
656
|
+
reasoning.push(`Premium/Discount: ${premiumDiscount.zone} (${premiumDiscount.fibLevel.toFixed(0)}%)`);
|
|
657
|
+
if (powerOf3.phase !== "unknown") {
|
|
658
|
+
reasoning.push(`Power of 3: ${powerOf3.phase} phase`);
|
|
659
|
+
}
|
|
660
|
+
// Calculate R:R
|
|
661
|
+
const riskAmount = Math.abs(entry.price - stopLoss);
|
|
662
|
+
const rewardAmount = Math.abs(tp2 - entry.price);
|
|
663
|
+
const riskRewardRatio = riskAmount > 0 ? rewardAmount / riskAmount : 0;
|
|
664
|
+
spinner.succeed(`ICT analysis complete for ${data.symbol}`);
|
|
665
|
+
return {
|
|
666
|
+
symbol: data.symbol,
|
|
667
|
+
currentPrice,
|
|
668
|
+
timestamp: Date.now(),
|
|
669
|
+
signal,
|
|
670
|
+
confidence,
|
|
671
|
+
modelType,
|
|
672
|
+
killzone,
|
|
673
|
+
inKillzone: killzone.active,
|
|
674
|
+
ote,
|
|
675
|
+
breakerBlocks,
|
|
676
|
+
activeBreaker,
|
|
677
|
+
inducements,
|
|
678
|
+
recentSweep,
|
|
679
|
+
displacement,
|
|
680
|
+
powerOf3,
|
|
681
|
+
marketStructure: {
|
|
682
|
+
trend,
|
|
683
|
+
lastBOS,
|
|
684
|
+
lastCHoCH,
|
|
685
|
+
mss,
|
|
686
|
+
},
|
|
687
|
+
premiumDiscount: {
|
|
688
|
+
zone: premiumDiscount.zone,
|
|
689
|
+
fibLevel: premiumDiscount.fibLevel,
|
|
690
|
+
},
|
|
691
|
+
entry,
|
|
692
|
+
stopLoss,
|
|
693
|
+
takeProfit1: tp1,
|
|
694
|
+
takeProfit2: tp2,
|
|
695
|
+
takeProfit3: tp3,
|
|
696
|
+
riskRewardRatio,
|
|
697
|
+
reasoning,
|
|
698
|
+
confluenceFactors,
|
|
699
|
+
warnings,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
catch (error) {
|
|
703
|
+
spinner.fail(`Failed to analyze ${symbol}`);
|
|
704
|
+
throw error;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
// ============================================
|
|
708
|
+
// DISPLAY FUNCTION
|
|
709
|
+
// ============================================
|
|
710
|
+
function formatPrice(price) {
|
|
711
|
+
if (price < 0.001)
|
|
712
|
+
return `$${price.toFixed(8)}`;
|
|
713
|
+
if (price < 1)
|
|
714
|
+
return `$${price.toFixed(6)}`;
|
|
715
|
+
if (price < 100)
|
|
716
|
+
return `$${price.toFixed(4)}`;
|
|
717
|
+
return `$${price.toLocaleString(undefined, { maximumFractionDigits: 2 })}`;
|
|
718
|
+
}
|
|
719
|
+
function getConfidenceBar(confidence, width = 20) {
|
|
720
|
+
const filled = Math.round((confidence / 100) * width);
|
|
721
|
+
const empty = width - filled;
|
|
722
|
+
let color = chalk_1.default.green;
|
|
723
|
+
if (confidence < 40)
|
|
724
|
+
color = chalk_1.default.red;
|
|
725
|
+
else if (confidence < 60)
|
|
726
|
+
color = chalk_1.default.yellow;
|
|
727
|
+
return "[" + color("█".repeat(filled)) + chalk_1.default.gray("░".repeat(empty)) + "]";
|
|
728
|
+
}
|
|
729
|
+
function displayICTSignal(result) {
|
|
730
|
+
console.log("");
|
|
731
|
+
// Header
|
|
732
|
+
const headerColor = result.signal === "BUY" ? chalk_1.default.green : result.signal === "SELL" ? chalk_1.default.red : chalk_1.default.yellow;
|
|
733
|
+
const signalIcon = result.signal === "BUY" ? "🟢" : result.signal === "SELL" ? "🔴" : "⏳";
|
|
734
|
+
console.log(headerColor(" ╔═══════════════════════════════════════════════════════════════════════╗"));
|
|
735
|
+
console.log(headerColor(` ║ ${signalIcon} ICT TRADING STRATEGY - ${result.symbol.padEnd(20)} ║`));
|
|
736
|
+
console.log(headerColor(" ╚═══════════════════════════════════════════════════════════════════════╝"));
|
|
737
|
+
console.log("");
|
|
738
|
+
// Current Price & Signal
|
|
739
|
+
console.log(` ${chalk_1.default.cyan("Current Price:")} ${chalk_1.default.white.bold(formatPrice(result.currentPrice))}`);
|
|
740
|
+
console.log("");
|
|
741
|
+
const signalBadge = result.signal === "BUY"
|
|
742
|
+
? chalk_1.default.bgGreen.white.bold(" BUY ")
|
|
743
|
+
: result.signal === "SELL"
|
|
744
|
+
? chalk_1.default.bgRed.white.bold(" SELL ")
|
|
745
|
+
: chalk_1.default.bgYellow.black.bold(" WAIT ");
|
|
746
|
+
const modelBadge = chalk_1.default.bgBlue.white(` ${result.modelType.toUpperCase().replace("_", " ")} `);
|
|
747
|
+
console.log(` ${signalBadge} ${modelBadge} Confidence: ${getConfidenceBar(result.confidence)} ${result.confidence}%`);
|
|
748
|
+
console.log("");
|
|
749
|
+
// Killzone Status
|
|
750
|
+
console.log(chalk_1.default.magenta(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
751
|
+
console.log(chalk_1.default.magenta(" │ ⏰ KILLZONE STATUS │"));
|
|
752
|
+
console.log(chalk_1.default.magenta(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
753
|
+
const kzColor = result.inKillzone ? chalk_1.default.green : chalk_1.default.yellow;
|
|
754
|
+
console.log(` │ ${kzColor(result.killzone.name)} ${result.inKillzone ? chalk_1.default.green("● ACTIVE") : chalk_1.default.yellow("○ INACTIVE")}`);
|
|
755
|
+
console.log(` │ ${chalk_1.default.dim(result.killzone.description)}`);
|
|
756
|
+
// Show all killzones with times
|
|
757
|
+
console.log(` │`);
|
|
758
|
+
console.log(` │ ${chalk_1.default.dim("Session Times (UTC):")}`);
|
|
759
|
+
console.log(` │ ${chalk_1.default.cyan("Asian:")} 00:00-06:00 ${chalk_1.default.yellow("London:")} 07:00-10:00`);
|
|
760
|
+
console.log(` │ ${chalk_1.default.green("NY AM:")} 13:00-16:00 ${chalk_1.default.red("NY PM:")} 18:00-21:00`);
|
|
761
|
+
console.log(` │ ${chalk_1.default.magenta("Silver Bullet:")} 14:00-15:00 & 19:00-20:00`);
|
|
762
|
+
console.log(chalk_1.default.magenta(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
763
|
+
console.log("");
|
|
764
|
+
// OTE Analysis
|
|
765
|
+
console.log(chalk_1.default.cyan(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
766
|
+
console.log(chalk_1.default.cyan(" │ 📐 OTE (OPTIMAL TRADE ENTRY) │"));
|
|
767
|
+
console.log(chalk_1.default.cyan(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
768
|
+
const oteQualityColor = result.ote.quality === "premium"
|
|
769
|
+
? chalk_1.default.green
|
|
770
|
+
: result.ote.quality === "standard"
|
|
771
|
+
? chalk_1.default.yellow
|
|
772
|
+
: chalk_1.default.red;
|
|
773
|
+
console.log(` │ ${chalk_1.default.dim("Quality:")} ${oteQualityColor(result.ote.quality.toUpperCase())}`);
|
|
774
|
+
console.log(` │ ${chalk_1.default.dim("Fib Level:")} ${(result.ote.fibLevel * 100).toFixed(1)}% (Optimal: 62-79%)`);
|
|
775
|
+
console.log(` │ ${chalk_1.default.dim("OTE Zone:")} ${formatPrice(result.ote.zone.low)} - ${formatPrice(result.ote.zone.high)}`);
|
|
776
|
+
console.log(` │ ${chalk_1.default.dim("Swing Range:")} ${formatPrice(result.ote.swingLow)} - ${formatPrice(result.ote.swingHigh)}`);
|
|
777
|
+
console.log(chalk_1.default.cyan(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
778
|
+
console.log("");
|
|
779
|
+
// Power of 3
|
|
780
|
+
console.log(chalk_1.default.yellow(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
781
|
+
console.log(chalk_1.default.yellow(" │ ⚡ POWER OF 3 (AMD MODEL) │"));
|
|
782
|
+
console.log(chalk_1.default.yellow(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
783
|
+
const phaseColor = result.powerOf3.phase === "accumulation"
|
|
784
|
+
? chalk_1.default.blue
|
|
785
|
+
: result.powerOf3.phase === "manipulation"
|
|
786
|
+
? chalk_1.default.yellow
|
|
787
|
+
: result.powerOf3.phase === "distribution"
|
|
788
|
+
? chalk_1.default.red
|
|
789
|
+
: chalk_1.default.gray;
|
|
790
|
+
console.log(` │ ${chalk_1.default.dim("Current Phase:")} ${phaseColor(result.powerOf3.phase.toUpperCase())}`);
|
|
791
|
+
if (result.powerOf3.asianRangeHigh > 0) {
|
|
792
|
+
console.log(` │ ${chalk_1.default.dim("Asian Range:")} ${formatPrice(result.powerOf3.asianRangeLow)} - ${formatPrice(result.powerOf3.asianRangeHigh)}`);
|
|
793
|
+
}
|
|
794
|
+
const manipColor = result.powerOf3.manipulation === "above"
|
|
795
|
+
? chalk_1.default.red
|
|
796
|
+
: result.powerOf3.manipulation === "below"
|
|
797
|
+
? chalk_1.default.green
|
|
798
|
+
: chalk_1.default.gray;
|
|
799
|
+
console.log(` │ ${chalk_1.default.dim("Manipulation:")} ${manipColor(result.powerOf3.manipulation)}`);
|
|
800
|
+
const expectedColor = result.powerOf3.expectedMove === "bullish"
|
|
801
|
+
? chalk_1.default.green
|
|
802
|
+
: result.powerOf3.expectedMove === "bearish"
|
|
803
|
+
? chalk_1.default.red
|
|
804
|
+
: chalk_1.default.yellow;
|
|
805
|
+
console.log(` │ ${chalk_1.default.dim("Expected Move:")} ${expectedColor(result.powerOf3.expectedMove)}`);
|
|
806
|
+
console.log(chalk_1.default.yellow(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
807
|
+
console.log("");
|
|
808
|
+
// Market Structure
|
|
809
|
+
console.log(chalk_1.default.blue(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
810
|
+
console.log(chalk_1.default.blue(" │ 📊 MARKET STRUCTURE │"));
|
|
811
|
+
console.log(chalk_1.default.blue(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
812
|
+
const trendColor = result.marketStructure.trend === "bullish"
|
|
813
|
+
? chalk_1.default.green
|
|
814
|
+
: result.marketStructure.trend === "bearish"
|
|
815
|
+
? chalk_1.default.red
|
|
816
|
+
: chalk_1.default.yellow;
|
|
817
|
+
console.log(` │ ${chalk_1.default.dim("Trend:")} ${trendColor(result.marketStructure.trend.toUpperCase())}`);
|
|
818
|
+
if (result.marketStructure.lastBOS) {
|
|
819
|
+
const bosColor = result.marketStructure.lastBOS.direction === "bullish" ? chalk_1.default.green : chalk_1.default.red;
|
|
820
|
+
console.log(` │ ${chalk_1.default.dim("Last BOS:")} ${bosColor(result.marketStructure.lastBOS.direction)} @ ${formatPrice(result.marketStructure.lastBOS.level)}`);
|
|
821
|
+
}
|
|
822
|
+
if (result.marketStructure.lastCHoCH) {
|
|
823
|
+
const chochColor = result.marketStructure.lastCHoCH.direction === "bullish" ? chalk_1.default.green : chalk_1.default.red;
|
|
824
|
+
console.log(` │ ${chalk_1.default.dim("Last CHoCH:")} ${chochColor(result.marketStructure.lastCHoCH.direction)} @ ${formatPrice(result.marketStructure.lastCHoCH.level)}`);
|
|
825
|
+
}
|
|
826
|
+
console.log(` │ ${chalk_1.default.dim("MSS (Shift):")} ${result.marketStructure.mss ? chalk_1.default.green("YES") : chalk_1.default.gray("NO")}`);
|
|
827
|
+
const pdColor = result.premiumDiscount.zone === "discount"
|
|
828
|
+
? chalk_1.default.green
|
|
829
|
+
: result.premiumDiscount.zone === "premium"
|
|
830
|
+
? chalk_1.default.red
|
|
831
|
+
: chalk_1.default.yellow;
|
|
832
|
+
console.log(` │ ${chalk_1.default.dim("Zone:")} ${pdColor(result.premiumDiscount.zone)} (${result.premiumDiscount.fibLevel.toFixed(0)}%)`);
|
|
833
|
+
console.log(chalk_1.default.blue(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
834
|
+
console.log("");
|
|
835
|
+
// Displacement & Inducement
|
|
836
|
+
console.log(chalk_1.default.gray(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
837
|
+
console.log(chalk_1.default.gray(" │ 💥 DISPLACEMENT & INDUCEMENT │"));
|
|
838
|
+
console.log(chalk_1.default.gray(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
839
|
+
if (result.displacement.detected) {
|
|
840
|
+
const dispColor = result.displacement.direction === "bullish" ? chalk_1.default.green : chalk_1.default.red;
|
|
841
|
+
console.log(` │ ${chalk_1.default.dim("Displacement:")} ${dispColor(result.displacement.direction)} (${result.displacement.strength.toFixed(1)}x ATR)`);
|
|
842
|
+
console.log(` │ ${chalk_1.default.dim("FVG Created:")} ${result.displacement.fvgCreated ? chalk_1.default.green("YES") : chalk_1.default.gray("NO")}`);
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
console.log(` │ ${chalk_1.default.dim("Displacement:")} ${chalk_1.default.gray("None detected")}`);
|
|
846
|
+
}
|
|
847
|
+
console.log(` │`);
|
|
848
|
+
console.log(` │ ${chalk_1.default.dim("Inducements:")} ${result.inducements.length} found`);
|
|
849
|
+
if (result.recentSweep) {
|
|
850
|
+
const sweepColor = result.recentSweep.type === "buy_side" ? chalk_1.default.red : chalk_1.default.green;
|
|
851
|
+
console.log(` │ ${chalk_1.default.yellow("⚠ Recent Sweep:")} ${sweepColor(result.recentSweep.type)} @ ${formatPrice(result.recentSweep.level)}`);
|
|
852
|
+
}
|
|
853
|
+
console.log(chalk_1.default.gray(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
854
|
+
console.log("");
|
|
855
|
+
// Breaker Blocks
|
|
856
|
+
if (result.breakerBlocks.length > 0) {
|
|
857
|
+
console.log(chalk_1.default.red(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
858
|
+
console.log(chalk_1.default.red(" │ 🔄 BREAKER BLOCKS │"));
|
|
859
|
+
console.log(chalk_1.default.red(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
860
|
+
result.breakerBlocks.slice(0, 4).forEach((bb) => {
|
|
861
|
+
const bbColor = bb.type === "bullish" ? chalk_1.default.green : chalk_1.default.red;
|
|
862
|
+
const isActive = result.activeBreaker === bb;
|
|
863
|
+
const marker = isActive ? chalk_1.default.yellow(" ← ACTIVE") : "";
|
|
864
|
+
console.log(` │ ${bbColor(bb.type.padEnd(8))} ${formatPrice(bb.bottom)} - ${formatPrice(bb.top)} [${bb.strength}]${marker}`);
|
|
865
|
+
});
|
|
866
|
+
console.log(chalk_1.default.red(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
867
|
+
console.log("");
|
|
868
|
+
}
|
|
869
|
+
// Trade Setup
|
|
870
|
+
if (result.signal !== "WAIT") {
|
|
871
|
+
console.log(chalk_1.default.green(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
872
|
+
console.log(chalk_1.default.green(" │ 📍 TRADE SETUP │"));
|
|
873
|
+
console.log(chalk_1.default.green(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
874
|
+
console.log(` │ ${chalk_1.default.cyan("Entry Type:")} ${result.entry.type}`);
|
|
875
|
+
console.log(` │ ${chalk_1.default.yellow("Entry Zone:")} ${formatPrice(result.entry.zone.low)} - ${formatPrice(result.entry.zone.high)}`);
|
|
876
|
+
console.log(` │ ${chalk_1.default.yellow("Entry Price:")} ${chalk_1.default.white.bold(formatPrice(result.entry.price))}`);
|
|
877
|
+
console.log(` │ ${chalk_1.default.dim(result.entry.reason)}`);
|
|
878
|
+
console.log(` │`);
|
|
879
|
+
console.log(` │ ${chalk_1.default.red("Stop Loss:")} ${chalk_1.default.red.bold(formatPrice(result.stopLoss))} ${chalk_1.default.dim(`(${((Math.abs(result.entry.price - result.stopLoss) / result.entry.price) * 100).toFixed(2)}%)`)}`);
|
|
880
|
+
console.log(` │`);
|
|
881
|
+
console.log(` │ ${chalk_1.default.green("TP1:")} ${formatPrice(result.takeProfit1)} ${chalk_1.default.dim("(2R)")}`);
|
|
882
|
+
console.log(` │ ${chalk_1.default.green("TP2:")} ${formatPrice(result.takeProfit2)} ${chalk_1.default.dim("(3R)")}`);
|
|
883
|
+
console.log(` │ ${chalk_1.default.green("TP3:")} ${formatPrice(result.takeProfit3)} ${chalk_1.default.dim("(5R)")}`);
|
|
884
|
+
console.log(` │`);
|
|
885
|
+
console.log(` │ ${chalk_1.default.cyan("R:R Ratio:")} ${chalk_1.default.cyan.bold(result.riskRewardRatio.toFixed(1) + ":1")}`);
|
|
886
|
+
console.log(chalk_1.default.green(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
887
|
+
console.log("");
|
|
888
|
+
}
|
|
889
|
+
// Confluence Factors
|
|
890
|
+
if (result.confluenceFactors.length > 0) {
|
|
891
|
+
console.log(chalk_1.default.cyan(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
892
|
+
console.log(chalk_1.default.cyan(" │ ✓ CONFLUENCE FACTORS │"));
|
|
893
|
+
console.log(chalk_1.default.cyan(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
894
|
+
result.confluenceFactors.forEach((cf) => {
|
|
895
|
+
console.log(` │ ${chalk_1.default.green("✓")} ${cf}`);
|
|
896
|
+
});
|
|
897
|
+
console.log(chalk_1.default.cyan(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
898
|
+
console.log("");
|
|
899
|
+
}
|
|
900
|
+
// Reasoning
|
|
901
|
+
console.log(chalk_1.default.gray(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
902
|
+
console.log(chalk_1.default.gray(" │ 🔍 ANALYSIS │"));
|
|
903
|
+
console.log(chalk_1.default.gray(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
904
|
+
result.reasoning.forEach((r) => {
|
|
905
|
+
console.log(` │ ${chalk_1.default.dim("•")} ${r}`);
|
|
906
|
+
});
|
|
907
|
+
console.log(chalk_1.default.gray(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
908
|
+
console.log("");
|
|
909
|
+
// Warnings
|
|
910
|
+
if (result.warnings.length > 0) {
|
|
911
|
+
console.log(chalk_1.default.red(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
912
|
+
console.log(chalk_1.default.red(" │ ⚠️ WARNINGS │"));
|
|
913
|
+
console.log(chalk_1.default.red(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
914
|
+
result.warnings.forEach((w) => {
|
|
915
|
+
console.log(` │ ${chalk_1.default.yellow("!")} ${chalk_1.default.yellow(w)}`);
|
|
916
|
+
});
|
|
917
|
+
console.log(chalk_1.default.red(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
918
|
+
console.log("");
|
|
919
|
+
}
|
|
920
|
+
// ICT Concepts Legend
|
|
921
|
+
console.log(chalk_1.default.dim(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
922
|
+
console.log(chalk_1.default.dim(" │ 📚 ICT CONCEPTS GUIDE │"));
|
|
923
|
+
console.log(chalk_1.default.dim(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
924
|
+
console.log(chalk_1.default.dim(" │ OTE: Optimal Trade Entry (62-79% Fib retracement) │"));
|
|
925
|
+
console.log(chalk_1.default.dim(" │ BOS: Break of Structure | CHoCH: Change of Character │"));
|
|
926
|
+
console.log(chalk_1.default.dim(" │ MSS: Market Structure Shift (trend reversal signal) │"));
|
|
927
|
+
console.log(chalk_1.default.dim(" │ AMD: Accumulation → Manipulation → Distribution │"));
|
|
928
|
+
console.log(chalk_1.default.dim(" │ Silver Bullet: High-probability 1hr entry windows │"));
|
|
929
|
+
console.log(chalk_1.default.dim(" │ Breaker: Failed OB that flips to support/resistance │"));
|
|
930
|
+
console.log(chalk_1.default.dim(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
931
|
+
console.log("");
|
|
932
|
+
// Disclaimer
|
|
933
|
+
console.log(chalk_1.default.dim.italic(" ⚠️ This is not financial advice. Always manage your risk and DYOR."));
|
|
934
|
+
console.log("");
|
|
935
|
+
}
|
|
936
|
+
// ============================================
|
|
937
|
+
// RUNNER
|
|
938
|
+
// ============================================
|
|
939
|
+
async function runICTStrategy(symbol, interval = "1h") {
|
|
940
|
+
try {
|
|
941
|
+
const result = await generateICTSignal(symbol, interval);
|
|
942
|
+
displayICTSignal(result);
|
|
943
|
+
return result;
|
|
944
|
+
}
|
|
945
|
+
catch (error) {
|
|
946
|
+
console.log("");
|
|
947
|
+
console.log(chalk_1.default.red(" ╔═══════════════════════════════════════════════════════════════════════╗"));
|
|
948
|
+
console.log(chalk_1.default.red(" ║ ❌ ICT STRATEGY ERROR ║"));
|
|
949
|
+
console.log(chalk_1.default.red(" ╚═══════════════════════════════════════════════════════════════════════╝"));
|
|
950
|
+
console.log("");
|
|
951
|
+
console.log(chalk_1.default.yellow(` ⚠️ ${error.message || "An unexpected error occurred"}`));
|
|
952
|
+
console.log("");
|
|
953
|
+
return null;
|
|
954
|
+
}
|
|
955
|
+
}
|