Referencia técnica · Paso 2 · Validación de datos
Formalización del control de calidad OHLCV: los quince chequeos y sus condiciones, la fórmula del quality score con su descomposición presencia + extensión, el veredicto por umbral, y la calibración empírica que ancla los thresholds en la cola del propio activo.
Cada chequeo produce a lo sumo un issue con severidad ∈ {CRITICAL, WARNING, INFO}, su count de filas afectadas y un flag de si se pudo corregir. La mayoría son condiciones booleanas de coherencia; cuatro llevan métrica real (marcados).
| ID | Condición | Severidad |
|---|---|---|
| A · coherencia de la vela | ||
| A1 | high < low | CRITICAL |
| A2 | close > high | CRITICAL |
| A3 | close < low | CRITICAL |
| A4 | open > high | CRITICAL |
| A5 | open < low | CRITICAL |
| B · precios anómalos | ||
| B1 | precio ≤ 0 | CRITICAL |
| B2 ◆ | (high − low) / open > τspike | CRITICAL |
| B3 ◆ | |(opent − closet−1) / closet−1| > τgap | WARNING / CRIT* |
| C · volumen | ||
| C1 | volume == 0 | WARNING |
| C2 | volume < 0 | CRITICAL |
| D · tiempo | ||
| D1 | timestamps no monótonos | — (ordenar) |
| D2 | timestamps duplicados | — (dedup) |
| D3 | barras en fin de semana | según tipo |
| D4 ◆ | Δt > 10 · moda(Δt) | WARNING |
| E · NaN | ||
| E1 ◆ | pctNaN > τnan → WARN, si no INFO | WARN / INFO |
* B3 depende de instrument_type: en equity/fx/commodity se descartan los gaps con Δt extendido (Δt > mediana(Δt)·1.5 → post weekend/holiday, esperados, los cubre D4) → WARNING. En crypto (24/7) no se descarta ninguno → CRITICAL.
B2 mide el rango intrabarra (high−low)/open, no el log-return entre cierres (enfoque previo, ya reemplazado). Los saltos inter-barra son responsabilidad de B3.
No es incidental: dos precedencias son necesarias por dependencia de adyacencia.
Reordenar y deduplicar cambia qué barra es "la anterior" (closet−1), de la que depende el cálculo del gap. Por eso el saneamiento temporal precede a los chequeos que usan adyacencia.
Se parte de 100 y cada issue resta una penalidad con dos componentes: uno fijo por presencia y uno proporcional a la extensión. Un issue ya corregido casi no pesa.
| Severidad | wsev (presencia) | multsev (extensión) |
|---|---|---|
| CRITICAL | 15 | 50 |
| WARNING | 5 | 10 |
| INFO | 1 | 2 |
Diseño: un 5% de spikes CRITICAL sin corregir penaliza 15·(1 + 0.05·50) = 52.5 pts → manda a RECHAZAR por sí solo. Un WARNING estructural afectando 15% penaliza 5·(1+0.15·10) = 12.5 → no domina. El factor de fix (0.05) hace que lo ya corregido pese ~nada.
Umbrales sobre el score puro (sin gate por presencia de críticos — un crítico sin corregir ya no fuerza rechazo por sí mismo). Calibrados con datasets reales, que caen típicamente en 72–80 por eventos extremos esperados (Brexit, COVID, FTX).
En vez de asumir umbrales fijos, se miden desde la cola del propio activo — dos distribuciones distintas, alineadas con cómo el checker mide cada cosa. Válido solo con muestra suficiente.
Distribuciones medidas:
Thresholds calibrados (percentil × factor de seguridad, con piso):
Factor de seguridad 1.5: evita marcar la barra contigua al evento extremo real.
Cap del τ_nan: impide que un dataset corrupto "se ajuste" su propio umbral y oculte el problema.
Muestra mínima N ≥ 500: con menos, los percentiles altos (p99.9) son inestables → devuelve None y se usa el fallback.
Controlan qué hace el checker con lo que detecta. Default conservative.
Defaults de instrumento: instrument_type = equity. El tipo controla D3 (fin de semana) y el trato de gaps en B3.
validate_column_map) viven en domain/indicators_quality/ y se aplican durante la generación de indicadores → se formalizan en ese paso.Fuentes:
· domain/ohlcv_quality/checker.py — chequeos A1–E1, orden de ejecución, condiciones B2/B3/D4/E1
· domain/ohlcv_quality/report.py — quality_score, recommendation, SCORE_WEIGHTS, SEVERITY_PCT_MULT, THRESHOLDS
· domain/ohlcv_quality/empirical.py — compute_empirical_thresholds (percentiles, safety, floor/cap)
· domain/ohlcv_quality/config.py — defaults hardcoded, fix_mode, instrument_type