trading-platform/docs/01-arquitectura/INTEGRACION-LLM-FINE-TUNING.md
rckrdmrd c1b5081208 feat(ml): Complete FASE 11 - BTCUSD update and comprehensive documentation alignment
ML Engine Updates:
- Updated BTCUSD with Polygon API data (2024-2025): 215,699 new records
- Re-trained all ML models: Attention (R²: 0.223), Base, Metamodel (87.3% confidence)
- Backtest results: +176.71R profit with aggressive_filter strategy

Documentation Consolidation:
- Created docs/99-analisis/_MAP.md index with 13 new analysis documents
- Consolidated inventories: removed duplicates from orchestration/inventarios/
- Updated ML_INVENTORY.yml with BTCUSD metrics and training results
- Added execution reports: FASE11-BTCUSD, correction issues, alignment validation

Architecture & Integration:
- Updated all module documentation with NEXUS v3.4 frontmatter
- Fixed _MAP.md indexes across all folders
- Updated orchestration plans and traces

Files: 229 changed, 5064 insertions(+), 1872 deletions(-)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 09:31:29 -06:00

1700 lines
60 KiB
Markdown

---
id: "INTEGRACION-LLM-FINE-TUNING"
title: "Integracion LLM con Fine-Tuning para Trading Agent"
type: "Documentation"
project: "trading-platform"
version: "1.0.0"
created_date: "2026-01-04"
updated_date: "2026-01-04"
author: "Orquestador Agent - Trading Platform"
---
# Integracion LLM con Fine-Tuning para Trading Agent
**Version:** 1.0.0
**Fecha:** 2026-01-04
**Modulo:** OQI-010-llm-trading-integration
**Hardware:** GPU NVIDIA 16GB VRAM
---
## Tabla de Contenidos
1. [Vision General](#vision-general)
2. [Arquitectura Unificada](#arquitectura-unificada)
3. [Modelo LLM y Fine-Tuning](#modelo-llm-y-fine-tuning)
4. [Integracion MCP Servers](#integracion-mcp-servers)
5. [Gestion de Riesgo](#gestion-de-riesgo)
6. [Analisis de Predicciones ML](#analisis-de-predicciones-ml)
7. [API para Frontend](#api-para-frontend)
8. [Persistencia en PostgreSQL](#persistencia-en-postgresql)
9. [Pipeline de Fine-Tuning](#pipeline-de-fine-tuning)
10. [Implementacion](#implementacion)
11. [Testing y Validacion](#testing-y-validacion)
---
## Vision General
### Objetivo
Crear un agente LLM inteligente que funcione como cerebro del sistema de trading, capaz de:
1. **Analizar y explicar** predicciones de los modelos ML (AMD, ICT/SMC, Range Predictor)
2. **Gestionar riesgo** de forma autonoma con reglas configurables
3. **Orquestar operaciones** via MCP servers (MT4 y Binance)
4. **Tomar decisiones** basadas en confluencia de senales
5. **Aprender y adaptarse** mediante fine-tuning con datos de estrategias
### Flujo de Alto Nivel
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ LLM TRADING AGENT │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ LAYER 1: INPUT SOURCES │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ ML Engine │ │ Market │ │ User │ │ Portfolio │ │ │
│ │ │ Signals │ │ Data │ │ Commands │ │ State │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ └─────────┼────────────────┼────────────────┼────────────────┼──────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ LAYER 2: LLM CORE (Fine-Tuned) │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ chatgpt-oss / Llama 3 8B │ │ │
│ │ │ Fine-tuned with Trading Strategies │ │ │
│ │ │ 16GB VRAM Local GPU │ │ │
│ │ └──────────────────────────────┬──────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌──────────────────────────────▼──────────────────────────────────────┐ │ │
│ │ │ REASONING ENGINE │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ AMD/ICT │ │ Risk │ │ Decision │ │ │ │
│ │ │ │ Analysis │ │ Assessment │ │ Making │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ LAYER 3: ACTION LAYER │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │MCP MT4 │ │MCP Binance │ │ Risk │ │ Alert │ │ │
│ │ │Connector │ │Connector │ │ Manager │ │ System │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ └─────────┼────────────────┼────────────────┼────────────────┼──────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ LAYER 4: PERSISTENCE │ │
│ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │
│ │ │ PostgreSQL (Schema: llm + ml) │ │ │
│ │ │ - Predictions - Decisions - Risk Events - Trade History │ │ │
│ │ └─────────────────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
```
---
## Arquitectura Unificada
### Componentes del Sistema
```
┌──────────────────────────────────────────────────────────────────────────────┐
│ COMPONENTES PRINCIPALES │
├──────────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. LLM SERVICE (apps/llm-agent/) │
│ ├── Core LLM Engine (chatgpt-oss fine-tuned) │
│ ├── Trading Tools (12+ herramientas) │
│ ├── Context Manager (Redis) │
│ ├── Risk Assessment Module (NUEVO) │
│ └── MCP Orchestrator (NUEVO) │
│ │
│ 2. MCP SERVERS │
│ ├── mcp-mt4-connector/ (existente) │
│ │ └── 6 tools: account, positions, quotes, trading │
│ └── mcp-binance-connector/ (NUEVO) │
│ └── 8 tools: market, account, orders, positions │
│ │
│ 3. ML ENGINE (apps/ml-engine/) │
│ ├── AMD Detector │
│ ├── Range Predictor │
│ ├── Signal Generator │
│ ├── ICT/SMC Detector │
│ └── Predictions API │
│ │
│ 4. RISK MANAGEMENT SERVICE (NUEVO) │
│ ├── Position Sizing Calculator │
│ ├── Drawdown Monitor │
│ ├── Exposure Tracker │
│ └── Circuit Breaker │
│ │
│ 5. PERSISTENCE LAYER │
│ ├── PostgreSQL (predictions, decisions, risk_events) │
│ └── Redis (context, sessions, cache) │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```
### Puertos y Servicios
| Servicio | Puerto | Descripcion |
|----------|--------|-------------|
| Frontend | 3080 | React SPA |
| Backend API | 3081 | Express.js REST |
| WebSocket | 3082 | Real-time updates |
| ML Engine | 3083 | FastAPI predictions |
| Data Service | 3084 | Market data |
| LLM Agent | 3085 | Trading copilot |
| Trading Agents | 3086 | Atlas, Orion, Nova |
| MCP MT4 | 3605 | MT4 connector |
| MCP Binance | 3606 | Binance connector (NUEVO) |
| Ollama | 11434 | LLM inference |
| PostgreSQL | 5432 | Database |
| Redis | 6379 | Cache |
---
## Modelo LLM y Fine-Tuning
### Modelo Base Recomendado
Para 16GB de VRAM, las opciones son:
| Modelo | VRAM | Context | Ventajas | Fine-Tuning |
|--------|------|---------|----------|-------------|
| **Llama 3 8B** | 10GB | 8K | Balance calidad/velocidad | LoRA |
| **Mistral 7B** | 8GB | 8K | Rapido, buena calidad | LoRA |
| **Qwen2 7B** | 9GB | 32K | Largo contexto | LoRA |
| **Phi-3 Medium** | 7GB | 4K | Eficiente, razonamiento | LoRA |
**Recomendacion:** Llama 3 8B con quantizacion Q5_K_M para fine-tuning con LoRA.
### Dataset de Fine-Tuning
El fine-tuning se realizara con definiciones de estrategias de trading:
```yaml
# Estructura del dataset de fine-tuning
dataset:
name: trading_data_strategies_v1
format: JSONL
categories:
- amd_phases:
description: "Fases Accumulation-Manipulation-Distribution"
samples: 5000+
- ict_concepts:
description: "Conceptos ICT/SMC (OTE, FVG, BOS, CHOCH)"
samples: 3000+
- risk_management:
description: "Reglas de gestion de riesgo"
samples: 2000+
- trade_decisions:
description: "Decisiones de trading con razonamiento"
samples: 10000+
- market_analysis:
description: "Analisis de mercado y contexto"
samples: 5000+
```
### Formato del Dataset
```jsonl
{"instruction": "Analiza esta senal de trading y determina si es una buena entrada", "input": "Simbolo: XAUUSD, Fase AMD: Accumulation (78% confianza), Killzone: London Open, RSI: 42, MACD: positivo, Precio cerca de soporte", "output": "ANALISIS:\n\n1. FASE AMD: Accumulation (78%)\n - Las instituciones estan acumulando posiciones largas\n - Esta es una fase FAVORABLE para entradas LONG\n\n2. KILLZONE: London Open\n - Alta liquidez y probabilidad de movimiento direccional\n - Horario optimo para entradas\n\n3. INDICADORES:\n - RSI 42: Zona neutral, no sobrecomprado\n - MACD positivo: Momentum alcista\n\n4. ESTRUCTURA:\n - Precio cerca de soporte: Punto de entrada con riesgo definido\n\nDECISION: LONG recomendado\n- Entry: Nivel de soporte actual\n- Stop Loss: 1-2% debajo del soporte\n- Take Profit: Siguiente resistencia (R:R minimo 1:2)\n\nRIESGO: 2% maximo del capital"}
{"instruction": "Que accion tomar cuando el mercado esta en fase de Manipulation?", "input": "Fase AMD actual: Manipulation (85%), precio haciendo spike hacia arriba, volume bajo", "output": "ALERTA: FASE DE MANIPULACION DETECTADA\n\n1. ACCION RECOMENDADA: NO OPERAR / ESPERAR\n\n2. RAZONAMIENTO:\n - La fase de Manipulation (85% confianza) indica caza de stops\n - Los spikes con bajo volumen son senales clasicas de manipulacion\n - Las instituciones estan barriendo liquidez antes del movimiento real\n\n3. QUE ESPERAR:\n - Transicion a fase de Distribution o Re-accumulation\n - Confirmacion de direccion con volumen\n - Nueva estructura de mercado clara\n\n4. REGLA DE RIESGO:\n - NUNCA entrar durante Manipulation\n - Si hay posiciones abiertas: ajustar stops, considerar cierre parcial\n\nESTADO: STANDBY - Esperar siguiente fase"}
```
### Proceso de Fine-Tuning
```python
# fine_tuning/train_lora.py
from datasets import load_dataset
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer
# Configuracion LoRA para 16GB VRAM
lora_config = LoraConfig(
r=16, # Rank de LoRA
lora_alpha=32, # Scaling factor
target_modules=[
"q_proj", "k_proj", "v_proj",
"o_proj", "gate_proj", "up_proj", "down_proj"
],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
# Training config optimizado para GPU 16GB
training_args = TrainingArguments(
output_dir="./trading-llm-finetuned",
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
num_train_epochs=3,
learning_rate=2e-4,
fp16=True, # Mixed precision para ahorrar VRAM
logging_steps=10,
save_strategy="epoch",
evaluation_strategy="epoch",
warmup_ratio=0.1,
optim="adamw_8bit", # Optimizer de 8 bits
max_grad_norm=0.3,
)
# Metricas de evaluacion
def compute_metrics(eval_preds):
# Evaluar calidad de decisiones de trading
pass
```
---
## Integracion MCP Servers
### MCP MT4 Connector (Existente)
Ya implementado en `apps/mcp-mt4-connector/`:
```typescript
// Tools disponibles
const MT4_TOOLS = [
"mt4_get_account", // Balance, equity, margin
"mt4_get_positions", // Posiciones abiertas
"mt4_get_quote", // Precio bid/ask
"mt4_execute_trade", // Ejecutar orden
"mt4_close_position", // Cerrar posicion
"mt4_modify_position" // Modificar SL/TP
];
```
### MCP Binance Connector (NUEVO)
Nueva app a crear en `apps/mcp-binance-connector/`:
```
mcp-binance-connector/
├── src/
│ ├── index.ts # Entry point
│ ├── config.ts # Configuration
│ ├── services/
│ │ └── binance-client.ts # CCXT wrapper
│ └── tools/
│ ├── index.ts # Tool registry
│ ├── market.ts # Market data tools
│ ├── account.ts # Account info
│ ├── orders.ts # Order management
│ └── positions.ts # Position tracking
├── docs/
│ ├── ARCHITECTURE.md
│ └── MCP-TOOLS-SPEC.md
├── package.json
├── tsconfig.json
└── README.md
```
### Tools del MCP Binance
```typescript
// tools/index.ts
export const BINANCE_TOOLS = [
// Market Data (Read-only, bajo riesgo)
{
name: "binance_get_ticker",
description: "Obtiene precio actual de un simbolo",
parameters: {
symbol: { type: "string", required: true }
},
risk: "low"
},
{
name: "binance_get_orderbook",
description: "Obtiene order book con profundidad",
parameters: {
symbol: { type: "string", required: true },
limit: { type: "number", default: 20 }
},
risk: "low"
},
{
name: "binance_get_klines",
description: "Obtiene velas historicas",
parameters: {
symbol: { type: "string", required: true },
interval: { type: "string", enum: ["1m","5m","15m","1h","4h","1d"] },
limit: { type: "number", default: 100 }
},
risk: "low"
},
// Account Info (Read-only, bajo riesgo)
{
name: "binance_get_account",
description: "Obtiene balance y estado de cuenta",
parameters: {},
risk: "low"
},
{
name: "binance_get_positions",
description: "Obtiene posiciones abiertas (futures)",
parameters: {},
risk: "low"
},
// Order Management (Alto riesgo, requiere confirmacion)
{
name: "binance_create_order",
description: "Crea orden de mercado o limite",
parameters: {
symbol: { type: "string", required: true },
side: { type: "string", enum: ["BUY", "SELL"], required: true },
type: { type: "string", enum: ["MARKET", "LIMIT", "STOP_MARKET"] },
quantity: { type: "number", required: true },
price: { type: "number" },
stopPrice: { type: "number" }
},
risk: "high",
requiresConfirmation: true
},
{
name: "binance_cancel_order",
description: "Cancela orden pendiente",
parameters: {
symbol: { type: "string", required: true },
orderId: { type: "string", required: true }
},
risk: "medium"
},
{
name: "binance_close_position",
description: "Cierra posicion completa",
parameters: {
symbol: { type: "string", required: true }
},
risk: "high",
requiresConfirmation: true
}
];
```
### Orquestacion de MCP desde LLM
```python
# core/mcp_orchestrator.py
from typing import Dict, Any, List
import httpx
class MCPOrchestrator:
"""
Orquesta llamadas a multiples MCP servers
"""
def __init__(self, config: Dict):
self.mt4_url = config.get('mcp_mt4_url', 'http://localhost:3605')
self.binance_url = config.get('mcp_binance_url', 'http://localhost:3606')
async def call_tool(
self,
server: str, # "mt4" or "binance"
tool: str,
params: Dict
) -> Dict[str, Any]:
"""
Llama a una herramienta MCP
"""
url = self.mt4_url if server == "mt4" else self.binance_url
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(
f"{url}/tools/{tool}",
json=params
)
return response.json()
async def get_combined_portfolio(self) -> Dict[str, Any]:
"""
Obtiene portfolio combinado de MT4 y Binance
"""
mt4_account = await self.call_tool("mt4", "mt4_get_account", {})
binance_account = await self.call_tool("binance", "binance_get_account", {})
return {
"mt4": mt4_account,
"binance": binance_account,
"total_equity": mt4_account.get("equity", 0) + binance_account.get("total_balance", 0)
}
async def execute_trade_on_best_venue(
self,
symbol: str,
action: str,
size: float,
stop_loss: float,
take_profit: float
) -> Dict[str, Any]:
"""
Ejecuta trade en el mejor venue disponible
"""
# Logica para determinar mejor venue
# MT4 para forex/metales, Binance para crypto
if symbol in ["XAUUSD", "EURUSD", "GBPUSD", "USDJPY"]:
return await self.call_tool("mt4", "mt4_execute_trade", {
"symbol": symbol,
"action": action,
"size": size,
"stop_loss": stop_loss,
"take_profit": take_profit
})
else:
return await self.call_tool("binance", "binance_create_order", {
"symbol": symbol,
"side": action,
"type": "MARKET",
"quantity": size
})
```
---
## Gestion de Riesgo
### Risk Manager Integrado
```python
# services/risk_manager.py
from typing import Dict, Any, Optional
from dataclasses import dataclass
from enum import Enum
class RiskLevel(Enum):
MINIMAL = "minimal" # 0.5% max per trade
CONSERVATIVE = "conservative" # 1% max per trade
MODERATE = "moderate" # 2% max per trade
AGGRESSIVE = "aggressive" # 3% max per trade
@dataclass
class RiskLimits:
max_position_size_pct: float # % del capital por posicion
max_daily_drawdown_pct: float # % max perdida diaria
max_total_exposure_pct: float # % max exposicion total
max_correlated_positions: int # Max posiciones correlacionadas
max_trades_per_day: int # Max trades por dia
class RiskManager:
"""
Gestor de riesgo integrado con el LLM Agent
"""
# Limites por nivel de riesgo
RISK_PROFILES = {
RiskLevel.MINIMAL: RiskLimits(
max_position_size_pct=0.5,
max_daily_drawdown_pct=1.0,
max_total_exposure_pct=5.0,
max_correlated_positions=2,
max_trades_per_day=3
),
RiskLevel.CONSERVATIVE: RiskLimits(
max_position_size_pct=1.0,
max_daily_drawdown_pct=2.0,
max_total_exposure_pct=10.0,
max_correlated_positions=3,
max_trades_per_day=5
),
RiskLevel.MODERATE: RiskLimits(
max_position_size_pct=2.0,
max_daily_drawdown_pct=5.0,
max_total_exposure_pct=20.0,
max_correlated_positions=5,
max_trades_per_day=10
),
RiskLevel.AGGRESSIVE: RiskLimits(
max_position_size_pct=3.0,
max_daily_drawdown_pct=10.0,
max_total_exposure_pct=30.0,
max_correlated_positions=8,
max_trades_per_day=20
)
}
def __init__(self, risk_level: RiskLevel, capital: float):
self.risk_level = risk_level
self.limits = self.RISK_PROFILES[risk_level]
self.capital = capital
self.daily_pnl = 0.0
self.current_exposure = 0.0
self.trades_today = 0
def can_open_position(
self,
position_size: float,
stop_loss_pips: float,
pip_value: float
) -> Dict[str, Any]:
"""
Verifica si se puede abrir una nueva posicion
"""
# Calcular riesgo de la posicion
position_risk = stop_loss_pips * pip_value * position_size
position_risk_pct = (position_risk / self.capital) * 100
checks = {
"position_size_ok": position_risk_pct <= self.limits.max_position_size_pct,
"daily_drawdown_ok": abs(self.daily_pnl) < self.limits.max_daily_drawdown_pct,
"exposure_ok": self.current_exposure + position_risk_pct <= self.limits.max_total_exposure_pct,
"trades_limit_ok": self.trades_today < self.limits.max_trades_per_day
}
return {
"allowed": all(checks.values()),
"checks": checks,
"position_risk_pct": position_risk_pct,
"recommended_size": self._calculate_safe_size(stop_loss_pips, pip_value)
}
def _calculate_safe_size(
self,
stop_loss_pips: float,
pip_value: float
) -> float:
"""
Calcula tamano de posicion seguro basado en limites
"""
max_risk = self.capital * (self.limits.max_position_size_pct / 100)
safe_size = max_risk / (stop_loss_pips * pip_value)
return round(safe_size, 2)
def check_circuit_breaker(self) -> Dict[str, Any]:
"""
Verifica si se activa el circuit breaker
"""
daily_loss_pct = abs(self.daily_pnl)
if daily_loss_pct >= self.limits.max_daily_drawdown_pct:
return {
"triggered": True,
"reason": "daily_drawdown_limit",
"message": f"Se alcanzo el limite de perdida diaria ({daily_loss_pct:.2f}%)",
"action": "STOP_TRADING"
}
if daily_loss_pct >= self.limits.max_daily_drawdown_pct * 0.8:
return {
"triggered": False,
"warning": True,
"message": f"Cerca del limite de perdida diaria ({daily_loss_pct:.2f}%)",
"action": "REDUCE_RISK"
}
return {"triggered": False, "warning": False}
```
### Reglas de Riesgo para LLM
```python
# prompts/risk_rules.py
RISK_RULES_PROMPT = """
## REGLAS DE GESTION DE RIESGO (OBLIGATORIAS)
Como Trading Agent, DEBES seguir estas reglas de riesgo SIEMPRE:
### 1. TAMANO DE POSICION
- NUNCA arriesgar mas del {max_position_pct}% del capital en una operacion
- Calcular tamano basado en distancia al stop loss
- Formula: Size = (Capital * Risk%) / (StopLoss_pips * Pip_value)
### 2. DRAWDOWN DIARIO
- Limite de perdida diaria: {max_daily_dd}%
- Si se alcanza, DETENER operaciones por el resto del dia
- Alertar al usuario cuando llegue al 80% del limite
### 3. EXPOSICION TOTAL
- Maximo {max_exposure}% del capital expuesto simultaneamente
- Incluye todas las posiciones abiertas
- Considerar correlacion entre pares
### 4. STOP LOSS OBLIGATORIO
- TODA operacion DEBE tener stop loss definido
- NUNCA mover stop loss hacia atras (aumentar riesgo)
- Solo mover a breakeven o trailing
### 5. CORRELACION
- Maximo {max_correlated} posiciones correlacionadas
- EUR/USD y GBP/USD se consideran correlacionados
- BTC y ETH se consideran correlacionados
### 6. CIRCUIT BREAKER
- Despues de {max_consecutive_losses} perdidas consecutivas: pausa 1 hora
- Despues de alcanzar daily DD: stop hasta manana
- KILL SWITCH manual siempre disponible
### FORMATO DE RESPUESTA CUANDO SE EJECUTA TRADE:
**VALIDACION DE RIESGO:**
- Tamano posicion: {size} lots = {risk_pct}% del capital
- Exposicion actual: {current_exp}% -> {new_exp}%
- Trades hoy: {trades_today} de {max_trades}
- Estado: [APROBADO/RECHAZADO]
"""
```
---
## Analisis de Predicciones ML
### Integracion ML Engine
```python
# services/ml_analyzer.py
from typing import Dict, Any, List
import httpx
class MLAnalyzer:
"""
Analiza y procesa predicciones del ML Engine
"""
def __init__(self, ml_engine_url: str = "http://localhost:3083"):
self.ml_engine_url = ml_engine_url
async def get_full_analysis(self, symbol: str) -> Dict[str, Any]:
"""
Obtiene analisis completo de todos los modelos ML
"""
async with httpx.AsyncClient(timeout=30.0) as client:
# Obtener predicciones de todos los modelos
tasks = [
client.get(f"{self.ml_engine_url}/api/amd_phase", params={"symbol": symbol}),
client.get(f"{self.ml_engine_url}/api/range", params={"symbol": symbol}),
client.get(f"{self.ml_engine_url}/api/signal", params={"symbol": symbol}),
client.get(f"{self.ml_engine_url}/api/ict_context", params={"symbol": symbol}),
]
responses = await asyncio.gather(*tasks)
return {
"symbol": symbol,
"amd_phase": responses[0].json(),
"range_prediction": responses[1].json(),
"signal": responses[2].json(),
"ict_context": responses[3].json(),
"confluence_score": self._calculate_confluence(responses)
}
def _calculate_confluence(self, predictions: List) -> float:
"""
Calcula score de confluencia entre modelos
"""
amd = predictions[0].json()
signal = predictions[2].json()
ict = predictions[3].json()
score = 0.0
# AMD en fase favorable
if amd.get("phase") in ["accumulation", "re_accumulation"]:
if signal.get("direction") == "LONG":
score += 0.3
elif amd.get("phase") == "distribution":
if signal.get("direction") == "SHORT":
score += 0.3
# Killzone activa
if ict.get("killzone_active"):
score += 0.2
# OTE zone correcta
if ict.get("ote_zone") == "discount" and signal.get("direction") == "LONG":
score += 0.2
elif ict.get("ote_zone") == "premium" and signal.get("direction") == "SHORT":
score += 0.2
# Confianza del modelo
signal_confidence = signal.get("confidence", 0)
score += signal_confidence * 0.3
return min(score, 1.0)
def generate_explanation(self, analysis: Dict[str, Any]) -> str:
"""
Genera explicacion en lenguaje natural del analisis
"""
amd = analysis["amd_phase"]
signal = analysis["signal"]
ict = analysis["ict_context"]
confluence = analysis["confluence_score"]
explanation = f"""
## Analisis ML para {analysis["symbol"]}
### 1. Fase AMD
- Fase actual: **{amd.get("phase", "N/A")}** ({amd.get("confidence", 0)*100:.1f}% confianza)
- Interpretacion: {self._explain_amd_phase(amd.get("phase"))}
### 2. Senal de Trading
- Direccion: **{signal.get("direction", "N/A")}**
- Confianza: {signal.get("confidence", 0)*100:.1f}%
- Entry: {signal.get("entry_price", "N/A")}
- Stop Loss: {signal.get("stop_loss", "N/A")}
- Take Profit: {signal.get("take_profit", "N/A")}
### 3. Contexto ICT/SMC
- Killzone: {ict.get("killzone", "None")} {"(ACTIVA)" if ict.get("killzone_active") else ""}
- Zona OTE: {ict.get("ote_zone", "N/A")}
- FVG detectado: {"Si" if ict.get("fvg_present") else "No"}
### 4. Score de Confluencia
**{confluence*100:.0f}%** - {"Alta confluencia, senal fuerte" if confluence > 0.7 else "Confluencia media" if confluence > 0.5 else "Baja confluencia, precaucion"}
"""
return explanation
def _explain_amd_phase(self, phase: str) -> str:
explanations = {
"accumulation": "Las instituciones estan acumulando. Favorable para LONG.",
"manipulation": "Fase de caza de stops. EVITAR nuevas entradas.",
"distribution": "Las instituciones estan distribuyendo. Favorable para SHORT.",
"re_accumulation": "Consolidacion antes de continuacion alcista."
}
return explanations.get(phase, "Fase no identificada")
```
---
## API para Frontend
### Endpoints de Predicciones
```python
# api/predictions.py
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
from typing import List, Optional
router = APIRouter(prefix="/api/v1/predictions", tags=["predictions"])
class PredictionRequest(BaseModel):
symbol: str
timeframe: str = "5m"
class PredictionResponse(BaseModel):
symbol: str
timestamp: str
amd_phase: dict
signal: dict
range_prediction: dict
ict_context: dict
confluence_score: float
explanation: str
risk_assessment: dict
class HistoricalPrediction(BaseModel):
id: str
symbol: str
timestamp: str
prediction: dict
outcome: Optional[dict] = None
accuracy: Optional[float] = None
@router.post("/analyze", response_model=PredictionResponse)
async def analyze_symbol(request: PredictionRequest):
"""
Analiza un simbolo con todos los modelos ML
y retorna prediccion con explicacion
"""
ml_analyzer = MLAnalyzer()
analysis = await ml_analyzer.get_full_analysis(request.symbol)
explanation = ml_analyzer.generate_explanation(analysis)
return PredictionResponse(
symbol=request.symbol,
timestamp=datetime.utcnow().isoformat(),
amd_phase=analysis["amd_phase"],
signal=analysis["signal"],
range_prediction=analysis["range_prediction"],
ict_context=analysis["ict_context"],
confluence_score=analysis["confluence_score"],
explanation=explanation,
risk_assessment=await get_risk_assessment(request.symbol, analysis)
)
@router.get("/history/{symbol}", response_model=List[HistoricalPrediction])
async def get_prediction_history(
symbol: str,
limit: int = 50,
include_outcomes: bool = True
):
"""
Obtiene historial de predicciones para un simbolo
"""
predictions = await prediction_repository.get_history(
symbol=symbol,
limit=limit,
include_outcomes=include_outcomes
)
return predictions
@router.get("/accuracy/{symbol}")
async def get_model_accuracy(symbol: str, days: int = 30):
"""
Obtiene metricas de accuracy del modelo para un simbolo
"""
return await prediction_repository.get_accuracy_metrics(symbol, days)
@router.get("/active-signals")
async def get_active_signals():
"""
Obtiene todas las senales activas con confluencia > 60%
"""
return await prediction_repository.get_active_signals(min_confluence=0.6)
```
### WebSocket para Predicciones en Tiempo Real
```python
# api/websocket.py
from fastapi import WebSocket, WebSocketDisconnect
from typing import Dict, Set
import asyncio
import json
class PredictionWebSocketManager:
def __init__(self):
self.connections: Dict[str, Set[WebSocket]] = {}
async def connect(self, websocket: WebSocket, symbol: str):
await websocket.accept()
if symbol not in self.connections:
self.connections[symbol] = set()
self.connections[symbol].add(websocket)
def disconnect(self, websocket: WebSocket, symbol: str):
if symbol in self.connections:
self.connections[symbol].discard(websocket)
async def broadcast_prediction(self, symbol: str, prediction: dict):
if symbol in self.connections:
message = json.dumps(prediction)
for connection in self.connections[symbol]:
try:
await connection.send_text(message)
except:
self.disconnect(connection, symbol)
manager = PredictionWebSocketManager()
@router.websocket("/ws/predictions/{symbol}")
async def prediction_websocket(websocket: WebSocket, symbol: str):
await manager.connect(websocket, symbol)
try:
while True:
# Enviar prediccion cada 5 segundos
prediction = await ml_analyzer.get_full_analysis(symbol)
await websocket.send_json(prediction)
await asyncio.sleep(5)
except WebSocketDisconnect:
manager.disconnect(websocket, symbol)
```
---
## Persistencia en PostgreSQL
### Nuevas Tablas
```sql
-- Schema: ml (agregar a existente)
-- Tabla de predicciones del LLM Agent
CREATE TABLE IF NOT EXISTS ml.llm_predictions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
symbol VARCHAR(20) NOT NULL,
timeframe VARCHAR(10) NOT NULL,
-- Prediccion
amd_phase VARCHAR(50),
amd_confidence DECIMAL(5,4),
signal_direction VARCHAR(10),
signal_confidence DECIMAL(5,4),
entry_price DECIMAL(20,8),
stop_loss DECIMAL(20,8),
take_profit DECIMAL(20,8),
-- Contexto ICT
killzone VARCHAR(50),
ote_zone VARCHAR(20),
-- Confluencia
confluence_score DECIMAL(5,4),
-- Explicacion generada por LLM
explanation TEXT,
-- Metadata
model_version VARCHAR(50),
created_at TIMESTAMPTZ DEFAULT NOW(),
CONSTRAINT chk_signal_direction CHECK (signal_direction IN ('LONG', 'SHORT', 'HOLD'))
);
-- Indice para busquedas rapidas
CREATE INDEX idx_llm_predictions_symbol_time ON ml.llm_predictions(symbol, created_at DESC);
-- Tabla de outcomes para tracking de accuracy
CREATE TABLE IF NOT EXISTS ml.prediction_outcomes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
prediction_id UUID REFERENCES ml.llm_predictions(id),
-- Resultado real
actual_direction VARCHAR(10),
actual_high DECIMAL(20,8),
actual_low DECIMAL(20,8),
-- Metricas de precision
direction_correct BOOLEAN,
target_reached BOOLEAN,
stop_hit BOOLEAN,
pnl_pips DECIMAL(10,2),
pnl_percentage DECIMAL(10,4),
-- Tiempo de resolucion
resolved_at TIMESTAMPTZ,
resolution_candles INT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabla de decisiones del LLM Agent
CREATE TABLE IF NOT EXISTS ml.llm_decisions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
prediction_id UUID REFERENCES ml.llm_predictions(id),
-- Decision
decision_type VARCHAR(50), -- 'TRADE', 'ALERT', 'WAIT', 'CLOSE'
action_taken VARCHAR(50),
reasoning TEXT,
-- Risk assessment
risk_level VARCHAR(20),
position_size DECIMAL(10,4),
risk_pct DECIMAL(5,4),
-- Execution
executed BOOLEAN DEFAULT FALSE,
execution_venue VARCHAR(20), -- 'MT4', 'BINANCE'
order_id VARCHAR(100),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabla de eventos de riesgo
CREATE TABLE IF NOT EXISTS ml.risk_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
event_type VARCHAR(50), -- 'CIRCUIT_BREAKER', 'DAILY_LIMIT', 'EXPOSURE_LIMIT'
severity VARCHAR(20),
details JSONB,
action_taken VARCHAR(100),
resolved BOOLEAN DEFAULT FALSE,
resolved_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Funcion para calcular accuracy
CREATE OR REPLACE FUNCTION ml.calculate_prediction_accuracy(
p_symbol VARCHAR,
p_days INT DEFAULT 30
)
RETURNS TABLE(
total_predictions INT,
direction_accuracy DECIMAL,
target_hit_rate DECIMAL,
avg_pnl_pips DECIMAL,
profit_factor DECIMAL
) AS $$
BEGIN
RETURN QUERY
SELECT
COUNT(*)::INT as total_predictions,
AVG(CASE WHEN o.direction_correct THEN 1 ELSE 0 END)::DECIMAL as direction_accuracy,
AVG(CASE WHEN o.target_reached THEN 1 ELSE 0 END)::DECIMAL as target_hit_rate,
AVG(o.pnl_pips)::DECIMAL as avg_pnl_pips,
CASE
WHEN SUM(CASE WHEN o.pnl_pips < 0 THEN ABS(o.pnl_pips) ELSE 0 END) > 0
THEN SUM(CASE WHEN o.pnl_pips > 0 THEN o.pnl_pips ELSE 0 END) /
SUM(CASE WHEN o.pnl_pips < 0 THEN ABS(o.pnl_pips) ELSE 0 END)
ELSE 0
END::DECIMAL as profit_factor
FROM ml.llm_predictions p
JOIN ml.prediction_outcomes o ON p.id = o.prediction_id
WHERE p.symbol = p_symbol
AND p.created_at >= NOW() - (p_days || ' days')::INTERVAL;
END;
$$ LANGUAGE plpgsql;
COMMENT ON TABLE ml.llm_predictions IS 'Predicciones generadas por el LLM Trading Agent';
COMMENT ON TABLE ml.prediction_outcomes IS 'Resultados reales de las predicciones para tracking de accuracy';
COMMENT ON TABLE ml.llm_decisions IS 'Decisiones tomadas por el LLM Agent';
COMMENT ON TABLE ml.risk_events IS 'Eventos de gestion de riesgo';
```
### Repository Pattern
```python
# repositories/prediction_repository.py
from typing import List, Optional, Dict, Any
import asyncpg
from datetime import datetime, timedelta
class PredictionRepository:
def __init__(self, pool: asyncpg.Pool):
self.pool = pool
async def save_prediction(self, prediction: Dict[str, Any]) -> str:
"""Guarda una nueva prediccion"""
query = """
INSERT INTO ml.llm_predictions (
symbol, timeframe, amd_phase, amd_confidence,
signal_direction, signal_confidence, entry_price,
stop_loss, take_profit, killzone, ote_zone,
confluence_score, explanation, model_version
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
RETURNING id
"""
async with self.pool.acquire() as conn:
row = await conn.fetchrow(query,
prediction["symbol"],
prediction["timeframe"],
prediction.get("amd_phase", {}).get("phase"),
prediction.get("amd_phase", {}).get("confidence"),
prediction.get("signal", {}).get("direction"),
prediction.get("signal", {}).get("confidence"),
prediction.get("signal", {}).get("entry_price"),
prediction.get("signal", {}).get("stop_loss"),
prediction.get("signal", {}).get("take_profit"),
prediction.get("ict_context", {}).get("killzone"),
prediction.get("ict_context", {}).get("ote_zone"),
prediction.get("confluence_score"),
prediction.get("explanation"),
prediction.get("model_version", "v1.0")
)
return str(row["id"])
async def save_outcome(self, prediction_id: str, outcome: Dict[str, Any]):
"""Guarda el resultado de una prediccion"""
query = """
INSERT INTO ml.prediction_outcomes (
prediction_id, actual_direction, actual_high, actual_low,
direction_correct, target_reached, stop_hit,
pnl_pips, pnl_percentage, resolved_at, resolution_candles
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
"""
async with self.pool.acquire() as conn:
await conn.execute(query,
prediction_id,
outcome["actual_direction"],
outcome["actual_high"],
outcome["actual_low"],
outcome["direction_correct"],
outcome["target_reached"],
outcome["stop_hit"],
outcome["pnl_pips"],
outcome["pnl_percentage"],
outcome.get("resolved_at", datetime.utcnow()),
outcome.get("resolution_candles", 0)
)
async def get_history(
self,
symbol: str,
limit: int = 50,
include_outcomes: bool = True
) -> List[Dict]:
"""Obtiene historial de predicciones"""
query = """
SELECT
p.*,
o.direction_correct,
o.target_reached,
o.pnl_pips
FROM ml.llm_predictions p
LEFT JOIN ml.prediction_outcomes o ON p.id = o.prediction_id
WHERE p.symbol = $1
ORDER BY p.created_at DESC
LIMIT $2
"""
async with self.pool.acquire() as conn:
rows = await conn.fetch(query, symbol, limit)
return [dict(row) for row in rows]
async def get_accuracy_metrics(
self,
symbol: str,
days: int = 30
) -> Dict[str, Any]:
"""Obtiene metricas de accuracy"""
async with self.pool.acquire() as conn:
row = await conn.fetchrow(
"SELECT * FROM ml.calculate_prediction_accuracy($1, $2)",
symbol, days
)
return dict(row) if row else {}
```
---
## Pipeline de Fine-Tuning
### Generacion de Dataset
```python
# fine_tuning/generate_dataset.py
import json
from typing import List, Dict
import asyncpg
class DatasetGenerator:
"""
Genera dataset de fine-tuning a partir de:
1. Predicciones historicas con outcomes
2. Decisiones correctas del sistema
3. Reglas de trading documentadas
"""
async def generate_from_predictions(
self,
pool: asyncpg.Pool,
min_accuracy: float = 0.7
) -> List[Dict]:
"""
Genera ejemplos de predicciones exitosas
"""
query = """
SELECT
p.symbol, p.amd_phase, p.amd_confidence,
p.signal_direction, p.signal_confidence,
p.killzone, p.ote_zone, p.confluence_score,
o.direction_correct, o.target_reached, o.pnl_pips
FROM ml.llm_predictions p
JOIN ml.prediction_outcomes o ON p.id = o.prediction_id
WHERE o.direction_correct = true
AND p.confluence_score >= $1
"""
async with pool.acquire() as conn:
rows = await conn.fetch(query, min_accuracy)
examples = []
for row in rows:
example = self._create_training_example(dict(row))
examples.append(example)
return examples
def _create_training_example(self, prediction: Dict) -> Dict:
"""Crea ejemplo de entrenamiento en formato instruction/input/output"""
instruction = "Analiza esta senal de trading y proporciona tu recomendacion"
input_text = f"""
Simbolo: {prediction['symbol']}
Fase AMD: {prediction['amd_phase']} ({prediction['amd_confidence']*100:.0f}% confianza)
Senal: {prediction['signal_direction']} ({prediction['signal_confidence']*100:.0f}%)
Killzone: {prediction['killzone']}
Zona OTE: {prediction['ote_zone']}
Confluencia: {prediction['confluence_score']*100:.0f}%
"""
output_text = self._generate_analysis_output(prediction)
return {
"instruction": instruction,
"input": input_text.strip(),
"output": output_text
}
def generate_from_strategy_docs(self, docs_path: str) -> List[Dict]:
"""
Genera ejemplos a partir de documentacion de estrategias
"""
examples = []
# AMD Phase examples
examples.extend(self._amd_examples())
# ICT/SMC examples
examples.extend(self._ict_examples())
# Risk management examples
examples.extend(self._risk_examples())
return examples
def _amd_examples(self) -> List[Dict]:
return [
{
"instruction": "Explica que es la fase de Accumulation en AMD",
"input": "",
"output": """# Fase de Accumulation (Acumulacion)
## Definicion
La fase de Accumulation es cuando las instituciones (smart money) estan comprando activamente mientras el precio se mantiene en un rango. Es la primera fase del ciclo AMD.
## Caracteristicas
1. **Precio**: Se mueve lateralmente o con leve tendencia alcista
2. **Volumen**: Incrementa en impulsos alcistas, decrece en retrocesos
3. **Estructura**: Minimos mas altos dentro del rango
4. **Duracion**: Puede durar dias o semanas
## Como Tradear
- **Direccion preferida**: LONG
- **Entrada**: En retrocesos hacia la parte baja del rango
- **Stop Loss**: Debajo del ultimo minimo significativo
- **Take Profit**: Parte alta del rango o ruptura
## Senales de Confirmacion
- Rechazo de precios bajos con volumen
- Velas de absorcion en soporte
- RSI formando divergencias alcistas
- MACD cruzando hacia arriba
## Transicion
La fase de Accumulation termina cuando:
1. El precio rompe la resistencia con volumen
2. Comienza la fase de Markup (tendencia alcista)
3. O inicia fase de Manipulation (falsa ruptura)"""
},
{
"instruction": "Que hacer cuando se detecta fase de Manipulation",
"input": "El mercado muestra fase de Manipulation con 85% de confianza",
"output": """# ALERTA: Fase de Manipulation Detectada
## Accion Recomendada: NO OPERAR
La fase de Manipulation es la mas peligrosa para traders retail. Las instituciones estan barriendo liquidez (stops) antes del movimiento real.
## Porque NO Operar
1. **Alta probabilidad de stops**: Las instituciones buscan liquidez en zonas obvias
2. **Movimientos erraticos**: El precio puede ir en ambas direcciones rapidamente
3. **Senales falsas**: Los indicadores tecnicos generan senales contradictorias
4. **Volumen enganoso**: Spikes de volumen que no indican direccion real
## Que Esperar
- Transicion a Distribution (movimiento bajista)
- O transicion a Re-accumulation (continuacion alcista)
- Tiempo estimado: 1-4 horas en timeframes de 5min
## Si Tienes Posiciones Abiertas
1. Mover stop loss a breakeven si es posible
2. Considerar cierre parcial (50%)
3. NO agregar a la posicion
4. Estar listo para cierre manual si es necesario
## Siguiente Paso
Esperar confirmacion de nueva fase con:
- Cambio en estructura de mercado
- Volumen direccional claro
- Confluencia de indicadores"""
}
]
def save_dataset(self, examples: List[Dict], output_path: str):
"""Guarda dataset en formato JSONL"""
with open(output_path, 'w') as f:
for example in examples:
f.write(json.dumps(example, ensure_ascii=False) + '\n')
```
### Script de Entrenamiento
```bash
#!/bin/bash
# fine_tuning/train.sh
# Configuracion
MODEL_NAME="meta-llama/Meta-Llama-3-8B-Instruct"
OUTPUT_DIR="./trading-llm-finetuned"
DATASET_PATH="./data/trading_strategies.jsonl"
# Verificar GPU
nvidia-smi
# Activar ambiente
source activate trading-llm
# Ejecutar entrenamiento
python train_lora.py \
--model_name $MODEL_NAME \
--dataset_path $DATASET_PATH \
--output_dir $OUTPUT_DIR \
--num_epochs 3 \
--batch_size 4 \
--learning_rate 2e-4 \
--lora_r 16 \
--lora_alpha 32 \
--max_length 2048 \
--fp16 \
--gradient_checkpointing
# Merge LoRA weights
python merge_lora.py \
--base_model $MODEL_NAME \
--lora_weights $OUTPUT_DIR \
--output_dir "${OUTPUT_DIR}-merged"
# Convertir a GGUF para Ollama
python convert_to_gguf.py \
--model_path "${OUTPUT_DIR}-merged" \
--output_path "${OUTPUT_DIR}.gguf" \
--quantization q5_K_M
echo "Fine-tuning completado. Modelo en: ${OUTPUT_DIR}.gguf"
```
---
## Implementacion
### Docker Compose Completo
```yaml
# docker-compose.llm-advanced.yaml
version: '3.8'
services:
# Ollama con modelo fine-tuned
ollama:
image: ollama/ollama:latest
container_name: trading-ollama
ports:
- "11434:11434"
volumes:
- ollama_data:/root/.ollama
- ./models:/models # Para modelos custom
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
environment:
- OLLAMA_MODELS=/models
restart: unless-stopped
# LLM Agent Service
llm-agent:
build:
context: ./apps/llm-agent
dockerfile: Dockerfile
container_name: trading-llm-agent
ports:
- "3085:3085"
environment:
- OLLAMA_URL=http://ollama:11434
- LLM_MODEL=trading-trading:latest # Modelo fine-tuned
- REDIS_URL=redis://redis:6379
- DATABASE_URL=postgresql://user:pass@postgres:5432/trading
- ML_ENGINE_URL=http://ml-engine:3083
- MCP_MT4_URL=http://mcp-mt4:3605
- MCP_BINANCE_URL=http://mcp-binance:3606
depends_on:
- ollama
- redis
- postgres
restart: unless-stopped
# MCP MT4 Connector
mcp-mt4:
build:
context: ./apps/mcp-mt4-connector
dockerfile: Dockerfile
container_name: trading-mcp-mt4
ports:
- "3605:3605"
environment:
- MT4_GATEWAY_HOST=${MT4_GATEWAY_HOST}
- MT4_GATEWAY_TOKEN=${MT4_GATEWAY_TOKEN}
restart: unless-stopped
# MCP Binance Connector (NUEVO)
mcp-binance:
build:
context: ./apps/mcp-binance-connector
dockerfile: Dockerfile
container_name: trading-mcp-binance
ports:
- "3606:3606"
environment:
- BINANCE_API_KEY=${BINANCE_API_KEY}
- BINANCE_API_SECRET=${BINANCE_API_SECRET}
- BINANCE_TESTNET=${BINANCE_TESTNET:-true}
restart: unless-stopped
# ML Engine
ml-engine:
build:
context: ./apps/ml-engine
dockerfile: Dockerfile
container_name: trading-ml-engine
ports:
- "3083:3083"
environment:
- DATABASE_URL=postgresql://user:pass@postgres:5432/trading
- REDIS_URL=redis://redis:6379
volumes:
- ml_models:/app/models
restart: unless-stopped
# Redis
redis:
image: redis:7-alpine
container_name: trading-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
restart: unless-stopped
# PostgreSQL
postgres:
image: postgres:16-alpine
container_name: trading-postgres
ports:
- "5432:5432"
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=trading
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
ollama_data:
redis_data:
postgres_data:
ml_models:
```
### Script de Inicializacion
```bash
#!/bin/bash
# scripts/init_llm_system.sh
echo "=== Trading Platform LLM Trading System Setup ==="
# 1. Verificar GPU
echo "[1/6] Verificando GPU..."
nvidia-smi || { echo "Error: GPU no detectada"; exit 1; }
# 2. Iniciar servicios base
echo "[2/6] Iniciando servicios base..."
docker-compose -f docker-compose.llm-advanced.yaml up -d postgres redis
# 3. Esperar a que postgres este listo
echo "[3/6] Esperando PostgreSQL..."
sleep 10
docker exec trading-postgres pg_isready
# 4. Ejecutar migraciones
echo "[4/6] Ejecutando migraciones SQL..."
docker exec -i trading-postgres psql -U user -d trading < ./apps/database/ddl/schemas/ml/llm_predictions.sql
# 5. Iniciar Ollama y cargar modelo
echo "[5/6] Iniciando Ollama..."
docker-compose -f docker-compose.llm-advanced.yaml up -d ollama
sleep 10
# Verificar si existe modelo fine-tuned
if [ -f "./models/trading-trading.gguf" ]; then
echo "Cargando modelo fine-tuned..."
docker exec trading-ollama ollama create trading-trading -f /models/Modelfile
else
echo "Modelo fine-tuned no encontrado, usando Llama 3..."
docker exec trading-ollama ollama pull llama3:8b-instruct-q5_K_M
fi
# 6. Iniciar resto de servicios
echo "[6/6] Iniciando servicios de aplicacion..."
docker-compose -f docker-compose.llm-advanced.yaml up -d
echo ""
echo "=== Setup Completado ==="
echo "LLM Agent: http://localhost:3085"
echo "ML Engine: http://localhost:3083"
echo "MCP MT4: http://localhost:3605"
echo "MCP Binance: http://localhost:3606"
echo ""
```
---
## Testing y Validacion
### Test Cases
```python
# tests/test_llm_trading.py
import pytest
import httpx
from datetime import datetime
LLM_URL = "http://localhost:3085"
ML_URL = "http://localhost:3083"
@pytest.mark.asyncio
async def test_llm_analyze_with_confluence():
"""Test analisis con confluencia de modelos"""
async with httpx.AsyncClient(timeout=60.0) as client:
response = await client.post(
f"{LLM_URL}/api/v1/analyze",
json={"symbol": "XAUUSD", "timeframe": "5m"}
)
assert response.status_code == 200
data = response.json()
# Verificar campos requeridos
assert "amd_phase" in data
assert "signal" in data
assert "confluence_score" in data
assert "explanation" in data
assert "risk_assessment" in data
@pytest.mark.asyncio
async def test_risk_management_validation():
"""Test validacion de riesgo antes de trade"""
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(
f"{LLM_URL}/api/v1/validate-trade",
json={
"symbol": "XAUUSD",
"direction": "LONG",
"size": 0.1,
"stop_loss_pips": 50
}
)
assert response.status_code == 200
data = response.json()
assert "allowed" in data
assert "checks" in data
assert "recommended_size" in data
@pytest.mark.asyncio
async def test_mcp_binance_connection():
"""Test conexion MCP Binance"""
async with httpx.AsyncClient(timeout=10.0) as client:
response = await client.get("http://localhost:3606/health")
assert response.status_code == 200
@pytest.mark.asyncio
async def test_prediction_persistence():
"""Test persistencia de predicciones"""
# 1. Generar prediccion
async with httpx.AsyncClient(timeout=60.0) as client:
response = await client.post(
f"{LLM_URL}/api/v1/predictions/analyze",
json={"symbol": "BTCUSDT"}
)
assert response.status_code == 200
# 2. Verificar en historial
history_response = await client.get(
f"{LLM_URL}/api/v1/predictions/history/BTCUSDT?limit=1"
)
assert history_response.status_code == 200
assert len(history_response.json()) > 0
@pytest.mark.asyncio
async def test_fine_tuned_trading_knowledge():
"""Test conocimiento de trading del modelo fine-tuned"""
async with httpx.AsyncClient(timeout=60.0) as client:
response = await client.post(
f"{LLM_URL}/api/v1/chat",
json={
"message": "Explica que es la fase de Accumulation en AMD y como tradearla",
"session_id": "test_knowledge"
}
)
assert response.status_code == 200
content = response.json()["response"]
# Verificar conocimiento especifico
assert "acumulacion" in content.lower() or "accumulation" in content.lower()
assert "instituciones" in content.lower() or "smart money" in content.lower()
```
### Metricas de Validacion
| Metrica | Target | Como Medir |
|---------|--------|------------|
| Response Time | <5s | pytest benchmark |
| Direction Accuracy | >65% | Historical outcomes |
| Confluence Score Reliability | >70% | Correlation with outcomes |
| Risk Limit Adherence | 100% | Audit logs |
| MCP Uptime | >99% | Health checks |
| Fine-tuning Quality | Perplexity <3.0 | Eval dataset |
---
## Proximos Pasos
### Fase 1: Infraestructura (1-2 semanas)
1. [ ] Crear MCP Binance Connector
2. [ ] Implementar DDL nuevas tablas
3. [ ] Configurar Docker Compose completo
4. [ ] Setup pipeline de CI/CD
### Fase 2: Core LLM (2-3 semanas)
1. [ ] Generar dataset de fine-tuning
2. [ ] Entrenar modelo con LoRA
3. [ ] Integrar modelo en Ollama
4. [ ] Implementar Risk Manager
### Fase 3: Integracion (1-2 semanas)
1. [ ] Conectar ML Engine con LLM
2. [ ] Implementar MCP Orchestrator
3. [ ] API de predicciones para frontend
4. [ ] WebSocket real-time
### Fase 4: Testing y Deployment (1 semana)
1. [ ] Tests de integracion
2. [ ] Backtesting de decisiones
3. [ ] Documentacion final
4. [ ] Deployment a produccion
---
**Documento Generado:** 2026-01-04
**Autor:** Orquestador Agent - Trading Platform
**Version:** 1.0.0