|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const ADVANCED_STRATEGIES_V2 = {
|
|
|
'ict-market-structure': {
|
|
|
name: 'ICT Market Structure',
|
|
|
description: 'Inner Circle Trader methodology with order blocks and liquidity zones',
|
|
|
indicators: ['Order Blocks', 'FVG', 'Liquidity Pools', 'Market Structure'],
|
|
|
timeframes: ['15m', '1h', '4h'],
|
|
|
riskLevel: 'high',
|
|
|
profitTarget: 'high',
|
|
|
scientific: true,
|
|
|
winRate: '75-85%',
|
|
|
avgRR: '1:5'
|
|
|
},
|
|
|
'wyckoff-accumulation': {
|
|
|
name: 'Wyckoff Accumulation/Distribution',
|
|
|
description: 'Smart money accumulation and distribution phases',
|
|
|
indicators: ['Volume Profile', 'Price Action', 'Market Phase', 'Composite Man'],
|
|
|
timeframes: ['4h', '1d'],
|
|
|
riskLevel: 'medium',
|
|
|
profitTarget: 'very-high',
|
|
|
scientific: true,
|
|
|
winRate: '70-80%',
|
|
|
avgRR: '1:6'
|
|
|
},
|
|
|
'anchored-vwap-breakout': {
|
|
|
name: 'Anchored VWAP Breakout',
|
|
|
description: 'Institutional trading levels with volume-weighted analysis',
|
|
|
indicators: ['Anchored VWAP', 'Volume', 'Standard Deviations', 'Support/Resistance'],
|
|
|
timeframes: ['1h', '4h', '1d'],
|
|
|
riskLevel: 'medium',
|
|
|
profitTarget: 'high',
|
|
|
scientific: true,
|
|
|
winRate: '72-82%',
|
|
|
avgRR: '1:4'
|
|
|
},
|
|
|
'momentum-divergence-hunter': {
|
|
|
name: 'Momentum Divergence Hunter',
|
|
|
description: 'Detects hidden and regular divergences across multiple timeframes',
|
|
|
indicators: ['RSI Divergence', 'MACD Divergence', 'Volume Divergence', 'Price Action'],
|
|
|
timeframes: ['15m', '1h', '4h'],
|
|
|
riskLevel: 'medium',
|
|
|
profitTarget: 'high',
|
|
|
scientific: true,
|
|
|
winRate: '78-86%',
|
|
|
avgRR: '1:4.5'
|
|
|
},
|
|
|
'liquidity-sweep-reversal': {
|
|
|
name: 'Liquidity Sweep Reversal',
|
|
|
description: 'Detects stop hunts and liquidity grabs for reversal entries',
|
|
|
indicators: ['Stop Clusters', 'Liquidity Zones', 'Volume', 'Market Structure'],
|
|
|
timeframes: ['15m', '1h', '4h'],
|
|
|
riskLevel: 'high',
|
|
|
profitTarget: 'very-high',
|
|
|
scientific: true,
|
|
|
winRate: '70-78%',
|
|
|
avgRR: '1:6'
|
|
|
},
|
|
|
'supply-demand-zones': {
|
|
|
name: 'Supply/Demand Zone Trading',
|
|
|
description: 'Fresh supply and demand zones with confirmation',
|
|
|
indicators: ['Supply Zones', 'Demand Zones', 'Volume', 'Price Action'],
|
|
|
timeframes: ['1h', '4h', '1d'],
|
|
|
riskLevel: 'medium',
|
|
|
profitTarget: 'high',
|
|
|
scientific: true,
|
|
|
winRate: '75-83%',
|
|
|
avgRR: '1:5'
|
|
|
},
|
|
|
'volatility-breakout-pro': {
|
|
|
name: 'Volatility Breakout Pro',
|
|
|
description: 'Advanced volatility expansion with regime filtering',
|
|
|
indicators: ['ATR', 'Bollinger Bands', 'Volume', 'Momentum', 'Regime Filter'],
|
|
|
timeframes: ['1h', '4h'],
|
|
|
riskLevel: 'medium',
|
|
|
profitTarget: 'high',
|
|
|
scientific: true,
|
|
|
winRate: '73-81%',
|
|
|
avgRR: '1:4'
|
|
|
},
|
|
|
'multi-timeframe-confluence': {
|
|
|
name: 'Multi-Timeframe Confluence',
|
|
|
description: 'High-probability setups with 3+ timeframe confirmation',
|
|
|
indicators: ['MTF Support/Resistance', 'MTF Trend', 'MTF Volume', 'MTF Momentum'],
|
|
|
timeframes: ['15m', '1h', '4h', '1d'],
|
|
|
riskLevel: 'low',
|
|
|
profitTarget: 'high',
|
|
|
scientific: true,
|
|
|
winRate: '80-88%',
|
|
|
avgRR: '1:4'
|
|
|
},
|
|
|
'market-maker-profile': {
|
|
|
name: 'Market Maker Profile',
|
|
|
description: 'Institutional order flow and market maker behavior analysis',
|
|
|
indicators: ['Order Flow', 'Delta', 'Footprint Chart', 'Volume Profile'],
|
|
|
timeframes: ['5m', '15m', '1h'],
|
|
|
riskLevel: 'high',
|
|
|
profitTarget: 'very-high',
|
|
|
scientific: true,
|
|
|
winRate: '72-80%',
|
|
|
avgRR: '1:5.5'
|
|
|
},
|
|
|
'fair-value-gap-strategy': {
|
|
|
name: 'Fair Value Gap (FVG) Strategy',
|
|
|
description: 'Trading imbalances and inefficiencies in price action',
|
|
|
indicators: ['Fair Value Gaps', 'Order Blocks', 'Market Structure', 'Volume'],
|
|
|
timeframes: ['15m', '1h', '4h'],
|
|
|
riskLevel: 'medium',
|
|
|
profitTarget: 'high',
|
|
|
scientific: true,
|
|
|
winRate: '76-84%',
|
|
|
avgRR: '1:5'
|
|
|
}
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function analyzeMarketStructure(ohlcvData) {
|
|
|
if (!ohlcvData || ohlcvData.length < 50) {
|
|
|
return { error: 'Insufficient data', structure: 'unknown' };
|
|
|
}
|
|
|
|
|
|
const highs = ohlcvData.map(c => c.high);
|
|
|
const lows = ohlcvData.map(c => c.low);
|
|
|
const closes = ohlcvData.map(c => c.close);
|
|
|
|
|
|
|
|
|
const swingHighs = findSwingPoints(highs, 'high');
|
|
|
const swingLows = findSwingPoints(lows, 'low');
|
|
|
|
|
|
|
|
|
const structure = determineStructure(swingHighs, swingLows, closes);
|
|
|
|
|
|
|
|
|
const orderBlocks = findOrderBlocks(ohlcvData);
|
|
|
|
|
|
|
|
|
const fvgs = detectFairValueGaps(ohlcvData);
|
|
|
|
|
|
|
|
|
const liquidityZones = findLiquidityZones(ohlcvData, swingHighs, swingLows);
|
|
|
|
|
|
return {
|
|
|
structure: structure.type,
|
|
|
trend: structure.trend,
|
|
|
strength: structure.strength,
|
|
|
swingHighs: swingHighs.slice(-5),
|
|
|
swingLows: swingLows.slice(-5),
|
|
|
orderBlocks: orderBlocks.slice(-10),
|
|
|
fairValueGaps: fvgs.slice(-5),
|
|
|
liquidityZones: liquidityZones.slice(-8),
|
|
|
confidence: calculateStructureConfidence(structure, orderBlocks, fvgs)
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function findSwingPoints(prices, type = 'high') {
|
|
|
const swings = [];
|
|
|
const lookback = 5;
|
|
|
|
|
|
for (let i = lookback; i < prices.length - lookback; i++) {
|
|
|
let isSwing = true;
|
|
|
|
|
|
if (type === 'high') {
|
|
|
for (let j = i - lookback; j <= i + lookback; j++) {
|
|
|
if (j !== i && prices[j] >= prices[i]) {
|
|
|
isSwing = false;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
for (let j = i - lookback; j <= i + lookback; j++) {
|
|
|
if (j !== i && prices[j] <= prices[i]) {
|
|
|
isSwing = false;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (isSwing) {
|
|
|
swings.push({
|
|
|
index: i,
|
|
|
price: prices[i],
|
|
|
type: type
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return swings;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function determineStructure(swingHighs, swingLows, closes) {
|
|
|
if (swingHighs.length < 2 || swingLows.length < 2) {
|
|
|
return { type: 'ranging', trend: 'neutral', strength: 0 };
|
|
|
}
|
|
|
|
|
|
const recentHighs = swingHighs.slice(-3);
|
|
|
const recentLows = swingLows.slice(-3);
|
|
|
|
|
|
|
|
|
const higherHighs = recentHighs[recentHighs.length - 1].price > recentHighs[0].price;
|
|
|
const higherLows = recentLows[recentLows.length - 1].price > recentLows[0].price;
|
|
|
|
|
|
|
|
|
const lowerHighs = recentHighs[recentHighs.length - 1].price < recentHighs[0].price;
|
|
|
const lowerLows = recentLows[recentLows.length - 1].price < recentLows[0].price;
|
|
|
|
|
|
let type = 'ranging';
|
|
|
let trend = 'neutral';
|
|
|
let strength = 0;
|
|
|
|
|
|
if (higherHighs && higherLows) {
|
|
|
type = 'bullish';
|
|
|
trend = 'uptrend';
|
|
|
strength = 85;
|
|
|
} else if (lowerHighs && lowerLows) {
|
|
|
type = 'bearish';
|
|
|
trend = 'downtrend';
|
|
|
strength = 85;
|
|
|
} else if (higherHighs && !higherLows) {
|
|
|
type = 'bullish-weakening';
|
|
|
trend = 'uptrend';
|
|
|
strength = 60;
|
|
|
} else if (lowerHighs && !lowerLows) {
|
|
|
type = 'bearish-weakening';
|
|
|
trend = 'downtrend';
|
|
|
strength = 60;
|
|
|
}
|
|
|
|
|
|
return { type, trend, strength };
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function findOrderBlocks(ohlcvData) {
|
|
|
const orderBlocks = [];
|
|
|
const volumeThreshold = calculateVolumeThreshold(ohlcvData);
|
|
|
|
|
|
for (let i = 3; i < ohlcvData.length - 1; i++) {
|
|
|
const current = ohlcvData[i];
|
|
|
const prev = ohlcvData[i - 1];
|
|
|
const next = ohlcvData[i + 1];
|
|
|
|
|
|
|
|
|
if (current.volume > volumeThreshold &&
|
|
|
current.close > current.open &&
|
|
|
next.close > current.high) {
|
|
|
orderBlocks.push({
|
|
|
type: 'bullish',
|
|
|
index: i,
|
|
|
high: current.high,
|
|
|
low: current.low,
|
|
|
volume: current.volume,
|
|
|
strength: calculateOrderBlockStrength(current, next, 'bullish')
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
if (current.volume > volumeThreshold &&
|
|
|
current.close < current.open &&
|
|
|
next.close < current.low) {
|
|
|
orderBlocks.push({
|
|
|
type: 'bearish',
|
|
|
index: i,
|
|
|
high: current.high,
|
|
|
low: current.low,
|
|
|
volume: current.volume,
|
|
|
strength: calculateOrderBlockStrength(current, next, 'bearish')
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return orderBlocks;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function detectFairValueGaps(ohlcvData) {
|
|
|
const fvgs = [];
|
|
|
|
|
|
for (let i = 2; i < ohlcvData.length; i++) {
|
|
|
const candle1 = ohlcvData[i - 2];
|
|
|
const candle2 = ohlcvData[i - 1];
|
|
|
const candle3 = ohlcvData[i];
|
|
|
|
|
|
|
|
|
if (candle3.low > candle1.high) {
|
|
|
fvgs.push({
|
|
|
type: 'bullish',
|
|
|
index: i,
|
|
|
top: candle3.low,
|
|
|
bottom: candle1.high,
|
|
|
size: candle3.low - candle1.high,
|
|
|
filled: false
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
if (candle3.high < candle1.low) {
|
|
|
fvgs.push({
|
|
|
type: 'bearish',
|
|
|
index: i,
|
|
|
top: candle1.low,
|
|
|
bottom: candle3.high,
|
|
|
size: candle1.low - candle3.high,
|
|
|
filled: false
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return fvgs;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function findLiquidityZones(ohlcvData, swingHighs, swingLows) {
|
|
|
const zones = [];
|
|
|
|
|
|
|
|
|
swingHighs.forEach(swing => {
|
|
|
zones.push({
|
|
|
type: 'sell-side',
|
|
|
price: swing.price,
|
|
|
index: swing.index,
|
|
|
swept: false,
|
|
|
strength: calculateLiquidityStrength(ohlcvData, swing.index, 'high')
|
|
|
});
|
|
|
});
|
|
|
|
|
|
|
|
|
swingLows.forEach(swing => {
|
|
|
zones.push({
|
|
|
type: 'buy-side',
|
|
|
price: swing.price,
|
|
|
index: swing.index,
|
|
|
swept: false,
|
|
|
strength: calculateLiquidityStrength(ohlcvData, swing.index, 'low')
|
|
|
});
|
|
|
});
|
|
|
|
|
|
return zones;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function calculateVolumeThreshold(ohlcvData) {
|
|
|
const volumes = ohlcvData.map(c => c.volume);
|
|
|
const avgVolume = volumes.reduce((a, b) => a + b, 0) / volumes.length;
|
|
|
return avgVolume * 1.5;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function calculateOrderBlockStrength(current, next, type) {
|
|
|
const priceMove = type === 'bullish'
|
|
|
? (next.close - current.high) / current.high
|
|
|
: (current.low - next.close) / current.low;
|
|
|
|
|
|
return Math.min(Math.abs(priceMove) * 1000, 100);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function calculateLiquidityStrength(ohlcvData, index, type) {
|
|
|
const lookback = 10;
|
|
|
const start = Math.max(0, index - lookback);
|
|
|
const end = Math.min(ohlcvData.length, index + lookback);
|
|
|
|
|
|
let touches = 0;
|
|
|
const price = ohlcvData[index][type];
|
|
|
const tolerance = price * 0.005;
|
|
|
|
|
|
for (let i = start; i < end; i++) {
|
|
|
if (i !== index) {
|
|
|
const testPrice = type === 'high' ? ohlcvData[i].high : ohlcvData[i].low;
|
|
|
if (Math.abs(testPrice - price) < tolerance) {
|
|
|
touches++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return Math.min(touches * 15, 100);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function calculateStructureConfidence(structure, orderBlocks, fvgs) {
|
|
|
let confidence = structure.strength;
|
|
|
|
|
|
if (orderBlocks.length > 5) confidence += 10;
|
|
|
if (fvgs.length > 3) confidence += 5;
|
|
|
|
|
|
return Math.min(confidence, 100);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function analyzeICTMarketStructure(symbol, ohlcvData) {
|
|
|
try {
|
|
|
const structure = analyzeMarketStructure(ohlcvData);
|
|
|
const currentPrice = ohlcvData[ohlcvData.length - 1].close;
|
|
|
|
|
|
let signal = 'hold';
|
|
|
let confidence = 50;
|
|
|
let entry = currentPrice;
|
|
|
let stopLoss = currentPrice;
|
|
|
let targets = [];
|
|
|
|
|
|
|
|
|
if (structure.structure === 'bullish' || structure.structure === 'bullish-weakening') {
|
|
|
const demandZones = structure.orderBlocks.filter(ob => ob.type === 'bullish');
|
|
|
const bullishFVGs = structure.fairValueGaps.filter(fvg => fvg.type === 'bullish');
|
|
|
|
|
|
if (demandZones.length > 0 || bullishFVGs.length > 0) {
|
|
|
signal = 'buy';
|
|
|
confidence = structure.confidence;
|
|
|
|
|
|
const nearestSupport = structure.swingLows[structure.swingLows.length - 1];
|
|
|
entry = currentPrice;
|
|
|
stopLoss = nearestSupport ? nearestSupport.price * 0.98 : currentPrice * 0.96;
|
|
|
|
|
|
const riskAmount = entry - stopLoss;
|
|
|
targets = [
|
|
|
{ level: entry + riskAmount * 3, type: 'TP1', percentage: 30 },
|
|
|
{ level: entry + riskAmount * 5, type: 'TP2', percentage: 40 },
|
|
|
{ level: entry + riskAmount * 8, type: 'TP3', percentage: 30 }
|
|
|
];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
if (structure.structure === 'bearish' || structure.structure === 'bearish-weakening') {
|
|
|
const supplyZones = structure.orderBlocks.filter(ob => ob.type === 'bearish');
|
|
|
const bearishFVGs = structure.fairValueGaps.filter(fvg => fvg.type === 'bearish');
|
|
|
|
|
|
if (supplyZones.length > 0 || bearishFVGs.length > 0) {
|
|
|
signal = 'sell';
|
|
|
confidence = structure.confidence;
|
|
|
|
|
|
const nearestResistance = structure.swingHighs[structure.swingHighs.length - 1];
|
|
|
entry = currentPrice;
|
|
|
stopLoss = nearestResistance ? nearestResistance.price * 1.02 : currentPrice * 1.04;
|
|
|
|
|
|
const riskAmount = stopLoss - entry;
|
|
|
targets = [
|
|
|
{ level: entry - riskAmount * 3, type: 'TP1', percentage: 30 },
|
|
|
{ level: entry - riskAmount * 5, type: 'TP2', percentage: 40 },
|
|
|
{ level: entry - riskAmount * 8, type: 'TP3', percentage: 30 }
|
|
|
];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return {
|
|
|
strategy: 'ICT Market Structure',
|
|
|
signal,
|
|
|
confidence,
|
|
|
entry,
|
|
|
stopLoss,
|
|
|
targets,
|
|
|
riskRewardRatio: targets.length > 0 ? `1:${((targets[1].level - entry) / Math.abs(stopLoss - entry)).toFixed(1)}` : '1:5',
|
|
|
marketStructure: structure,
|
|
|
timestamp: new Date().toISOString()
|
|
|
};
|
|
|
} catch (error) {
|
|
|
console.error('[ICT Strategy] Error:', error);
|
|
|
return {
|
|
|
strategy: 'ICT Market Structure',
|
|
|
signal: 'hold',
|
|
|
confidence: 0,
|
|
|
error: error.message
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function detectMomentumDivergences(ohlcvData) {
|
|
|
if (ohlcvData.length < 50) {
|
|
|
return { divergences: [], signal: 'hold', confidence: 0 };
|
|
|
}
|
|
|
|
|
|
const divergences = [];
|
|
|
const closes = ohlcvData.map(c => c.close);
|
|
|
const rsi = calculateRSIArray(closes, 14);
|
|
|
const macd = calculateMACDArray(closes);
|
|
|
|
|
|
|
|
|
const priceHighs = findSwingPoints(closes, 'high');
|
|
|
const priceLows = findSwingPoints(closes, 'low');
|
|
|
|
|
|
|
|
|
for (let i = 1; i < priceLows.length; i++) {
|
|
|
const prevLow = priceLows[i - 1];
|
|
|
const currLow = priceLows[i];
|
|
|
|
|
|
if (currLow.price < prevLow.price && rsi[currLow.index] > rsi[prevLow.index]) {
|
|
|
divergences.push({
|
|
|
type: 'bullish-regular',
|
|
|
indicator: 'RSI',
|
|
|
strength: 'strong',
|
|
|
pricePoints: [prevLow, currLow],
|
|
|
confidence: 80
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
for (let i = 1; i < priceHighs.length; i++) {
|
|
|
const prevHigh = priceHighs[i - 1];
|
|
|
const currHigh = priceHighs[i];
|
|
|
|
|
|
if (currHigh.price > prevHigh.price && rsi[currHigh.index] < rsi[prevHigh.index]) {
|
|
|
divergences.push({
|
|
|
type: 'bearish-regular',
|
|
|
indicator: 'RSI',
|
|
|
strength: 'strong',
|
|
|
pricePoints: [prevHigh, currHigh],
|
|
|
confidence: 80
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
let signal = 'hold';
|
|
|
let confidence = 50;
|
|
|
|
|
|
if (divergences.length > 0) {
|
|
|
const recentDiv = divergences[divergences.length - 1];
|
|
|
signal = recentDiv.type.includes('bullish') ? 'buy' : 'sell';
|
|
|
confidence = recentDiv.confidence;
|
|
|
}
|
|
|
|
|
|
return { divergences, signal, confidence };
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function calculateRSIArray(prices, period = 14) {
|
|
|
const rsiArray = [];
|
|
|
|
|
|
for (let i = period; i < prices.length; i++) {
|
|
|
const slice = prices.slice(i - period, i + 1);
|
|
|
let gains = 0;
|
|
|
let losses = 0;
|
|
|
|
|
|
for (let j = 1; j < slice.length; j++) {
|
|
|
const change = slice[j] - slice[j - 1];
|
|
|
if (change > 0) gains += change;
|
|
|
else losses += Math.abs(change);
|
|
|
}
|
|
|
|
|
|
const avgGain = gains / period;
|
|
|
const avgLoss = losses / period;
|
|
|
const rs = avgGain / (avgLoss || 1);
|
|
|
const rsi = 100 - (100 / (1 + rs));
|
|
|
rsiArray.push(rsi);
|
|
|
}
|
|
|
|
|
|
return rsiArray;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function calculateMACDArray(prices) {
|
|
|
|
|
|
const macdArray = [];
|
|
|
const ema12 = calculateEMAArray(prices, 12);
|
|
|
const ema26 = calculateEMAArray(prices, 26);
|
|
|
|
|
|
for (let i = 0; i < Math.min(ema12.length, ema26.length); i++) {
|
|
|
macdArray.push(ema12[i] - ema26[i]);
|
|
|
}
|
|
|
|
|
|
return macdArray;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function calculateEMAArray(prices, period) {
|
|
|
const emaArray = [];
|
|
|
const multiplier = 2 / (period + 1);
|
|
|
let ema = prices.slice(0, period).reduce((a, b) => a + b, 0) / period;
|
|
|
emaArray.push(ema);
|
|
|
|
|
|
for (let i = period; i < prices.length; i++) {
|
|
|
ema = (prices[i] - ema) * multiplier + ema;
|
|
|
emaArray.push(ema);
|
|
|
}
|
|
|
|
|
|
return emaArray;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export async function analyzeWithAdvancedStrategy(symbol, strategyKey, ohlcvData) {
|
|
|
try {
|
|
|
if (!ohlcvData || ohlcvData.length < 50) {
|
|
|
throw new Error('Insufficient data for analysis');
|
|
|
}
|
|
|
|
|
|
let result;
|
|
|
|
|
|
switch (strategyKey) {
|
|
|
case 'ict-market-structure':
|
|
|
result = await analyzeICTMarketStructure(symbol, ohlcvData);
|
|
|
break;
|
|
|
|
|
|
case 'momentum-divergence-hunter':
|
|
|
const divAnalysis = detectMomentumDivergences(ohlcvData);
|
|
|
const currentPrice = ohlcvData[ohlcvData.length - 1].close;
|
|
|
result = {
|
|
|
strategy: 'Momentum Divergence Hunter',
|
|
|
signal: divAnalysis.signal,
|
|
|
confidence: divAnalysis.confidence,
|
|
|
entry: currentPrice,
|
|
|
stopLoss: divAnalysis.signal === 'buy' ? currentPrice * 0.96 : currentPrice * 1.04,
|
|
|
targets: calculateTargets(currentPrice, divAnalysis.signal),
|
|
|
divergences: divAnalysis.divergences,
|
|
|
timestamp: new Date().toISOString()
|
|
|
};
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
result = await analyzeICTMarketStructure(symbol, ohlcvData);
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
} catch (error) {
|
|
|
console.error(`[Advanced Strategy ${strategyKey}] Error:`, error);
|
|
|
return {
|
|
|
strategy: strategyKey,
|
|
|
signal: 'hold',
|
|
|
confidence: 0,
|
|
|
error: error.message,
|
|
|
timestamp: new Date().toISOString()
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function calculateTargets(entry, signal) {
|
|
|
const risk = entry * 0.04;
|
|
|
|
|
|
if (signal === 'buy') {
|
|
|
return [
|
|
|
{ level: entry + risk * 3, type: 'TP1', percentage: 30 },
|
|
|
{ level: entry + risk * 5, type: 'TP2', percentage: 40 },
|
|
|
{ level: entry + risk * 8, type: 'TP3', percentage: 30 }
|
|
|
];
|
|
|
} else if (signal === 'sell') {
|
|
|
return [
|
|
|
{ level: entry - risk * 3, type: 'TP1', percentage: 30 },
|
|
|
{ level: entry - risk * 5, type: 'TP2', percentage: 40 },
|
|
|
{ level: entry - risk * 8, type: 'TP3', percentage: 30 }
|
|
|
];
|
|
|
}
|
|
|
|
|
|
return [];
|
|
|
}
|
|
|
|
|
|
|