"""Diagrama din `gen/strategii/intrarea_cazul_lui.spec.txt` (TIP: PRET). Trade-ul userului din A3 §2.1, reconstruit din descriere: downtrend pe 15 min până la suportul weekly 100.00, buy momentum pe o verde mare, intrare la close 102.10, imediat o roșie mare care acoperă 83% din corpul verzii, apoi trendul. Ieșirea userului la 102.60, înainte de TP1; vârful 105.20 după. Pe același grafic, nivelul 1/2 = 101.20 unde s-ar fi umplut varianta B. Toate cifrele sunt CONSTRUITE (fără ticker); mediile SMA 5 / SMA 10 sunt ilustrative — lecția 10 nu dă lungimile reale. Rulează: python3 gen/strategii/intrarea_cazul_lui.py Scrie lângă el `intrarea_cazul_lui.svg`. """ import re import sys from pathlib import Path sys.path.insert(0, "/workspace/atm-curs-dl") from svg_candles import Chart, Level, Mark, MA, from_closes # noqa: E402 OUT = Path(__file__).resolve().parent / "intrarea_cazul_lui.svg" GRAY, RED, GREEN, BLUE, ORANGE = "#777", "#c00", "#188a3e", "#1a5fb4", "#b06000" MA5_C, MA10_C = "#8a3ea8", "#2a8a8a" SUPORT, SL, ENTRY, HALF, TP1 = 100.00, 99.90, 102.10, 101.20, 104.30 CLOSES = [ 103.80, 103.50, 103.60, 103.20, 102.90, 103.00, 102.60, 102.30, 101.90, 101.40, 101.00, # 0-10 100.70, 100.45, 100.30, # 11-13 la suport 102.10, # 14 buy momentum 100.60, # 15 roșie mare 101.10, 101.60, 101.90, # 16-18 102.60, # 19 ieșirea userului 102.90, 102.70, 103.20, 103.60, 103.40, 103.90, 104.20, 104.10, 104.60, 104.90, 104.70, 105.00, 105.20, 105.00, # 20-33 ] assert len(CLOSES) == 34, len(CLOSES) # (sus, jos); excepțiile fixează exact low-urile/high-urile din specificație WICKS = [(0.12, 0.10)] * 34 WICKS[10] = (0.10, 0.20) # low 100.80 WICKS[11] = (0.10, 0.30) # low 100.40 WICKS[12] = (0.10, 0.55) # low 99.90, wick sub 100.00 WICKS[13] = (0.10, 0.20) # low 100.10 WICKS[14] = (0.15, 0.10) # h 102.25, l 100.20 WICKS[15] = (0.10, 0.10) # h 102.20, l 100.50 # spec zice „candela 31 (close 105.20)", dar în lista lui 105.20 e la indexul 32; # vârful e pus pe bara 32, unde e de fapt close-ul 105.20. WICKS[31] = (0.10, 0.10) # h 105.10 < 105.20 WICKS[32] = (0.00, 0.10) # h 105.20 = maximul WICKS[33] = (0.00, 0.10) # open 105.20 → high nu poate fi sub 105.20 cds = from_closes(CLOSES, wicks=WICKS, start=104.00) R = lambda x: round(x, 2) # noqa: E731 # ── assert-urile din specificație ────────────────────────────────────────── # 1. open == close anterior for a, b in zip(cds, cds[1:]): assert a.c == b.o, (a.c, b.o) g, r = cds[14], cds[15] assert (R(g.o), R(g.c), R(g.h), R(g.l)) == (100.30, 102.10, 102.25, 100.20), g assert (R(r.o), R(r.c), R(r.h), R(r.l)) == (102.10, 100.60, 102.20, 100.50), r assert (R(cds[10].l), R(cds[11].l), R(cds[12].l), R(cds[13].l)) == (100.80, 100.40, 99.90, 100.10) # 2. SL = low 4 candele; nici verdea, nici roșia nu îl ating assert R(min(c.l for c in cds[10:14])) == SL assert g.l > SL and r.l > SL # 3. culori assert g.c > g.o and r.c < r.o # 4. roșia acoperă 83% din corpul verzii acop = (r.o - r.c) / (g.c - g.o) assert abs(acop - 0.83) <= 0.01, acop # 5. 1/2 din corp, atins de roșie half = (g.o + g.c) / 2 assert R(half) == HALF and r.l <= half, (half, r.l) # 6. R-urile risc = ENTRY - SL assert R(risc) == 2.20 and R(ENTRY + risc) == TP1 flot = (r.c - ENTRY) / risc iesire = (cds[19].c - ENTRY) / risc varf = (105.20 - ENTRY) / risc assert (R(flot), R(iesire), R(varf)) == (-0.68, 0.23, 1.41), (flot, iesire, varf) # 7. mediile mobile sma = lambda n, i: sum(CLOSES[i + 1 - n:i + 1]) / n # noqa: E731 assert g.c > sma(5, 14) and g.c > sma(10, 14) assert r.c < sma(5, 15) and r.c < sma(10, 15) assert (R(sma(5, 15)), round(sma(10, 15), 3)) == (100.83, 101.335) # 8. ieșirea înainte de TP1; vârful assert cds[19].c < TP1 and all(c.h < TP1 for c in cds[15:20]) assert R(max(c.h for c in cds)) == 105.20 and R(cds[32].h) == 105.20 == cds[32].c assert all(c.h < 105.20 - 1e-9 for c in cds[:32]) # varianta B (doar în legendă) assert R(g.c - (g.c - g.o) / 3) == 101.50 assert R(HALF - SL) == 1.30 and R(HALF + (HALF - SL)) == 102.50 levels = [ Level(TP1, "TP1 104.30 (1:1)", BLUE, label_at="left"), Level(ENTRY, "intrare la close 102.10", GREEN), Level(HALF, "1/2 = 101.20 (B s-ar fi umplut aici)", ORANGE, dash="2 3"), Level(SUPORT, "suport weekly 100.00", GRAY, label_at="left"), Level(SL, "", RED), # eticheta SL sub linie, mai jos (0.10 sub suport) Level(99.50, "", "none", dash=""), # rezervă loc sub SL pentru etichete ] marks = [ Mark(14, "▲ buy momentum", GREEN, "above", dy=-20), # peste SMA 10 Mark(32, "vârf 105.20 = +1.41R", GRAY, "above"), ] ch = Chart( candles=cds, levels=levels, marks=marks, mas=[MA(5, MA5_C), MA(10, MA10_C, dash="5 3")], scale=60, gap=16, body_w=10, left=44, width=640, title="Exemplu construit (fără ticker) — 15 min, suport weekly", ) svg = ch.render() # barele 15 și 19 au candele lipite în stânga/dreapta: un Mark centrat le-ar # tăia, așa că eticheta lor stă în golul de lângă candelă (roșia: ▲ chiar sub # low-urile barelor 16+, peste suport; ieșirea: deasupra barelor 14-19, # terminată în bara 19, cu linie de legătură). y19 = ch._y(103.30) extra = [ f'▲ roșie mare: −0.68R flotant', f'ieși aici: 102.60 = +0.23R', f'', f'SL 99.90 (low 4 candele)', f'' f'── SMA 5 / - - SMA 10 ilustrative', ] legend = [ "Exemplu construit, fără ticker. Prețurile, mediile mobile și ieșirea sunt", "ilustrative; secvența (verde mare → roșie mare → trend) e cea descrisă de user.", "Varianta B (ordin la 1/2 = 101.20, risc 1.30, TP1 102.50) e aritmetică pe", "aceleași cifre, nu un trade din curs. 1/3 din corp = 101.50.", "Close-ul roșiei (100.60): sub ambele MA (SMA 5 = 100.83, SMA 10 = 101.34).", ] H0 = float(re.findall(r'viewBox="0 0 \d+ ([0-9.]+)"', svg)[0]) extra += [f'{t}' for i, t in enumerate(legend)] new_h = H0 + 10 + 17 * (len(legend) - 1) + 12 svg = re.sub(r'(viewBox="0 0 \d+ )[0-9.]+(")', lambda m: m.group(1) + f"{new_h:.0f}" + m.group(2), svg, count=1) svg = svg.replace("\n", "\n " + "\n ".join(extra) + "\n") svg = re.sub(r"\n ]*>", "", svg) # etichete goale (SL, rezervă) svg = re.sub(r"\n ]*stroke=\"none\"[^>]*/>", "", svg) assert "\n\n" not in svg OUT.write_text(svg, encoding="utf-8") print(f"scris {OUT.name}: acoperire {acop:.3f}, flotant {flot:+.2f}R, " f"ieșire {iesire:+.2f}R, vârf {varf:+.2f}R, SMA5/10@15 = " f"{sma(5, 15):.2f}/{sma(10, 15):.3f}")