Golden SkyGolden SkyGuía Técnica

Referencia técnica · Paso 2 · Validación de datos

Score y calibración

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.

§0Notación

nfilas del dataset
countfilas afectadas por un issue
pctcount / n
Δtdiff temporal entre barras
Pq(·)percentil q de una distribución
moda(·)valor más frecuente
τthreshold (spike / gap / nan)
clipacotar entre floor y cap

§1Los quince chequeos

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).

IDCondiciónSeveridad
A · coherencia de la vela
A1high < lowCRITICAL
A2close > highCRITICAL
A3close < lowCRITICAL
A4open > highCRITICAL
A5open < lowCRITICAL
B · precios anómalos
B1precio ≤ 0CRITICAL
B2 ◆(high − low) / open > τspikeCRITICAL
B3 ◆|(opent − closet−1) / closet−1| > τgapWARNING / CRIT*
C · volumen
C1volume == 0WARNING
C2volume < 0CRITICAL
D · tiempo
D1timestamps no monótonos— (ordenar)
D2timestamps duplicados— (dedup)
D3barras en fin de semanasegún tipo
D4 ◆Δt > 10 · moda(Δt)WARNING
E · NaN
E1 ◆pctNaN > τnan → WARN, si no INFOWARN / 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.

§2Orden de ejecución

No es incidental: dos precedencias son necesarias por dependencia de adyacencia.

D1 (ordenar) → D2 (dedup) → E1 (NaN)  // antes de los A-checks
B3 (gap inter-barra)  antes de  B2 (spike intrabarra)

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.

§3Quality score

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.

quality_score score = 100
∀ issue:
  pct = countn   ·   penalty = wsev · ( 1 + pct · multsev )
  si fix_applied: penalty · 0.05
  score −= penalty
score = max( 0, round(score, 1) )
Severidadwsev (presencia)multsev (extensión)
CRITICAL1550
WARNING510
INFO12

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.

§4Veredicto

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).

score ≥ 72
PROCEDER
60 ≤ score < 72
REVISAR
score < 60
RECHAZAR

§5Calibración empírica de thresholds

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:

range_pct = high − lowopen  // spike intrabarra
gap_pct = | open − closet−1closet−1 |  // inter-barra; excluye Δt > mediana(Δt)·1.5

Thresholds calibrados (percentil × factor de seguridad, con piso):

compute_empirical_thresholds τspike = max( P99.9(range_pct) · 1.5 , 0.005 )  // floor 0.5%
τgap   = max( P99(gap_pct) · 1.5 , 1×10⁻⁴ )  // floor = 1 bp (epsilon numérico)
τnan   = clip( max( nanobs · 1.5 , 0.01 ) , ≤ 0.05 )  // floor 1%, cap 5%

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.

Fallback hardcoded (si N < 500 o sin calibrar)

τspike = 0.20  (20%)  ·  τgap = 0.10  (10%)  ·  τnan = 0.02  (2%)

§6Modos de corrección

Controlan qué hace el checker con lo que detecta. Default conservative.

auto     → aplica todas las correcciones, incluso eliminar filas de spike (B2)
conservative → correcciones seguras; los spikes solo se flaggean (no se eliminan)
report_only  → no modifica datos; solo lista los issues

Defaults de instrumento: instrument_type = equity. El tipo controla D3 (fin de semana) y el trato de gaps en B3.

Fuera de alcance de este paso

  • La winsorización MAD-sigma y el chequeo de leakage (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