> ## Documentation Index
> Fetch the complete documentation index at: https://docs.innova-trading.com/llms.txt
> Use this file to discover all available pages before exploring further.

# PD Array Matrix

> Cómo funciona el motor de scoring del PD Array Matrix en Innova Trading — Order Blocks, Breakers, Rejection Blocks, CISD y el Market Intention Score, y cómo consultarlo

## Qué es esta página

[PD Array Matrix — Teoría](/learn/institutional/pd-arrays) ya cubre el concepto ICT completo (qué es un PD array, jerarquía, Premium/Discount, catálogo). Esta página documenta **la implementación real** en Innova Trading: qué está efectivamente calculado, con qué parámetros, y — el punto más importante — **cómo se consulta**.

<Warning>
  **El PD Array Matrix completo (Order Blocks, Breaker Blocks, Rejection Blocks, Volume Imbalances, Mitigation Blocks, Market Intention Score, CISD) no tiene indicador visual en el chart hoy.** Es una capa de análisis consumible **exclusivamente vía trading-bridge** (MCP tools para Claude Code / agentes). El motor ISS lo calcula internamente (`backend/services/iss/core.py`), pero el módulo de estructura que se dibuja en el gráfico (`InnovaStructureModuleV2.tsx`) no renderiza ninguno de estos arrays — solo swings, rangos y CHoCH/BOS. Si buscás esto en el panel de indicadores del chart, no lo vas a encontrar.
</Warning>

## Cómo se consulta — 4 tools de trading-bridge

Todos fetchean el snapshot completo del motor ISS (`POST /api/iss/query`) y extraen la porción relevante:

| Tool | Qué devuelve |
| - | - |
| `get_pd_array_matrix(symbol, timeframe, bars=300)` | Lista TODOS los arrays activos (OBs, FVGs, breakers, rejections, volume imbalances, mitigation blocks), cada uno clasificado Premium/Discount respecto al rango actual |
| `get_market_intention(symbol, timeframe, bars=300)` | El Market Intention Score (MIS): score numérico, clasificación, desglose bullish/bearish, breakdown por array |
| `get_cisd_events(symbol, timeframe, bars=300, limit=10)` | Timeline de eventos CISD (Change In State of Delivery) |
| `get_breaker_blocks(symbol, timeframe, bars=300)` | Lista de breakers activos |

La clasificación Premium/Discount de cada array (`_classify_zone`) es simple: precio medio del array por encima del punto medio del rango actual → `PREMIUM`; por debajo → `DISCOUNT`.

## Order Blocks

El **`OrderBlockConfig`** real usado por el motor ISS (`backend/schemas/iss_engine.py`, \~línea 777) es el que gobierna la detección en producción — no confundir con el dataclass `OBConfig` del módulo standalone `backend/indicators/order_blocks/`, que tiene menos campos.

| Parámetro | Default | Opciones | Qué hace |
| - | - | - | - |
| `reference_point` | `open` | open / low / body / ce | Qué nivel define el borde de referencia de la zona |
| `validation` | `close_through` | close\_through / body\_break / wick\_touch / any | Cómo debe interactuar el precio con el OB para validarlo |
| `ob_definition` | `last_candle` | last\_candle / consecutive / body\_only | Una sola vela, grupo de velas consecutivas opuestas, o solo el cuerpo (sin mechas) |
| `min_impulse_bars` | 3 | ≥2 | Barras mínimas de impulso posterior requeridas |
| `min_impulse_atr` | 1.0 | ≥0 | Impulso mínimo como múltiplo de ATR(14) |
| `require_fvg_inside` | `false` | bool | Exige que el displacement deje un FVG dentro |
| `require_strong_momentum` | `false` | bool | — |
| `require_body_close` | `true` | bool | Requiere cierre más allá del nivel de referencia, no solo mecha |
| `mitigation_type` | `wick` | wick / body / 50\_percent | Cómo se considera "llenada" la zona |
| `max_touches` | 3 | ≥1 | Toques antes de expirar/invalidar |
| `max_bars` | 50 | ≥10 | Edad máxima antes de expirar |

**Algoritmo de detección** (`backend/indicators/order_blocks/detector.py`): busca impulsos donde el movimiento desde el low/high más extremo del segmento hasta el cierre final supera `min_impulse_atr × ATR(14)`, con al menos 60% de las velas del segmento en la dirección del impulso durante `min_impulse_bars` consecutivas. Luego retrocede hasta encontrar la última vela de color opuesto — esa es la vela candidata a OB.

**Ciclo de vida**: `PENDING → VALIDATED → TESTED → (INVALIDATED | EXPIRED)`. Invalidación: cierre que sobrepasa el lado equivocado de la zona (`close < ob.low` para bullish, `close > ob.high` para bearish). Expiración: solo por edad en estado `PENDING` (`age > max_bars`).

<Warning>
  El detector local (`backend/indicators/order_blocks/detector.py`) define el estado `MITIGATED` pero **nunca lo asigna** — solo transiciona a `TESTED` (contador de toques sin límite) o `INVALIDATED`. La lógica de `max_touches`/`mitigation_type` vive en el `OrderBlockConfig` del schema del motor ISS, pero no está confirmado en qué punto exacto de `core.py` se aplica sobre el detector base. Tampoco confirmes que `reference_point` cambia el comportamiento de validación del detector local — la validación ahí usa siempre el rango completo (`ob.high`/`ob.low`), independientemente de qué `reference_point` esté configurado.
</Warning>

**Niveles calculados**: `midpoint` (Mean Threshold, 50%), `premium_level` (75%), `discount_level` (25%) — ver también [PD Array Matrix — Teoría](/learn/institutional/pd-arrays) para la relación con la zona Premium/Discount del rango general.

## Breaker Blocks

<Warning>
  **Hay dos definiciones distintas conviviendo en el código.** El docstring del tool `get_breaker_blocks` describe el Breaker Block clásico ICT: "un OB validado se invalida (precio cierra a través); el OB invierte de rol — un OB bullish roto se vuelve breaker bajista (resistencia)". Pero el detector real que efectivamente corre (`backend/indicators/breaker_blocks/detector.py`, invocado desde `backend/services/iss/core.py`) implementa algo **distinto**: "la vela en un swing point que fue roto por un CHoCH o BOS" — no deriva de un Order Block invalidado, sino de un swing estructural roto. Los campos que el tool intenta leer (`breaker_type`, `original_type`, `original_ob_id`) no existen en el schema real y van a mostrar `"?"` en la respuesta — la lógica real usa `direction` (bullish=soporte / bearish=resistencia), `origin` (choch/bos), `swing_bar`, `swing_price`, `swing_classification` (HH/HL/LH/LL).
</Warning>

Un Bullish CHoCH/BOS que rompe un swing HIGH crea un breaker bullish (soporte); un Bearish CHoCH/BOS que rompe un swing LOW crea un breaker bearish (resistencia). Ciclo de vida: `ACTIVE → TESTED → (MITIGATED | INVALIDATED | EXPIRED)` — mitigación cuando el precio cierra a través del CE (punto medio de la zona), invalidación cuando cierra completamente a través, expiración por `age > max_age` (default **100** barras).

## Rejection Blocks

Zona formada por una mecha larga: **desde el precio de apertura de la vela hasta la punta de la mecha** (no el cuerpo).

| Parámetro | Default | Qué exige |
| - | - | - |
| `min_wick_ratio` | 2.0 | La mecha debe ser al menos 2× el tamaño del cuerpo |
| `min_wick_atr` | 1.5 | La mecha debe ser al menos 1.5× el ATR(14) |
| `max_age` | 80 barras | Expiración por edad sin interacción |

Bullish = mecha inferior larga; Bearish = mecha superior larga. Mismo ciclo de vida que los otros arrays: `ACTIVE → TESTED → (MITIGATED | INVALIDATED | EXPIRED)`.

## Volume Imbalances y Mitigation Blocks

<Info>
  Ninguno de los dos es un módulo independiente — no existe `backend/indicators/volume_imbalance/` ni `backend/indicators/mitigation_block/`. Ambos viven inline dentro de otros archivos.
</Info>

* **Volume Imbalance**: método `detect_volume_imbalances()` del propio detector de FVG (`backend/indicators/fvg/detector.py`) — un micro-gap entre los **cuerpos** (no las mechas) de dos velas consecutivas. El razonamiento ICT: "el algoritmo no entregó precio eficientemente entre estos 2 puntos".
* **Mitigation Block**: método `_detect_mitigation_blocks()` dentro de `backend/services/iss/core.py` — patrón estructural de 3 puntos (`Low → High → Higher Low` para bullish, `High → Low → Lower High` para bearish) **sin barrido de liquidez** (a diferencia de un breaker, que sí requiere una ruptura CHoCH/BOS).

## CISD — Change In State of Delivery

Regla ICT literal en el código: *"When 3 PD arrays fail, your idea is flawed."* El detector (`MarketIntentionScorer.detect_cisd` en `backend/indicators/cisd/detector.py`) trackea fallos consecutivos (`state == INVALIDATED`) del mismo lado (bullish o bearish). Cuando se acumulan **3 o más fallos consecutivos del mismo lado** (`cisd_threshold=3`), emite un `CISDEvent`. Cualquier array no-fallido resetea el contador de esa racha.

* `confidence = min(1.0, suma_de_pesos_fallados / 6.0)`
* El evento registra `score_before`/`score_after` (el score corriendo antes y después de la racha de fallos) y la lista de IDs de arrays fallados.

## Market Intention Score (MIS)

Motor de scoring puro — **no detecta nada, solo pondera** lo que ya detectaron los detectores individuales. Vive en `backend/indicators/cisd/detector.py` (`MarketIntentionScorer.calculate_score`), invocado desde `backend/services/iss/core.py`.

**Pesos por tipo de array** (`PD_ARRAY_WEIGHTS`):

| Array | Peso |
| - | - |
| Propulsion Block (FVG que solapa ≥50% con un OB activo) | 2.5 |
| Order Block | 2.0 |
| Breaker Block | 2.0 |
| Mitigation Block | 1.5 |
| Liquidity Sweep | 1.5 |
| FVG (no-propulsión) | 1.0 |
| Rejection Block | 1.0 |
| Volume Imbalance | 0.5 |

**Lógica de puntos por estado** (signo según dirección: bullish `+1`, bearish `-1`):

| Estado | Puntos |
| - | - |
| `VALIDATED` / `ACTIVE` / `TESTED` | `weight × direction_sign` (crédito completo) |
| `INVALIDATED` | `-weight × direction_sign` (invierte el signo — un OB bullish invalidado suma puntos bajistas) |
| `MITIGATED` | `0.5 × weight × direction_sign` (medio crédito, "cumplió su propósito") |

`score = suma de todos los puntos bullish + suma de todos los puntos bearish`.

**Clasificación**:

| Score | Clasificación |
| - | - |
| > +5 | strong\_bullish |
| +3 a +5 | bullish |
| +1 a +3 | mild\_bullish |
| -1 a +1 | neutral |
| -3 a -1 | mild\_bearish |
| -5 a -3 | bearish |
| \< -5 | strong\_bearish |

## Recetas

<AccordionGroup>
  <Accordion title="1. Leer el sesgo agregado antes de una entrada manual">
    `get_market_intention(symbol, timeframe)` te da el score y clasificación en un solo llamado — útil como filtro rápido antes de buscar una entrada específica con [FVG](/learn/indicators/fvg) o [ISS](/learn/indicators/innova-smart-structure) en el chart.
  </Accordion>

  <Accordion title="2. Confirmar una idea con confluencia de arrays">
    `get_pd_array_matrix(symbol, timeframe)` lista todos los arrays activos clasificados por zona — buscá confluencia (ej. un Order Block y un FVG bullish ambos en Discount) antes de tomar una entrada, siguiendo la jerarquía de [PD Array Matrix — Teoría](/learn/institutional/pd-arrays).
  </Accordion>

  <Accordion title="3. Detectar cambios de sesgo con CISD">
    `get_cisd_events(symbol, timeframe, limit=10)` — si ves 3+ fallos consecutivos del mismo lado con confianza alta, es la señal ICT de "tu idea está mal" — considerá invertir el sesgo en vez de insistir con la dirección original.
  </Accordion>
</AccordionGroup>

***

<CardGroup cols={2}>
  <Card title="PD Array Matrix — Teoría" icon="layer-group" href="/learn/institutional/pd-arrays">
    El catálogo ICT completo: jerarquía, Premium/Discount, criterios de calidad.
  </Card>

  <Card title="Innova Smart Structure (ISS)" icon="sitemap" href="/learn/indicators/innova-smart-structure">
    El motor que produce los swings, rangos y eventos CHoCH/BOS que alimentan estos arrays.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.