trading-platform/docs/02-definicion-modulos/OQI-006-ml-signals/especificaciones/ET-ML-008-ict-analysis-card.md
Adrian Flores Cortes cea9ae85f1 docs: Add 8 ET specifications from TASK-002 audit gaps
Complete remaining ET specs identified in INTEGRATION-PLAN:
- ET-EDU-007: Video Player Advanced (554 LOC component)
- ET-MT4-001: WebSocket Integration (BLOCKER - 0% implemented)
- ET-ML-009: Ensemble Signal (Multi-strategy aggregation)
- ET-TRD-009: Risk-Based Position Sizer (391 LOC component)
- ET-TRD-010: Drawing Tools Persistence (backend + store)
- ET-TRD-011: Market Bias Indicator (multi-timeframe analysis)
- ET-PFM-009: Custom Charts (SVG AllocationChart + Canvas PerformanceChart)
- ET-ML-008: ICT Analysis Card (expanded - 294 LOC component)

All specs include:
- Architecture diagrams
- Complete code examples
- API contracts
- Implementation guides
- Testing scenarios

Related: TASK-2026-01-25-002-FRONTEND-COMPREHENSIVE-AUDIT
Priority: P1-P3 (mixed)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 14:20:53 -06:00

24 KiB

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:

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:

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).

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

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

POST /api/ml/ict-analysis/:symbol
Content-Type: application/json

{
  "symbol": "BTCUSD",
  "timeframe": "1h",
  "lookback_periods": 200
}

4.2 Response

{
  "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)

// apps/frontend/src/modules/ml/components/ICTAnalysisCard.tsx

export const ICTAnalysisCard: React.FC<ICTAnalysisCardProps> = ({
  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 (
    <div className="bg-gray-900 border border-gray-800 rounded-xl p-5">
      {/* Score Badge */}
      <div className={`text-3xl font-bold ${getScoreColor(analysis.score)}`}>
        {analysis.score}
      </div>

      {/* Market Bias */}
      <div className={`flex items-center gap-3 p-3 rounded-lg border ${getBiasColor()}`}>
        {getBiasIcon()}
        <div>
          <p className="font-semibold uppercase">{analysis.market_bias} Bias</p>
          <p className="text-sm">{Math.round(analysis.bias_confidence * 100)}% confidence</p>
        </div>
      </div>

      {/* Trade Setup */}
      <div className="grid grid-cols-2 gap-2">
        <div className="p-3 bg-blue-900/20 border border-blue-800/30 rounded-lg">
          <p className="text-xs text-blue-400">Entry Zone</p>
          <p className="font-mono text-white">
            {analysis.entry_zone.low.toFixed(5)} - {analysis.entry_zone.high.toFixed(5)}
          </p>
        </div>
        {/* Stop Loss, Take Profits */}
      </div>

      {/* Order Blocks */}
      {validOrderBlocks.map((ob, idx) => (
        <div className={ob.type === 'bullish' ? 'bg-green-900/20' : 'bg-red-900/20'}>
          <span>{ob.low.toFixed(5)} - {ob.high.toFixed(5)}</span>
          <span>{Math.round(ob.strength * 100)}%</span>
          {ob.touched ? <ExclamationTriangleIcon /> : <CheckCircleIcon />}
        </div>
      ))}

      {/* Fair Value Gaps, Premium/Discount Zones, Signals */}

      {/* Execute Trade Button */}
      {onExecuteTrade && analysis.score >= 50 && (
        <button
          onClick={() => onExecuteTrade(
            analysis.market_bias === 'bullish' ? 'buy' : 'sell',
            analysis
          )}
          className={analysis.market_bias === 'bullish' ? 'bg-green-600' : 'bg-red-600'}
        >
          {analysis.market_bias === 'bullish' ? 'Execute Buy' : 'Execute Sell'}
        </button>
      )}
    </div>
  );
};

5.2 Props Interface

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

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 <Loader />;

  return (
    <ICTAnalysisCard
      analysis={ictAnalysis}
      onExecuteTrade={(direction, analysis) => {
        console.log(`Execute ${direction} trade:`, analysis);
        // Open order form with pre-filled data
      }}
    />
  );
}

6.2 Integration with Trading Page

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 (
    <div className="grid grid-cols-2 gap-6">
      <ICTAnalysisCard
        analysis={ictAnalysis}
        onExecuteTrade={handleExecuteTrade}
      />
      <OrderForm initialData={orderFormData} />
    </div>
  );
}

7. Referencias


Última actualización: 2026-01-25 Responsable: ML Engineer + Frontend Lead