"""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'', f'', f'' f'pivot weekly (mic)', f'' f'pivot monthly (mare)', ] 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}")