Files
atm-curs-dl/gen/strategii/mp2_exemplu.py
Claude Agent 01599d2e9d strategii: primele 30 de diagrame, cu generatoarele lor
Cate un agent grafician per diagrama, fiecare cu generatorul si SVG-ul lui.
Graficele de pret trec prin svg_candles, cu assert-urile din specificatie
scrise in generator — verifica structura, nu doar ca ruleaza: ca al doilea
picior e mai jos, ca intrarea e close-ul barei de confirmare, ca 1:1 e exact.

Verificare prin sondaj pe buy_doji_ansamblu, cu screenshot citit: serie
continua de 32 de candele, panou de volum, MA(20), doji-ul si ieșirea pe
trail etichetate, cifrele identice cu specificatia.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
2026-09-18 19:22:13 +00:00

148 lines
6.7 KiB
Python

"""Diagrama din `gen/strategii/mp2_exemplu.spec.txt` (TIP: PRET).
Exemplul complet din curs: SPY long la bottom-ul de aprilie 2020 — double
bottom + Inverted Head & Shoulders la suport quarterly, trigger MP² long
(pivotul mic închide peste cel mare), prima candelă verde după umărul drept.
Intrare 577.00, SL 554.40 (1R = 22.60), TP1 599.60, ținta 4R era 667.00, iar
mișcarea reală s-a oprit la 646.00 (~3R) într-o lună.
Toate cifrele vin din `summaries/09_QA/01_2026-08-25.md:384-394,485-494`
(liniile citate în spec). Serie continuă de 38 de candele daily
(`from_closes`), panou de volum, SMA-20, niveluri reale și marcaje ancorate.
"""
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 / "mp2_exemplu.svg"
# ── cifrele din material (09_QA/01_2026-08-25.md:384-394,485-494) ───────────
ENTRY = 577.00 # candela de intrare (prima verde după umărul drept)
SL = 554.40 # sub umărul drept, chiar peste suportul quarterly
TP1 = 599.60 # 577.00 + 22.60 (1R)
TARGET_4R = 667.00 # ținta declarată; 4R exact = 667.40
REAL = 646.00 # mișcarea reală (~3R, +12% efectiv)
QUARTERLY = 554.00 # suport quarterly
SHOULDER_L = 566.0 # umăr stâng
HEAD = 555.0 # head (cel mai jos)
SHOULDER_R = 568.0 # umăr drept
NECKLINE = 578.00
# ── structura seriei (spec): ~14 coborâre → ~10 bază → intrare → ~12 urcare ─
closes = [
# 0-13: ~14 candele de coborâre de la ~600 spre umărul stâng 566
600.0, 597.0, 594.0, 596.5, 591.0, 587.5, 590.0,
584.0, 579.5, 581.5, 576.0, 571.0, 567.0,
566.0, # 13 umăr stâng
# 14-24: baza — double bottom + Inverted Head & Shoulders
570.5, 578.0, 572.0, 567.0, 560.0,
555.0, # 19 head (cel mai jos)
561.5, 568.0, 578.0, 573.0,
568.0, # 24 umăr drept
# 25: candela de intrare, prima verde după umărul drept
577.00,
# 26-37: ~12 candele de urcare spre 646.00 (marcajul „real")
581.0, 585.5, 589.0, 584.0, 590.5, 596.0, 602.0,
609.0, 616.0, 624.0, 635.0, 646.0,
]
assert len(closes) == 38, len(closes)
ENTRY_I = 25
HEAD_I = 19
SHL_I = 13
SHR_I = 24
wicks = [(0.4, 0.4)] * len(closes)
wicks[SHL_I] = (0.4, 0.5) # low umăr stâng 565.50
wicks[HEAD_I] = (0.4, 0.6) # low head = 555.0 - 0.6 = 554.40 (suportul atins)
wicks[SHR_I] = (0.4, 0.5)
wicks[15] = (0.4, 0.4) # vârf 578.0 = neckline
wicks[22] = (0.4, 0.4) # vârf 578.0 = neckline
wicks[ENTRY_I] = (0.7, 0.4) # intrare verde, wick mic
wicks[37] = (0.0, 0.3) # high = 646.00 exact (mișcarea reală se oprește aici)
vols = [
# coborâre
48, 46, 50, 44, 52, 49, 45, 53, 55, 47, 50, 54, 58, 62,
# bază (head-ul are volum mare — capitulare)
60, 72, 65, 58, 66, 88, 70, 64, 74, 60, 56,
# intrare
92,
# urcare
78, 72, 68, 60, 66, 74, 82, 88, 80, 84, 90, 95,
]
assert len(vols) == len(closes)
cds = from_closes(closes, wicks=wicks, vols=vols, start=602.0)
# ── assert-urile din specificație ───────────────────────────────────────────
entry = cds[ENTRY_I].c
assert abs(entry - 577.00) < 0.05, entry
assert abs(SL - 554.40) < 1e-9, SL
assert SL > QUARTERLY, (SL, QUARTERLY) # peste suportul quarterly
assert abs((ENTRY - SL) - 22.60) < 0.05, ENTRY - SL # 1R
assert abs(TP1 - (ENTRY + 22.60)) < 0.05, TP1 # TP1 = intrare + 1R
target_4r = ENTRY + 4 * (ENTRY - SL)
assert abs(target_4r - 667.40) < 0.05, target_4r # 4R exact
assert abs(target_4r - TARGET_4R) < 0.5, target_4r # ≈ 667.00, rotunjit în curs
assert abs((REAL - ENTRY) / (ENTRY - SL) - 3.05) < 0.02, (REAL - ENTRY) / (ENTRY - SL)
assert abs((REAL - ENTRY) / (ENTRY - SL) - 4.0) > 0.5, "mișcarea reală NU e 4R"
# structura care susține afirmațiile din text
assert abs(cds[SHL_I].c - SHOULDER_L) < 0.05, cds[SHL_I].c
assert abs(cds[HEAD_I].c - HEAD) < 0.05, cds[HEAD_I].c
assert abs(cds[SHR_I].c - SHOULDER_R) < 0.05, cds[SHR_I].c
assert HEAD < SHOULDER_L and HEAD < SHOULDER_R, (HEAD, SHOULDER_L, SHOULDER_R)
assert cds[SHL_I].c == min(c.c for c in cds[SHL_I - 1:SHL_I + 2]), "umărul stâng nu e minim local"
assert cds[HEAD_I].c == min(c.c for c in cds[HEAD_I - 1:HEAD_I + 2]), "head-ul nu e minim local"
assert cds[SHR_I].c == min(c.c for c in cds[SHR_I - 1:SHR_I + 2]), "umărul drept nu e minim local"
min_pre = min(c.l for c in cds[:ENTRY_I])
assert abs(min_pre - 554.0) < 1.0, min_pre # suportul quarterly atins
assert abs(min_pre - SL) < 0.05, (min_pre, SL) # SL chiar la minimul head-ului
assert cds[ENTRY_I].c > cds[ENTRY_I].o, "candela de intrare trebuie verde"
assert cds[ENTRY_I - 1].c < cds[ENTRY_I - 1].o, "umărul drept e roșu"
assert abs(cds[37].c - REAL) < 0.05, cds[37].c
assert all(c.vol is not None for c in cds), "lipsește panoul de volum"
assert len(cds) == 38
# ── desenul ─────────────────────────────────────────────────────────────────
levels = [
Level(TARGET_4R, "ținta 4R era 667.00 (+16%)", "#555"),
Level(REAL, "646.00 — +12% efectiv (~3R)", "#188a3e", label_at="left"),
Level(TP1, "TP1 599.60", "#1a5fb4"),
Level(NECKLINE, "neckline 578.00", "#1a5fb4"),
Level(SL, "SL 554.40", "#c00"),
Level(QUARTERLY, "suport quarterly 554.00", "#777", label_at="left"),
]
marks = [
Mark(SHL_I, "umăr stâng 566", "#1a1a1a", "below"),
Mark(HEAD_I, "head 555", "#1a1a1a", "below"),
Mark(SHR_I, "umăr drept 568", "#1a1a1a", "below"),
Mark(ENTRY_I, "intrare 577.00", "#188a3e", "above", dy=-10),
]
ch = Chart(
candles=cds,
levels=levels,
marks=marks,
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=3.8, width=720, gap=15, body_w=9, left=44, vol_h=70,
vol_label="volum", title="SPY — daily",
caption=("Intrare 577.00 = prima verde după umărul drept (MP² long). "
"1R = 22.60; 646.00 ~3R, într-o lună."),
)
svg = ch.render()
assert svg.count("\n\n") == 0, "linie goală în SVG — rupe markdown-ul"
OUT.write_text(svg)
print(f"serie {len(cds)} candele | intrare {entry:.2f} @ {ENTRY_I} | "
f"SL {SL:.2f} | 1R {ENTRY - SL:.2f} | TP1 {TP1:.2f} | "
f"4R {target_4r:.2f} (ținta declarată {TARGET_4R:.2f}) | "
f"real {REAL:.2f} = {(REAL - ENTRY) / (ENTRY - SL):.2f}R | "
f"min pre-intrare {min_pre:.2f}")
print(f"scris {OUT}")