# ET-ML-008: ICT/SMC Analysis Card - Comprehensive Spec **Versión:** 2.0.0 **Fecha:** 2026-01-25 **Epic:** OQI-006 - ML Signals y Predicciones **Componente:** Frontend + Backend ML Engine **Estado:** ✅ Implementado (documentación retroactiva expandida) **Prioridad:** P3 --- ## Metadata | Campo | Valor | |-------|-------| | **ID** | ET-ML-008 | | **Tipo** | Especificación Técnica | | **Epic** | OQI-006 | | **US Relacionada** | US-ML-008 (Ver Análisis ICT/SMC) | | **Componente Frontend** | `ICTAnalysisCard.tsx` (294 líneas) | | **Backend Endpoint** | `/api/ml/ict-analysis/:symbol` | | **Metodología** | Inner Circle Trader (ICT) + Smart Money Concepts (SMC) | | **Complejidad** | Alta (análisis institucional multi-factor) | --- ## 1. Descripción General **ICT/SMC Analysis** es un sistema de análisis técnico avanzado que detecta el comportamiento de "dinero institucional" (Smart Money) en el mercado utilizando: - **Order Blocks:** Zonas donde instituciones acumularon órdenes - **Fair Value Gaps (FVG):** Ineficiencias de precio que tienden a rellenarse - **Premium/Discount Zones:** Áreas de sobrecompra/sobreventa según Fibonacci - **Liquidity Sweeps:** Cacería de liquidez retail antes de movimientos institucionales - **Market Structure Shifts:** Cambios en tendencia (Higher Highs → Lower Lows) ### Conceptos ICT/SMC **Inner Circle Trader (ICT):** Metodología desarrollada por Michael J. Huddleston que enseña cómo identificar el comportamiento de grandes instituciones ("Smart Money") en los mercados financieros. **Smart Money Concepts (SMC):** Framework derivado de ICT que se enfoca en detectar acumulación, manipulación y distribución institucional. --- ## 2. Arquitectura de Análisis ### 2.1 Flujo de Datos ICT ``` ┌────────────────────────────────────────────────────────────────┐ │ ICT/SMC Analysis Architecture │ ├────────────────────────────────────────────────────────────────┤ │ │ │ Market Data (BTCUSD, 1h candles, last 200) │ │ │ │ │ v │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Step 1: Identify Market Structure │ │ │ │ • Higher Highs / Higher Lows (uptrend) │ │ │ │ • Lower Highs / Lower Lows (downtrend) │ │ │ │ • Break of Structure (BOS) │ │ │ │ • Change of Character (CHoCH) │ │ │ └──────────────┬───────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Step 2: Detect Order Blocks │ │ │ │ • Last bearish candle before strong move up (bullish OB)│ │ │ │ • Last bullish candle before strong move down (bearish) │ │ │ │ • Validate with volume spike │ │ │ │ • Mark as "fresh" (untouched) or "touched" │ │ │ └──────────────┬───────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Step 3: Identify Fair Value Gaps (FVG) │ │ │ │ • 3-candle pattern with gap │ │ │ │ • Candle 1 high < Candle 3 low (bullish FVG) │ │ │ │ • Candle 1 low > Candle 3 high (bearish FVG) │ │ │ │ • Size >= 0.3% of price │ │ │ └──────────────┬───────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Step 4: Calculate Premium/Discount Zones (Fibonacci) │ │ │ │ • High = Recent swing high │ │ │ │ • Low = Recent swing low │ │ │ │ • Equilibrium = 0.5 Fib (50%) │ │ │ │ • Premium = 0.5 - 1.0 Fib (sell zone) │ │ │ │ • Discount = 0.0 - 0.5 Fib (buy zone) │ │ │ └──────────────┬───────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Step 5: Determine Market Bias │ │ │ │ • Bullish: Higher highs, price in discount, bullish OBs │ │ │ │ • Bearish: Lower lows, price in premium, bearish OBs │ │ │ │ • Neutral: Choppy structure, no clear bias │ │ │ │ • Confidence = weighted score (0.0 - 1.0) │ │ │ └──────────────┬───────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Step 6: Generate Trade Setup │ │ │ │ • Entry Zone = Nearest fresh OB in bias direction │ │ │ │ • Stop Loss = Below OB low (buy) / Above OB high (sell) │ │ │ │ • TP1 = Equilibrium (0.5 Fib) │ │ │ │ • TP2 = Next FVG or OB │ │ │ │ • TP3 = Opposite premium/discount zone │ │ │ │ • Risk:Reward = (TP - Entry) / (Entry - SL) │ │ │ └──────────────┬───────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Step 7: Calculate Setup Score (0-100) │ │ │ │ • Market structure clarity: 30 pts │ │ │ │ • Fresh order blocks: 25 pts │ │ │ │ • Unfilled FVGs: 20 pts │ │ │ │ • Risk:Reward > 2: 15 pts │ │ │ │ • Volume confirmation: 10 pts │ │ │ └──────────────┬───────────────────────────────────────────┘ │ │ │ │ │ v │ │ ┌──────────────────────────────────────────────────────────┐ │ │ │ Output: ICT Analysis Object │ │ │ │ • Bias: BULLISH (78% confidence) │ │ │ │ • 3 Fresh OBs, 2 Unfilled FVGs │ │ │ │ • Entry: 43200-43250, SL: 43100, TP1: 43500 │ │ │ │ • R:R = 2.5, Score: 72/100 │ │ │ └──────────────────────────────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────┘ ``` --- ## 3. Conceptos Técnicos ICT/SMC ### 3.1 Order Blocks (OB) **Definición:** Zona de precio donde instituciones colocaron grandes órdenes, creando soporte/resistencia institucional. **Detección:** ```python def detect_order_blocks(candles: List[Candle]) -> List[OrderBlock]: order_blocks = [] for i in range(2, len(candles)): # Bullish Order Block # Last bearish candle before strong bullish move if (candles[i].close > candles[i].open and # Current is bullish candles[i-1].close < candles[i-1].open and # Previous is bearish candles[i].close > candles[i-1].high): # Strong move up ob = OrderBlock( type='bullish', high=candles[i-1].high, low=candles[i-1].low, midpoint=(candles[i-1].high + candles[i-1].low) / 2, strength=calculate_ob_strength(candles, i-1), valid=True, touched=False ) order_blocks.append(ob) # Bearish Order Block # Last bullish candle before strong bearish move if (candles[i].close < candles[i].open and # Current is bearish candles[i-1].close > candles[i-1].open and # Previous is bullish candles[i].close < candles[i-1].low): # Strong move down ob = OrderBlock( type='bearish', high=candles[i-1].high, low=candles[i-1].low, midpoint=(candles[i-1].high + candles[i-1].low) / 2, strength=calculate_ob_strength(candles, i-1), valid=True, touched=False ) order_blocks.append(ob) return order_blocks ``` **Validación:** - **Fresh (no tocado):** OB nunca fue retestado → Mayor probabilidad de reacción - **Touched:** OB ya fue tocado → Menor fuerza - **Strength:** Basado en volumen, tamaño del candle, distancia al precio actual ### 3.2 Fair Value Gaps (FVG) **Definición:** Gap de precio causado por movimiento institucional rápido que "salta" niveles de precio, creando ineficiencia que el mercado tiende a rellenar. **Detección:** ```python def detect_fair_value_gaps(candles: List[Candle]) -> List[FairValueGap]: fvgs = [] for i in range(1, len(candles) - 1): # Bullish FVG: Candle 0 high < Candle 2 low if candles[i-1].high < candles[i+1].low: gap_size = candles[i+1].low - candles[i-1].high gap_size_percent = (gap_size / candles[i].close) * 100 if gap_size_percent >= 0.3: # At least 0.3% gap fvg = FairValueGap( type='bullish', high=candles[i+1].low, low=candles[i-1].high, midpoint=(candles[i+1].low + candles[i-1].high) / 2, size_percent=gap_size_percent, filled=False ) fvgs.append(fvg) # Bearish FVG: Candle 0 low > Candle 2 high if candles[i-1].low > candles[i+1].high: gap_size = candles[i-1].low - candles[i+1].high gap_size_percent = (gap_size / candles[i].close) * 100 if gap_size_percent >= 0.3: fvg = FairValueGap( type='bearish', high=candles[i-1].low, low=candles[i+1].high, midpoint=(candles[i-1].low + candles[i+1].high) / 2, size_percent=gap_size_percent, filled=False ) fvgs.append(fvg) return fvgs ``` **Tipos de FVG:** - **Bullish FVG:** Gap hacia arriba → Precio debería volver a llenar el gap desde abajo - **Bearish FVG:** Gap hacia abajo → Precio debería volver a llenar desde arriba - **Filled:** Gap rellenado al 50% → Ya no es válido ### 3.3 Premium/Discount Zones (Fibonacci) **Definición:** Zonas basadas en Fibonacci desde el swing high hasta swing low reciente que indican si el precio está "caro" (premium) o "barato" (discount). ```python def calculate_premium_discount_zones(candles: List[Candle]) -> dict: # Find recent swing high/low (last 50 candles) recent = candles[-50:] swing_high = max([c.high for c in recent]) swing_low = min([c.low for c in recent]) range_size = swing_high - swing_low return { 'equilibrium': swing_low + (range_size * 0.5), # 50% Fib 'premium_zone': { 'low': swing_low + (range_size * 0.5), # 50% Fib 'high': swing_high # 100% Fib }, 'discount_zone': { 'low': swing_low, # 0% Fib 'high': swing_low + (range_size * 0.5) # 50% Fib } } ``` **Trading Logic:** - **In Premium Zone → Look for SELL setups** (price is expensive) - **In Discount Zone → Look for BUY setups** (price is cheap) - **At Equilibrium → Wait for direction confirmation** ### 3.4 Market Bias Calculation ```python def calculate_market_bias( candles: List[Candle], order_blocks: List[OrderBlock], fvgs: List[FairValueGap], zones: dict ) -> dict: current_price = candles[-1].close score = 0 max_score = 100 # Factor 1: Market Structure (30 points) structure_score = analyze_market_structure(candles) # HH/HL vs LH/LL score += structure_score * 0.30 * max_score # Factor 2: Fresh Order Blocks (25 points) fresh_bullish_obs = [ob for ob in order_blocks if ob.type == 'bullish' and not ob.touched] fresh_bearish_obs = [ob for ob in order_blocks if ob.type == 'bearish' and not ob.touched] ob_score = len(fresh_bullish_obs) - len(fresh_bearish_obs) score += (ob_score / max(len(order_blocks), 1)) * 0.25 * max_score # Factor 3: Unfilled FVGs (20 points) unfilled_bullish_fvgs = [f for f in fvgs if f.type == 'bullish' and not f.filled] unfilled_bearish_fvgs = [f for f in fvgs if f.type == 'bearish' and not f.filled] fvg_score = len(unfilled_bullish_fvgs) - len(unfilled_bearish_fvgs) score += (fvg_score / max(len(fvgs), 1)) * 0.20 * max_score # Factor 4: Price in Premium/Discount (15 points) if current_price < zones['equilibrium']: score += 0.15 * max_score # Discount = bullish elif current_price > zones['equilibrium']: score -= 0.15 * max_score # Premium = bearish # Factor 5: Volume trend (10 points) volume_trend = calculate_volume_trend(candles) score += volume_trend * 0.10 * max_score # Determine bias if score > 60: bias = 'bullish' confidence = score / 100 elif score < 40: bias = 'bearish' confidence = (100 - score) / 100 else: bias = 'neutral' confidence = 0.5 return { 'market_bias': bias, 'bias_confidence': confidence, 'score': int(score) } ``` --- ## 4. API Endpoint ### 4.1 Request ```http POST /api/ml/ict-analysis/:symbol Content-Type: application/json { "symbol": "BTCUSD", "timeframe": "1h", "lookback_periods": 200 } ``` ### 4.2 Response ```json { "symbol": "BTCUSD", "timeframe": "1h", "market_bias": "bullish", "bias_confidence": 0.78, "current_trend": "Higher Highs + Higher Lows", "score": 72, "order_blocks": [ { "type": "bullish", "high": 43280.50, "low": 43150.00, "midpoint": 43215.25, "strength": 0.85, "valid": true, "touched": false }, { "type": "bullish", "high": 43050.00, "low": 42900.00, "midpoint": 42975.00, "strength": 0.72, "valid": true, "touched": true } ], "fair_value_gaps": [ { "type": "bullish", "high": 43350.00, "low": 43280.00, "midpoint": 43315.00, "size_percent": 0.16, "filled": false } ], "premium_zone": { "low": 43500.00, "high": 44000.00 }, "discount_zone": { "low": 42500.00, "high": 43500.00 }, "equilibrium": 43500.00, "entry_zone": { "low": 43200.00, "high": 43250.00 }, "stop_loss": 43100.00, "take_profits": { "tp1": 43500.00, "tp2": 43750.00, "tp3": 44000.00 }, "risk_reward": 2.5, "signals": [ "FRESH_BULLISH_OB", "PRICE_IN_DISCOUNT", "UNFILLED_FVG_ABOVE", "HIGHER_HIGHS_HIGHER_LOWS", "VOLUME_INCREASING" ], "timestamp": "2026-01-25T10:30:15Z" } ``` --- ## 5. Frontend Component ### 5.1 Component Code (Key Sections) ```tsx // apps/frontend/src/modules/ml/components/ICTAnalysisCard.tsx export const ICTAnalysisCard: React.FC = ({ analysis, onExecuteTrade, }) => { const getBiasColor = () => { switch (analysis.market_bias) { case 'bullish': return 'bg-green-500/20 text-green-400 border-green-500/30'; case 'bearish': return 'bg-red-500/20 text-red-400 border-red-500/30'; default: return 'bg-gray-500/20 text-gray-400 border-gray-500/30'; } }; const getScoreColor = (score: number) => { if (score >= 70) return 'text-green-400'; if (score >= 50) return 'text-yellow-400'; return 'text-red-400'; }; const validOrderBlocks = analysis.order_blocks.filter(ob => ob.valid); const unfilledFVGs = analysis.fair_value_gaps.filter(fvg => !fvg.filled); return (
{/* Score Badge */}
{analysis.score}
{/* Market Bias */}
{getBiasIcon()}

{analysis.market_bias} Bias

{Math.round(analysis.bias_confidence * 100)}% confidence

{/* Trade Setup */}

Entry Zone

{analysis.entry_zone.low.toFixed(5)} - {analysis.entry_zone.high.toFixed(5)}

{/* Stop Loss, Take Profits */}
{/* Order Blocks */} {validOrderBlocks.map((ob, idx) => (
{ob.low.toFixed(5)} - {ob.high.toFixed(5)} {Math.round(ob.strength * 100)}% {ob.touched ? : }
))} {/* Fair Value Gaps, Premium/Discount Zones, Signals */} {/* Execute Trade Button */} {onExecuteTrade && analysis.score >= 50 && ( )}
); }; ``` ### 5.2 Props Interface ```typescript interface ICTAnalysisCardProps { analysis: ICTAnalysis; onExecuteTrade?: (direction: 'buy' | 'sell', analysis: ICTAnalysis) => void; className?: string; } interface ICTAnalysis { symbol: string; timeframe: string; market_bias: 'bullish' | 'bearish' | 'neutral'; bias_confidence: number; current_trend: string; order_blocks: OrderBlock[]; fair_value_gaps: FairValueGap[]; entry_zone?: { low: number; high: number }; stop_loss?: number; take_profits: { tp1?: number; tp2?: number; tp3?: number }; risk_reward?: number; signals: string[]; score: number; premium_zone: { low: number; high: number }; discount_zone: { low: number; high: number }; equilibrium: number; } ``` --- ## 6. Uso e Integración ### 6.1 Standalone ```tsx import ICTAnalysisCard from '@/modules/ml/components/ICTAnalysisCard'; function MLDashboard() { const { data: ictAnalysis } = useQuery({ queryKey: ['ict-analysis', 'BTCUSD'], queryFn: () => mlService.getICTAnalysis('BTCUSD', '1h') }); if (!ictAnalysis) return ; return ( { console.log(`Execute ${direction} trade:`, analysis); // Open order form with pre-filled data }} /> ); } ``` ### 6.2 Integration with Trading Page ```tsx function TradingPage() { const [selectedSymbol, setSelectedSymbol] = useState('BTCUSD'); const handleExecuteTrade = (direction: 'buy' | 'sell', analysis: ICTAnalysis) => { // Pre-fill order form setOrderFormData({ symbol: analysis.symbol, type: direction, entry: analysis.entry_zone?.low, stopLoss: analysis.stop_loss, takeProfit: analysis.take_profits.tp1 }); }; return (
); } ``` --- ## 7. Referencias - **Componente:** `apps/frontend/src/modules/ml/components/ICTAnalysisCard.tsx` (294 líneas) - **Backend ML:** `apps/ml-engine/models/ict_analyzer.py` - **Spec General:** `ET-ML-008-frontend.md` - **US:** `US-ML-008-ver-ict-analysis.md` - **ICT Methodology:** https://www.theinnercircletrader.com/ - **SMC Concepts:** https://smartmoneytrading.com/concepts --- **Última actualización:** 2026-01-25 **Responsable:** ML Engineer + Frontend Lead