"""MDSRT, Pasul 4 — trigger valid (DA) vs. trigger prematur (NU). Aceeași formă de candelă, două locuri diferite. Sus: candela-trigger apare după ce M e complet (prețul e în zona pivotului și divergența s-a format acolo) — seria e cea canonică a capitolului, importată din `mdsrt_ansamblu`. Jos: o candelă la fel de frumoasă, dar la 2.50 deasupra zonei; M nu e complet, iar stopul pus sub ea e lovit de candela următoare. Regula „forma candelei nu e trigger dacă M nu e complet" e a cursului (`05_MODUL_4/02_strategia_5_mdsrt.md:249-311`); prețurile sunt construite, pe scara exemplului din capitol. Rulează: python3 gen/strategii/mdsrt_trigger.py """ import re import sys from pathlib import Path sys.path.insert(0, "/workspace/atm-curs-dl") sys.path.insert(0, str(Path(__file__).parent)) from svg_candles import Chart, Level, Zone, Arrow, from_closes # noqa: E402 from mdsrt_ansamblu import serie, SUPORT, TRIG, CONF, ENTRY, SL, MARJA # noqa: E402 OUT = Path(__file__).with_suffix(".svg") GREEN, RED, BLUE, GRAY, ORANGE = "#188a3e", "#c00", "#1a5fb4", "#555", "#b06000" W, VGAP = 700, 16 S = 8 # prima bară arătată din seria canonică # ---------------------------------------------------------------- panoul DA da = serie()[S:CONF + 4] t, cf = TRIG - S, CONF - S assert da[t].l == 589.50 < SUPORT, da[t].l assert da[cf].c == ENTRY > da[t].h, (ENTRY, da[t].h) # ---------------------------------------------------------------- panoul NU NU_CLOSES = [595.80, 595.20, 594.60, 594.00, 593.40, 592.90, 592.55, 592.50, # 7 = doji frumos, dar sus 592.10, 591.60, 591.20, 590.80, 590.50, 590.20, 589.90, 589.60] NU_WICKS = [(0.25, 0.30)] * len(NU_CLOSES) NU_WICKS[7] = (0.35, 0.35) nu = from_closes(NU_CLOSES, wicks=NU_WICKS, start=596.20) D = 7 NU_SL = round(nu[D].l - MARJA, 2) # doji: corp de cel mult 10 % din înălțimea candelei, fitile în ambele părți body = abs(nu[D].o - nu[D].c) rng = nu[D].h - nu[D].l assert body <= 0.10 * rng, (body, rng) assert nu[D].h > max(nu[D].o, nu[D].c) and nu[D].l < min(nu[D].o, nu[D].c) # e la 2.50 deasupra zonei — asta e tot ce-l deosebește de cel de sus assert round(nu[D].c - SUPORT, 2) == 2.50, nu[D].c - SUPORT # stopul pus sub el e lovit chiar de candela următoare lovit = next(i for i in range(D + 1, len(nu)) if nu[i].l <= NU_SL) assert lovit == D + 1, lovit # prețul chiar ajunge, mai târziu, în zona în care trigger-ul ar fi contat assert min(c.l for c in nu) < SUPORT print(f"trigger: DA la {da[t].l:.2f} (sub {SUPORT:.2f}), intrare {ENTRY:.2f}, SL {SL:.2f}; " f"NU la {nu[D].c:.2f} (+2.50), stop {NU_SL:.2f} lovit la bara {lovit}") common: dict = dict(scale=40.0, gap=20, body_w=10, left=170, width=W) sus = Chart( candles=da, levels=[Level(SUPORT, f"pivot daily {SUPORT:.2f}", BLUE, label_at="left"), Level(ENTRY, f"intrare {ENTRY:.2f}", GREEN, "6 3"), Level(SL, f"SL {SL:.2f}", RED, "4 3")], zones=[Zone(t, cf, "M complet: preț în zonă + divergență acolo", GREEN)], arrows=[Arrow(t, "DA — aceeași formă, dar în zonă:\ntrigger-ul contează", where="below", price=da[t].l, color=GREEN, dx=140, dy=30)], title="DA — trigger valid: candela apare după ce M e complet", **common, ) jos = Chart( candles=nu, levels=[Level(SUPORT, f"pivot daily {SUPORT:.2f} — zona e abia aici", BLUE, label_at="left"), Level(NU_SL, f"stopul pus sub doji: {NU_SL:.2f}", RED, "4 3")], zones=[Zone(D, D, "doji corect ca formă", ORANGE)], arrows=[ Arrow(D, f"NU — doji la {nu[D].c:.2f}, cu 2.50 deasupra zonei:\n" f"M nu e complet, deci nu e trigger", where="above", color=RED, dx=60, dy=-18), Arrow(D + 1, f"stopul de sub el, {NU_SL:.2f}, e lovit\nchiar de candela următoare", where="below", price=NU_SL, color=RED, dx=170, dy=30), ], title="NU — trigger prematur: aceeași candelă, dar deasupra zonei", caption="Ce deosebește cele două candele nu e forma, ci unde stă prețul când apar.", **common, ) def panou(ch, sus_de=0.0): ch.top += sus_de svg = ch.render() h = float(re.search(r'viewBox="0 0 [\d.]+ ([\d.]+)"', svg).group(1)) off = float(re.search(r'") + 1:svg.rindex("")].strip(), h body_sus, h_sus = panou(sus) body_jos, h_jos = panou(jos, h_sus + VGAP) H = h_jos + 8 svg = "\n ".join([ f'', body_sus, f'', body_jos, ]) + "\n" assert "\n\n" not in svg, "linie goală în SVG" for x, y in re.findall(r'