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