# SIGNALS.md — Módulo de señales AI Referencia para el frontend: señales generadas por la pipeline FinBERT + Qwen3-8B sobre mercados de Polymarket. --- ## Variables de entorno (opcionales) | Variable | Descripción | |---|---| | `HF_TOKEN` | HuggingFace Pro token — FinBERT + Qwen3-8B | | `OPENROUTER_API_KEY` | Fallback LLM si HuggingFace está saturado | | `FINNHUB_API_KEY` | Noticias financieras para contexto | Sin ninguna clave, el backend usa una señal **rule-based** derivada de los precios del mercado. --- ## Endpoints ### `GET /api/v1/markets/:id/signal` Señal AI más reciente para el mercado. **No requiere autenticación.** **Params** | Param | Tipo | Descripción | |---|---|---| | `id` | string | ID numérico de Polymarket (ej. `559677`) | **Respuesta `200`** ```json { "ok": true, "data": { "id": 81, "marketId": "559677", "signal": "bearish", "confidence": 0.9, "summary": "Market strongly favors NO at 99% probability. Downside momentum dominates.", "keyRisk": "Unexpected positive developments could reverse this rapidly.", "newsCount": 0, "modelVersion": "Qwen3-8B", "generatedAt": "2026-05-16T09:35:00.110Z" } } ``` **Campos** | Campo | Tipo | Descripción | |---|---|---| | `id` | int | ID de la señal en DB | | `marketId` | string | ID del mercado | | `signal` | `"bullish"` \| `"bearish"` \| `"neutral"` | Dirección recomendada | | `confidence` | float (0–1) | Nivel de confianza del modelo | | `summary` | string | Resumen del análisis | | `keyRisk` | string \| null | Principal riesgo identificado | | `newsCount` | int | Noticias procesadas por Finnhub | | `modelVersion` | string | Modelo que generó la señal (`Qwen3-8B`, `OpenRouter`, `rule-based`) | | `generatedAt` | ISO 8601 | Timestamp de generación | **Respuesta `404`** ```json { "ok": false, "error": { "code": "NOT_FOUND", "message": "No signal found for this market" } } ``` --- ## Pipeline de generación 1. **Finnhub** → noticias relacionadas por keywords del `question` 2. **FinBERT** (HuggingFace) → filtro de sentimiento; descarta noticias irrelevantes 3. **Qwen3-8B** (HuggingFace) → genera señal JSON `{ signal, confidence, summary, keyRisk }` 4. **OpenRouter** → fallback si HF está saturado (HTTP 503) 5. **Rule-based** → fallback final: `yesPrice > 0.6 → bullish`, `yesPrice < 0.4 → bearish`, else `neutral` La señal se persiste en `AISignal` y se emite por socket (`ai_signal`). --- ## Socket — evento `ai_signal` Emitido por `src/socket/broadcaster.js` cada 5 min (tras `generateSignals`). **Nombre del evento:** `ai_signal` **Payload** ```json { "marketId": "559677", "signal": "bearish", "confidence": 0.9, "summary": "Market strongly favors NO at 99% probability." } ``` **Uso en el frontend** ```js socket.on('ai_signal', ({ marketId, signal, confidence }) => { // actualizar badge de señal en la tarjeta del mercado }); ``` --- ## Ejemplos `curl` ```bash # Señal más reciente de un mercado curl "http://localhost:7860/api/v1/markets/559677/signal" ``` --- ## Códigos de error | HTTP | Código | Cuándo | |---|---|---| | `404` | `NOT_FOUND` | No hay señal generada aún para ese mercado | | `500` | `INTERNAL` | Error inesperado del servidor |