#!/usr/bin/env python3 """Trigger-ul buy hammer: un singur DA și două feluri de NU. Trei panouri cu ACELEAȘI șase bare (scădere + hammer 63.30 / 62.10) și cu o singură bară diferită la final — candela următoare. Axa de preț e comună: toate trei folosesc același `pmax`, verificat prin assert, deci liniile 63.30 și 62.10 cad la același y pe toate panourile. Rulare: python3 gen/strategii/hammer_mbt10_bh_trigger.py """ import re import sys; sys.path.insert(0, "/workspace/atm-curs-dl") from pathlib import Path from svg_candles import Arrow, Chart, from_closes OUT = Path(__file__).with_suffix(".svg") GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555" BAZA = [65.20, 64.60, 64.10, 63.60, 63.05, 63.30] # 5 = hammer H_HAM, L_HAM = 63.30, 62.10 ULTIMA = {"DA": 63.35, "DEVREME": 63.20, "MORT": 62.00} def serie(ultim): closes = BAZA + [ultim] w = [(0.15, 0.15)] * len(closes) w[5] = (0.00, 0.95) return from_closes(closes, wicks=w, start=65.70) S = {k: serie(v) for k, v in ULTIMA.items()} # --- verificări ------------------------------------------------------------- for k, cds in S.items(): for i in range(1, len(cds)): assert abs(cds[i].o - cds[i - 1].c) < 1e-9, f"{k}: open[{i}] != close[{i-1}]" h = cds[5] assert (round(h.h, 2), round(h.l, 2)) == (H_HAM, L_HAM), (k, h) assert (h.o - h.l) >= 2 * (h.c - h.o), f"{k}: bara 5 nu e hammer" assert [round(c.c, 2) for c in cds[:6]] == BAZA, k assert S["DA"][6].c > H_HAM, "DA: candela următoare nu închide peste high" assert L_HAM <= S["DEVREME"][6].c <= H_HAM, "DEVREME: închiderea trebuie între low și high" assert S["MORT"][6].c < L_HAM, "MORT: candela următoare nu închide sub low" # --- layout ----------------------------------------------------------------- W, PW = 760, 240 PX = [12, 12 + PW + 14, 12 + 2 * (PW + 14)] SCALE, TOP, SHIFT = 46.0, 96, 30 CFG = [ ("DA", PX[0], GREEN, "DA — închide peste high", Arrow(6, "close 63.35, peste 63.30:\naici intri", where="above", color=GREEN, dx=-70, dy=-18)), ("DEVREME", PX[1], RED, "NU — încă sub high", Arrow(6, "close 63.20, sub 63.30:\nnu s-a întâmplat nimic,\naștepți mai departe", where="above", color=RED, dx=-78, dy=-18)), ("MORT", PX[2], RED, "NU — închide sub low", Arrow(6, "close 62.00, sub 62.10:\nvânzătorii au dus prețul\nsub fitil — setup mort", where="below", color=RED, dx=-84, dy=26)), ] bodies, inalt, charts = [], [], {} for k, px, col, _, arr in CFG: ch = Chart(candles=S[k], arrows=[arr], scale=SCALE, gap=20, body_w=11, left=px + 46, width=px + PW, top=TOP) body = ch._render() assert f'viewBox="0 0 {px + PW} ' in body, f"panoul {k}: textul iese din cadru" assert (ch.top, ch.left) == (TOP, px + 46), f"panoul {k}: Chart a mutat graficul" charts[k] = ch inalt.append(float(re.search(r'viewBox="0 0 [\d.]+ ([\d.]+)"', body).group(1))) bodies.append(f'' + body.split(">", 1)[1].rsplit("", 1)[0].strip() + '') pmax = {k: c._pmax for k, c in charts.items()} assert len(set(pmax.values())) == 1, f"panourile n-au aceeași axă: {pmax}" y = lambda p: charts["DA"]._y(p) + SHIFT # noqa: E731 H = int(max(inalt)) + SHIFT + 44 parts = [ f'', 'Trigger-ul: contează unde se ' 'închide candela următoare — daily, exemplu construit', ] for (k, px, col, titlu, _), corp in zip(CFG, bodies): parts.append(f'{titlu}') for p, c, txt in ((H_HAM, ORANGE, "high 63.30"), (L_HAM, BLUE, "low 62.10")): yy = y(p) parts.append(f'') parts.append(f'' f'{txt}') parts.append(corp) for px in PX[1:]: parts.append(f'') parts += [ f'Regula e a lecției de pattern: intri la close-ul ' 'candelei următoare, dacă acea închidere e peste high-ul hammer-ului. O atingere', f'intraday peste 63.30, urmată de o închidere sub el, ' 'nu e trigger. Prețurile sunt construite.', "", ] svg = "\n ".join(parts).replace("\n ", "\n") assert "\n\n" not in svg, "linie goală în SVG" OUT.write_text(svg, encoding="utf-8") print(f"scris {OUT.name} ({W}x{H})")