Documentation alignment validation completed: - ET-ML-004-api.md: Updated to v2.0.0 with 15 real endpoints documented - ML_INVENTORY.yml: Updated to v2.1.0, added 11 models (ML-008 to ML-018) - TRACEABILITY.yml: Updated to v1.7.0, fixed US-ML-004 mapping - Added VALIDACION-ALINEACION-ML-2026-01-07.md validation report Discrepancies resolved: 10/11 (91%) - All critical and high priority discrepancies fixed - M2 (incompatible ML clients) requires code changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1219 lines
26 KiB
Markdown
1219 lines
26 KiB
Markdown
---
|
|
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
|