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
This commit is contained in:
Claude Agent
2026-09-20 12:45:14 +00:00
parent 3143e35ed9
commit 0ed607134d
13 changed files with 1610 additions and 527 deletions

136
gen/strategii/m2d_stop.py Normal file
View File

@@ -0,0 +1,136 @@
#!/usr/bin/env python3
"""M2D, pasul 4 — stopul: extrema ultimelor 4 bare, și alternativa 2 × ATR(10).
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: stop -->`.
Sus: exemplul construit din tot capitolul (3 min). Numeri 4 bare înapoi de la
bara de trigger, iei cel mai jos low și acolo stă stopul — fix pe el, fără
marjă; asta e regula folosită în TOATE diagramele capitolului.
Jos: exemplul SPY din curs, singurul loc din material unde apar cifre
absolute pentru stop. Reale din curs: close-ul de trigger 517.78, ATR(10)
2.88, stopul 2×ATR 512.02 și low-ul metodei pe 4 candele 512.87. Restul
seriei e construit ca să scoată exact acel low.
Rulare: python3 gen/strategii/m2d_stop.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 = 680
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
STOP_BARS = 4
# --- panoul 1: exemplul construit, 3 min (aceleași bare ca în ansamblu) ----
MIC = [(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),
(100.02, 100.45, 100.00, 100.40), # 9: trigger
(100.40, 100.60, 100.35, 100.55), (100.55, 100.75, 100.50, 100.70)]
TRIG_M = 9
# --- panoul 2: SPY, 15 min. Reale: 517.78, 2.88, 512.02, 512.87 -----------
SPY_CLOSE_TRIG = 517.78
SPY_ATR = 2.88
SPY_ATR_STOP = 512.02
SPY_LOW4 = 512.87
SPY = [(521.40, 521.80, 520.10, 520.50), (520.50, 520.90, 519.20, 519.60),
(519.60, 519.80, 518.10, 518.40), (518.40, 518.70, 516.90, 517.20),
(517.20, 517.40, 515.70, 516.10), (516.10, 516.40, 514.90, 515.30),
(515.30, 515.60, 513.40, 514.60),
(514.60, 514.90, 513.40, 514.00), # 7
(514.00, 514.30, SPY_LOW4, 513.50), # 8: cel mai jos low din 4
(513.50, 514.20, 513.20, 513.90), # 9
(513.90, 518.10, 513.80, SPY_CLOSE_TRIG)] # 10: trigger
TRIG_S = 10
# ---------------------------------------------------------------- verificări
for nume, bars in (("mic", MIC), ("SPY", SPY)):
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"
ENTRY_M = MIC[TRIG_M][3]
SL_M = min(b[2] for b in MIC[TRIG_M - STOP_BARS + 1:TRIG_M + 1])
RISK_M = round(ENTRY_M - SL_M, 2)
assert (ENTRY_M, SL_M, RISK_M) == (100.40, 99.90, 0.50), (ENTRY_M, SL_M, RISK_M)
# stopul nu e „undeva pe-aproape": e minimul celor 4 bare, și e minimul întregii serii
assert abs(SL_M - min(b[2] for b in MIC)) < 1e-9, "stopul nu e minimul seriei mici"
# a cincea bară înapoi are un low mai mare — deci numărul 4 chiar contează
assert MIC[TRIG_M - STOP_BARS][2] > SL_M, "a 5-a bară strică demonstrația celor 4"
PCT_M = RISK_M / ENTRY_M * 100
SL_S = min(b[2] for b in SPY[TRIG_S - STOP_BARS + 1:TRIG_S + 1])
assert abs(SL_S - SPY_LOW4) < 1e-9, f"low-ul pe 4 bare iese {SL_S}, nu {SPY_LOW4}"
assert abs(SPY[TRIG_S][3] - SPY_CLOSE_TRIG) < 1e-9
assert abs((SPY_CLOSE_TRIG - 2 * SPY_ATR) - SPY_ATR_STOP) < 1e-9, \
"2×ATR nu dă stopul din curs"
MARJA = round(SPY_LOW4 - SPY_ATR_STOP, 2)
assert MARJA == 0.85, MARJA
RISK_S4 = round(SPY_CLOSE_TRIG - SPY_LOW4, 2)
RISK_SA = round(SPY_CLOSE_TRIG - SPY_ATR_STOP, 2)
assert (RISK_S4, RISK_SA) == (4.91, 5.76), (RISK_S4, RISK_SA)
assert SPY_ATR_STOP < SPY_LOW4, "ATR ar trebui să dea un stop mai larg"
def chart(bars, scale, gap, left, body_w, arrows, top=64):
return Chart(candles=[Candle(*b) for b in bars], arrows=arrows, scale=scale,
gap=gap, body_w=body_w, left=left, width=W, top=top)
ch_m = chart(MIC, 150.0, 34, 62, 13, [
Arrow(TRIG_M, "bara de trigger: de la ea numeri înapoi",
where="above", color=GREEN, dx=-30, dy=-6),
Arrow(TRIG_M - STOP_BARS + 2, "cel mai jos low dintre cele 4 bare: 99.90.\n"
"Stopul stă FIX acolo, fără marjă",
where="below", color=RED, dx=-40, dy=40)])
ch_s = chart(SPY, 17.0, 34, 62, 13, [
Arrow(TRIG_S, "close-ul barei de trigger 517.78",
where="above", color=GREEN, dx=-60, dy=-4),
Arrow(8, "2 × ATR(10) = 5.76 sub close:\n"
"stop 512.02, cu 0.85 sub low-ul celor 4 bare",
where="below", color=ORANGE, dx=-20, dy=52)])
body_m, h_m = duo.panel(ch_m, W)
body_s, h_s = duo.panel(ch_s, W)
extra_m = (duo.titlu("Metoda de bază — cele 4 bare", color=RED)
+ duo.zone(ch_m, TRIG_M - STOP_BARS + 1, TRIG_M,
f"{STOP_BARS} bare, numărate de la trigger înapoi", RED,
pad=13, lift=30)
+ duo.level(ch_m, ENTRY_M, ["intrare 100.40"], GREEN, W, at_left=False)
+ duo.level(ch_m, SL_M, ["stop 99.90 — risc 0.50 pe acțiune (0,50 %)"],
RED, W, below=True))
extra_s = (duo.titlu("Alternativa din curs — 2 × ATR(10), pe SPY", color=ORANGE)
+ duo.zone(ch_s, TRIG_S - STOP_BARS + 1, TRIG_S, "", RED, pad=13)
+ duo.level(ch_s, SPY_CLOSE_TRIG, ["intrare 517.78"], GREEN, W, at_left=False)
+ duo.level(ch_s, SPY_LOW4, ["stop pe 4 bare 512.87 — risc 4.91"],
RED, W, below=False)
+ duo.level(ch_s, SPY_ATR_STOP, ["stop 2×ATR 512.02 — risc 5.76"],
ORANGE, W, below=True, dash="2 3"))
svg, H, n = duo.build(
[("mic", body_m, h_m, extra_m), ("SPY", body_s, h_s, extra_s)],
["Sus: serie construită, aceleași cifre ca în restul capitolului.",
"Jos: din curs sunt reale doar 517.78, ATR(10) = 2.88, 512.02 și 512.87; "
"restul barelor sunt construite.",
"ATR-ul dă un stop mai larg, deci un risc mai mare pe acțiune — și, la același",
"risc în dolari, mai puține acțiuni."],
W)
duo.fara_preturi_straine(svg, [ENTRY_M, SL_M, RISK_M, SPY_CLOSE_TRIG, SPY_LOW4,
SPY_ATR_STOP, SPY_ATR, RISK_S4, RISK_SA, MARJA,
2 * SPY_ATR, PCT_M])
OUT.write_text(svg, encoding="utf-8")
print(f"scris {OUT} ({W}x{H:.0f}), {n} etichete | mic: intrare {ENTRY_M:.2f} stop {SL_M:.2f} "
f"risc {RISK_M:.2f} ({PCT_M:.2f} %) | SPY: intrare {SPY_CLOSE_TRIG:.2f}, 4 bare "
f"{SPY_LOW4:.2f} (risc {RISK_S4:.2f}), 2×ATR {SPY_ATR_STOP:.2f} (risc {RISK_SA:.2f}), "
f"diferență {MARJA:.2f}")