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,445 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Order Block Trading Strategy
|
|
4
|
+
* Focused analysis for order block-based 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.generateOrderBlockSignal = generateOrderBlockSignal;
|
|
11
|
+
exports.displayOrderBlockSignal = displayOrderBlockSignal;
|
|
12
|
+
exports.runOrderBlockStrategy = runOrderBlockStrategy;
|
|
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
|
+
// ORDER BLOCK ANALYSIS
|
|
20
|
+
// ============================================
|
|
21
|
+
/**
|
|
22
|
+
* Find the nearest unmitigated order block to current price
|
|
23
|
+
*/
|
|
24
|
+
function findNearestOrderBlock(orderBlocks, currentPrice, direction) {
|
|
25
|
+
const filtered = direction
|
|
26
|
+
? orderBlocks.filter((ob) => ob.type === direction && !ob.mitigated)
|
|
27
|
+
: orderBlocks.filter((ob) => !ob.mitigated);
|
|
28
|
+
if (filtered.length === 0)
|
|
29
|
+
return null;
|
|
30
|
+
return filtered.sort((a, b) => {
|
|
31
|
+
const distA = Math.min(Math.abs(currentPrice - a.top), Math.abs(currentPrice - a.bottom));
|
|
32
|
+
const distB = Math.min(Math.abs(currentPrice - b.top), Math.abs(currentPrice - b.bottom));
|
|
33
|
+
return distA - distB;
|
|
34
|
+
})[0];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if price is in or near an order block zone
|
|
38
|
+
*/
|
|
39
|
+
function checkPriceInOBZone(price, ob, tolerance = 0.005 // 0.5%
|
|
40
|
+
) {
|
|
41
|
+
const toleranceAmount = (ob.top - ob.bottom) * tolerance;
|
|
42
|
+
const expandedTop = ob.top + toleranceAmount;
|
|
43
|
+
const expandedBottom = ob.bottom - toleranceAmount;
|
|
44
|
+
const inZone = price >= ob.bottom && price <= ob.top;
|
|
45
|
+
const nearZone = price >= expandedBottom && price <= expandedTop;
|
|
46
|
+
let distancePercent;
|
|
47
|
+
if (inZone) {
|
|
48
|
+
distancePercent = 0;
|
|
49
|
+
}
|
|
50
|
+
else if (price > ob.top) {
|
|
51
|
+
distancePercent = ((price - ob.top) / price) * 100;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
distancePercent = ((ob.bottom - price) / price) * 100;
|
|
55
|
+
}
|
|
56
|
+
return { inZone, nearZone, distancePercent };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Calculate confidence score for order block trade
|
|
60
|
+
*/
|
|
61
|
+
function calculateOBConfidence(ob, currentPrice, trend, premiumDiscount, rsi) {
|
|
62
|
+
let score = 50;
|
|
63
|
+
// Order block strength
|
|
64
|
+
if (ob.strength === "strong")
|
|
65
|
+
score += 15;
|
|
66
|
+
else if (ob.strength === "moderate")
|
|
67
|
+
score += 10;
|
|
68
|
+
else
|
|
69
|
+
score += 5;
|
|
70
|
+
// Trend alignment
|
|
71
|
+
if (ob.type === "bullish" && trend === "bullish")
|
|
72
|
+
score += 15;
|
|
73
|
+
else if (ob.type === "bearish" && trend === "bearish")
|
|
74
|
+
score += 15;
|
|
75
|
+
else if (trend === "sideways")
|
|
76
|
+
score += 5;
|
|
77
|
+
else
|
|
78
|
+
score -= 10; // Counter-trend
|
|
79
|
+
// Premium/Discount alignment
|
|
80
|
+
if (ob.type === "bullish" && premiumDiscount === "discount")
|
|
81
|
+
score += 10;
|
|
82
|
+
else if (ob.type === "bearish" && premiumDiscount === "premium")
|
|
83
|
+
score += 10;
|
|
84
|
+
// RSI confirmation
|
|
85
|
+
if (ob.type === "bullish" && rsi < 40)
|
|
86
|
+
score += 10;
|
|
87
|
+
else if (ob.type === "bearish" && rsi > 60)
|
|
88
|
+
score += 10;
|
|
89
|
+
// Price proximity
|
|
90
|
+
const { inZone, nearZone, distancePercent } = checkPriceInOBZone(currentPrice, ob);
|
|
91
|
+
if (inZone)
|
|
92
|
+
score += 15;
|
|
93
|
+
else if (nearZone)
|
|
94
|
+
score += 10;
|
|
95
|
+
else if (distancePercent < 2)
|
|
96
|
+
score += 5;
|
|
97
|
+
return Math.min(100, Math.max(0, score));
|
|
98
|
+
}
|
|
99
|
+
// ============================================
|
|
100
|
+
// MAIN STRATEGY FUNCTION
|
|
101
|
+
// ============================================
|
|
102
|
+
async function generateOrderBlockSignal(symbol, interval = "4h") {
|
|
103
|
+
const spinner = (0, ora_1.default)(`Analyzing ${symbol} for Order Block setups...`).start();
|
|
104
|
+
try {
|
|
105
|
+
// Fetch data
|
|
106
|
+
spinner.text = "Fetching market data...";
|
|
107
|
+
const data = await (0, data_fetcher_1.fetchCryptoData)(symbol, interval, 200);
|
|
108
|
+
const candles = data.candles;
|
|
109
|
+
const currentPrice = data.currentPrice;
|
|
110
|
+
// Find Order Blocks
|
|
111
|
+
spinner.text = "Identifying Order Blocks...";
|
|
112
|
+
const allOBs = (0, smc_indicators_1.findOrderBlocks)(candles, 100);
|
|
113
|
+
const bullishOBs = allOBs.filter((ob) => ob.type === "bullish" && !ob.mitigated);
|
|
114
|
+
const bearishOBs = allOBs.filter((ob) => ob.type === "bearish" && !ob.mitigated);
|
|
115
|
+
// Find swing points for context
|
|
116
|
+
const swingPoints = (0, smc_indicators_1.findSwingPoints)(candles, 3);
|
|
117
|
+
// Calculate indicators
|
|
118
|
+
const closes = candles.map((c) => c.close);
|
|
119
|
+
const rsi = (0, indicators_1.calculateRSI)(closes, 14);
|
|
120
|
+
const trend = (0, indicators_1.analyzeTrend)(candles);
|
|
121
|
+
const premiumDiscount = (0, smc_indicators_1.calculatePremiumDiscount)(candles, 50);
|
|
122
|
+
const atr = (0, indicators_1.calculateATR)(candles, 14);
|
|
123
|
+
// Find nearest order blocks
|
|
124
|
+
const nearestBullishOB = findNearestOrderBlock(allOBs, currentPrice, "bullish");
|
|
125
|
+
const nearestBearishOB = findNearestOrderBlock(allOBs, currentPrice, "bearish");
|
|
126
|
+
const nearestOB = findNearestOrderBlock(allOBs, currentPrice);
|
|
127
|
+
// Determine signal
|
|
128
|
+
let signal = "WAIT";
|
|
129
|
+
let activeOB = null;
|
|
130
|
+
let entry = {
|
|
131
|
+
price: currentPrice,
|
|
132
|
+
zone: { low: currentPrice, high: currentPrice },
|
|
133
|
+
type: "Wait for OB",
|
|
134
|
+
};
|
|
135
|
+
let stopLoss = currentPrice;
|
|
136
|
+
let tp1 = currentPrice, tp2 = currentPrice, tp3 = currentPrice;
|
|
137
|
+
const reasoning = [];
|
|
138
|
+
const warnings = [];
|
|
139
|
+
let confidence = 0;
|
|
140
|
+
// Check if price is at a bullish OB (BUY signal)
|
|
141
|
+
if (nearestBullishOB) {
|
|
142
|
+
const check = checkPriceInOBZone(currentPrice, nearestBullishOB);
|
|
143
|
+
if (check.inZone || (check.nearZone && check.distancePercent < 1)) {
|
|
144
|
+
signal = "BUY";
|
|
145
|
+
confidence = calculateOBConfidence(nearestBullishOB, currentPrice, trend.direction, premiumDiscount.zone, rsi.current);
|
|
146
|
+
activeOB = {
|
|
147
|
+
type: "bullish",
|
|
148
|
+
top: nearestBullishOB.top,
|
|
149
|
+
bottom: nearestBullishOB.bottom,
|
|
150
|
+
midpoint: (nearestBullishOB.top + nearestBullishOB.bottom) / 2,
|
|
151
|
+
strength: nearestBullishOB.strength,
|
|
152
|
+
distancePercent: check.distancePercent,
|
|
153
|
+
priceInZone: check.inZone,
|
|
154
|
+
};
|
|
155
|
+
entry = {
|
|
156
|
+
price: (nearestBullishOB.top + nearestBullishOB.bottom) / 2,
|
|
157
|
+
zone: { low: nearestBullishOB.bottom, high: nearestBullishOB.top },
|
|
158
|
+
type: "Bullish Order Block",
|
|
159
|
+
};
|
|
160
|
+
// Stop loss below OB
|
|
161
|
+
stopLoss = nearestBullishOB.bottom * 0.995;
|
|
162
|
+
// Take profits based on risk
|
|
163
|
+
const risk = entry.price - stopLoss;
|
|
164
|
+
tp1 = entry.price + risk * 1.5;
|
|
165
|
+
tp2 = entry.price + risk * 2.5;
|
|
166
|
+
tp3 = entry.price + risk * 4;
|
|
167
|
+
reasoning.push(`Price at ${nearestBullishOB.strength} bullish Order Block`);
|
|
168
|
+
reasoning.push(`OB Zone: $${nearestBullishOB.bottom.toFixed(2)} - $${nearestBullishOB.top.toFixed(2)}`);
|
|
169
|
+
if (trend.direction === "bullish") {
|
|
170
|
+
reasoning.push("Trend aligned with OB (bullish)");
|
|
171
|
+
}
|
|
172
|
+
else if (trend.direction === "bearish") {
|
|
173
|
+
warnings.push("Counter-trend trade - higher risk");
|
|
174
|
+
}
|
|
175
|
+
if (premiumDiscount.zone === "discount") {
|
|
176
|
+
reasoning.push("Price in discount zone - favorable for longs");
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Check if price is at a bearish OB (SELL signal)
|
|
181
|
+
if (nearestBearishOB && signal === "WAIT") {
|
|
182
|
+
const check = checkPriceInOBZone(currentPrice, nearestBearishOB);
|
|
183
|
+
if (check.inZone || (check.nearZone && check.distancePercent < 1)) {
|
|
184
|
+
signal = "SELL";
|
|
185
|
+
confidence = calculateOBConfidence(nearestBearishOB, currentPrice, trend.direction, premiumDiscount.zone, rsi.current);
|
|
186
|
+
activeOB = {
|
|
187
|
+
type: "bearish",
|
|
188
|
+
top: nearestBearishOB.top,
|
|
189
|
+
bottom: nearestBearishOB.bottom,
|
|
190
|
+
midpoint: (nearestBearishOB.top + nearestBearishOB.bottom) / 2,
|
|
191
|
+
strength: nearestBearishOB.strength,
|
|
192
|
+
distancePercent: check.distancePercent,
|
|
193
|
+
priceInZone: check.inZone,
|
|
194
|
+
};
|
|
195
|
+
entry = {
|
|
196
|
+
price: (nearestBearishOB.top + nearestBearishOB.bottom) / 2,
|
|
197
|
+
zone: { low: nearestBearishOB.bottom, high: nearestBearishOB.top },
|
|
198
|
+
type: "Bearish Order Block",
|
|
199
|
+
};
|
|
200
|
+
// Stop loss above OB
|
|
201
|
+
stopLoss = nearestBearishOB.top * 1.005;
|
|
202
|
+
// Take profits based on risk
|
|
203
|
+
const risk = stopLoss - entry.price;
|
|
204
|
+
tp1 = entry.price - risk * 1.5;
|
|
205
|
+
tp2 = entry.price - risk * 2.5;
|
|
206
|
+
tp3 = entry.price - risk * 4;
|
|
207
|
+
reasoning.push(`Price at ${nearestBearishOB.strength} bearish Order Block`);
|
|
208
|
+
reasoning.push(`OB Zone: $${nearestBearishOB.bottom.toFixed(2)} - $${nearestBearishOB.top.toFixed(2)}`);
|
|
209
|
+
if (trend.direction === "bearish") {
|
|
210
|
+
reasoning.push("Trend aligned with OB (bearish)");
|
|
211
|
+
}
|
|
212
|
+
else if (trend.direction === "bullish") {
|
|
213
|
+
warnings.push("Counter-trend trade - higher risk");
|
|
214
|
+
}
|
|
215
|
+
if (premiumDiscount.zone === "premium") {
|
|
216
|
+
reasoning.push("Price in premium zone - favorable for shorts");
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// If no active signal, provide waiting guidance
|
|
221
|
+
if (signal === "WAIT") {
|
|
222
|
+
confidence = 30;
|
|
223
|
+
if (nearestBullishOB) {
|
|
224
|
+
const distBullish = checkPriceInOBZone(currentPrice, nearestBullishOB).distancePercent;
|
|
225
|
+
reasoning.push(`Nearest bullish OB at $${nearestBullishOB.bottom.toFixed(2)} (${distBullish.toFixed(1)}% away)`);
|
|
226
|
+
}
|
|
227
|
+
if (nearestBearishOB) {
|
|
228
|
+
const distBearish = checkPriceInOBZone(currentPrice, nearestBearishOB).distancePercent;
|
|
229
|
+
reasoning.push(`Nearest bearish OB at $${nearestBearishOB.top.toFixed(2)} (${distBearish.toFixed(1)}% away)`);
|
|
230
|
+
}
|
|
231
|
+
if (bullishOBs.length === 0 && bearishOBs.length === 0) {
|
|
232
|
+
reasoning.push("No valid Order Blocks found - wait for new OB formation");
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
reasoning.push("Wait for price to reach an Order Block zone");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Add general context
|
|
239
|
+
reasoning.push(`RSI: ${rsi.current.toFixed(1)} (${rsi.current < 30 ? "oversold" : rsi.current > 70 ? "overbought" : "neutral"})`);
|
|
240
|
+
reasoning.push(`Trend: ${trend.direction} | Premium/Discount: ${premiumDiscount.zone}`);
|
|
241
|
+
// Calculate R:R
|
|
242
|
+
const riskAmount = Math.abs(entry.price - stopLoss);
|
|
243
|
+
const rewardAmount = Math.abs(tp2 - entry.price);
|
|
244
|
+
const riskRewardRatio = riskAmount > 0 ? rewardAmount / riskAmount : 0;
|
|
245
|
+
// Add warnings
|
|
246
|
+
if (atr.current / currentPrice > 0.03) {
|
|
247
|
+
warnings.push("High volatility - consider smaller position size");
|
|
248
|
+
}
|
|
249
|
+
if (rsi.current > 75 && signal === "BUY") {
|
|
250
|
+
warnings.push("RSI overbought - potential reversal risk");
|
|
251
|
+
}
|
|
252
|
+
else if (rsi.current < 25 && signal === "SELL") {
|
|
253
|
+
warnings.push("RSI oversold - potential bounce risk");
|
|
254
|
+
}
|
|
255
|
+
spinner.succeed(`Order Block analysis complete for ${data.symbol}`);
|
|
256
|
+
return {
|
|
257
|
+
symbol: data.symbol,
|
|
258
|
+
currentPrice,
|
|
259
|
+
signal,
|
|
260
|
+
confidence,
|
|
261
|
+
activeOB,
|
|
262
|
+
bullishOBs,
|
|
263
|
+
bearishOBs,
|
|
264
|
+
entry,
|
|
265
|
+
stopLoss,
|
|
266
|
+
takeProfit1: tp1,
|
|
267
|
+
takeProfit2: tp2,
|
|
268
|
+
takeProfit3: tp3,
|
|
269
|
+
riskRewardRatio,
|
|
270
|
+
trend: trend.direction,
|
|
271
|
+
premiumDiscount: premiumDiscount.zone,
|
|
272
|
+
reasoning,
|
|
273
|
+
warnings,
|
|
274
|
+
timestamp: Date.now(),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
spinner.fail(`Failed to analyze ${symbol}`);
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// ============================================
|
|
283
|
+
// DISPLAY FUNCTION
|
|
284
|
+
// ============================================
|
|
285
|
+
function formatPrice(price) {
|
|
286
|
+
if (price < 0.001)
|
|
287
|
+
return `$${price.toFixed(8)}`;
|
|
288
|
+
if (price < 1)
|
|
289
|
+
return `$${price.toFixed(6)}`;
|
|
290
|
+
if (price < 100)
|
|
291
|
+
return `$${price.toFixed(4)}`;
|
|
292
|
+
return `$${price.toLocaleString(undefined, { maximumFractionDigits: 2 })}`;
|
|
293
|
+
}
|
|
294
|
+
function getConfidenceBar(confidence, width = 20) {
|
|
295
|
+
const filled = Math.round((confidence / 100) * width);
|
|
296
|
+
const empty = width - filled;
|
|
297
|
+
let color = chalk_1.default.green;
|
|
298
|
+
if (confidence < 40)
|
|
299
|
+
color = chalk_1.default.red;
|
|
300
|
+
else if (confidence < 60)
|
|
301
|
+
color = chalk_1.default.yellow;
|
|
302
|
+
return "[" + color("█".repeat(filled)) + chalk_1.default.gray("░".repeat(empty)) + "]";
|
|
303
|
+
}
|
|
304
|
+
function displayOrderBlockSignal(result) {
|
|
305
|
+
console.log("");
|
|
306
|
+
// Header
|
|
307
|
+
const headerColor = result.signal === "BUY" ? chalk_1.default.green : result.signal === "SELL" ? chalk_1.default.red : chalk_1.default.yellow;
|
|
308
|
+
const signalIcon = result.signal === "BUY" ? "🟢" : result.signal === "SELL" ? "🔴" : "⏳";
|
|
309
|
+
console.log(headerColor(" ╔═══════════════════════════════════════════════════════════════════════╗"));
|
|
310
|
+
console.log(headerColor(` ║ ${signalIcon} ORDER BLOCK STRATEGY - ${result.symbol.padEnd(20)} ║`));
|
|
311
|
+
console.log(headerColor(" ╚═══════════════════════════════════════════════════════════════════════╝"));
|
|
312
|
+
console.log("");
|
|
313
|
+
// Current Price
|
|
314
|
+
console.log(` ${chalk_1.default.cyan("Current Price:")} ${chalk_1.default.white.bold(formatPrice(result.currentPrice))}`);
|
|
315
|
+
console.log("");
|
|
316
|
+
// Signal Badge
|
|
317
|
+
const signalBadge = result.signal === "BUY"
|
|
318
|
+
? chalk_1.default.bgGreen.white.bold(" BUY ")
|
|
319
|
+
: result.signal === "SELL"
|
|
320
|
+
? chalk_1.default.bgRed.white.bold(" SELL ")
|
|
321
|
+
: chalk_1.default.bgYellow.black.bold(" WAIT ");
|
|
322
|
+
const confidenceBar = getConfidenceBar(result.confidence);
|
|
323
|
+
console.log(` ${signalBadge} Confidence: ${confidenceBar} ${result.confidence}%`);
|
|
324
|
+
console.log("");
|
|
325
|
+
// Order Block Details
|
|
326
|
+
console.log(chalk_1.default.cyan(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
327
|
+
console.log(chalk_1.default.cyan(" │ 📦 ORDER BLOCK ANALYSIS │"));
|
|
328
|
+
console.log(chalk_1.default.cyan(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
329
|
+
console.log(` │ ${chalk_1.default.green("Bullish OBs:")} ${result.bullishOBs.length} unmitigated`);
|
|
330
|
+
console.log(` │ ${chalk_1.default.red("Bearish OBs:")} ${result.bearishOBs.length} unmitigated`);
|
|
331
|
+
if (result.activeOB) {
|
|
332
|
+
const obColor = result.activeOB.type === "bullish" ? chalk_1.default.green : chalk_1.default.red;
|
|
333
|
+
console.log(` │`);
|
|
334
|
+
console.log(` │ ${chalk_1.default.yellow("Active OB:")} ${obColor(result.activeOB.type.toUpperCase())} (${result.activeOB.strength})`);
|
|
335
|
+
console.log(` │ ${chalk_1.default.dim("Zone:")} ${formatPrice(result.activeOB.bottom)} - ${formatPrice(result.activeOB.top)}`);
|
|
336
|
+
console.log(` │ ${chalk_1.default.dim("Midpoint:")} ${formatPrice(result.activeOB.midpoint)}`);
|
|
337
|
+
console.log(` │ ${chalk_1.default.dim("Price in Zone:")} ${result.activeOB.priceInZone ? chalk_1.default.green("YES") : chalk_1.default.yellow("NEAR")}`);
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
console.log(` │`);
|
|
341
|
+
console.log(` │ ${chalk_1.default.yellow("No active Order Block at current price")}`);
|
|
342
|
+
}
|
|
343
|
+
console.log(chalk_1.default.cyan(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
344
|
+
console.log("");
|
|
345
|
+
// Trade Setup (if signal is BUY or SELL)
|
|
346
|
+
if (result.signal !== "WAIT") {
|
|
347
|
+
console.log(chalk_1.default.magenta(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
348
|
+
console.log(chalk_1.default.magenta(" │ 📍 TRADE SETUP │"));
|
|
349
|
+
console.log(chalk_1.default.magenta(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
350
|
+
console.log(` │ ${chalk_1.default.cyan("Entry Type:")} ${result.entry.type}`);
|
|
351
|
+
console.log(` │ ${chalk_1.default.yellow("Entry Zone:")} ${formatPrice(result.entry.zone.low)} - ${formatPrice(result.entry.zone.high)}`);
|
|
352
|
+
console.log(` │ ${chalk_1.default.yellow("Entry Price:")} ${chalk_1.default.white.bold(formatPrice(result.entry.price))}`);
|
|
353
|
+
console.log(` │`);
|
|
354
|
+
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)}%)`)}`);
|
|
355
|
+
console.log(` │`);
|
|
356
|
+
console.log(` │ ${chalk_1.default.green("Take Profit 1:")} ${chalk_1.default.green(formatPrice(result.takeProfit1))} ${chalk_1.default.dim("(1.5R)")}`);
|
|
357
|
+
console.log(` │ ${chalk_1.default.green("Take Profit 2:")} ${chalk_1.default.green(formatPrice(result.takeProfit2))} ${chalk_1.default.dim("(2.5R)")}`);
|
|
358
|
+
console.log(` │ ${chalk_1.default.green("Take Profit 3:")} ${chalk_1.default.green(formatPrice(result.takeProfit3))} ${chalk_1.default.dim("(4R)")}`);
|
|
359
|
+
console.log(` │`);
|
|
360
|
+
console.log(` │ ${chalk_1.default.cyan("Risk/Reward:")} ${chalk_1.default.cyan.bold(result.riskRewardRatio.toFixed(1) + ":1")}`);
|
|
361
|
+
console.log(chalk_1.default.magenta(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
362
|
+
console.log("");
|
|
363
|
+
}
|
|
364
|
+
// Visual Order Block Map
|
|
365
|
+
console.log(chalk_1.default.blue(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
366
|
+
console.log(chalk_1.default.blue(" │ 📊 ORDER BLOCK MAP │"));
|
|
367
|
+
console.log(chalk_1.default.blue(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
368
|
+
// Show nearest OBs visually
|
|
369
|
+
const allOBs = [...result.bullishOBs, ...result.bearishOBs].sort((a, b) => b.top - a.top);
|
|
370
|
+
const visibleOBs = allOBs.slice(0, 6);
|
|
371
|
+
if (visibleOBs.length > 0) {
|
|
372
|
+
visibleOBs.forEach((ob) => {
|
|
373
|
+
const obColor = ob.type === "bullish" ? chalk_1.default.green : chalk_1.default.red;
|
|
374
|
+
const icon = ob.type === "bullish" ? "▲" : "▼";
|
|
375
|
+
const isNear = result.currentPrice >= ob.bottom * 0.99 && result.currentPrice <= ob.top * 1.01;
|
|
376
|
+
const marker = isNear ? chalk_1.default.yellow(" ← PRICE HERE") : "";
|
|
377
|
+
console.log(` │ ${obColor(icon)} ${ob.type.padEnd(8)} ${formatPrice(ob.bottom).padStart(12)} - ${formatPrice(ob.top).padEnd(12)} [${ob.strength}]${marker}`);
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
console.log(` │ ${chalk_1.default.gray("No unmitigated Order Blocks found")}`);
|
|
382
|
+
}
|
|
383
|
+
// Show current price line
|
|
384
|
+
console.log(` │`);
|
|
385
|
+
console.log(` │ ${chalk_1.default.white("→ Current:")} ${chalk_1.default.white.bold(formatPrice(result.currentPrice))}`);
|
|
386
|
+
console.log(chalk_1.default.blue(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
387
|
+
console.log("");
|
|
388
|
+
// Context
|
|
389
|
+
console.log(chalk_1.default.gray(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
390
|
+
console.log(chalk_1.default.gray(" │ 🔍 CONTEXT & REASONING │"));
|
|
391
|
+
console.log(chalk_1.default.gray(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
392
|
+
console.log(` │ ${chalk_1.default.dim("Trend:")} ${result.trend === "bullish" ? chalk_1.default.green("▲ Bullish") : result.trend === "bearish" ? chalk_1.default.red("▼ Bearish") : chalk_1.default.yellow("● Sideways")}`);
|
|
393
|
+
console.log(` │ ${chalk_1.default.dim("Zone:")} ${result.premiumDiscount === "discount" ? chalk_1.default.green("Discount") : result.premiumDiscount === "premium" ? chalk_1.default.red("Premium") : chalk_1.default.yellow("Equilibrium")}`);
|
|
394
|
+
console.log(` │`);
|
|
395
|
+
result.reasoning.forEach((r) => {
|
|
396
|
+
console.log(` │ ${chalk_1.default.cyan("•")} ${chalk_1.default.gray(r)}`);
|
|
397
|
+
});
|
|
398
|
+
console.log(chalk_1.default.gray(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
399
|
+
console.log("");
|
|
400
|
+
// Warnings
|
|
401
|
+
if (result.warnings.length > 0) {
|
|
402
|
+
console.log(chalk_1.default.red(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
403
|
+
console.log(chalk_1.default.red(" │ ⚠️ WARNINGS │"));
|
|
404
|
+
console.log(chalk_1.default.red(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
405
|
+
result.warnings.forEach((w) => {
|
|
406
|
+
console.log(` │ ${chalk_1.default.yellow("!")} ${chalk_1.default.yellow(w)}`);
|
|
407
|
+
});
|
|
408
|
+
console.log(chalk_1.default.red(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
409
|
+
console.log("");
|
|
410
|
+
}
|
|
411
|
+
// How Order Blocks are Calculated (Educational)
|
|
412
|
+
console.log(chalk_1.default.dim(" ┌─────────────────────────────────────────────────────────────────────┐"));
|
|
413
|
+
console.log(chalk_1.default.dim(" │ 📚 HOW ORDER BLOCKS WORK │"));
|
|
414
|
+
console.log(chalk_1.default.dim(" ├─────────────────────────────────────────────────────────────────────┤"));
|
|
415
|
+
console.log(chalk_1.default.dim(" │ Bullish OB: Last bearish candle before strong bullish move │"));
|
|
416
|
+
console.log(chalk_1.default.dim(" │ → BUY when price returns to this zone │"));
|
|
417
|
+
console.log(chalk_1.default.dim(" │ Bearish OB: Last bullish candle before strong bearish move │"));
|
|
418
|
+
console.log(chalk_1.default.dim(" │ → SELL when price returns to this zone │"));
|
|
419
|
+
console.log(chalk_1.default.dim(' │ Mitigated: OB is "used" when price fully trades through it │'));
|
|
420
|
+
console.log(chalk_1.default.dim(" └─────────────────────────────────────────────────────────────────────┘"));
|
|
421
|
+
console.log("");
|
|
422
|
+
// Disclaimer
|
|
423
|
+
console.log(chalk_1.default.dim.italic(" ⚠️ This is not financial advice. Always manage your risk and DYOR."));
|
|
424
|
+
console.log("");
|
|
425
|
+
}
|
|
426
|
+
// ============================================
|
|
427
|
+
// RUNNER
|
|
428
|
+
// ============================================
|
|
429
|
+
async function runOrderBlockStrategy(symbol, interval = "4h") {
|
|
430
|
+
try {
|
|
431
|
+
const result = await generateOrderBlockSignal(symbol, interval);
|
|
432
|
+
displayOrderBlockSignal(result);
|
|
433
|
+
return result;
|
|
434
|
+
}
|
|
435
|
+
catch (error) {
|
|
436
|
+
console.log("");
|
|
437
|
+
console.log(chalk_1.default.red(" ╔═══════════════════════════════════════════════════════════════════════╗"));
|
|
438
|
+
console.log(chalk_1.default.red(" ║ ❌ ORDER BLOCK ERROR ║"));
|
|
439
|
+
console.log(chalk_1.default.red(" ╚═══════════════════════════════════════════════════════════════════════╝"));
|
|
440
|
+
console.log("");
|
|
441
|
+
console.log(chalk_1.default.yellow(` ⚠️ ${error.message || "An unexpected error occurred"}`));
|
|
442
|
+
console.log("");
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
}
|