prab-cli 1.2.0 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +175 -4
- package/dist/lib/config.js +60 -1
- package/dist/lib/crypto/analyzer.js +275 -0
- package/dist/lib/crypto/chart-visual.js +548 -0
- package/dist/lib/crypto/data-fetcher.js +166 -0
- package/dist/lib/crypto/index.js +47 -0
- package/dist/lib/crypto/indicators.js +390 -0
- package/dist/lib/crypto/market-analyzer.js +497 -0
- package/dist/lib/crypto/signal-generator.js +559 -0
- package/dist/lib/crypto/smc-analyzer.js +418 -0
- package/dist/lib/crypto/smc-indicators.js +512 -0
- package/dist/lib/slash-commands.js +24 -0
- package/dist/lib/ui.js +70 -8
- package/package.json +1 -1
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* global fetch */
|
|
3
|
+
/**
|
|
4
|
+
* Advanced Market Analyzer
|
|
5
|
+
* Multi-timeframe analysis with timing recommendations
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.analyzeMarket = analyzeMarket;
|
|
9
|
+
const data_fetcher_1 = require("./data-fetcher");
|
|
10
|
+
const indicators_1 = require("./indicators");
|
|
11
|
+
// ============================================
|
|
12
|
+
// ANALYSIS FUNCTIONS
|
|
13
|
+
// ============================================
|
|
14
|
+
/**
|
|
15
|
+
* Analyze a single timeframe
|
|
16
|
+
*/
|
|
17
|
+
function analyzeTimeframe(data) {
|
|
18
|
+
const closePrices = data.candles.map((c) => c.close);
|
|
19
|
+
const ema9 = (0, indicators_1.calculateEMA)(closePrices, 9);
|
|
20
|
+
const ema21 = (0, indicators_1.calculateEMA)(closePrices, 21);
|
|
21
|
+
const ema50 = (0, indicators_1.calculateEMA)(closePrices, 50);
|
|
22
|
+
const ema200 = (0, indicators_1.calculateEMA)(closePrices, 200);
|
|
23
|
+
const rsi = (0, indicators_1.calculateRSI)(closePrices, 14);
|
|
24
|
+
const macd = (0, indicators_1.calculateMACD)(closePrices);
|
|
25
|
+
const bollinger = (0, indicators_1.calculateBollingerBands)(closePrices);
|
|
26
|
+
const trend = (0, indicators_1.analyzeTrend)(data.candles);
|
|
27
|
+
// Determine signal
|
|
28
|
+
let bullishPoints = 0;
|
|
29
|
+
let bearishPoints = 0;
|
|
30
|
+
// EMA alignment
|
|
31
|
+
const currentEMA9 = ema9[ema9.length - 1] || 0;
|
|
32
|
+
const currentEMA21 = ema21[ema21.length - 1] || 0;
|
|
33
|
+
const currentEMA50 = ema50[ema50.length - 1] || 0;
|
|
34
|
+
if (currentEMA9 > currentEMA21 && currentEMA21 > currentEMA50)
|
|
35
|
+
bullishPoints += 2;
|
|
36
|
+
else if (currentEMA9 < currentEMA21 && currentEMA21 < currentEMA50)
|
|
37
|
+
bearishPoints += 2;
|
|
38
|
+
// RSI
|
|
39
|
+
if (rsi.condition === "oversold")
|
|
40
|
+
bullishPoints += 1;
|
|
41
|
+
if (rsi.condition === "overbought")
|
|
42
|
+
bearishPoints += 1;
|
|
43
|
+
if (rsi.divergence === "bullish")
|
|
44
|
+
bullishPoints += 2;
|
|
45
|
+
if (rsi.divergence === "bearish")
|
|
46
|
+
bearishPoints += 2;
|
|
47
|
+
// MACD
|
|
48
|
+
if (macd.crossover === "bullish")
|
|
49
|
+
bullishPoints += 2;
|
|
50
|
+
if (macd.crossover === "bearish")
|
|
51
|
+
bearishPoints += 2;
|
|
52
|
+
if (macd.momentum === "increasing" && macd.current.histogram > 0)
|
|
53
|
+
bullishPoints += 1;
|
|
54
|
+
if (macd.momentum === "decreasing" && macd.current.histogram < 0)
|
|
55
|
+
bearishPoints += 1;
|
|
56
|
+
// Bollinger
|
|
57
|
+
if (bollinger.pricePosition === "below_lower")
|
|
58
|
+
bullishPoints += 1;
|
|
59
|
+
if (bollinger.pricePosition === "above_upper")
|
|
60
|
+
bearishPoints += 1;
|
|
61
|
+
// Trend
|
|
62
|
+
if (trend.direction === "bullish")
|
|
63
|
+
bullishPoints += 2;
|
|
64
|
+
if (trend.direction === "bearish")
|
|
65
|
+
bearishPoints += 2;
|
|
66
|
+
let signal = "neutral";
|
|
67
|
+
if (bullishPoints > bearishPoints + 2)
|
|
68
|
+
signal = "bullish";
|
|
69
|
+
else if (bearishPoints > bullishPoints + 2)
|
|
70
|
+
signal = "bearish";
|
|
71
|
+
return {
|
|
72
|
+
interval: data.interval,
|
|
73
|
+
trend,
|
|
74
|
+
rsi,
|
|
75
|
+
macd,
|
|
76
|
+
bollinger,
|
|
77
|
+
ema: {
|
|
78
|
+
ema9: currentEMA9,
|
|
79
|
+
ema21: currentEMA21,
|
|
80
|
+
ema50: currentEMA50,
|
|
81
|
+
ema200: ema200[ema200.length - 1] || 0,
|
|
82
|
+
},
|
|
83
|
+
signal,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Generate timing recommendation
|
|
88
|
+
*/
|
|
89
|
+
function generateTimingRecommendation(analysis, indicators, currentPrice, recommendation) {
|
|
90
|
+
const { supportResistance, rsi, macd, bollinger } = indicators;
|
|
91
|
+
// Default entry zone
|
|
92
|
+
let entryLow = currentPrice * 0.99;
|
|
93
|
+
let entryHigh = currentPrice * 1.01;
|
|
94
|
+
if (recommendation.includes("BUY")) {
|
|
95
|
+
// For buy signals
|
|
96
|
+
if (rsi.current > 60) {
|
|
97
|
+
// RSI high, wait for pullback
|
|
98
|
+
entryLow = supportResistance.nearestSupport;
|
|
99
|
+
entryHigh = analysis.ema.ema21;
|
|
100
|
+
return {
|
|
101
|
+
action: "wait_for_pullback",
|
|
102
|
+
timing: "Wait for price to pull back to EMA21 or support level",
|
|
103
|
+
entryZone: { low: entryLow, high: entryHigh },
|
|
104
|
+
reason: `RSI at ${rsi.current.toFixed(0)} is elevated. Better entry near $${entryHigh.toFixed(2)}`,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
else if (bollinger.squeeze) {
|
|
108
|
+
// Squeeze, wait for breakout
|
|
109
|
+
entryLow = bollinger.current.upper;
|
|
110
|
+
entryHigh = bollinger.current.upper * 1.01;
|
|
111
|
+
return {
|
|
112
|
+
action: "wait_for_breakout",
|
|
113
|
+
timing: "Wait for breakout above Bollinger upper band",
|
|
114
|
+
entryZone: { low: entryLow, high: entryHigh },
|
|
115
|
+
reason: "Bollinger squeeze detected. Wait for volatility expansion",
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
else if (macd.crossover === "bullish") {
|
|
119
|
+
// Fresh MACD crossover, enter now
|
|
120
|
+
return {
|
|
121
|
+
action: "enter_now",
|
|
122
|
+
timing: "Enter on current candle close",
|
|
123
|
+
entryZone: { low: currentPrice * 0.995, high: currentPrice * 1.005 },
|
|
124
|
+
reason: "Fresh MACD bullish crossover provides good entry",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Wait for confirmation
|
|
129
|
+
return {
|
|
130
|
+
action: "wait_for_confirmation",
|
|
131
|
+
timing: "Wait for next 1-4 hour candle to confirm direction",
|
|
132
|
+
entryZone: { low: analysis.ema.ema9, high: currentPrice },
|
|
133
|
+
reason: "Wait for price to hold above EMA9 for confirmation",
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (recommendation.includes("SELL")) {
|
|
138
|
+
// For sell signals
|
|
139
|
+
if (rsi.current < 40) {
|
|
140
|
+
entryHigh = supportResistance.nearestResistance;
|
|
141
|
+
entryLow = analysis.ema.ema21;
|
|
142
|
+
return {
|
|
143
|
+
action: "wait_for_pullback",
|
|
144
|
+
timing: "Wait for price to bounce to resistance before shorting",
|
|
145
|
+
entryZone: { low: entryLow, high: entryHigh },
|
|
146
|
+
reason: `RSI at ${rsi.current.toFixed(0)} is low. Wait for bounce to short`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
else if (macd.crossover === "bearish") {
|
|
150
|
+
return {
|
|
151
|
+
action: "enter_now",
|
|
152
|
+
timing: "Enter short on current candle close",
|
|
153
|
+
entryZone: { low: currentPrice * 0.995, high: currentPrice * 1.005 },
|
|
154
|
+
reason: "Fresh MACD bearish crossover provides good short entry",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
return {
|
|
159
|
+
action: "wait_for_confirmation",
|
|
160
|
+
timing: "Wait for break below EMA21 to confirm",
|
|
161
|
+
entryZone: { low: analysis.ema.ema21 * 0.99, high: analysis.ema.ema21 },
|
|
162
|
+
reason: "Wait for price to break below EMA21 for confirmation",
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// HOLD
|
|
168
|
+
return {
|
|
169
|
+
action: "avoid",
|
|
170
|
+
timing: "No clear setup - wait for better opportunity",
|
|
171
|
+
entryZone: {
|
|
172
|
+
low: supportResistance.nearestSupport,
|
|
173
|
+
high: supportResistance.nearestResistance,
|
|
174
|
+
},
|
|
175
|
+
reason: "Mixed signals suggest waiting for clearer direction",
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Generate trade setup with stop loss and targets
|
|
181
|
+
*/
|
|
182
|
+
function generateTradeSetup(currentPrice, indicators, recommendation) {
|
|
183
|
+
const { atr, supportResistance } = indicators;
|
|
184
|
+
const atrValue = atr.current;
|
|
185
|
+
const entry = currentPrice;
|
|
186
|
+
let stopLoss;
|
|
187
|
+
let target1;
|
|
188
|
+
let target2;
|
|
189
|
+
let target3;
|
|
190
|
+
if (recommendation.includes("BUY") || recommendation === "HOLD") {
|
|
191
|
+
// Long setup
|
|
192
|
+
stopLoss = Math.max(supportResistance.nearestSupport * 0.99, currentPrice - atrValue * 2);
|
|
193
|
+
target1 = currentPrice + atrValue * 1.5;
|
|
194
|
+
target2 = currentPrice + atrValue * 3;
|
|
195
|
+
target3 = supportResistance.nearestResistance;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
// Short setup
|
|
199
|
+
stopLoss = Math.min(supportResistance.nearestResistance * 1.01, currentPrice + atrValue * 2);
|
|
200
|
+
target1 = currentPrice - atrValue * 1.5;
|
|
201
|
+
target2 = currentPrice - atrValue * 3;
|
|
202
|
+
target3 = supportResistance.nearestSupport;
|
|
203
|
+
}
|
|
204
|
+
const risk = Math.abs(entry - stopLoss);
|
|
205
|
+
const reward = Math.abs(target2 - entry);
|
|
206
|
+
const riskRewardRatio = reward / risk;
|
|
207
|
+
// Position size based on 2% account risk
|
|
208
|
+
const positionSizeRisk = (2 / ((risk / entry) * 100)) * 100;
|
|
209
|
+
return {
|
|
210
|
+
entry,
|
|
211
|
+
stopLoss,
|
|
212
|
+
target1,
|
|
213
|
+
target2,
|
|
214
|
+
target3,
|
|
215
|
+
riskRewardRatio: Math.round(riskRewardRatio * 10) / 10,
|
|
216
|
+
positionSizeRisk: Math.min(positionSizeRisk, 100),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Determine market condition
|
|
221
|
+
*/
|
|
222
|
+
function determineMarketCondition(indicators, timeframe) {
|
|
223
|
+
const { atr, bollinger, volume, trend } = indicators;
|
|
224
|
+
if (bollinger.squeeze && volume.trend === "decreasing") {
|
|
225
|
+
return {
|
|
226
|
+
type: "ranging",
|
|
227
|
+
description: "Market is consolidating in a tight range",
|
|
228
|
+
tradingAdvice: "Wait for breakout or trade range boundaries",
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (atr.volatility === "high" && volume.volumeRatio > 1.5) {
|
|
232
|
+
return {
|
|
233
|
+
type: "volatile",
|
|
234
|
+
description: "High volatility with increased volume",
|
|
235
|
+
tradingAdvice: "Use wider stops, reduce position size",
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
if (trend.phase === "trending" && trend.strength > 70) {
|
|
239
|
+
return {
|
|
240
|
+
type: "trending",
|
|
241
|
+
description: `Strong ${trend.direction} trend in progress`,
|
|
242
|
+
tradingAdvice: trend.direction === "bullish"
|
|
243
|
+
? "Buy dips, trail stops, add on pullbacks"
|
|
244
|
+
: "Sell rallies, trail stops, add on bounces",
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (bollinger.current.bandwidth > 10 && !bollinger.squeeze) {
|
|
248
|
+
return {
|
|
249
|
+
type: "breakout",
|
|
250
|
+
description: "Potential breakout in progress",
|
|
251
|
+
tradingAdvice: "Watch for continuation or false breakout",
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
type: "ranging",
|
|
256
|
+
description: "No clear trend, choppy price action",
|
|
257
|
+
tradingAdvice: "Reduce position size, trade with caution",
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Generate detailed reasoning
|
|
262
|
+
*/
|
|
263
|
+
function generateReasoning(indicators, timeframes, currentPrice) {
|
|
264
|
+
const bullishFactors = [];
|
|
265
|
+
const bearishFactors = [];
|
|
266
|
+
const keyLevels = [];
|
|
267
|
+
const warnings = [];
|
|
268
|
+
const { rsi, macd, bollinger, volume, supportResistance, trend, atr } = indicators;
|
|
269
|
+
// RSI analysis
|
|
270
|
+
if (rsi.condition === "oversold") {
|
|
271
|
+
bullishFactors.push(`RSI oversold at ${rsi.current.toFixed(1)} - potential bounce`);
|
|
272
|
+
}
|
|
273
|
+
else if (rsi.condition === "overbought") {
|
|
274
|
+
bearishFactors.push(`RSI overbought at ${rsi.current.toFixed(1)} - potential pullback`);
|
|
275
|
+
}
|
|
276
|
+
if (rsi.divergence === "bullish") {
|
|
277
|
+
bullishFactors.push("Bullish RSI divergence detected - reversal signal");
|
|
278
|
+
}
|
|
279
|
+
else if (rsi.divergence === "bearish") {
|
|
280
|
+
bearishFactors.push("Bearish RSI divergence detected - reversal signal");
|
|
281
|
+
}
|
|
282
|
+
// MACD analysis
|
|
283
|
+
if (macd.crossover === "bullish") {
|
|
284
|
+
bullishFactors.push("MACD bullish crossover - momentum shifting up");
|
|
285
|
+
}
|
|
286
|
+
else if (macd.crossover === "bearish") {
|
|
287
|
+
bearishFactors.push("MACD bearish crossover - momentum shifting down");
|
|
288
|
+
}
|
|
289
|
+
if (macd.current.histogram > 0 && macd.momentum === "increasing") {
|
|
290
|
+
bullishFactors.push("MACD histogram increasing - strong bullish momentum");
|
|
291
|
+
}
|
|
292
|
+
else if (macd.current.histogram < 0 && macd.momentum === "decreasing") {
|
|
293
|
+
bearishFactors.push("MACD histogram decreasing - strong bearish momentum");
|
|
294
|
+
}
|
|
295
|
+
// Bollinger analysis
|
|
296
|
+
if (bollinger.pricePosition === "below_lower") {
|
|
297
|
+
bullishFactors.push("Price below lower Bollinger Band - oversold");
|
|
298
|
+
}
|
|
299
|
+
else if (bollinger.pricePosition === "above_upper") {
|
|
300
|
+
bearishFactors.push("Price above upper Bollinger Band - overbought");
|
|
301
|
+
}
|
|
302
|
+
if (bollinger.squeeze) {
|
|
303
|
+
warnings.push("Bollinger squeeze - expect volatility expansion soon");
|
|
304
|
+
}
|
|
305
|
+
// Volume analysis
|
|
306
|
+
if (volume.volumeRatio > 1.5 && volume.confirmation) {
|
|
307
|
+
bullishFactors.push("High volume confirming price movement");
|
|
308
|
+
}
|
|
309
|
+
else if (volume.volumeRatio < 0.5) {
|
|
310
|
+
warnings.push("Low volume - move may lack conviction");
|
|
311
|
+
}
|
|
312
|
+
// Trend analysis
|
|
313
|
+
if (trend.direction === "bullish" && trend.strength > 60) {
|
|
314
|
+
bullishFactors.push(`Strong uptrend (${trend.strength}% strength)`);
|
|
315
|
+
}
|
|
316
|
+
else if (trend.direction === "bearish" && trend.strength > 60) {
|
|
317
|
+
bearishFactors.push(`Strong downtrend (${trend.strength}% strength)`);
|
|
318
|
+
}
|
|
319
|
+
if (trend.phase === "reversing") {
|
|
320
|
+
warnings.push("Trend may be reversing - watch for confirmation");
|
|
321
|
+
}
|
|
322
|
+
// Multi-timeframe
|
|
323
|
+
const { short, medium, long } = timeframes;
|
|
324
|
+
if (short.signal === medium.signal && medium.signal === long.signal) {
|
|
325
|
+
if (short.signal === "bullish") {
|
|
326
|
+
bullishFactors.push("All timeframes aligned bullish - high probability setup");
|
|
327
|
+
}
|
|
328
|
+
else if (short.signal === "bearish") {
|
|
329
|
+
bearishFactors.push("All timeframes aligned bearish - high probability setup");
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
warnings.push("Timeframes not aligned - reduced probability");
|
|
334
|
+
}
|
|
335
|
+
// Key levels
|
|
336
|
+
keyLevels.push(`Support: $${supportResistance.nearestSupport.toFixed(2)} (${supportResistance.distanceToSupport.toFixed(1)}% away)`);
|
|
337
|
+
keyLevels.push(`Resistance: $${supportResistance.nearestResistance.toFixed(2)} (${supportResistance.distanceToResistance.toFixed(1)}% away)`);
|
|
338
|
+
keyLevels.push(`EMA21: $${timeframes.medium.ema.ema21.toFixed(2)}`);
|
|
339
|
+
keyLevels.push(`EMA50: $${timeframes.medium.ema.ema50.toFixed(2)}`);
|
|
340
|
+
// Volatility warning
|
|
341
|
+
if (atr.volatility === "high") {
|
|
342
|
+
warnings.push(`High volatility (ATR: ${atr.percentOfPrice.toFixed(1)}%) - use wider stops`);
|
|
343
|
+
}
|
|
344
|
+
// Generate summary
|
|
345
|
+
let summary;
|
|
346
|
+
if (bullishFactors.length > bearishFactors.length + 2) {
|
|
347
|
+
summary = `Strong bullish setup with ${bullishFactors.length} positive factors. `;
|
|
348
|
+
summary += bullishFactors[0] + ". ";
|
|
349
|
+
if (warnings.length > 0)
|
|
350
|
+
summary += `Caution: ${warnings[0]}`;
|
|
351
|
+
}
|
|
352
|
+
else if (bearishFactors.length > bullishFactors.length + 2) {
|
|
353
|
+
summary = `Strong bearish setup with ${bearishFactors.length} negative factors. `;
|
|
354
|
+
summary += bearishFactors[0] + ". ";
|
|
355
|
+
if (warnings.length > 0)
|
|
356
|
+
summary += `Caution: ${warnings[0]}`;
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
summary = "Mixed signals present. ";
|
|
360
|
+
if (bullishFactors.length > 0)
|
|
361
|
+
summary += bullishFactors[0] + ", but ";
|
|
362
|
+
if (bearishFactors.length > 0)
|
|
363
|
+
summary += bearishFactors[0] + ". ";
|
|
364
|
+
summary += "Wait for clearer setup.";
|
|
365
|
+
}
|
|
366
|
+
return { summary, bullishFactors, bearishFactors, keyLevels, warnings };
|
|
367
|
+
}
|
|
368
|
+
// ============================================
|
|
369
|
+
// MAIN ANALYSIS FUNCTION
|
|
370
|
+
// ============================================
|
|
371
|
+
/**
|
|
372
|
+
* Perform comprehensive market analysis
|
|
373
|
+
*/
|
|
374
|
+
async function analyzeMarket(symbol) {
|
|
375
|
+
// Fetch data for multiple timeframes in parallel
|
|
376
|
+
const [data1h, data4h, data1d] = await Promise.all([
|
|
377
|
+
(0, data_fetcher_1.fetchCryptoData)(symbol, "1h", 200),
|
|
378
|
+
(0, data_fetcher_1.fetchCryptoData)(symbol, "4h", 200),
|
|
379
|
+
(0, data_fetcher_1.fetchCryptoData)(symbol, "1d", 200),
|
|
380
|
+
]);
|
|
381
|
+
// Analyze each timeframe
|
|
382
|
+
const shortTF = analyzeTimeframe(data1h);
|
|
383
|
+
const mediumTF = analyzeTimeframe(data4h);
|
|
384
|
+
const longTF = analyzeTimeframe(data1d);
|
|
385
|
+
// Calculate all indicators on 4h (primary timeframe)
|
|
386
|
+
const closePrices = data4h.candles.map((c) => c.close);
|
|
387
|
+
const indicators = {
|
|
388
|
+
rsi: (0, indicators_1.calculateRSI)(closePrices),
|
|
389
|
+
macd: (0, indicators_1.calculateMACD)(closePrices),
|
|
390
|
+
bollinger: (0, indicators_1.calculateBollingerBands)(closePrices),
|
|
391
|
+
atr: (0, indicators_1.calculateATR)(data4h.candles),
|
|
392
|
+
volume: (0, indicators_1.analyzeVolume)(data4h.candles),
|
|
393
|
+
supportResistance: (0, indicators_1.calculateSupportResistance)(data4h.candles),
|
|
394
|
+
trend: (0, indicators_1.analyzeTrend)(data4h.candles),
|
|
395
|
+
};
|
|
396
|
+
// Determine timeframe alignment
|
|
397
|
+
let timeframeAlignment = "mixed";
|
|
398
|
+
if (shortTF.signal === "bullish" &&
|
|
399
|
+
mediumTF.signal === "bullish" &&
|
|
400
|
+
longTF.signal === "bullish") {
|
|
401
|
+
timeframeAlignment = "aligned_bullish";
|
|
402
|
+
}
|
|
403
|
+
else if (shortTF.signal === "bearish" &&
|
|
404
|
+
mediumTF.signal === "bearish" &&
|
|
405
|
+
longTF.signal === "bearish") {
|
|
406
|
+
timeframeAlignment = "aligned_bearish";
|
|
407
|
+
}
|
|
408
|
+
// Calculate recommendation score
|
|
409
|
+
let score = 0;
|
|
410
|
+
// RSI contribution (-2 to +2)
|
|
411
|
+
if (indicators.rsi.condition === "oversold")
|
|
412
|
+
score += 2;
|
|
413
|
+
else if (indicators.rsi.condition === "overbought")
|
|
414
|
+
score -= 2;
|
|
415
|
+
if (indicators.rsi.divergence === "bullish")
|
|
416
|
+
score += 2;
|
|
417
|
+
else if (indicators.rsi.divergence === "bearish")
|
|
418
|
+
score -= 2;
|
|
419
|
+
// MACD contribution (-2 to +2)
|
|
420
|
+
if (indicators.macd.crossover === "bullish")
|
|
421
|
+
score += 2;
|
|
422
|
+
else if (indicators.macd.crossover === "bearish")
|
|
423
|
+
score -= 2;
|
|
424
|
+
if (indicators.macd.current.histogram > 0)
|
|
425
|
+
score += 1;
|
|
426
|
+
else
|
|
427
|
+
score -= 1;
|
|
428
|
+
// Bollinger contribution (-1 to +1)
|
|
429
|
+
if (indicators.bollinger.pricePosition === "below_lower")
|
|
430
|
+
score += 1;
|
|
431
|
+
else if (indicators.bollinger.pricePosition === "above_upper")
|
|
432
|
+
score -= 1;
|
|
433
|
+
// Trend contribution (-3 to +3)
|
|
434
|
+
if (indicators.trend.direction === "bullish")
|
|
435
|
+
score += Math.ceil(indicators.trend.strength / 33);
|
|
436
|
+
else if (indicators.trend.direction === "bearish")
|
|
437
|
+
score -= Math.ceil(indicators.trend.strength / 33);
|
|
438
|
+
// Timeframe alignment contribution (-3 to +3)
|
|
439
|
+
if (timeframeAlignment === "aligned_bullish")
|
|
440
|
+
score += 3;
|
|
441
|
+
else if (timeframeAlignment === "aligned_bearish")
|
|
442
|
+
score -= 3;
|
|
443
|
+
// Volume confirmation
|
|
444
|
+
if (indicators.volume.confirmation)
|
|
445
|
+
score += score > 0 ? 1 : -1;
|
|
446
|
+
// Determine recommendation
|
|
447
|
+
let recommendation;
|
|
448
|
+
if (score >= 8)
|
|
449
|
+
recommendation = "STRONG_BUY";
|
|
450
|
+
else if (score >= 4)
|
|
451
|
+
recommendation = "BUY";
|
|
452
|
+
else if (score >= 1)
|
|
453
|
+
recommendation = "WAIT_TO_BUY";
|
|
454
|
+
else if (score >= -1)
|
|
455
|
+
recommendation = "HOLD";
|
|
456
|
+
else if (score >= -4)
|
|
457
|
+
recommendation = "WAIT_TO_SELL";
|
|
458
|
+
else if (score >= -8)
|
|
459
|
+
recommendation = "SELL";
|
|
460
|
+
else
|
|
461
|
+
recommendation = "STRONG_SELL";
|
|
462
|
+
// Calculate confidence
|
|
463
|
+
const maxScore = 15;
|
|
464
|
+
const confidence = Math.min(Math.round((Math.abs(score) / maxScore) * 100), 95);
|
|
465
|
+
// Determine risk level
|
|
466
|
+
let riskLevel = "medium";
|
|
467
|
+
if (indicators.atr.volatility === "high" || !indicators.volume.confirmation) {
|
|
468
|
+
riskLevel = "high";
|
|
469
|
+
}
|
|
470
|
+
else if (timeframeAlignment !== "mixed" && indicators.trend.strength > 70) {
|
|
471
|
+
riskLevel = "low";
|
|
472
|
+
}
|
|
473
|
+
const timeframes = { short: shortTF, medium: mediumTF, long: longTF };
|
|
474
|
+
// Generate timing recommendation
|
|
475
|
+
const timing = generateTimingRecommendation(mediumTF, indicators, data4h.currentPrice, recommendation);
|
|
476
|
+
// Generate trade setup
|
|
477
|
+
const tradeSetup = generateTradeSetup(data4h.currentPrice, indicators, recommendation);
|
|
478
|
+
// Determine market condition
|
|
479
|
+
const marketCondition = determineMarketCondition(indicators, mediumTF);
|
|
480
|
+
// Generate reasoning
|
|
481
|
+
const reasoning = generateReasoning(indicators, timeframes, data4h.currentPrice);
|
|
482
|
+
return {
|
|
483
|
+
symbol: data4h.symbol,
|
|
484
|
+
currentPrice: data4h.currentPrice,
|
|
485
|
+
priceChange24h: data4h.priceChangePercent24h,
|
|
486
|
+
recommendation,
|
|
487
|
+
confidence,
|
|
488
|
+
riskLevel,
|
|
489
|
+
timeframes,
|
|
490
|
+
timeframeAlignment,
|
|
491
|
+
indicators,
|
|
492
|
+
timing,
|
|
493
|
+
tradeSetup,
|
|
494
|
+
marketCondition,
|
|
495
|
+
reasoning,
|
|
496
|
+
};
|
|
497
|
+
}
|