Files
atm-curs-dl/gen/strategii/m2d_secventa.py
Claude Agent 0ed607134d m2d: diagramele refacute; ansamblul primeste corespondenta de TF
Ansamblul arata acum 15 min si 3 min ca descompunere reala (k=5, cu
assert), cu caseta punctata, ghidaje si nivelul comun legat prin
conector — sablonul din buy_doji_perechi_tf.

Noi, pentru pasii care nu aveau diagrama: directie (15 min ramane in Buy
vs. se inchide Sell), trigger (bara inchisa peste capat vs. atinsa doar
cu fitilul, plus al doilea semnal marcat "nu mai intri"), stop (cele 4
bare si alternativa 2xATR, cu cifrele SPY din curs), iesire (TP1 plus
bull trail, long si short, oglinda calculata nu desenata din ochi).
Secventa era din polilinii desenate de mana — rescrisa pe serie.

Stopul e fix pe extrema celor 4 bare, fara marja: asa spune cursul aici,
spre deosebire de 01_buy_doji. Diferenta trebuie spusa in text.

Textul capitolului e neatins — agentul a atins pragul de context.

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

126 lines
6.0 KiB
Python

#!/usr/bin/env python3
"""M2D, pasul 2 — pullback-ul (M) pe TF mic: DA (există) vs. NU (lipsește).
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: secventa -->`.
Panoul de sus e chiar graficul de 3 minute din diagrama de ansamblu, primele
13 bare — aceleași cifre în tot capitolul. Panoul de jos pornește din același
preț, dar urcă fără să se oprească: nu există pullback, deci nu există setup
M2D, oricât de frumoasă ar fi mișcarea.
Definiția pe care o susține desenul: pullback = revenire scurtă contra
direcției mari care NU rupe minimul din care a pornit mișcarea. Minimul acela
e low-ul candelei de 15 min care a dat semnalul (99.80) și e desenat pe
ambele panouri.
Rulare: python3 gen/strategii/m2d_secventa.py
"""
import sys
from pathlib import Path
sys.path.insert(0, "/workspace/atm-curs-dl")
sys.path.insert(0, str(Path(__file__).resolve().parent))
from svg_candles import Arrow, Candle, Chart # noqa: E402
import m2d_duo as duo # noqa: E402
OUT = Path(__file__).with_suffix(".svg")
W, SCALE, GAP, LEFT = 680, 108.0, 32, 66
GREEN, RED, BLUE, CYAN, GREY = "#188a3e", "#c00", "#1a5fb4", "#0891b2", "#555"
REF_LOW = 99.80 # low-ul candelei de 15 min de semnal (vezi diagrama „directie")
SEMNAL = 100.60 # close-ul ei = open-ul primei bare de 3 min
# --- DA: primele 13 bare din seria de 3 min a diagramei de ansamblu --------
DA = [(100.60, 100.70, 100.40, 100.45), (100.45, 100.50, 100.25, 100.30),
(100.30, 100.35, 100.15, 100.20), (100.20, 100.25, 100.05, 100.10),
(100.10, 100.15, 100.00, 100.05), (100.05, 100.10, 99.95, 100.00),
(100.00, 100.05, 99.92, 99.95), (99.95, 100.00, 99.90, 99.98),
(99.98, 100.08, 99.94, 100.02), # 8: capătul pullback-ului
(100.02, 100.45, 100.00, 100.40), # 9: primul Buy = trigger
(100.40, 100.60, 100.35, 100.55), (100.55, 100.75, 100.50, 100.70),
(100.70, 101.00, 100.65, 100.95)]
PULL_END = 8
# --- NU: aceeași plecare, dar urcare continuă, fără pullback --------------
NU = [(100.60, 100.80, 100.55, 100.75), (100.75, 100.95, 100.70, 100.90),
(100.90, 101.10, 100.85, 101.05), (101.05, 101.20, 101.00, 101.15),
(101.15, 101.35, 101.10, 101.30), (101.30, 101.45, 101.25, 101.40),
(101.40, 101.60, 101.35, 101.55), (101.55, 101.75, 101.50, 101.70),
(101.70, 101.90, 101.65, 101.85), (101.85, 102.00, 101.80, 101.95),
(101.95, 102.15, 101.90, 102.10), (102.10, 102.25, 102.05, 102.20),
(102.20, 102.40, 102.15, 102.35)]
# ---------------------------------------------------------------- verificări
for nume, bars in (("DA", DA), ("NU", NU)):
for i, (o, h, l, c) in enumerate(bars):
assert h >= max(o, c) and l <= min(o, c), f"{nume}[{i}]: high/low incoerent"
if i:
assert abs(o - bars[i - 1][3]) < 1e-9, f"{nume}[{i}]: open != close precedent"
assert abs(bars[0][0] - SEMNAL) < 1e-9, f"{nume}: nu pornește din close-ul semnalului"
def run_in_jos(bars):
"""Cel mai lung șir de close-uri strict descrescătoare."""
best = cur = 1
for a, b in zip(bars, bars[1:]):
cur = cur + 1 if b[3] < a[3] else 1
best = max(best, cur)
return best
assert run_in_jos(DA) >= 3, "DA nu are pullback (niciun șir de 3 close-uri în jos)"
assert run_in_jos(NU) < 3, "NU are totuși un pullback"
PULL_LOW = min(b[2] for b in DA[:PULL_END + 1])
assert abs(PULL_LOW - 99.90) < 1e-9, PULL_LOW
assert PULL_LOW > REF_LOW, "pullback-ul rupe minimul din care a pornit mișcarea"
assert DA[0][3] > DA[PULL_END - 1][3], "pullback-ul nu coboară"
assert DA[9][3] > max(b[1] for b in DA[6:9]), "bara 9 nu rupe în sus capătul pullback-ului"
assert min(b[3] for b in NU) > SEMNAL, "NU: o bară se închide sub prețul de plecare"
def chart(bars, arrows):
return Chart(candles=[Candle(*b) for b in bars], arrows=arrows,
scale=SCALE, gap=GAP, body_w=11, left=LEFT, width=W, top=64)
ch_da = chart(DA, [
Arrow(PULL_END - 1, "M: pullback-ul obligatoriu — prețul merge\n"
"contra direcției mari, dar se oprește la 99.90",
where="below", color=RED, dx=-24, dy=46),
Arrow(9, "prima bară care urcă peste capătul pullback-ului:\n"
"aici începe pasul 3 (trigger-ul)",
where="above", color=GREEN, dx=-40, dy=6)])
ch_nu = chart(NU, [
Arrow(6, "urcare continuă, fără nicio pauză în jos:\n"
"asta e breakout, nu M2D — nu ai unde pune stopul",
where="below", color=RED, dx=-70, dy=40)])
body_da, h_da = duo.panel(ch_da, W)
body_nu, h_nu = duo.panel(ch_nu, W)
extra_da = (duo.titlu("DA — pullback pe 3 min, care nu rupe minimul de referință", color=GREEN)
+ duo.zone(ch_da, 0, PULL_END, "M: pullback", RED, pad=12, lift=26)
+ duo.level(ch_da, REF_LOW,
["minimul din care a pornit mișcarea 99.80 — sub el nu mai e pullback"],
GREY, W, below=True, dash="2 3")
+ duo.level(ch_da, PULL_LOW, ["cel mai jos punct al pullback-ului 99.90"],
RED, W, below=False, at_left=False))
extra_nu = (duo.titlu("NU — niciun pullback: nu ai setup, oricât de frumoasă e urcarea",
color=RED)
+ duo.level(ch_nu, SEMNAL,
["close-ul candelei de 15 min de semnal 100.60"], CYAN, W,
below=True, at_left=False))
svg, H, n = duo.build(
[("DA", body_da, h_da, extra_da), ("NU", body_nu, h_nu, extra_nu)],
["Ambele panouri: 3 minute, serie construită, aceleași cifre ca în diagrama de ansamblu.",
'Pullback nu înseamnă „nu mai face minim nou": înseamnă că nu rupe minimul '
'din care a pornit mișcarea.'],
W)
duo.fara_preturi_straine(svg, [REF_LOW, PULL_LOW, SEMNAL])
OUT.write_text(svg, encoding="utf-8")
print(f"scris {OUT} ({W}x{H:.0f}), {n} etichete | DA: șir în jos de {run_in_jos(DA)} bare, "
f"minim {PULL_LOW:.2f} peste referința {REF_LOW:.2f} | NU: șir în jos de "
f"{run_in_jos(NU)} bare")