640 lines
24 KiB
Markdown
640 lines
24 KiB
Markdown
---
|
|
description: Analyze price trends with technical indicators, pattern recognition, and market structure analysis
|
|
shortcut: at
|
|
---
|
|
|
|
# Analyze Market Trends
|
|
|
|
Advanced trend analysis system using technical indicators, chart patterns, and market structure to identify trading opportunities.
|
|
|
|
## Usage
|
|
|
|
When the user wants to analyze market trends, implement comprehensive technical analysis with these components:
|
|
|
|
### Required Parameters
|
|
- **Symbol**: Asset to analyze
|
|
- **Timeframe**: 1m, 5m, 15m, 1h, 4h, 1d, 1w
|
|
- **Period**: How far back to analyze (e.g., "30 days", "6 months")
|
|
- **Analysis Type**: technical, fundamental, sentiment, or combined
|
|
- **Output Format**: report, signals, dashboard
|
|
|
|
## Implementation
|
|
|
|
### 1. Technical Analysis Engine
|
|
|
|
```javascript
|
|
class TrendAnalyzer {
|
|
constructor() {
|
|
this.indicators = new TechnicalIndicators();
|
|
this.patterns = new PatternRecognition();
|
|
this.marketStructure = new MarketStructureAnalysis();
|
|
this.signals = new SignalGenerator();
|
|
}
|
|
|
|
async analyzeTrends(params) {
|
|
const {
|
|
symbol,
|
|
timeframe = '1h',
|
|
period = '30d',
|
|
analysisType = 'technical',
|
|
includeVolume = true
|
|
} = params;
|
|
|
|
// Fetch historical data
|
|
const historicalData = await this.fetchHistoricalData(symbol, timeframe, period);
|
|
|
|
// Perform analysis based on type
|
|
const analysis = {
|
|
timestamp: Date.now(),
|
|
symbol,
|
|
timeframe,
|
|
period,
|
|
dataPoints: historicalData.length,
|
|
trend: await this.identifyTrend(historicalData),
|
|
momentum: await this.analyzeMomentum(historicalData),
|
|
volatility: await this.analyzeVolatility(historicalData),
|
|
patterns: await this.detectPatterns(historicalData),
|
|
indicators: await this.calculateIndicators(historicalData),
|
|
structure: await this.analyzeStructure(historicalData),
|
|
signals: await this.generateSignals(historicalData),
|
|
forecast: await this.generateForecast(historicalData)
|
|
};
|
|
|
|
// Add volume analysis if requested
|
|
if (includeVolume) {
|
|
analysis.volume = await this.analyzeVolume(historicalData);
|
|
}
|
|
|
|
// Generate trading recommendations
|
|
analysis.recommendations = this.generateRecommendations(analysis);
|
|
|
|
return analysis;
|
|
}
|
|
|
|
async identifyTrend(data) {
|
|
const prices = data.map(d => d.close);
|
|
const highs = data.map(d => d.high);
|
|
const lows = data.map(d => d.low);
|
|
|
|
// Calculate trend using multiple methods
|
|
const methods = {
|
|
movingAverage: this.trendByMovingAverage(prices),
|
|
higherHighsLows: this.trendByHigherHighsLows(highs, lows),
|
|
linearRegression: this.trendByLinearRegression(prices),
|
|
adx: this.trendByADX(data)
|
|
};
|
|
|
|
// Determine overall trend
|
|
const trendVotes = Object.values(methods);
|
|
const bullishCount = trendVotes.filter(v => v === 'BULLISH').length;
|
|
const bearishCount = trendVotes.filter(v => v === 'BEARISH').length;
|
|
|
|
let overallTrend;
|
|
if (bullishCount > bearishCount + 1) {
|
|
overallTrend = 'STRONG_BULLISH';
|
|
} else if (bullishCount > bearishCount) {
|
|
overallTrend = 'BULLISH';
|
|
} else if (bearishCount > bullishCount + 1) {
|
|
overallTrend = 'STRONG_BEARISH';
|
|
} else if (bearishCount > bullishCount) {
|
|
overallTrend = 'BEARISH';
|
|
} else {
|
|
overallTrend = 'NEUTRAL';
|
|
}
|
|
|
|
return {
|
|
overall: overallTrend,
|
|
strength: this.calculateTrendStrength(data),
|
|
duration: this.calculateTrendDuration(data),
|
|
methods,
|
|
confidence: (Math.max(bullishCount, bearishCount) / trendVotes.length) * 100
|
|
};
|
|
}
|
|
|
|
trendByMovingAverage(prices) {
|
|
const ma20 = this.calculateSMA(prices, 20);
|
|
const ma50 = this.calculateSMA(prices, 50);
|
|
const ma200 = this.calculateSMA(prices, 200);
|
|
|
|
const currentPrice = prices[prices.length - 1];
|
|
|
|
if (currentPrice > ma20 && ma20 > ma50 && ma50 > ma200) {
|
|
return 'BULLISH';
|
|
} else if (currentPrice < ma20 && ma20 < ma50 && ma50 < ma200) {
|
|
return 'BEARISH';
|
|
} else {
|
|
return 'NEUTRAL';
|
|
}
|
|
}
|
|
|
|
trendByHigherHighsLows(highs, lows) {
|
|
const recentHighs = highs.slice(-10);
|
|
const recentLows = lows.slice(-10);
|
|
|
|
let higherHighs = 0;
|
|
let lowerLows = 0;
|
|
let higherLows = 0;
|
|
let lowerHighs = 0;
|
|
|
|
for (let i = 1; i < recentHighs.length; i++) {
|
|
if (recentHighs[i] > recentHighs[i-1]) higherHighs++;
|
|
if (recentHighs[i] < recentHighs[i-1]) lowerHighs++;
|
|
if (recentLows[i] > recentLows[i-1]) higherLows++;
|
|
if (recentLows[i] < recentLows[i-1]) lowerLows++;
|
|
}
|
|
|
|
if (higherHighs > lowerHighs && higherLows > lowerLows) {
|
|
return 'BULLISH';
|
|
} else if (lowerHighs > higherHighs && lowerLows > higherLows) {
|
|
return 'BEARISH';
|
|
} else {
|
|
return 'NEUTRAL';
|
|
}
|
|
}
|
|
|
|
calculateTrendStrength(data) {
|
|
const adx = this.calculateADX(data, 14);
|
|
const currentADX = adx[adx.length - 1];
|
|
|
|
if (currentADX > 50) return 'VERY_STRONG';
|
|
if (currentADX > 40) return 'STRONG';
|
|
if (currentADX > 25) return 'MODERATE';
|
|
if (currentADX > 20) return 'WEAK';
|
|
return 'VERY_WEAK';
|
|
}
|
|
|
|
async analyzeMomentum(data) {
|
|
const prices = data.map(d => d.close);
|
|
|
|
return {
|
|
rsi: this.calculateRSI(prices, 14),
|
|
stochastic: this.calculateStochastic(data, 14, 3, 3),
|
|
macd: this.calculateMACD(prices),
|
|
momentum: this.calculateMomentum(prices, 10),
|
|
roc: this.calculateROC(prices, 12),
|
|
williamsPR: this.calculateWilliamsPR(data, 14),
|
|
cci: this.calculateCCI(data, 20),
|
|
mfi: this.calculateMFI(data, 14),
|
|
interpretation: this.interpretMomentum(prices)
|
|
};
|
|
}
|
|
|
|
calculateRSI(prices, period = 14) {
|
|
if (prices.length < period + 1) return null;
|
|
|
|
const gains = [];
|
|
const losses = [];
|
|
|
|
for (let i = 1; i < prices.length; i++) {
|
|
const change = prices[i] - prices[i - 1];
|
|
gains.push(change > 0 ? change : 0);
|
|
losses.push(change < 0 ? Math.abs(change) : 0);
|
|
}
|
|
|
|
const avgGain = gains.slice(-period).reduce((a, b) => a + b) / period;
|
|
const avgLoss = losses.slice(-period).reduce((a, b) => a + b) / period;
|
|
|
|
if (avgLoss === 0) return 100;
|
|
|
|
const rs = avgGain / avgLoss;
|
|
const rsi = 100 - (100 / (1 + rs));
|
|
|
|
return {
|
|
value: rsi,
|
|
signal: rsi > 70 ? 'OVERBOUGHT' : rsi < 30 ? 'OVERSOLD' : 'NEUTRAL',
|
|
divergence: this.checkDivergence(prices, rsi)
|
|
};
|
|
}
|
|
|
|
calculateMACD(prices) {
|
|
const ema12 = this.calculateEMA(prices, 12);
|
|
const ema26 = this.calculateEMA(prices, 26);
|
|
const macdLine = [];
|
|
|
|
for (let i = 0; i < Math.min(ema12.length, ema26.length); i++) {
|
|
macdLine.push(ema12[i] - ema26[i]);
|
|
}
|
|
|
|
const signal = this.calculateEMA(macdLine, 9);
|
|
const histogram = [];
|
|
|
|
for (let i = 0; i < Math.min(macdLine.length, signal.length); i++) {
|
|
histogram.push(macdLine[i] - signal[i]);
|
|
}
|
|
|
|
return {
|
|
macd: macdLine[macdLine.length - 1],
|
|
signal: signal[signal.length - 1],
|
|
histogram: histogram[histogram.length - 1],
|
|
crossover: this.detectCrossover(macdLine, signal),
|
|
trend: histogram[histogram.length - 1] > 0 ? 'BULLISH' : 'BEARISH'
|
|
};
|
|
}
|
|
|
|
async detectPatterns(data) {
|
|
const patterns = [];
|
|
const prices = data.map(d => ({ open: d.open, high: d.high, low: d.low, close: d.close }));
|
|
|
|
// Chart Patterns
|
|
const chartPatterns = {
|
|
headAndShoulders: this.detectHeadAndShoulders(prices),
|
|
doubleTop: this.detectDoubleTop(prices),
|
|
doubleBottom: this.detectDoubleBottom(prices),
|
|
triangle: this.detectTriangle(prices),
|
|
wedge: this.detectWedge(prices),
|
|
flag: this.detectFlag(prices),
|
|
pennant: this.detectPennant(prices),
|
|
cup: this.detectCupAndHandle(prices)
|
|
};
|
|
|
|
// Candlestick Patterns
|
|
const candlePatterns = {
|
|
hammer: this.detectHammer(prices),
|
|
doji: this.detectDoji(prices),
|
|
engulfing: this.detectEngulfing(prices),
|
|
morningStar: this.detectMorningStar(prices),
|
|
eveningStar: this.detectEveningStar(prices),
|
|
shootingStar: this.detectShootingStar(prices),
|
|
harami: this.detectHarami(prices),
|
|
threeWhiteSoldiers: this.detectThreeWhiteSoldiers(prices)
|
|
};
|
|
|
|
// Combine and score patterns
|
|
for (const [name, result] of Object.entries(chartPatterns)) {
|
|
if (result.detected) {
|
|
patterns.push({
|
|
type: 'CHART',
|
|
name: name.toUpperCase(),
|
|
confidence: result.confidence,
|
|
direction: result.direction,
|
|
target: result.target,
|
|
stopLoss: result.stopLoss
|
|
});
|
|
}
|
|
}
|
|
|
|
for (const [name, result] of Object.entries(candlePatterns)) {
|
|
if (result.detected) {
|
|
patterns.push({
|
|
type: 'CANDLE',
|
|
name: name.toUpperCase(),
|
|
confidence: result.confidence,
|
|
signal: result.signal,
|
|
position: result.position
|
|
});
|
|
}
|
|
}
|
|
|
|
return patterns;
|
|
}
|
|
|
|
detectHeadAndShoulders(prices) {
|
|
const highs = prices.map(p => p.high);
|
|
const result = { detected: false, confidence: 0, direction: null };
|
|
|
|
if (highs.length < 50) return result;
|
|
|
|
// Look for pattern in recent data
|
|
const recent = highs.slice(-50);
|
|
const peaks = this.findPeaks(recent);
|
|
|
|
if (peaks.length >= 3) {
|
|
const [leftShoulder, head, rightShoulder] = peaks.slice(-3);
|
|
|
|
// Check if middle peak is highest (head)
|
|
if (head.value > leftShoulder.value &&
|
|
head.value > rightShoulder.value &&
|
|
Math.abs(leftShoulder.value - rightShoulder.value) / leftShoulder.value < 0.03) {
|
|
|
|
result.detected = true;
|
|
result.confidence = 85;
|
|
result.direction = 'BEARISH';
|
|
result.neckline = Math.min(
|
|
...recent.slice(leftShoulder.index, rightShoulder.index + 1)
|
|
);
|
|
result.target = result.neckline - (head.value - result.neckline);
|
|
result.stopLoss = head.value * 1.01;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
async analyzeVolume(data) {
|
|
const volumes = data.map(d => d.volume);
|
|
const prices = data.map(d => d.close);
|
|
|
|
return {
|
|
average: volumes.reduce((a, b) => a + b) / volumes.length,
|
|
trend: this.analyzeVolumeTrend(volumes),
|
|
obv: this.calculateOBV(prices, volumes),
|
|
adl: this.calculateADL(data),
|
|
mfi: this.calculateMFI(data, 14),
|
|
vwap: this.calculateVWAP(data),
|
|
volumeProfile: this.calculateVolumeProfile(data),
|
|
accumulation: this.detectAccumulationDistribution(data),
|
|
spikes: this.detectVolumeSpikes(volumes)
|
|
};
|
|
}
|
|
|
|
calculateOBV(prices, volumes) {
|
|
const obv = [volumes[0]];
|
|
|
|
for (let i = 1; i < prices.length; i++) {
|
|
if (prices[i] > prices[i - 1]) {
|
|
obv.push(obv[i - 1] + volumes[i]);
|
|
} else if (prices[i] < prices[i - 1]) {
|
|
obv.push(obv[i - 1] - volumes[i]);
|
|
} else {
|
|
obv.push(obv[i - 1]);
|
|
}
|
|
}
|
|
|
|
return {
|
|
values: obv,
|
|
current: obv[obv.length - 1],
|
|
trend: this.calculateTrend(obv.slice(-20)),
|
|
divergence: this.checkVolumePriceDivergence(prices, obv)
|
|
};
|
|
}
|
|
|
|
async generateSignals(data) {
|
|
const signals = [];
|
|
const analysis = {
|
|
trend: await this.identifyTrend(data),
|
|
momentum: await this.analyzeMomentum(data),
|
|
patterns: await this.detectPatterns(data)
|
|
};
|
|
|
|
// Trend-based signals
|
|
if (analysis.trend.overall === 'STRONG_BULLISH') {
|
|
signals.push({
|
|
type: 'BUY',
|
|
strength: 'STRONG',
|
|
reason: 'Strong bullish trend confirmed',
|
|
confidence: analysis.trend.confidence
|
|
});
|
|
}
|
|
|
|
// Momentum signals
|
|
if (analysis.momentum.rsi.value < 30) {
|
|
signals.push({
|
|
type: 'BUY',
|
|
strength: 'MEDIUM',
|
|
reason: 'RSI oversold condition',
|
|
confidence: 70
|
|
});
|
|
}
|
|
|
|
// Pattern signals
|
|
for (const pattern of analysis.patterns) {
|
|
if (pattern.type === 'CHART' && pattern.confidence > 80) {
|
|
signals.push({
|
|
type: pattern.direction === 'BULLISH' ? 'BUY' : 'SELL',
|
|
strength: 'STRONG',
|
|
reason: `${pattern.name} pattern detected`,
|
|
confidence: pattern.confidence,
|
|
target: pattern.target,
|
|
stopLoss: pattern.stopLoss
|
|
});
|
|
}
|
|
}
|
|
|
|
// MACD crossover signals
|
|
if (analysis.momentum.macd.crossover === 'BULLISH') {
|
|
signals.push({
|
|
type: 'BUY',
|
|
strength: 'MEDIUM',
|
|
reason: 'MACD bullish crossover',
|
|
confidence: 65
|
|
});
|
|
}
|
|
|
|
return this.prioritizeSignals(signals);
|
|
}
|
|
|
|
prioritizeSignals(signals) {
|
|
// Sort by confidence and strength
|
|
return signals.sort((a, b) => {
|
|
const strengthScore = { STRONG: 3, MEDIUM: 2, WEAK: 1 };
|
|
const scoreA = a.confidence * strengthScore[a.strength];
|
|
const scoreB = b.confidence * strengthScore[b.strength];
|
|
return scoreB - scoreA;
|
|
}).slice(0, 5); // Top 5 signals
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. Market Structure Analysis
|
|
|
|
```javascript
|
|
class MarketStructureAnalysis {
|
|
analyzeStructure(data) {
|
|
return {
|
|
marketPhase: this.identifyMarketPhase(data),
|
|
keyLevels: this.identifyKeyLevels(data),
|
|
liquidityZones: this.findLiquidityZones(data),
|
|
orderFlow: this.analyzeOrderFlow(data),
|
|
marketProfile: this.createMarketProfile(data),
|
|
supplyDemand: this.identifySupplyDemandZones(data)
|
|
};
|
|
}
|
|
|
|
identifyMarketPhase(data) {
|
|
const volatility = this.calculateVolatility(data);
|
|
const trend = this.calculateTrendStrength(data);
|
|
const volume = this.analyzeVolumeCharacteristics(data);
|
|
|
|
if (volatility < 0.01 && trend < 25) {
|
|
return {
|
|
phase: 'ACCUMULATION',
|
|
characteristics: 'Low volatility, sideways movement, smart money accumulating',
|
|
tradingStrategy: 'Buy at support, sell at resistance'
|
|
};
|
|
} else if (trend > 40 && volume.trend === 'INCREASING') {
|
|
return {
|
|
phase: 'MARK_UP',
|
|
characteristics: 'Strong trend, increasing volume, institutional buying',
|
|
tradingStrategy: 'Trend following, buy dips'
|
|
};
|
|
} else if (volatility > 0.03 && trend < 25) {
|
|
return {
|
|
phase: 'DISTRIBUTION',
|
|
characteristics: 'High volatility, topping pattern, smart money distributing',
|
|
tradingStrategy: 'Take profits, short at resistance'
|
|
};
|
|
} else if (trend > 40 && volume.trend === 'DECREASING') {
|
|
return {
|
|
phase: 'MARK_DOWN',
|
|
characteristics: 'Downtrend, panic selling, capitulation',
|
|
tradingStrategy: 'Stay out or short rallies'
|
|
};
|
|
} else {
|
|
return {
|
|
phase: 'TRANSITION',
|
|
characteristics: 'Changing market dynamics',
|
|
tradingStrategy: 'Wait for confirmation'
|
|
};
|
|
}
|
|
}
|
|
|
|
identifyKeyLevels(data) {
|
|
const levels = [];
|
|
const highs = data.map(d => d.high);
|
|
const lows = data.map(d => d.low);
|
|
const closes = data.map(d => d.close);
|
|
|
|
// Psychological levels (round numbers)
|
|
const currentPrice = closes[closes.length - 1];
|
|
const roundLevels = this.findRoundNumbers(currentPrice);
|
|
|
|
// Historical support/resistance
|
|
const historicalLevels = this.findHistoricalLevels(highs, lows, closes);
|
|
|
|
// Volume-based levels
|
|
const volumeLevels = this.findVolumeLevels(data);
|
|
|
|
// Fibonacci levels
|
|
const fibLevels = this.calculateFibonacciLevels(
|
|
Math.min(...lows),
|
|
Math.max(...highs)
|
|
);
|
|
|
|
return {
|
|
psychological: roundLevels,
|
|
historical: historicalLevels,
|
|
volume: volumeLevels,
|
|
fibonacci: fibLevels,
|
|
combined: this.combineAndRankLevels([
|
|
...roundLevels,
|
|
...historicalLevels,
|
|
...volumeLevels,
|
|
...fibLevels
|
|
])
|
|
};
|
|
}
|
|
|
|
findLiquidityZones(data) {
|
|
const zones = [];
|
|
const volumes = data.map(d => d.volume);
|
|
const avgVolume = volumes.reduce((a, b) => a + b) / volumes.length;
|
|
|
|
for (let i = 0; i < data.length - 10; i++) {
|
|
const window = data.slice(i, i + 10);
|
|
const windowVolume = window.reduce((sum, d) => sum + d.volume, 0);
|
|
|
|
if (windowVolume > avgVolume * 10 * 1.5) {
|
|
const highPrice = Math.max(...window.map(d => d.high));
|
|
const lowPrice = Math.min(...window.map(d => d.low));
|
|
|
|
zones.push({
|
|
type: 'HIGH_LIQUIDITY',
|
|
upperBound: highPrice,
|
|
lowerBound: lowPrice,
|
|
volume: windowVolume,
|
|
strength: windowVolume / (avgVolume * 10)
|
|
});
|
|
}
|
|
}
|
|
|
|
return zones;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Display and Reporting
|
|
|
|
```javascript
|
|
class TrendReport {
|
|
generateReport(analysis) {
|
|
return `
|
|
╔════════════════════════════════════════════════════════════════╗
|
|
║ TREND ANALYSIS REPORT ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
║ Symbol: ${analysis.symbol.padEnd(48)} ║
|
|
║ Timeframe: ${analysis.timeframe.padEnd(48)} ║
|
|
║ Period: ${analysis.period.padEnd(48)} ║
|
|
║ Data Points: ${analysis.dataPoints.toString().padEnd(48)} ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
║ TREND ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
║ Direction: ${this.formatTrend(analysis.trend.overall).padEnd(48)} ║
|
|
║ Strength: ${analysis.trend.strength.padEnd(48)} ║
|
|
║ Duration: ${analysis.trend.duration.padEnd(48)} ║
|
|
║ Confidence: ${this.formatPercentage(analysis.trend.confidence).padEnd(48)} ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
║ MOMENTUM ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
║ RSI (14): ${this.formatRSI(analysis.momentum.rsi).padEnd(48)} ║
|
|
║ MACD: ${this.formatMACD(analysis.momentum.macd).padEnd(48)} ║
|
|
║ Stochastic: ${this.formatStochastic(analysis.momentum.stochastic).padEnd(48)} ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
║ PATTERNS ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
${this.formatPatterns(analysis.patterns)}
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
║ TOP SIGNALS ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
${this.formatSignals(analysis.signals)}
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
║ RECOMMENDATIONS ║
|
|
╠════════════════════════════════════════════════════════════════╣
|
|
${this.formatRecommendations(analysis.recommendations)}
|
|
╚════════════════════════════════════════════════════════════════╝
|
|
`;
|
|
}
|
|
|
|
formatTrend(trend) {
|
|
const icons = {
|
|
STRONG_BULLISH: ' Strong Bullish',
|
|
BULLISH: ' Bullish',
|
|
NEUTRAL: ' Neutral',
|
|
BEARISH: ' Bearish',
|
|
STRONG_BEARISH: ' Strong Bearish'
|
|
};
|
|
return icons[trend] || trend;
|
|
}
|
|
|
|
formatPatterns(patterns) {
|
|
if (patterns.length === 0) {
|
|
return '║ No significant patterns detected ║';
|
|
}
|
|
|
|
return patterns.slice(0, 3).map(p =>
|
|
`║ ${p.name.padEnd(20)} Confidence: ${p.confidence}% ${p.direction.padEnd(20)} ║`
|
|
).join('\n');
|
|
}
|
|
|
|
formatSignals(signals) {
|
|
if (signals.length === 0) {
|
|
return '║ No strong signals at this time ║';
|
|
}
|
|
|
|
return signals.slice(0, 3).map(s =>
|
|
`║ ${s.type} - ${s.reason.padEnd(35)} [${s.confidence}%] ║`
|
|
).join('\n');
|
|
}
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
```javascript
|
|
try {
|
|
const analyzer = new TrendAnalyzer();
|
|
const analysis = await analyzer.analyzeTrends({
|
|
symbol: 'BTC/USDT',
|
|
timeframe: '4h',
|
|
period: '30d',
|
|
analysisType: 'technical'
|
|
});
|
|
|
|
const report = new TrendReport();
|
|
console.log(report.generateReport(analysis));
|
|
|
|
} catch (error) {
|
|
console.error('Trend analysis failed:', error);
|
|
}
|
|
```
|
|
|
|
This command provides comprehensive trend analysis with technical indicators, pattern recognition, and actionable trading signals. |