---
id: "ET-ML-004"
title: "FastAPI Endpoints"
type: "Technical Specification"
status: "Done"
priority: "Alta"
epic: "OQI-006"
project: "trading-platform"
version: "2.0.0"
created_date: "2025-12-05"
updated_date: "2026-01-07"
---

# ET-ML-004: FastAPI Endpoints

## Metadata

| Campo | Valor |
|-------|-------|
| **ID** | ET-ML-004 |
| **Épica** | OQI-006 - Señales ML |
| **Tipo** | Especificación Técnica |
| **Versión** | 2.0.0 |
| **Estado** | Implementado |
| **Última actualización** | 2026-01-07 |

---

## Propósito

Especificar los endpoints de la API REST del ML Engine, incluyendo schemas de request/response, validación, autenticación y documentación OpenAPI.

---

## ⚠️ IMPORTANTE: Realidad vs Planificación

Este documento contiene DOS secciones de endpoints:
1. **ENDPOINTS IMPLEMENTADOS** (v2.0.0) - Endpoints reales en producción
2. **ENDPOINTS PLANIFICADOS** (v1.0.0) - Diseño original (para referencia)

---

## Base URL

```
Production:  https://ml.orbiquant.com/
Development: http://localhost:3083/
```

> **NOTA:** La API NO usa versionado en rutas (`/api/v1`). El versionado se maneja via headers.

---

# ENDPOINTS IMPLEMENTADOS (v2.0.0)

Esta sección documenta los endpoints **realmente implementados** en `apps/ml-engine/src/api/main.py`.

## 1. Health & System

### GET /health
Health check básico.

**Response:**
```typescript
{
  status: string;           // "healthy"
  version: string;          // "0.1.0"
  models_loaded: boolean;
  timestamp: string;        // ISO 8601
}
```

### GET /models
Lista modelos disponibles y su estado.

**Response:**
```typescript
Array<{
  model_type: string;       // "range_predictor" | "tpsl_classifier"
  version: string;
  status: string;           // "deployed"
  horizons: string[];       // ["15m", "1h"]
  supported_symbols: string[];
  last_trained?: string;
  metrics?: Record<string, number>;
}>
```

### GET /symbols
Lista símbolos de trading disponibles.

**Response:**
```typescript
["XAUUSD", "EURUSD", "GBPUSD", "USDJPY", "BTCUSD", "ETHUSD"]
```

---

## 2. Predictions

### POST /predict/range
Predice rangos de precio (ΔHigh/ΔLow) para un símbolo.

**Request:**
```typescript
{
  symbol: string;           // "XAUUSD"
  timeframe?: string;       // "5m" | "15m" | "30m" | "1h" | "4h" | "1d" (default: "15m")
  horizon?: string;         // Prediction horizon (default: "15m")
  features?: Record<string, number>;  // Pre-computed features (optional)
}
```

**Response:**
```typescript
Array<{
  horizon: string;
  delta_high: number;
  delta_low: number;
  delta_high_bin?: number;
  delta_low_bin?: number;
  confidence_high: number;
  confidence_low: number;
}>
```

### POST /predict/tpsl
Predice probabilidad de alcanzar TP antes que SL.

**Request:**
```typescript
{
  symbol: string;
  timeframe?: string;       // default: "15m"
  horizon?: string;
}
```

**Query Parameters:**
- `rr_config`: string - "rr_2_1" | "rr_3_1" (default: "rr_2_1")

**Response:**
```typescript
{
  prob_tp_first: number;    // 0.0 - 1.0
  rr_config: string;
  confidence: number;
  calibrated: boolean;
}
```

---

## 3. Signals

### POST /generate/signal
Genera señal de trading completa combinando range prediction, TP/SL y AMD.

**Request:**
```typescript
{
  symbol: string;
  timeframe?: string;
  horizon?: string;
  features?: Record<string, number>;
}
```

**Query Parameters:**
- `rr_config`: string - Risk/Reward config (default: "rr_2_1")

**Response:**
```typescript
{
  signal_id: string;
  symbol: string;
  direction: "long" | "short";
  entry_price: number;
  stop_loss: number;
  take_profit: number;
  risk_reward_ratio: number;
  prob_tp_first: number;
  confidence_score: number;
  amd_phase: "accumulation" | "manipulation" | "distribution" | "unknown";
  volatility_regime: "low" | "medium" | "high" | "extreme";
  range_prediction: RangePredictionResponse;
  timestamp: string;
  valid_until: string;
  metadata?: Record<string, any>;
}
```

### GET /api/signals/active
Obtiene señales activas para múltiples símbolos en paralelo.

**Query Parameters:**
- `symbols`: string - Comma-separated (default: all)
- `timeframe`: string - "15m" | "1h" etc. (default: "15m")
- `rr_config`: string - (default: "rr_2_1")

**Response:**
```typescript
{
  signals: SignalResponse[];
  generated_at: string;
  symbols_processed: string[];
  errors: string[];
}
```

---

## 4. AMD (Accumulation-Manipulation-Distribution)

### POST /api/amd/{symbol}
Detecta fase AMD actual para un símbolo usando Smart Money Concepts.

**Path Parameters:**
- `symbol`: string - Trading symbol

**Query Parameters:**
- `timeframe`: string - (default: "15m")
- `lookback_periods`: number - 50-500 (default: 100)

**Response:**
```typescript
{
  phase: "accumulation" | "manipulation" | "distribution" | "unknown";
  confidence: number;
  start_time: string;
  end_time?: string;
  characteristics: Record<string, number>;
  signals: string[];
  strength: number;
  trading_bias: Record<string, any>;
}
```

---

## 5. ICT/SMC (Inner Circle Trader / Smart Money Concepts)

### POST /api/ict/{symbol}
Análisis ICT/SMC completo detectando Order Blocks, FVG, Liquidity Sweeps, etc.

**Path Parameters:**
- `symbol`: string - Trading symbol

**Query Parameters:**
- `timeframe`: string - (default: "1h")
- `lookback_periods`: number - 100-500 (default: 200)

**Response:**
```typescript
{
  timestamp: string;
  symbol: string;
  timeframe: string;
  market_bias: string;
  bias_confidence: number;
  current_trend: string;
  order_blocks: OrderBlock[];
  fair_value_gaps: FVG[];
  liquidity_sweeps: LiquiditySweep[];
  structure_breaks: StructureBreak[];
  premium_zone: { low: number; high: number };
  discount_zone: { low: number; high: number };
  equilibrium: number;
  entry_zone?: { low: number; high: number };
  stop_loss?: number;
  take_profits: { tp1?: number; tp2?: number; tp3?: number };
  risk_reward?: number;
  signals: string[];
  score: number;
}
```

---

## 6. Ensemble (Multi-Strategy)

### POST /api/ensemble/{symbol}
Obtiene señal combinada del ensemble de estrategias.

Combina:
- AMD Detector (25% weight)
- ICT/SMC Detector (35% weight)
- Range Predictor (20% weight)
- TP/SL Classifier (20% weight)

**Path Parameters:**
- `symbol`: string

**Query Parameters:**
- `timeframe`: string - (default: "1h")

**Response:**
```typescript
{
  timestamp: string;
  symbol: string;
  timeframe: string;
  action: string;
  confidence: number;
  strength: string;
  scores: { bullish: number; bearish: number; net: number };
  levels: { entry?: number; stop_loss?: number; take_profit_1?: number; ... };
  position: { risk_percent: number; size_multiplier: number };
  model_signals: ModelSignal[];
  confluence_count: number;
  market_phase: string;
  market_bias: string;
  key_levels: Record<string, number>;
  signals: string[];
  setup_score: number;
}
```

### GET /api/ensemble/quick/{symbol}
Señal rápida simplificada para consumo inmediato.

**Path Parameters:**
- `symbol`: string

**Query Parameters:**
- `timeframe`: string - (default: "1h")

**Response:** Simplified signal object

---

## 7. Scanner (Multi-Symbol)

### POST /api/scan
Escanea múltiples símbolos buscando oportunidades de trading.

**Request:**
```typescript
{
  symbols: string[];        // ["XAUUSD", "EURUSD", ...]
  timeframe?: string;       // default: "1h"
  min_score?: number;       // 0-100 (default: 50)
}
```

**Response:**
```typescript
{
  timestamp: string;
  signals: QuickSignal[];
  best_setups: QuickSignal[];  // Top 5 by score
  market_overview: {
    total_analyzed: number;
    bullish: number;
    bearish: number;
    neutral: number;
    sentiment: "bullish" | "bearish" | "neutral";
  };
}
```

---

## 8. Training & Backtesting

### POST /api/backtest
Ejecuta backtest en datos históricos (mock implementation).

**Request:**
```typescript
{
  symbol: string;
  start_date: string;
  end_date: string;
  initial_capital?: number;   // default: 10000
  risk_per_trade?: number;    // 0.001-0.1 (default: 0.02)
  rr_config?: string;
  filter_by_amd?: boolean;    // default: true
  min_confidence?: number;    // 0-1 (default: 0.55)
}
```

### POST /api/train/full
Entrena modelos ML con walk-forward validation (mock implementation).

**Request:**
```typescript
{
  symbol: string;
  start_date: string;
  end_date: string;
  models_to_train?: string[];  // default: ["range_predictor", "tpsl_classifier"]
  use_walk_forward?: boolean;  // default: true
  n_splits?: number;           // 2-10 (default: 5)
}
```

---

## 9. WebSocket

### WS /ws/signals
WebSocket para señales en tiempo real.

**Connection:** `ws://localhost:3083/ws/signals`

**Message Format:**
```typescript
{
  type: "signal";
  data: {
    symbol: string;
    direction: string;
    timestamp: string;
  }
}
```

---

# ENDPOINTS PLANIFICADOS (v1.0.0 - Referencia)

Los siguientes endpoints fueron el diseño original pero **NO están implementados** o tienen rutas diferentes:

---

## Autenticación

Todos los endpoints requieren API Key en el header:

```http
X-API-Key: your-api-key-here
```

---

## Endpoints

### 1. Predictions

#### POST /predictions

Genera predicción de rango de precio.

**Request:**
```typescript
{
  symbol: string;      // "BTCUSDT" | "ETHUSDT"
  horizon: number;     // 6 | 18 | 36 | 72 (candles)
}
```

**Response:**
```typescript
{
  success: boolean;
  data: {
    symbol: string;
    horizon: number;
    horizon_label: string;  // "scalping" | "intraday" | "swing" | "position"
    timestamp: string;      // ISO 8601

    current_price: number;
    predicted_high: number;
    predicted_low: number;

    delta_high_percent: number;
    delta_low_percent: number;
    range_percent: number;

    confidence: {
      mae: number;          // Historical MAE for this horizon
      model_version: string;
    };

    expires_at: string;     // ISO 8601 - When this prediction expires
  };
  metadata: {
    request_id: string;
    latency_ms: number;
    cached: boolean;
  };
}
```

**Example:**
```bash
curl -X POST https://ml.trading.com/api/v1/predictions \
  -H "X-API-Key: your-key" \
  -H "Content-Type: application/json" \
  -d '{"symbol": "BTCUSDT", "horizon": 18}'
```

**Response Example:**
```json
{
  "success": true,
  "data": {
    "symbol": "BTCUSDT",
    "horizon": 18,
    "horizon_label": "intraday",
    "timestamp": "2025-12-05T10:30:00Z",
    "current_price": 43250.50,
    "predicted_high": 43520.75,
    "predicted_low": 43012.30,
    "delta_high_percent": 0.625,
    "delta_low_percent": -0.551,
    "range_percent": 1.176,
    "confidence": {
      "mae": 0.32,
      "model_version": "v1.2.0"
    },
    "expires_at": "2025-12-05T12:00:00Z"
  },
  "metadata": {
    "request_id": "req_abc123",
    "latency_ms": 45,
    "cached": false
  }
}
```

---

### 2. Signals

#### POST /signals

Genera señal de trading.

**Request:**
```typescript
{
  symbol: string;
  horizon: number;
  include_range?: boolean;  // Include price range prediction
  include_tpsl?: boolean;   // Include TP/SL prediction
}
```

**Response:**
```typescript
{
  success: boolean;
  data: {
    symbol: string;
    horizon: number;
    timestamp: string;

    signal: {
      type: "buy" | "sell" | "hold";
      confidence: number;       // 0.0 - 1.0
      strength: "weak" | "moderate" | "strong";

      probabilities: {
        hold: number;
        buy: number;
        sell: number;
      };
    };

    price_range?: {             // If include_range = true
      current: number;
      predicted_high: number;
      predicted_low: number;
    };

    tpsl?: {                    // If include_tpsl = true
      prediction: "take_profit" | "stop_loss";
      probability_tp: number;
      probability_sl: number;
      suggested_tp_percent: number;
      suggested_sl_percent: number;
    };

    recommendation: {
      action: "BUY" | "SELL" | "HOLD";
      entry_zone?: {
        min: number;
        max: number;
      };
      take_profit?: number;
      stop_loss?: number;
      risk_reward?: string;     // "1:2.5"
      quality: "low" | "medium" | "high";
      reason: string;
    };
  };
}
```

**Example:**
```bash
curl -X POST https://ml.trading.com/api/v1/signals \
  -H "X-API-Key: your-key" \
  -H "Content-Type: application/json" \
  -d '{"symbol": "BTCUSDT", "horizon": 18, "include_range": true, "include_tpsl": true}'
```

---

#### GET /signals/history

Obtiene historial de señales.

**Query Parameters:**
```
symbol:     string (required)
horizon:    number (optional)
type:       string (optional) - "buy" | "sell" | "hold"
from:       string (optional) - ISO 8601 date
to:         string (optional) - ISO 8601 date
limit:      number (optional) - default 50, max 100
offset:     number (optional) - default 0
```

**Response:**
```typescript
{
  success: boolean;
  data: {
    signals: Array<{
      id: string;
      symbol: string;
      horizon: number;
      type: string;
      confidence: number;
      current_price: number;
      created_at: string;
      outcome?: {
        result: "profit" | "loss" | "pending";
        pnl_percent?: number;
        closed_at?: string;
      };
    }>;
    pagination: {
      total: number;
      limit: number;
      offset: number;
      has_more: boolean;
    };
  };
}
```

---

### 3. Indicators

#### GET /indicators

Obtiene indicadores técnicos actuales.

**Query Parameters:**
```
symbol:     string (required)
indicators: string (optional) - comma-separated list
```

**Response:**
```typescript
{
  success: boolean;
  data: {
    symbol: string;
    timestamp: string;
    price: number;

    indicators: {
      rsi_14: number;
      macd: {
        line: number;
        signal: number;
        histogram: number;
      };
      bollinger: {
        upper: number;
        middle: number;
        lower: number;
        position: number;  // 0-100
      };
      moving_averages: {
        sma_20: number;
        sma_50: number;
        ema_12: number;
        ema_26: number;
      };
      momentum: {
        roc_10: number;
        stochastic_k: number;
        stochastic_d: number;
        williams_r: number;
      };
      volume: {
        current: number;
        avg_20: number;
        ratio: number;
        mfi_14: number;
      };
      volatility: {
        atr_14: number;
        atr_percent: number;
        std_20: number;
      };
    };

    summary: {
      trend: "bullish" | "bearish" | "neutral";
      momentum: "overbought" | "oversold" | "neutral";
      volatility: "high" | "normal" | "low";
    };
  };
}
```

---

### 4. Models

#### GET /models/status

Estado de los modelos cargados.

**Response:**
```typescript
{
  success: boolean;
  data: {
    models: Array<{
      name: string;
      type: "regressor" | "classifier";
      version: string;
      loaded: boolean;
      last_trained: string;

      metrics: {
        accuracy?: number;
        mae?: number;
        f1_score?: number;
      };

      symbols: string[];
      horizons: number[];
    }>;

    system: {
      total_models: number;
      loaded_models: number;
      memory_usage_mb: number;
    };
  };
}
```

#### GET /models/{model_name}/metrics

Métricas detalladas de un modelo.

**Response:**
```typescript
{
  success: boolean;
  data: {
    model_name: string;
    version: string;

    training: {
      samples: number;
      features: number;
      trained_at: string;
      training_time_seconds: number;
    };

    performance: {
      // For regressors
      mae?: number;
      mse?: number;
      rmse?: number;
      mape?: number;

      // For classifiers
      accuracy?: number;
      precision?: number;
      recall?: number;
      f1_score?: number;
      auc?: number;
    };

    feature_importance: Array<{
      feature: string;
      importance: number;
    }>;

    recent_predictions: {
      total: number;
      correct: number;
      accuracy_24h: number;
    };
  };
}
```

---

### 5. Health

#### GET /health

Health check básico.

**Response:**
```typescript
{
  status: "healthy" | "degraded" | "unhealthy";
  timestamp: string;
}
```

#### GET /health/detailed

Health check detallado.

**Response:**
```typescript
{
  status: "healthy" | "degraded" | "unhealthy";
  timestamp: string;

  components: {
    api: {
      status: "up" | "down";
      response_time_ms: number;
    };
    models: {
      status: "up" | "down";
      loaded_count: number;
      total_count: number;
    };
    redis: {
      status: "up" | "down";
      latency_ms: number;
    };
    binance: {
      status: "up" | "down";
      last_price_update: string;
    };
    database: {
      status: "up" | "down";
      connection_pool: {
        active: number;
        idle: number;
        max: number;
      };
    };
  };

  metrics: {
    uptime_seconds: number;
    requests_per_minute: number;
    avg_latency_ms: number;
    error_rate_percent: number;
  };
}
```

---

## Schemas (Pydantic)

```python
# app/schemas/prediction.py
from pydantic import BaseModel, Field, validator
from typing import Optional, Literal
from datetime import datetime

class PredictionRequest(BaseModel):
    symbol: str = Field(..., description="Trading pair symbol")
    horizon: int = Field(..., description="Prediction horizon in candles")

    @validator('symbol')
    def validate_symbol(cls, v):
        valid_symbols = ['BTCUSDT', 'ETHUSDT']
        if v not in valid_symbols:
            raise ValueError(f'Symbol must be one of: {valid_symbols}')
        return v

    @validator('horizon')
    def validate_horizon(cls, v):
        valid_horizons = [6, 18, 36, 72]
        if v not in valid_horizons:
            raise ValueError(f'Horizon must be one of: {valid_horizons}')
        return v

    class Config:
        schema_extra = {
            "example": {
                "symbol": "BTCUSDT",
                "horizon": 18
            }
        }

class PredictionConfidence(BaseModel):
    mae: float
    model_version: str

class PredictionData(BaseModel):
    symbol: str
    horizon: int
    horizon_label: str
    timestamp: datetime

    current_price: float
    predicted_high: float
    predicted_low: float

    delta_high_percent: float
    delta_low_percent: float
    range_percent: float

    confidence: PredictionConfidence
    expires_at: datetime

class ResponseMetadata(BaseModel):
    request_id: str
    latency_ms: int
    cached: bool

class PredictionResponse(BaseModel):
    success: bool
    data: PredictionData
    metadata: ResponseMetadata
```

```python
# app/schemas/signal.py
from pydantic import BaseModel, Field
from typing import Optional, Literal
from datetime import datetime

class SignalRequest(BaseModel):
    symbol: str
    horizon: int
    include_range: bool = False
    include_tpsl: bool = False

class SignalProbabilities(BaseModel):
    hold: float
    buy: float
    sell: float

class Signal(BaseModel):
    type: Literal["buy", "sell", "hold"]
    confidence: float = Field(..., ge=0, le=1)
    strength: Literal["weak", "moderate", "strong"]
    probabilities: SignalProbabilities

class PriceRange(BaseModel):
    current: float
    predicted_high: float
    predicted_low: float

class TPSL(BaseModel):
    prediction: Literal["take_profit", "stop_loss"]
    probability_tp: float
    probability_sl: float
    suggested_tp_percent: float
    suggested_sl_percent: float

class EntryZone(BaseModel):
    min: float
    max: float

class Recommendation(BaseModel):
    action: Literal["BUY", "SELL", "HOLD"]
    entry_zone: Optional[EntryZone]
    take_profit: Optional[float]
    stop_loss: Optional[float]
    risk_reward: Optional[str]
    quality: Literal["low", "medium", "high"]
    reason: str

class SignalData(BaseModel):
    symbol: str
    horizon: int
    timestamp: datetime
    signal: Signal
    price_range: Optional[PriceRange]
    tpsl: Optional[TPSL]
    recommendation: Recommendation

class SignalResponse(BaseModel):
    success: bool
    data: SignalData
```

---

## Router Implementation

```python
# app/api/routers/predictions.py
from fastapi import APIRouter, Depends, HTTPException
from app.schemas.prediction import PredictionRequest, PredictionResponse
from app.services.predictor import PredictorService
from app.core.security import validate_api_key
from app.core.rate_limit import limiter
import uuid
import time

router = APIRouter()

@router.post("", response_model=PredictionResponse)
@limiter.limit("100/minute")
async def create_prediction(
    request: PredictionRequest,
    api_key: str = Depends(validate_api_key),
    predictor: PredictorService = Depends()
):
    """
    Generate price range prediction for a trading pair.

    - **symbol**: Trading pair (BTCUSDT, ETHUSDT)
    - **horizon**: Prediction horizon in 5-minute candles (6, 18, 36, 72)
    """
    start_time = time.time()
    request_id = str(uuid.uuid4())[:8]

    try:
        prediction, cached = await predictor.predict(
            symbol=request.symbol,
            horizon=request.horizon
        )

        latency_ms = int((time.time() - start_time) * 1000)

        return PredictionResponse(
            success=True,
            data=prediction,
            metadata={
                "request_id": f"req_{request_id}",
                "latency_ms": latency_ms,
                "cached": cached
            }
        )

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
```

```python
# app/api/routers/signals.py
from fastapi import APIRouter, Depends, Query
from typing import Optional, List
from app.schemas.signal import SignalRequest, SignalResponse, SignalHistoryResponse
from app.services.signal_generator import SignalGeneratorService
from app.core.security import validate_api_key

router = APIRouter()

@router.post("", response_model=SignalResponse)
async def generate_signal(
    request: SignalRequest,
    api_key: str = Depends(validate_api_key),
    signal_gen: SignalGeneratorService = Depends()
):
    """Generate trading signal with optional range and TP/SL predictions."""
    return await signal_gen.generate(
        symbol=request.symbol,
        horizon=request.horizon,
        include_range=request.include_range,
        include_tpsl=request.include_tpsl
    )

@router.get("/history")
async def get_signal_history(
    symbol: str,
    horizon: Optional[int] = None,
    type: Optional[str] = Query(None, regex="^(buy|sell|hold)$"),
    limit: int = Query(50, le=100),
    offset: int = 0,
    api_key: str = Depends(validate_api_key),
    signal_gen: SignalGeneratorService = Depends()
):
    """Get historical signals with optional filters."""
    return await signal_gen.get_history(
        symbol=symbol,
        horizon=horizon,
        signal_type=type,
        limit=limit,
        offset=offset
    )
```

---

## Error Responses

```python
# app/core/exceptions.py
from fastapi import HTTPException

class APIError(HTTPException):
    """Base API error"""
    pass

class ValidationError(APIError):
    def __init__(self, detail: str):
        super().__init__(status_code=400, detail=detail)

class AuthenticationError(APIError):
    def __init__(self):
        super().__init__(status_code=401, detail="Invalid API key")

class RateLimitError(APIError):
    def __init__(self):
        super().__init__(status_code=429, detail="Rate limit exceeded")

class ModelError(APIError):
    def __init__(self, detail: str):
        super().__init__(status_code=500, detail=f"Model error: {detail}")
```

**Error Response Format:**
```json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Symbol XYZUSDT is not supported",
    "details": {
      "field": "symbol",
      "valid_values": ["BTCUSDT", "ETHUSDT"]
    }
  },
  "metadata": {
    "request_id": "req_abc123",
    "timestamp": "2025-12-05T10:30:00Z"
  }
}
```

---

## Rate Limits

| Endpoint | Limit | Window |
|----------|-------|--------|
| POST /predictions | 100 | 1 minute |
| POST /signals | 100 | 1 minute |
| GET /signals/history | 60 | 1 minute |
| GET /indicators | 120 | 1 minute |
| GET /models/* | 30 | 1 minute |
| GET /health | Unlimited | - |

---

# RESUMEN DE DISCREPANCIAS

## Endpoints Documentados vs Implementados

| Endpoint Original | Estado | Endpoint Real |
|-------------------|--------|---------------|
| `POST /api/v1/predictions` | ⚠️ Diferente ruta | `POST /predict/range` |
| `POST /api/v1/signals` | ⚠️ Diferente ruta | `POST /generate/signal` |
| `GET /api/v1/signals/history` | ❌ No implementado | - |
| `GET /api/v1/indicators` | ❌ No implementado | - |
| `GET /api/v1/models/status` | ⚠️ Diferente ruta | `GET /models` |
| `GET /api/v1/models/{name}/metrics` | ❌ No implementado | - |
| `GET /api/v1/health` | ⚠️ Sin versioning | `GET /health` |
| `GET /api/v1/health/detailed` | ❌ No implementado | - |

## Endpoints Nuevos (No Documentados Originalmente)

| Endpoint | Descripción |
|----------|-------------|
| `POST /predict/tpsl` | Predicción TP/SL |
| `GET /symbols` | Lista de símbolos |
| `GET /api/signals/active` | Señales activas multi-símbolo |
| `POST /api/amd/{symbol}` | Detección AMD |
| `POST /api/ict/{symbol}` | Análisis ICT/SMC |
| `POST /api/ensemble/{symbol}` | Señal ensemble |
| `GET /api/ensemble/quick/{symbol}` | Señal rápida |
| `POST /api/scan` | Scanner multi-símbolo |
| `POST /api/backtest` | Backtesting |
| `POST /api/train/full` | Entrenamiento |
| `WS /ws/signals` | WebSocket tiempo real |

## Cambios Arquitectónicos

1. **Sin versionado de URL**: La API no usa `/api/v1/` en las rutas
2. **Autenticación**: API Key via header aún no implementado (CORS abierto en dev)
3. **Rate Limiting**: Pendiente de implementar
4. **Símbolos soportados**: XAUUSD, EURUSD, GBPUSD, USDJPY, BTCUSD, ETHUSD (no BTCUSDT/ETHUSDT)

---

## Referencias

- [ET-ML-001: Arquitectura](./ET-ML-001-arquitectura.md)
- [FastAPI Documentation](https://fastapi.tiangolo.com/)
- [OpenAPI Specification](https://swagger.io/specification/)
- **Código fuente**: `apps/ml-engine/src/api/main.py`

---

## Changelog

| Fecha | Versión | Cambio |
|-------|---------|--------|
| 2026-01-07 | 2.0.0 | Actualización completa con endpoints reales implementados |
| 2026-01-07 | 2.0.0 | Separación en secciones IMPLEMENTADOS vs PLANIFICADOS |
| 2026-01-07 | 2.0.0 | Documentación de 11 nuevos endpoints |
| 2025-12-05 | 1.0.0 | Creación inicial con diseño planificado |

---

**Autor:** Requirements-Analyst / ML-Architect
**Última actualización:** 2026-01-07
