Saltar a contenido

P10 · Ichimoku: Tenkan/Kijun y nube causal

Campo Valor
Familia Tendencia · cruce de medias de rango con filtro de nube desplazada; alterna plano y posición (nunca invierte)
Features requeridas ichimoku (salidas tenkan, kijun, senkou_a, senkou_b, estas dos ya desplazadas), construida sobre rolling_max(high) y rolling_min(low); la política lee además la columna close
Parámetros y defaults tenkan = 9, kijun = 26, span_b = 52, displacement = 26
Rejilla del catálogo tenkan ∈ {7, 9, 12}, kijun ∈ {22, 26, 30}, span_b ∈ {44, 52, 60}; displacement fijo en 26 → 27 candidatos, todos válidos
variant_keys tenkan, kijun, span_b
Restricciones enteros ≥ 1, tenkan < kijun < span_b (estricto), displacement ≥ 1 (si no, PolicyParamError)
first_decision_index span_b − 1 + displacement = 77 con defaults (85 en el peor punto de la rejilla)
Activos y timeframes NVDA y KO en los 7 TF (1min1d); AMZN, INTC, MSFT, TSLA en 1d; BME con reserva; FX con reserva grave (los extremos high/low son la única entrada)
Paridad en la matriz PASS en NT_FEATURES, NT_INTENT_REPLAY y NT_ONLINE(vectorta) (12/12 cada una). UNSUPPORTED en NT_ONLINE(native) (12/12): "nautilus_trader 1.231.0 no ofrece un indicador nativo para 'ichimoku'" en el registro del runner (ver nota en Qué mirar)

Fuentes: docs/estrategias/P10.md (especificación), catalog/strategy_catalog.json, docs/DATOS_POR_ESTRATEGIA.md, runs/parity/summary.json.

Qué vas a aprender

  • Qué son las cuatro líneas de Ichimoku y por qué todas se reducen a "punto medio del rango de las últimas p barras".
  • La diferencia entre la nube que dibuja una plataforma y la nube disponible en t: es toda la causalidad de esta estrategia.
  • Por qué P10 entra con desigualdades estrictas y sale con no estrictas, y por qué nunca invierte de un golpe.
  • A seguir en el fixture una entrada por cruce TK, una salida por nube sin cruce y una segunda entrada.
  • Por qué 27 candidatos solo necesitan 9 ventanas móviles distintas.

La idea en una frase

Entrar cuando la línea rápida (Tenkan) cruza la lenta (Kijun) con el cierre por encima de ambas, y salir en cuanto el cierre toca la nube que se calculó hace displacement barras o el cruce se deshace.

Intuición de mercado

Tenkan y Kijun no son medias de cierres: son el centro del rango (máximo más mínimo, entre dos) de las últimas 9 y 26 barras. Cuando el centro del rango corto sube por encima del centro del rango largo, el mercado está haciendo máximos y mínimos más altos que antes: tendencia alcista naciente. La nube (Senkou A y B) es un soporte/resistencia de fondo calculado en el pasado; mientras el precio se mantenga por encima, la tendencia "no se ha roto".

Analogía. La nube es la marca de la marea alta de hace 26 días pintada en el muelle. Si el agua de hoy (el cierre) vuelve a tocar esa marca por arriba, la subida que te hizo entrar ya no se sostiene y sales. Lo que no puedes hacer es pintar la marca con el agua de hoy y fingir que estaba ahí de antes.

Por qué podría funcionar. Como todo seguimiento de tendencia, apuesta por el momentum de medio plazo, pero con un filtro de confirmación (el cierre sobre ambas líneas) y una salida asimétrica, rápida, por nube.

Cuándo falla.

  • Rangos laterales: los cruces TK se multiplican y el cierre vive dentro de la nube; entradas que mueren a la barra siguiente.
  • Intradía con los defaults: 9/26/52/26 vienen de semanas de seis sesiones; sobre 5min, kijun = 26 son 130 minutos. Calculable y perfectamente arbitrario.
  • Tras huecos de datos (KO, 271 sesiones ausentes): las ventanas no se reinician; la señal siguiente mezcla precios de años distintos.

Sesgos típicos al evaluarla.

  • Fuga de nube: comparar close[t] con la nube calculada con la propia barra t (la que el gráfico dibuja 26 barras adelante). Da salidas sistemáticamente "mejores".
  • Chikou: leer close[t + 26] dibujado en t es leer el futuro. P10 no lo calcula.
  • Ventanas distintas por candidato: span_b = 44 empieza en la barra 69 y span_b = 60 en la 85; compara desde un inicio común.

Las reglas exactas

La regla canónica del catálogo: "Tenkan=midpoint de n1, Kijun=midpoint de n2, A=(Tenkan+Kijun)/2, B=midpoint de n3. Nube disponible dibujada en t: A[t-displacement], B[t-displacement]. Desde plano, largo al cruce Tenkan sobre Kijun con C sobre ambas; corto simétrico bajo ambas. Salir largo si C<=max(nube) o hay cruce TK bajista; salir corto si C>=min(nube) o hay cruce TK alcista. Salida tiene prioridad y no se invierte en esa decisión."

Definiciones (spec §4.b):

  • tk_up[t] = tenkan[t] > kijun[t] and tenkan[t−1] <= kijun[t−1]; tk_down simétrico. Cualquier NaN los hace falsos.
  • cloud_top[t] = max(senkou_a[t], senkou_b[t]), cloud_bottom[t] = min(...), con propagación de NaN (np.maximum, no np.fmax).
Situación en el cierre de t Objetivo target[t] Motivo (reason)
t < first_decision_index 0 WARMUP
plano y tk_up y close > tenkan y close > kijun +1 ENTRY
plano y tk_down y close < tenkan y close < kijun −1 ENTRY
largo y (close <= cloud_top o tk_down) 0 EXIT
corto y (close >= cloud_bottom o tk_up) 0 EXIT
ninguna de las anteriores, empate o NaN el anterior HOLD
barra no operable (is_tradable = False) se congela el publicado NOT_TRADABLE
  • Entrada: solo desde plano; desigualdades estrictas. "C sobre ambas" son las dos líneas (Tenkan y Kijun), no la nube: decisión declarada en la spec (§11, punto 2).
  • Salida: desigualdades no estrictas; basta con que el cierre toque la nube por su lado, aunque la atraviese entera de un gap.
  • Reversión: prohibida. Si una barra cumple a la vez exit_long y enter_short, el objetivo es 0; la barra siguiente decide desde plano. El ledger nunca ve un delta de 2.
  • Filtros: la propia nube, solo en la salida.
# decisión en el cierre de t, fill en el open de t+1
target_prev = 0
para cada barra t:
    si t < first_decision_index:                 target = 0              # WARMUP
    si no, si target_prev == +1:
        target = 0 si (close[t] <= cloud_top[t] o tk_down[t]) si no +1
    si no, si target_prev == -1:
        target = 0 si (close[t] >= cloud_bottom[t] o tk_up[t]) si no -1
    si no:                                       # plano
        si tk_up[t]   y close[t] > tenkan[t] y close[t] > kijun[t]:  target = +1
        si no, si tk_down[t] y close[t] < tenkan[t] y close[t] < kijun[t]: target = -1
        si no:                                   target = 0
    si target != target_prev:
        orden(target - target_prev)  -> fill a open[t+1]    # |delta| siempre 1
    target_prev = target

La nube de t es la de hace displacement barras

senkou_a[t] = senkou_a_raw[t − displacement]. La primitiva ichimoku devuelve las spans ya desplazadas y no expone las _raw: quien quiera la fuga tiene que escribirla a propósito. Si programas el adaptador a mano, no calcules (tenkan + kijun)/2 en t y lo llames nube.

Los indicadores que usa

Feature Fórmula first_valid (defaults)
rolling_max(p), rolling_min(p) máximo de high / mínimo de low de las p barras incluida t p − 1
tenkan (rolling_max(tenkan) + rolling_min(tenkan)) / 2 tenkan − 1 = 8
kijun ídem con kijun kijun − 1 = 25
senkou_a ((tenkan + kijun)/2)[t − displacement] kijun − 1 + displacement = 51
senkou_b midpoint(span_b)[t − displacement] span_b − 1 + displacement = 77

first_decision_index = max(first_valid) = span_b − 1 + displacement = 77, sin +1 aunque el cruce mire t−1 (en 77 Tenkan y Kijun llevan mucho tiempo válidas). La nube entra en el índice aunque la entrada no la use: así no se abre nunca una posición que no pueda cerrarse por nube.

Las ventanas son inclusivas; no confundir con el donchian de P11, que usa barras estrictamente anteriores. Más detalle en Las 23 primitivas de fase B y en Indicadores y features.

Ejemplo barra a barra

Fixture §6 de docs/estrategias/P10.md: tenkan = 2, kijun = 3, span_b = 4, displacement = 2 (fuera de rejilla a propósito; cumple 2 < 3 < 4), 18 barras, cash_inicial = 1.000,00, tick 0,01, sin costes. Construcción: open[t] = close[t−1], high = max(O,C) + 0,10, low = min(O,C) − 0,10. first_valid: tenkan 1, kijun 2, senkou_a 4, senkou_b 5 → first_decision_index = 5.

Las barras 0–3 (sin nube) se omiten; en la barra 3 ya existen tenkan 9,9500 y kijun 9,9500.

t O H L C tenkan kijun senkou_a senkou_b cruce target orden fill pos. PnL acum. sin costes equity con 5 bps*
4 9,70 9,80 9,50 9,60 9,7500 9,9000 10,0500 TK↓ 0 WARMUP 0 0,00 1.000,00
5 9,60 9,70 9,20 9,30 9,5000 9,6000 9,9500 9,9500 0 HOLD 0 0,00 1.000,00
6 9,30 9,70 9,20 9,60 9,4500 9,5000 9,8250 9,9000 0 HOLD 0 0,00 1.000,00
7 9,60 9,80 9,50 9,70 9,5000 9,5000 9,5500 9,7500 0 HOLD 0 0,00 1.000,00
8 9,70 10,10 9,60 10,00 9,8000 9,6500 9,4750 9,6000 TK↑ +1 ENTRY BUY 1 0 0,00 1.000,00
9 10,00 10,40 9,90 10,30 10,0000 9,9500 9,5000 9,5000 +1 10,00 +1 0,30 1.000,30
10 10,30 10,40 10,10 10,20 10,1500 10,0000 9,7250 9,6500 +1 +1 0,20 1.000,20
11 10,20 10,50 10,10 10,40 10,3000 10,2000 9,9750 9,8000 +1 +1 0,40 1.000,40
12 10,40 10,50 10,20 10,30 10,3000 10,3000 10,0750 9,9500 +1 +1 0,30 1.000,30
13 10,30 10,40 9,90 10,00 10,2000 10,2000 10,2500 10,0500 0 EXIT (nube) SELL 1 +1 0,00 1.000,00
14 10,00 10,30 9,90 10,20 10,1500 10,2000 10,3000 10,2000 TK↓ 0 10,00 0 0,00 1.000,00
15 10,20 10,50 10,10 10,40 10,2000 10,2000 10,2000 10,2000 0 0 0,00 1.000,00
16 10,40 10,50 10,30 10,40 10,3000 10,2000 10,1750 10,2000 TK↑ +1 ENTRY BUY 1 0 0,00 1.000,00
17 10,40 10,50 10,20 10,30 10,3500 10,3000 10,2000 10,2000 +1 10,40 +1 −0,10 999,89

OHLC, líneas, cruces, objetivos, fills (8→9 a 10,00; 13→14 a 10,00; 16→17 a 10,40) y equity en las barras 9, 14 y 17 son literales del fixture. El PnL de las barras intermedias es caja + pos · close − 1.000,00 con la caja del fixture. *"Equity con 5 bps" es cálculo de este manual: escenario hypothetical_5bps (fee_rate = 0,0005, sin spread ni deslizamiento), comisión por fill = |delta| · precio · 0,0005 redondeada al céntimo half-even y restada en la barra del fill:

  • fill 1 (barra 9): 10,00 · 0,0005 = 0,005 → 0,00 (medio céntimo exacto, redondea al par);
  • fill 2 (barra 14): 10,00 · 0,0005 = 0,005 → 0,00;
  • fill 3 (barra 17): 10,40 · 0,0005 = 0,0052 → 0,01.

Con precios de 10 dólares y una unidad, la comisión de 5 bps casi desaparece por redondeo: es un efecto del fixture, no una propiedad de la estrategia. Sobre NVDA a cientos de dólares no ocurre.

Lo que hay que ver en la tabla:

  1. Barra 4: senkou_a ya existe, senkou_b no: la nube no está completa y es warmup. En la barra 5 (primera decisión) no hay cruce, así que el 0 es "no entrar", no calentamiento.
  2. Barra 8: cruce TK alcista armado por igualdad en t−1 (9,50 <= 9,50), cierre 10,00 sobre ambas líneas → +1; fill al open de 9.
  3. Barra 13: salida por nube sin cruce: tenkan == kijun (10,20) no es tk_down, pero close = 10,00 <= cloud_top = 10,25. El cierre ha atravesado la nube entera (está bajo las dos bandas) y la regla cierra igual.
  4. Barra 16: segunda entrada; la estrategia no se queda bloqueada tras salir.
  5. Barra 17: posición abierta al final, valorada a 10,30: equity 999,90 sin costes. No hay liquidación automática.

Las cuentas de las barras clave

Primera tenkan (t=1):  (max(10,10;10,30) + min(9,90;9,90))/2 = (10,30+9,90)/2 = 10,100000
Primera B_raw (t=3):   (max(high[0..3]) + min(low[0..3]))/2 = (10,30+9,60)/2 = 9,950000
Nube completa (t=5):   senkou_a[5] = A_raw[3] = 9,95 ; senkou_b[5] = B_raw[3] = 9,95

Entrada (t=8):
  tenkan[8] = (max(9,80;10,10) + min(9,50;9,60))/2           = 9,800000
  kijun[8]  = (max(9,70;9,80;10,10) + min(9,20;9,50;9,60))/2  = 9,650000
  tenkan[7] = kijun[7] = 9,500000
  tk_up[8]  = (9,80 > 9,65) y (9,50 <= 9,50)                  = True
  close[8] = 10,00 > 9,80 y > 9,65                            -> +1

Salida (t=13):
  senkou_a[13] = A_raw[11] = (10,30 + 10,20)/2                = 10,250000
  senkou_b[13] = B_raw[11] = (max(high[8..11]) + min(low[8..11]))/2 = (10,50+9,60)/2 = 10,050000
  cloud_top[13] = 10,25 ; close[13] = 10,00 <= 10,25          -> 0
Caja:  1.000,00 − 10,00 = 990,00 (fill 1) ; 990,00 + 10,00 = 1.000,00 (fill 2) ; 1.000,00 − 10,40 = 989,60 (fill 3)
Equity final: 989,60 + 1 · 10,30 = 999,90

Comprobación de causalidad sobre la propia tabla: senkou_a[8] = 9,4750 = A_raw[6], y el A_raw[8] = 9,7250 de la propia barra 8 no aparece en la columna senkou_a hasta la barra 10.

Diagrama

flowchart LR
    W(["WARMUP: t < span_b-1+displacement"]) --> FLAT["Plano 0"]
    FLAT -->|"tk_up y C > tenkan y C > kijun · BUY 1"| L["Largo +1"]
    FLAT -->|"tk_down y C < tenkan y C < kijun · SELL 1"| S["Corto -1"]
    L -->|"C <= max(nube) o tk_down · SELL 1"| FLAT
    S -->|"C >= min(nube) o tk_up · BUY 1"| FLAT
    L -->|"sin salida"| L
    S -->|"sin salida"| S
    FLAT -->|"sin entrada, empate o NaN"| FLAT

No hay flecha directa entre largo y corto: toda salida pasa por plano, y la entrada contraria, si procede, se decide en la barra siguiente.

Cómo lanzarla

Backtest con ambos motores sobre NVDA 1d (el régimen donde 9/26/52 tienen su lectura tradicional), con los defaults:

BASE=http://localhost:8000
SID=$(curl -sS -X POST "$BASE/v1/backtest" -H 'Content-Type: application/json' -d '{
  "request_id": "manual-p10-0001",
  "correlation_id": null,
  "schema_version": "v1",
  "payload": {
    "strategy": {"template_id": "P10",
                 "params": {"tenkan": 9, "kijun": 26, "span_b": 52, "displacement": 26},
                 "name": "Ichimoku 9/26/52 base", "register": true},
    "data": {"asset_id": "NVDA", "timeframe": "1d",
             "window": {"start": "2015-01-01T00:00:00Z", "end": "2025-01-01T00:00:00Z",
                        "mode": "reset_flat"}},
    "execution": {"lane": "SIM-S", "contract_version": "1", "initial_cash": 100000,
                  "target_lots": [-1, 0, 1], "cost_scenario": "hypothetical_5bps"},
    "engine": "both",
    "cache": {"cache_mode": "WARM_FEATURES", "write_through": true},
    "output": {"output_mode": "metrics", "include_timings": true,
               "include_parity": true, "tail_rows": 5},
    "engine_options": {"vectorta": {"kernel": "scalar", "use_batch": true},
                       "nautilus": {"adapter": "NT_FEATURES"}}
  }}' | jq -r '.payload.signature.strategy_id')
echo "$SID"
import uuid, requests
BASE = "http://localhost:8000"
env = lambda payload: {"request_id": str(uuid.uuid4()), "correlation_id": None,
                       "schema_version": "v1", "payload": payload}
payload = {
    "strategy": {"template_id": "P10",
                 "params": {"tenkan": 9, "kijun": 26, "span_b": 52, "displacement": 26},
                 "register": True},
    "data": {"asset_id": "NVDA", "timeframe": "1d",
             "window": {"start": "2015-01-01T00:00:00Z",
                        "end": "2025-01-01T00:00:00Z", "mode": "reset_flat"}},
    "execution": {"lane": "SIM-S", "contract_version": "1", "initial_cash": 100000,
                  "target_lots": [-1, 0, 1], "cost_scenario": "hypothetical_5bps"},
    "engine": "both",
    "output": {"output_mode": "metrics", "include_parity": True},
    "engine_options": {"vectorta": {"kernel": "scalar", "use_batch": True},
                       "nautilus": {"adapter": "NT_FEATURES"}},
}
r = requests.post(f"{BASE}/v1/backtest", json=env(payload)).json()["payload"]
SID = r["signature"]["strategy_id"]
print(SID, r["parity"]["verdict"])

Derivar una variante con una nube más lenta (span_b = 60):

curl -sS -X POST "$BASE/v1/strategies/$SID/derive" -H 'Content-Type: application/json' -d '{
  "request_id": "manual-p10-derive", "correlation_id": null, "schema_version": "v1",
  "payload": {"param_overrides": {"span_b": 60}, "name": "Ichimoku 9/26/60",
              "slug": "ichimoku-9-26-60", "tags": ["sensibilidad"]}}' | jq '.payload.strategy_id, .payload.cache_forecast'

span_b es parámetro de feature: según la tabla de invalidación (§5.3 de la spec) cambia senkou_b y el first_decision_index (de 77 a 85). La especificación ichimoku(9,26,60,26) es otra entrada de caché; solo se reutilizan las ventanas de 9 y 26 si la caché guarda los eslabones rolling_max/rolling_min. Un cambio de fee_rate no toca ninguna feature: solo rehace el ledger.

Sweep de sus variant_keys (rejilla completa del catálogo):

curl -sS -X POST "$BASE/v1/sweep" -H 'Content-Type: application/json' -d '{
  "request_id": "manual-p10-sweep", "correlation_id": null, "schema_version": "v1",
  "payload": {"base_strategy_id": "'"$SID"'",
    "grid": {"tenkan": [7, 9, 12], "kijun": [22, 26, 30], "span_b": [44, 52, 60]},
    "candidate_policy": {"drop_invalid": true, "drop_duplicates": true,
                         "register_strategies": true,
                         "name_template": "{template_name} {tenkan}/{kijun}/{span_b}"},
    "data": {"asset_id": "NVDA", "timeframe": "1d",
             "window": {"start": "2015-01-01T00:00:00Z", "end": "2025-01-01T00:00:00Z", "mode": "reset_flat"}},
    "execution": {"lane": "SIM-S", "contract_version": "1", "initial_cash": 100000,
                  "cost_scenario": "hypothetical_5bps"},
    "engine": "vectorta", "cache": {"cache_mode": "OPT_FULL"},
    "output": {"output_mode": "metrics"},
    "engine_options": {"vectorta": {"kernel": "scalar", "use_batch": true}}}}' | jq '.payload.job_id, .payload.factorization_plan'

El resultado se consulta en GET /v1/jobs/{job_id}.

Cuánto cuesta la rejilla

Concepto Cuenta (spec §5.4 y §9.2)
Candidatos cartesianos 3 × 3 × 3 = 27 (displacement fijo no multiplica)
Inválidos por tenkan < kijun < span_b 0: max(tenkan) = 12 < min(kijun) = 22 y max(kijun) = 30 < min(span_b) = 44
Especificaciones ichimoku distintas 27
Periodos de ventana distintos {7, 9, 12, 22, 26, 30, 44, 52, 60} = 9 pares rolling_max/rolling_min
Ventanas sin caché de eslabones 27 × 3 = 81
senkou_a / senkou_b distintas 9 (una por pareja tenkan, kijun) / 3 (una por span_b)
Memoria de features con N = 632.095 ≈ 101 MiB con eslabones cacheados, ≈ 391 MiB sin ellos

Que los 27 sean válidos es una suerte de esta rejilla, no una propiedad de la restricción: con tenkan = 25 ya se caerían candidatos.

Qué mirar en los resultados

  • parity.verdict: PASS esperado con NT_FEATURES, NT_INTENT_REPLAY y NT_ONLINE con proveedor por defecto (ventanas incrementales custom_reference).
  • Reparto de salidas por nube frente a por cruce TK (métrica de la spec §10.2): 0 % por nube significa que P10 es un cruce TK con pasos extra; 100 %, que el cruce nunca llega a tiempo.
  • Fracción de cruces TK alcistas filtrados por "C sobre ambas" y distancia media de close a cloud_top en las entradas: si es negativa, las entradas nacen dentro de la nube y mueren a la barra siguiente.
  • fills = 2 × trades menos el trade abierto al final: |delta| siempre vale 1.
  • Arranque común en un sweep: 85 para la rejilla completa.
  • Overnight permitido: P10 mantiene posición entre sesiones; no la compares con P12 o P13 sin decirlo.
  • Nota sobre el carril nativo: la matriz marca NT_ONLINE(native) como UNSUPPORTED porque el runner no registra un indicador nativo para ichimoku. La spec (§3.5) documenta, con una sonda, que IchimokuCloud de Nautilus existe y coincide en valores, pero devuelve 0,0 antes de ser válido y libera senkou_a tarde: sería una variante de máscara (nt_ichimoku_zero_masked_late_span_a), pendiente de test en contenedor.

Causalidad comprobada

El test de "futuros alterados" de la spec (§8.2) perturba las barras 14–17 del fixture y exige que tenkan, kijun, senkou_a, senkou_b y objetivos en 0..13 queden idénticos bit a bit; con span_b = 4 y displacement = 2, senkou_b[13] depende de las barras 8–11. Una variante más afilada perturba solo la barra 17 para cazar ventanas centradas (el origin por defecto de maximum_filter1d centra la ventana y mete high[t+1] en rolling_max[t]).

Para reanudar en modo continue no bastan target, tenkan_prev y kijun_prev: hacen falta los últimos displacement valores de senkou_a_raw y senkou_b_raw (416 B con 26) y las ventanas de high/low. Sin el búfer de nube, la posición heredada no podría salir por nube durante 26 barras, sin ninguna excepción que lo delate.

Errores típicos

Error Consecuencia Cómo evitarlo
tenkan >= kijun o kijun >= span_b PolicyParamError (Nautilus acepta >=; aquí es estricto a propósito) Respeta tenkan < kijun < span_b
displacement = 0 PolicyParamError: sería la nube contemporánea, otra estrategia Déjalo en 26 salvo exploración explícita
Usar la nube dibujada en t (senkou_a_raw[t]) Salidas tardías y favorables: fuga Usa las spans desplazadas de la feature
Leer Chikou Lees 26 barras de futuro P10 no lo calcula ni lo expone
Exigir close > cloud_top para entrar Otra estrategia más restrictiva "Ambas" son las líneas
Esperar reversión directa No cuadra con el motor Salida a 0; la entrada contraria, en la barra siguiente
np.fmax para la nube Nube "válida a medias" np.maximum propaga NaN
Leer initialized de Nautilus como fin de warmup Lee senkou_b = 0,0 y decide con basura Contador propio hasta first_decision_index

Variantes y extensiones

  • Entrada sobre la nube: exigir close > cloud_top; es otra receta con otro id.
  • Barrer displacement: barato (solo se multiplican los shift), aunque el catálogo lo fija.
  • Solo largos: target_lots = [0, 1].
  • Parientes: P11 Donchian (canal de rango, ventana desplazada), P01 EMA (cruce de medias de cierre) y P08 (usa las mismas rolling_max/rolling_min).

Resumen

  • Tenkan, Kijun y Senkou B son puntos medios de rango ((máx + mín)/2) con ventana inclusiva; Senkou A es la media de las dos primeras.
  • La nube disponible en t se calculó displacement barras antes; la feature la entrega ya desplazada.
  • Entrada desde plano por cruce TK con el cierre sobre (o bajo) ambas líneas; salida al tocar la nube o al cruce contrario; nunca invierte.
  • first_decision_index = span_b − 1 + displacement = 77; el fixture sale por nube en la barra 13 sin cruce TK.
  • 27 candidatos, 9 ventanas distintas; la caché de eslabones divide por nueve el trabajo.

Para practicar

  1. Con el fixture, calcula a mano tenkan[16], kijun[16] y comprueba el tk_up[16] (pista: tenkan[15] = kijun[15] = 10,20). ¿Por qué el cierre 10,40 cumple la condición de precio?
  2. Cambia el fixture mentalmente: si en la barra 13 el cierre fuera 10,26, ¿saldría? ¿Y con 10,25 exacto? Justifícalo con la desigualdad no estricta.
  3. Lanza el sweep 3×3×3 sobre NVDA 1d y KO 1d y compara el reparto de salidas por nube frente a por cruce del mejor candidato en cada activo.