P03 · MACD: cruce de señal¶
| Campo | Valor |
|---|---|
| Familia | Tendencia · dirección continua (siempre largo o corto tras la primera señal) |
| Features requeridas | macd (una primitiva con tres salidas macd, signal, hist; depende de ema{fast} y ema{slow} sobre close) |
| Parámetros y defaults | fast = 12, slow = 26, signal = 9 |
| Rejilla del catálogo | fast ∈ {8, 12, 16}, slow ∈ {21, 26, 35}, signal ∈ {5, 9, 12} → 27 candidatos válidos; 6 EMA, 9 líneas MACD, 27 señales |
variant_keys |
fast, slow, signal |
| Restricciones | enteros ≥ 1, fast < slow y signal ≥ 2 (si no, PolicyParamError) |
first_decision_index |
slow + signal − 2 = 33 con defaults (la cadena suma) |
| Activos y timeframes | NVDA y KO en los 7 TF (1min … 1d); AMZN, INTC, MSFT, TSLA en 1d; BME y FX en 1d con reservas |
| 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 'macd'". No es un fallo: esa ruta no existe para P03 |
Fuentes: docs/estrategias/P03.md (especificación), catalog/strategy_catalog.json, docs/DATOS_POR_ESTRATEGIA.md, runs/parity/summary.json.
Qué vas a aprender¶
- Cómo se construye el MACD a partir de dos EMA y por qué la señal es una tercera EMA encadenada.
- Por qué el calentamiento de una cadena suma (
slow + signal − 2) en lugar de tomar el máximo. - El error clásico de rellenar con ceros los NaN del MACD antes de calcular la señal, y cómo lo detecta el fixture.
- Que P03 decide por el signo del histograma, no del MACD: puede ponerse corto con el MACD aún positivo.
- Cómo una rejilla de 27 candidatos se factoriza en 6 EMA y 9 líneas MACD.
La idea en una frase¶
Si el MACD está por encima de su propia media (histograma positivo), estar largo; si está por debajo, estar corto.
Intuición de mercado¶
El MACD es la distancia entre una EMA rápida y una lenta: mide cuánto se ha adelantado el precio reciente al de medio plazo, es decir, el momentum. La señal es una media de ese momentum. El histograma (MACD − señal) pregunta: "¿el momentum está acelerando o frenando?". P03 se pone largo cuando acelera y corto cuando frena.
Analogía. El velocímetro y la aceleración de un coche. P01 mira si el coche va hacia delante o hacia atrás (qué media está arriba); P03 mira el pie en el pedal: si el coche acelera, largo; si frena, corto, aunque todavía avance.
Por qué podría funcionar. Reacciona antes que un cruce de medias puro: detecta que una tendencia pierde fuerza antes de que las medias se crucen. En mercados con tendencias limpias, captura buena parte del movimiento con menos retraso que P01.
Cuándo falla.
- Mercados laterales y ruidosos: el histograma oscila alrededor de cero y cada cambio de signo es una reversión de 2 unidades; en
1mines un generador de costes. - Tendencias largas con pausas: una simple ralentización pone corto en plena tendencia alcista (el fixture lo muestra en la barra 6).
- Siempre en mercado: no hay estado plano tras la primera señal; toda la exposición es 100 %.
Sesgos típicos al evaluarla.
- Elegir 12/26/9 "porque es el estándar" y compararlo con candidatos probados en otra muestra: compara la rejilla completa sobre la misma muestra.
- Warmups distintos:
slow = 35, signal = 12pierde 45 barras;21/5, solo 24. Fija un inicio común. - Usar
ewm(adjust=True)de pandas para reproducirla fuera del banco: da otra semilla y otras señales al principio.
Las reglas exactas¶
La regla canónica del catálogo: "MACD=EMA(f)-EMA(s), señal=EMA(g) de MACD, histograma=MACD-señal. Objetivo +1 cuando histograma>0 y -1 cuando <0; cero conserva estado. Abrir solo tras la validez de toda la cadena." Y su nota de ingeniería: "La EMA de la señal comienza con los valores finitos de MACD; no sustituir NaN por cero."
Situación en el cierre de t |
Objetivo target[t] |
Motivo (reason) |
|---|---|---|
t < slow + signal − 2 (cadena incompleta) |
0 | WARMUP |
hist[t] > 0 (estricto) |
+1 | ENTRY / REVERSAL / HOLD |
hist[t] < 0 (estricto) |
−1 | ENTRY / REVERSAL / HOLD |
hist[t] == 0 exacto |
el anterior | HOLD |
hist[t] NaN tardío |
el anterior | HOLD |
barra no operable (is_tradable = False) |
se congela el publicado | NOT_TRADABLE |
- Entrada: la primera barra con cadena válida y
hist ≠ 0ya da ±1. - Salida: no hay salida a plano; la salida de un largo es la reversión a corto (delta 2).
- Reversión: permitida y habitual; todas las transiciones posteriores a la primera son reversiones.
- Filtros: ninguno. No es una regla de cruce: se compara el nivel de
hist[t]con 0, sin mirart−1. Conhistnunca exactamente 0, nivel y cruce dan la misma serie de objetivos; solo difieren en el empate, donde manda "cero conserva".
# decisión en el cierre de t, fill en el open de t+1
state = 0
para cada barra t:
si t < slow + signal - 2: target = 0 # WARMUP: la señal aún no existe
si no, si hist[t] > 0: target = +1
si no, si hist[t] < 0: target = -1
si no: target = state # hist == 0 o NaN: conserva
si target != state:
orden(target - state) -> fill a open[t+1] # ±1 al abrir, ±2 al invertir
state = target
El histograma, no el MACD
Confundir hist > 0 con macd > 0 da otra estrategia (el "cruce del cero" del MACD). En el fixture, en la barra 6 el MACD vale +0,0813 y el histograma −0,0192: P03 invierte a corto; la versión equivocada seguiría larga.
Los indicadores que usa¶
| Feature | Fórmula | first_valid |
|---|---|---|
ema{n} |
semilla SMA(close[0..n−1]) en n−1; α = 2/(n+1) |
n − 1 |
macd.macd |
ema{fast} − ema{slow} |
slow − 1 (25) |
macd.signal |
EMA(signal) de macd, sembrada con la SMA de los primeros signal valores finitos de macd |
slow + signal − 2 (33) |
macd.hist |
macd − signal |
slow + signal − 2 (33) |
first_decision_index = slow + signal − 2: 33 con defaults, 45 en el peor caso de la rejilla (35, 12) y 24 en el mejor (21, 5). Las dos EMA son paralelas (misma entrada, se combinan en la misma barra → máximo), pero la señal es una recursión encadenada sobre su resultado → suma signal − 1 barras (regla chained_sum, R1/R2 del contrato extendido).
Rellenar con ceros los slow − 1 NaN del MACD haría la señal válida desde signal − 1 (8 con defaults) con un arranque sesgado a cero: decenas de señales falsas al principio. Detalle en Indicadores paso a paso, Las 23 primitivas de fase B e Indicadores y features.
Ejemplo barra a barra¶
Fixture §6 de docs/estrategias/P03.md: fast = 2, slow = 3, signal = 2 (fuera de rejilla a propósito), cash_inicial = 1.000,00, tick 0,01, sin costes. first_decision_index = 3 + 2 − 2 = 3. Features con 4 decimales half-even, como en la spec.
Barras 0–1: O=10,00/10,00, H=10,10/10,25, L=9,95/9,98, C=10,00/10,20; objetivo 0 WARMUP (en la 1, ema2 = 10,1000 y el resto NaN).
| t | O | H | L | C | ema2 | ema3 | macd | signal | hist | target | orden | fill | pos. | PnL acum. sin costes* | equity con 5 bps* |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2 | 10,20 | 10,22 | 10,05 | 10,10 | 10,1000 | 10,1000 | 0,0000 | NaN | NaN | 0 WARMUP | — | — | 0 | 0,00 | 1.000,00 |
| 3 | 10,10 | 10,45 | 10,08 | 10,40 | 10,3000 | 10,2500 | 0,0500 | 0,0250 | 0,0250 | +1 ENTRY | BUY 1 | — | 0 | 0,00 | 1.000,00 |
| 4 | 10,40 | 10,95 | 10,38 | 10,90 | 10,7000 | 10,5750 | 0,1250 | 0,0917 | 0,0333 | +1 | — | 10,40 | +1 | 0,50 | 1.000,49 |
| 5 | 10,90 | 11,35 | 10,88 | 11,30 | 11,1000 | 10,9375 | 0,1625 | 0,1389 | 0,0236 | +1 | — | — | +1 | 0,90 | 1.000,89 |
| 6 | 11,30 | 11,32 | 11,05 | 11,10 | 11,1000 | 11,0188 | 0,0813 | 0,1005 | −0,0192 | −1 REVERSAL | SELL 2 | — | +1 | 0,70 | 1.000,69 |
| 7 | 11,10 | 11,12 | 10,65 | 10,70 | 10,8333 | 10,8594 | −0,0260 | 0,0161 | −0,0422 | −1 | — | 11,10 | −1 | 1,10 | 1.001,08 |
| 8 | 10,70 | 10,72 | 10,25 | 10,30 | 10,4778 | 10,5797 | −0,1019 | −0,0626 | −0,0393 | −1 | — | — | −1 | 1,50 | 1.001,48 |
| 9 | 10,30 | 10,32 | 10,05 | 10,10 | 10,2259 | 10,3398 | −0,1139 | −0,0968 | −0,0171 | −1 | — | — | −1 | 1,70 | 1.001,68 |
| 10 | 10,10 | 10,45 | 10,08 | 10,40 | 10,3420 | 10,3699 | −0,0279 | −0,0509 | 0,0230 | +1 REVERSAL | BUY 2 | — | −1 | 1,40 | 1.001,38 |
| 11 | 10,40 | 10,95 | 10,38 | 10,90 | 10,7140 | 10,6350 | 0,0790 | 0,0357 | 0,0433 | +1 | — | 10,40 | +1 | 1,90 | 1.001,87 |
| 12 | 10,90 | 11,45 | 10,88 | 11,40 | 11,1713 | 11,0175 | 0,1539 | 0,1145 | 0,0394 | +1 | — | — | +1 | 2,40 | 1.002,37 |
| 13 | 11,40 | 11,42 | 11,15 | 11,20 | 11,1904 | 11,1087 | 0,0817 | 0,0926 | −0,0109 | −1 REVERSAL | SELL 2 | — | +1 | 2,20 | 1.002,17 |
| 14 | 11,20 | 11,22 | 10,75 | 10,80 | 10,9301 | 10,9544 | −0,0242 | 0,0147 | −0,0389 | −1 | — | 11,20 | −1 | 2,60 | 1.002,56 |
| 15 | 10,80 | 10,82 | 10,45 | 10,50 | 10,6434 | 10,7272 | −0,0838 | −0,0510 | −0,0328 | −1 | — | — | −1 | 2,90 | 1.002,86 |
OHLC, features, objetivos, motivos y fills son literales del fixture. *El fixture solo da la equity en los cierres 4 (1.000,50) y 7 (1.001,10); la columna "PnL acumulado" completa es cálculo de este manual con la regla del ledger equity = cash + posición · close (caja: 989,60 tras el fill 1; 1.011,80 tras el 2; 991,00 tras el 3; 1.013,40 tras el 4), y coincide con el fixture en las dos barras que este da. "Equity con 5 bps" también es cálculo propio: hypothetical_5bps (fee_rate = 0,0005, sin spread ni deslizamiento), comisión = |delta| · precio · 0,0005 redondeada al céntimo half-even, restada en la barra del fill:
| Fill | Barra | Delta · precio | Cuenta | Comisión |
|---|---|---|---|---|
| 1 BUY 1 | 4 | 1 · 10,40 | 0,00520 |
0,01 |
| 2 SELL 2 | 7 | 2 · 11,10 | 0,01110 |
0,01 |
| 3 BUY 2 | 11 | 2 · 10,40 | 0,01040 |
0,01 |
| 4 SELL 2 | 14 | 2 · 11,20 | 0,01120 |
0,01 |
Lo que hay que ver en la tabla:
- Barra 2: el MACD ya es finito (0,0000) pero la señal no existe: sigue siendo
WARMUP. "Abrir solo tras la validez de toda la cadena". - Barra 3: primera decisión válida y ya es una entrada:
hist = 0,0250 > 0→ +1. Fill al open de 4 (10,40). - Barra 6: el MACD sigue positivo pero cae por debajo de su señal → reversión: SELL 2 en el open de 7.
- Barras 10 y 13: dos reversiones más. Cuatro fills, tres de ellos de 2 unidades: exposición del 100 % desde la barra 4.
- Barra 15: la posición corta queda abierta y se valora al cierre (10,50); no hay liquidación automática. La señal de la última barra no tendría fill.
Las cuentas de las barras clave¶
Semillas: ema2[1] = (10,00 + 10,20)/2 = 10,1000 (α2 = 2/3)
ema3[2] = (10,00 + 10,20 + 10,10)/3 = 10,1000 (α3 = 1/2)
t = 3: ema2[3] = (2/3)·10,40 + (1/3)·10,1000 = 10,3000
ema3[3] = 0,5·10,40 + 0,5·10,1000 = 10,2500
macd[2] = 0,0000 ; macd[3] = 0,0500
signal[3] = (macd[2] + macd[3])/2 = 0,0250 <- primeros 2 MACD FINITOS
hist[3] = 0,0500 − 0,0250 = 0,0250 > 0 -> +1 ENTRY
t = 6: ema2[6] = (2/3)·11,10 + (1/3)·11,1000 = 11,1000
ema3[6] = 0,5·11,10 + 0,5·10,9375 = 11,01875
macd[6] = 11,1000 − 11,01875 = 0,08125
signal[6] = (2/3)·0,08125 + (1/3)·0,138889 = 0,100463
hist[6] = 0,08125 − 0,100463 = −0,019213 < 0 -> −1 REVERSAL
Caja: 1.000,00 − 10,40 = 989,60 (fill 1, open[4]); equity cierre 4 = 989,60 + 10,90 = 1.000,50
989,60 + 2·11,10 = 1.011,80 (fill 2, open[7]); equity cierre 7 = 1.011,80 − 10,70 = 1.001,10
1.011,80 − 2·10,40 = 991,00 (fill 3, open[11])
991,00 + 2·11,20 = 1.013,40 (fill 4, open[14]); equity final = 1.013,40 − 10,50 = 1.002,90
Si se hubieran rellenado macd[0] y macd[1] con ceros, la señal existiría ya en la barra 1 y la primera decisión llegaría dos barras antes: el fixture exige decision_index_valid[0..2] = False justamente para detectarlo.
Diagrama¶
flowchart LR
W(["WARMUP: t < slow+signal-2"]) -->|"hist == 0"| FLAT["Plano 0"]
W -->|"hist > 0 · BUY 1"| L["Largo +1"]
W -->|"hist < 0 · SELL 1"| S["Corto -1"]
FLAT -->|"hist > 0 · BUY 1"| L
FLAT -->|"hist < 0 · SELL 1"| S
L -->|"hist < 0 · SELL 2"| S
S -->|"hist > 0 · BUY 2"| L
L -->|"hist >= 0"| L
S -->|"hist <= 0"| S
El plano solo existe al principio (serie constante o hist == 0 exacto); una vez en mercado, P03 alterna entre largo y corto como P01.
Cómo lanzarla¶
Backtest con ambos motores sobre NVDA 5min en 2024 con los defaults (forma "inline" de la API de backtesting, mismo payload que examples/api/01_backtest_p01_both.request.json):
BASE=http://localhost:8000
SID=$(curl -sS -X POST "$BASE/v1/backtest" -H 'Content-Type: application/json' -d '{
"request_id": "manual-p03-0001",
"correlation_id": null,
"schema_version": "v1",
"payload": {
"strategy": {"template_id": "P03", "params": {"fast": 12, "slow": 26, "signal": 9},
"name": "MACD 12/26/9 base", "register": true},
"data": {"asset_id": "NVDA", "timeframe": "5min",
"window": {"start": "2024-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": "P03",
"params": {"fast": 12, "slow": 26, "signal": 9}, "register": True},
"data": {"asset_id": "NVDA", "timeframe": "5min",
"window": {"start": "2024-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"])
for res in r["results"]:
print(res["adapter"], res["run_metrics"]["final_equity"], res["run_metrics"]["n_fills"])
No pidas NT_ONLINE con indicator_provider: "native": Nautilus 1.231.0 no tiene MACD nativo y la matriz lo registra como UNSUPPORTED. NT_FEATURES funciona porque recibe la feature ya calculada (D-14).
Derivar una variante con una señal más lenta:
curl -sS -X POST "$BASE/v1/strategies/$SID/derive" -H 'Content-Type: application/json' -d '{
"request_id": "manual-p03-derive", "correlation_id": null, "schema_version": "v1",
"payload": {"param_overrides": {"signal": 12}, "name": "MACD 12/26/12",
"slug": "macd-12-26-12", "tags": ["sensibilidad"]}}' \
| jq '.payload.strategy_id, .payload.cache_forecast'
En P03 ningún parámetro es solo de política: los tres entran en la FeatureSpec de macd, así que cache_forecast debe anunciar un fallo de caché de la feature macd. Según la tabla de invalidación (§5.3 de la spec), un cambio de signal reutiliza íntegras las dos EMA y la línea MACD de la pareja (12, 26) y solo rehace la recursión de la señal, el histograma, la política y el ledger. Cambiar fast o slow rehace además una EMA.
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-p03-sweep", "correlation_id": null, "schema_version": "v1",
"payload": {"base_strategy_id": "'"$SID"'",
"grid": {"fast": [8, 12, 16], "slow": [21, 26, 35], "signal": [5, 9, 12]},
"candidate_policy": {"drop_invalid": true, "drop_duplicates": true,
"register_strategies": true,
"name_template": "{template_name} {fast}/{slow}/{signal}"},
"data": {"asset_id": "NVDA", "timeframe": "5min",
"window": {"start": "2024-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'
Según §5.4 de la spec: 27 candidatos, 27 válidos. El resultado se consulta en GET /v1/jobs/{job_id}.
Cuánto cuesta la rejilla¶
| Concepto | Cuenta |
|---|---|
| Candidatos cartesianos | 3 × 3 × 3 = 27 |
Inválidos por fast < slow |
0 (máx. fast 16 < mín. slow 21); el validador la aplica igual |
| EMA distintas | {8, 12, 16} ∪ {21, 26, 35} = 6 |
| Líneas MACD distintas | 3 × 3 = 9 |
| Señales / histogramas | 27 (9 MACD × 3 signal) |
| Pasadas recursivas | 6 + 27 = 33 frente a 81 sin factorizar (ahorro del 59 %) |
La nota del catálogo lo pide expresamente: "agrupar por pareja fast/slow y reutilizar su MACD entre longitudes signal". Si la caché informa de 27 cálculos de ema{12}, la factorización no está funcionando.
Qué mirar en los resultados¶
parity.verdict: PASS esperado enNT_FEATURES,NT_INTENT_REPLAYyNT_ONLINE(vectorta); señales comparadas con igualdad exacta, nunca con tolerancia.- Número de reversiones frente a entradas: en P03 todas las transiciones tras la primera son reversiones (delta 2). Un cero espurio delata un bug.
- Exposición temporal: debe ser 100 % desde la primera barra con
hist ≠ 0. - Turnover y costes: en
1minel histograma cruza el cero muy a menudo; el escenario de 5 bps es el que separa candidatos. feature_build_nspor EMA, línea MACD y señal, para ver el ahorro de la factorización.DATA_GAP_SESSIONSen KO: las tres recursiones atraviesan los 271 huecos sin pausa.
Causalidad comprobada¶
Test de "futuros alterados" de la spec: 200 barras sintéticas, (12, 26, 9), t0 = 120; se multiplican por 1,5 los cierres posteriores. Deben quedar idénticos bit a bit en [0, 120] las dos EMA, macd, signal, hist, objetivos, motivos y fills con fill_index ≤ 120. Tolerancia 0: la EMA es una recursión hacia delante, cualquier diferencia delata un desplazamiento mal puesto. Un segundo test perturba solo close[t0+1] y exige que signal[t0] no cambie: la señal, EMA de una EMA, es donde un shift con signo equivocado se esconde mejor.
Checkpoint mínimo para continue: ema_fast, ema_slow y signal en el corte (tres recursiones), macd por verificación, el objetivo vigente y la identidad (params_hash, formula_version). Guardar solo el objetivo obliga a un replay completo.
Errores típicos¶
| Error | Consecuencia | Cómo evitarlo |
|---|---|---|
fast >= slow |
PolicyParamError (con igualdad, macd ≡ 0; con fast > slow, signo invertido en silencio) |
En un sweep cuenta como inválido, no desaparece |
signal = 1 |
PolicyParamError: la señal iguala al MACD y hist ≡ 0 |
Usa signal ≥ 2 (la rejilla empieza en 5) |
| Rellenar NaN del MACD con 0 | Señal válida desde signal − 1; señales falsas al inicio |
La señal se siembra con los primeros MACD finitos |
Operar el signo de macd en vez de hist |
Otra estrategia; gira más tarde | Compara macd con su señal |
hist >= 0 → +1 |
El empate se convierte en entrada larga | Desigualdades estrictas; cero conserva |
ewm(adjust=True) para replicarla |
Semilla distinta, señales distintas | Recursión con semilla SMA |
| Pedir la ruta nativa de Nautilus | UNSUPPORTED |
Usa NT_FEATURES o NT_ONLINE con streams de VectorTA |
Variantes y extensiones¶
- Cruce del cero del MACD (
macd > 0→ largo): más lenta, equivale a un cruce de medias como P01. - Solo largos con
target_lots = [0, 1]: el histograma negativo pone plano. - Banda muerta alrededor de 0 en el histograma para filtrar whipsaw; es otra receta.
- Filtro de régimen con ADX (P15) o con volatilidad (P05).
- Parientes: P01 cruce de EMA (la base del MACD) y P18 Hull (otra forma de reducir retraso).
Resumen¶
macd = EMA(fast) − EMA(slow),signal = EMA(g)del MACD,hist = macd − signal; +1 sihist > 0, −1 si< 0, cero conserva.- La señal se siembra con los primeros
gMACD finitos:first_decision_index = slow + signal − 2(33). - Sistema siempre en mercado tras la primera señal; las reversiones mueven 2 unidades.
- 27 candidatos se factorizan en 6 EMA y 9 líneas MACD.
- Paridad PASS en los tres carriles soportados; la ruta nativa de Nautilus no existe para MACD.
Para practicar¶
- Con el fixture, calcula a mano
ema2[7],ema3[7],macd[7],signal[7]yhist[7]a partir de la barra 6. Deben salir 10,8333; 10,8594; −0,0260; 0,0161; −0,0422. - Repite la barra 3 con el error: rellena
macd[0] = macd[1] = 0y calculasignal[1]. ¿En qué barra se tomaría la primera decisión y con qué objetivo? - Lanza el sweep 3×3×3 y ordena por equity final con y sin costes (
cost_scenariozerofrente ahypothetical_5bps). ¿Cambia el candidato ganador? ¿Tienen los ganadores más o menos reversiones?