#!/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, 54
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'",
]
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})")