Files
atm-curs-dl/gen/strategii/mp2_bottom.py
Claude Agent 2ea599f265 02_mp2: capitol reconstruit dupa sablon
Nivelurile 1-2-3, cei 6 pasi cu diagrama fiecare, mini-glosar de 34 de
termeni, oglinda pe short cu diagrama ei proprie, checklist. Sursele in
fise/02_mp2_surse.md.

Toate diagramele procedurii ies acum dintr-o singura serie
(mp2_serie.py), deci capitolul nu mai poate avea doua reguli numerice.
Ansamblul folosea NVDA cu stop la swing low absolut (-23 %), adica alta
regula decat procedura celor 4 bare; NVDA a devenit "bottom", la nivelul
3, marcat explicit ca exceptie.

perechi_tf e diagrama cu doua timeframe-uri: panoul mic e descompunerea
reala a ultimelor 2 candele daily (1 zi = 7 bare de 60 min), cu pivotul
weekly pe ambele panouri si conector. Pivotii se calculeaza din serie, nu
sunt scrisi de mana.

Reparate: trail-ul din proza era 600.05, calculul din serie da 600.75;
doua SVG-uri aveau trimiteri fisier:linie desenate pe ele.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
2026-09-20 12:51:58 +00:00

143 lines
6.8 KiB
Python
Raw Permalink 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.

"""MP² la un bottom major — NVDA (strategii/02_mp2.md, Nivelul 3).
Excepția de la regula stopului: la un bottom/top major stopul nu se
măsoară pe 4 candele, ci la swing low-ul absolut al mișcării.
„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_bottom.py
Scrie lângă el `mp2_bottom.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_bottom.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}")