Files
atm-curs-dl/gen/strategii/mp2_ansamblu.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

140 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Diagrama de ansamblu MP² — bottom major NVDA (strategii/02_mp2.md, Nivel 0).
„NVDA — weekly (pre-split 1:10)": downtrend masiv → bază/bottom oct. 2022 →
crossing-ul pivotului weekly (mic) peste cel monthly (mare) → candela de
trigger care închide peste pivotul mic (M+A) → intrare 13.80 → SL la swing
low-ul absolut 10.63 (−23 %) → urcare spre TP 17.25 (+25 %, ~9 săptămâni).
Cifrele (13.80 / 10.63 / 17.25 / −23 % / +25 %) sunt din
`summaries/04_MODUL_3/04_strategia_2_mp_patrat.md:341-357,435`.
Traseul de preț și cele două linii de pivot sunt schematice: cursul nu dă
valorile pivoților, doar faptul că micul trece deasupra marelui la crossing
(`...:326-335`).
Rulează:
python3 gen/strategii/mp2_ansamblu.py
Scrie lângă el `mp2_ansamblu.svg`.
"""
import sys
from pathlib import Path
sys.path.insert(0, "/workspace/atm-curs-dl")
from svg_candles import Chart, Level, Mark, from_closes # noqa: E402
OUT = Path(__file__).resolve().parent / "mp2_ansamblu.svg"
GRAY, RED, GREEN, BLUE = "#777", "#c00", "#188a3e", "#1a5fb4"
# ------------------------------------------------------------------ seria (38 bare)
# 16 bare de downtrend 32.00 -> 11.40 (minimul absolut 10.63 e fitilul barei 15),
# 10 bare de bază/recuperare 11.80 -> 13.80 (bara 25 = intrarea, după M+A),
# 12 bare de urcare 14.10 -> 17.25 (ținta). open-ul = close-ul precedentului.
DOWN = [32.00, 30.80, 29.60, 28.70, 27.40, 26.50, 25.30, 24.20, 23.60,
22.30, 21.10, 19.90, 18.50, 16.90, 15.20, 11.40] # 0-15
BASE = [11.80, 12.10, 12.35, 12.20, 12.55, 12.85, 13.05, 13.35, 13.55,
13.80] # 16-25
UP = [14.10, 14.45, 14.80, 15.10, 15.45, 15.80, 16.10, 15.90, 16.30,
16.60, 16.95, 17.25] # 26-37
CLOSES = DOWN + BASE + UP
assert len(CLOSES) == 38, len(CLOSES)
CAPIT, ENTRY, LAST = 15, 25, 37
# fitile (sus, jos) per bară; bara 15 are fitilul de jos până la minimul absolut
WICKS = ([(0.35, 0.35)] * 14
+ [(0.30, 0.30)] # 14
+ [(0.20, 0.77)] # 15: low = 11.40 - 0.77 = 10.63
+ [(0.30, 0.30)] * 9 # 16-24
+ [(0.25, 0.20)] # 25: candela de intrare
+ [(0.30, 0.30)] * 12) # 26-37
assert len(WICKS) == len(CLOSES)
VOLS = ([52, 55, 50, 58, 54, 49, 56, 52, 60, 57, 63, 68, 72, 80, 90, 120] # 0-15
+ [100, 72, 60, 55, 58, 62, 66, 70, 78, 95] # 16-25
+ [88, 80, 74, 70, 68, 72, 76, 70, 74, 78, 84, 92]) # 26-37
assert len(VOLS) == len(CLOSES)
cds = from_closes(CLOSES, wicks=WICKS, vols=VOLS, start=32.60)
# ------------------------------------------------- liniile de pivot (trepte)
# Stepped, schematice (cursul nu dă valorile): monthly „mare" se recalculează
# rar, weekly „mic" mai des. Crossing: micul trece deasupra marelui exact pe
# candela de intrare.
PMARE = [31.00] * 10 + [21.00] * 10 + [13.55] * 8 + [13.20] * 10 # monthly
PMIC = ([30.50] * 5 + [29.00] * 5 + [20.00] * 4 + [17.00] * 4
+ [12.60] * 3 + [12.95] * 2 + [13.20] * 2 + [13.70] * 3
+ [14.20] * 4 + [14.60] * 6) # weekly
assert len(PMARE) == len(PMIC) == len(CLOSES)
# ---------------------------------------------------------- assert-urile din spec
entry = cds[ENTRY].c
sl, tp = 10.63, cds[LAST].c
assert abs(entry - 13.80) < 0.05 # close-ul intrării == 13.80
assert abs(sl - 10.63) < 0.05 and sl < entry # SL = swing low absolut, sub entry
assert abs(tp - 17.25) < 0.10 and tp > entry # TP = 17.25, peste entry
# spec: `abs((entry/sl - 1)*100 - 23)`; formula din spec e inversată (dă +29.8,
# nu −23). Pierderea corectă din entry până la SL e (sl/entry - 1), deci o scriu așa:
loss_pct = (sl / entry - 1) * 100
assert abs(loss_pct + 23) < 1.5, loss_pct # SL ≈ −23 %
assert abs((tp / entry - 1) * 100 - 25) < 1.5 # TP ≈ +25 %
assert abs(min(c.l for c in cds) - 10.63) < 0.01 # minimul absolut al seriei = SL
assert min(c.l for c in cds[-5:-1]) > 10.63 # stopul de 4 bare ar fi mult mai sus
# crossing-ul pivoților, înainte/după candela de intrare
assert all(PMIC[i] < PMARE[i] for i in range(ENTRY - 4, ENTRY)), "mic < mare înainte de intrare"
assert all(PMIC[i] > PMARE[i] for i in range(ENTRY, ENTRY + 4)), "mic > mare după intrare"
assert cds[ENTRY].c > PMIC[ENTRY], "candela de trigger nu închide peste pivotul mic"
assert abs(cds[CAPIT].l - sl) < 1e-9, "fitilul barei 15 nu atinge exact SL-ul"
levels = [
Level(13.80, "entry ~13.80 (după M+A)", GREEN, label_at="left"),
Level(sl, "SL swing low absolut 10.63, −23%", RED, label_at="left"),
Level(tp, "TP ~+25% (17.25), ~9 săpt.", BLUE, label_at="left"),
]
marks = [
Mark(CAPIT, f"minim absolut {sl:.2f}", RED, "below", dy=-6),
Mark(ENTRY, "M+A", BLUE, "above"),
]
ch = Chart(candles=cds, levels=levels, marks=marks,
scale=17.0, gap=15, body_w=9, left=44, width=720, top=64, vol_h=70,
vol_label="volum", title="NVDA — weekly (pre-split 1:10)",
caption="Bottom oct. 2022: entry ~13.80, −23%, ~+25% în ~9 săpt. "
"Traseu și pivoți construiți (cursul nu dă valorile lor).")
svg = ch.render()
def step_points(vals: list[float]) -> str:
"""Polilinie în trepte: orizontal pe fiecare palier, vertical la schimbare."""
pts: list[tuple[float, float]] = []
for i, v in enumerate(vals):
x, y = ch._cx(i), ch._y(v)
if i == 0:
pts.append((x, y))
elif v != vals[i - 1]:
pts.append((x, ch._y(vals[i - 1]))) # orizontal până la bara nouă
pts.append((x, y)) # salt vertical la nivelul nou
else:
pts.append((x, y))
return " ".join(f"{x:.1f},{y:.1f}" for x, y in pts)
# injectate imediat după tag-ul de deschidere => desenate în spatele candelelor
inject = [
f'<polyline points="{step_points(PMARE)}" fill="none" stroke="{GRAY}" stroke-width="1.6"/>',
f'<polyline points="{step_points(PMIC)}" fill="none" stroke="{BLUE}" stroke-width="1.6"/>',
f'<text x="712" y="{ch._y(PMIC[-1]) - 6:.1f}" fill="{BLUE}" text-anchor="end">'
f'pivot weekly (mic)</text>',
f'<text x="712" y="{ch._y(PMARE[-1]) + 14:.1f}" fill="{GRAY}" text-anchor="end">'
f'pivot monthly (mare)</text>',
]
i = svg.index(">") + 1
svg = svg[:i] + "\n " + "\n ".join(inject) + svg[i:]
assert svg.count("\n\n") == 0, "linie goală în SVG rupe blocul din markdown"
OUT.write_text(svg)
print(f"scris {OUT.name}: {len(cds)} candele, entry {entry:.2f}, "
f"SL {sl:.2f} ({loss_pct:+.1f}%), TP {tp:.2f} "
f"({(tp/entry - 1) * 100:+.1f}%), crossing la bara {ENTRY}")