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

170 lines
8.0 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.

#!/usr/bin/env python3
"""M2D, pasul 5 — ieșirea: TP1 la 1:1 și restul pe trail, long și short.
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: iesire -->`.
Sus, LONG: barele de după trigger din seria de 3 minute a diagramei de
ansamblu. Prima tranșă iese la TP1 = 1:1. Restul merge pe bull trail: linia
sare pe low-ul fiecărei bare care se ÎNCHIDE peste high-ul precedentei și nu
coboară niciodată. Ieșirea vine la prima bară care se închide sub linie —
fitilul de dedesubt al barei dinainte nu scoate pe nimeni.
Jos, SHORT: exact aceeași serie oglindită în jurul lui 100.00 (p' = 200 − p),
deci bear trail-ul e construit de același cod, doar cu semnele întoarse.
Oglinda e calculată, nu desenată din ochi.
Rulare: python3 gen/strategii/m2d_iesire.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, 150.0, 40, 66
GREEN, RED, ORANGE, GREY = "#188a3e", "#c00", "#b06000", "#555"
OGLINDA = 200.0 # axa de oglindire: p' = OGLINDA − p
LONG = [(99.98, 100.08, 99.94, 100.02),
(100.02, 100.45, 100.00, 100.40), # 1: trigger, intrare
(100.40, 100.60, 100.35, 100.55), (100.55, 100.75, 100.50, 100.70),
(100.70, 101.00, 100.65, 100.95), # 4: TP1 atins
(100.95, 101.10, 100.88, 101.05), (101.05, 101.15, 100.95, 101.00),
(101.00, 101.40, 100.95, 101.35), (101.35, 101.55, 101.25, 101.45),
(101.45, 101.50, 101.20, 101.25), # 9: fitil sub linie, close peste
(101.25, 101.30, 101.05, 101.10), # 10: close sub linie = ieși
(101.10, 101.15, 100.90, 100.95)]
TRIG, SL_LONG = 1, 99.90 # stopul vine din pasul 4
SHORT = [(OGLINDA - o, OGLINDA - l, OGLINDA - h, OGLINDA - c) for o, h, l, c in LONG]
SL_SHORT = OGLINDA - SL_LONG
def trepte(bars, trig, sus):
"""Linia de trail, bară cu bară, de la trigger încolo.
sus=True: bull trail — sare pe low-ul barei care se ÎNCHIDE peste high-ul
precedentei. sus=False: bear trail — pe high-ul barei care se închide sub
low-ul precedentei. `None` cât timp linia nu există încă.
"""
linie, out, iesire = None, [], None
for i, (o, h, l, c) in enumerate(bars):
if i > trig and linie is not None and ((c < linie) if sus else (c > linie)):
iesire = i
out.append(linie)
break
if i > trig:
p = bars[i - 1]
if (c > p[1]) if sus else (c < p[2]):
linie = l if sus else h
out.append(linie)
return out + [linie] * (len(bars) - len(out)), iesire
# ---------------------------------------------------------------- verificări
for nume, bars in (("LONG", LONG), ("SHORT", SHORT)):
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"
E_L, E_S = LONG[TRIG][3], SHORT[TRIG][3]
R_L, R_S = round(E_L - SL_LONG, 2), round(SL_SHORT - E_S, 2)
TP_L, TP_S = round(E_L + R_L, 2), round(E_S - R_S, 2)
assert (E_L, R_L, TP_L) == (100.40, 0.50, 100.90), (E_L, R_L, TP_L)
assert (E_S, R_S, TP_S) == (99.60, 0.50, 99.10), (E_S, R_S, TP_S)
assert abs((OGLINDA - E_L) - E_S) < 1e-9 and abs((OGLINDA - TP_L) - TP_S) < 1e-9, \
"oglinda nu e exactă"
TP_BAR_L = next(i for i in range(TRIG + 1, len(LONG)) if LONG[i][1] >= TP_L - 1e-9)
TP_BAR_S = next(i for i in range(TRIG + 1, len(SHORT)) if SHORT[i][2] <= TP_S + 1e-9)
assert TP_BAR_L == TP_BAR_S == 4, (TP_BAR_L, TP_BAR_S)
LIN_L, EX_L = trepte(LONG, TRIG, True)
LIN_S, EX_S = trepte(SHORT, TRIG, False)
assert EX_L == EX_S == 10, (EX_L, EX_S)
TRAIL_L, TRAIL_S = LIN_L[EX_L], LIN_S[EX_S]
assert (TRAIL_L, TRAIL_S) == (101.25, 98.75), (TRAIL_L, TRAIL_S)
assert abs((OGLINDA - TRAIL_L) - TRAIL_S) < 1e-9, "trail-ul oglindit nu se potrivește"
# linia urcă (long) / coboară (short) și nu se întoarce niciodată
pas_l = [v for v in LIN_L[:EX_L + 1] if v is not None]
pas_s = [v for v in LIN_S[:EX_S + 1] if v is not None]
assert all(b >= a for a, b in zip(pas_l, pas_l[1:])), "bull trail-ul coboară"
assert all(b <= a for a, b in zip(pas_s, pas_s[1:])), "bear trail-ul urcă"
# bara 9: fitilul trece de linie, close-ul nu — deci nu scoate
assert LONG[9][2] < TRAIL_L <= LONG[9][3], "bara 9 nu mai ilustrează fitilul sub linie"
assert SHORT[9][1] > TRAIL_S >= SHORT[9][3], "oglinda barei 9 nu ține"
EXIT_L, EXIT_S = LONG[EX_L][3], SHORT[EX_S][3]
RR_L = round((EXIT_L - E_L) / R_L, 1)
RR_S = round((E_S - EXIT_S) / R_S, 1)
assert RR_L == RR_S == 1.4, (RR_L, RR_S)
def chart(bars, arrows, top=70):
return Chart(candles=[Candle(*b) for b in bars], arrows=arrows, scale=SCALE,
gap=GAP, body_w=14, left=LEFT, width=W, top=top)
def scara(ch, linie, pana_la, color):
"""Linia de trail desenată ca scară: un palier pe fiecare bară."""
seg, prev = [], None
for i, v in enumerate(linie[:pana_la + 1]):
if v is None:
continue
y, x0, x1 = ch._y(v), ch._cx(i) - GAP / 2, ch._cx(i) + GAP / 2
seg.append(f'<line x1="{x0:.1f}" y1="{y:.1f}" x2="{x1:.1f}" y2="{y:.1f}" '
f'stroke="{color}" stroke-width="2"/>')
if prev is not None and abs(prev - v) > 1e-9:
seg.append(f'<line x1="{x0:.1f}" y1="{ch._y(prev):.1f}" x2="{x0:.1f}" '
f'y2="{y:.1f}" stroke="{color}" stroke-width="1.2" '
f'stroke-dasharray="2 2"/>')
prev = v
return seg
ch_l = chart(LONG, [
Arrow(TP_BAR_L, "prima tranșă iese aici, la TP1",
where="above", color=GREEN, dx=-60, dy=-8),
Arrow(9, "fitilul trece sub linie, close-ul nu:\nnu ieși pe fitil",
where="below", color=GREY, dx=-30, dy=86),
Arrow(EX_L, "prima bară ÎNCHISĂ sub linie:\niese restul poziției, 1.4R",
where="below", color=ORANGE, dx=-20, dy=18)])
ch_s = chart(SHORT, [
Arrow(TP_BAR_S, "prima tranșă iese aici, la TP1",
where="below", color=GREEN, dx=-60, dy=20),
Arrow(EX_S, "prima bară ÎNCHISĂ peste linie:\niese restul poziției, 1.4R",
where="above", color=ORANGE, dx=-20, dy=-8)])
body_l, h_l = duo.panel(ch_l, W)
body_s, h_s = duo.panel(ch_s, W)
extra_l = (duo.titlu("LONG — bull trail: linia urcă, nu coboară", color=GREEN)
+ scara(ch_l, LIN_L, EX_L, ORANGE)
+ duo.level(ch_l, TP_L, ["TP1 100.90 = 1:1"], GREEN, W, at_left=False)
+ duo.level(ch_l, E_L, ["intrare 100.40"], GREEN, W, below=True, at_left=False)
+ duo.level(ch_l, SL_LONG, ["stop 99.90 (pasul 4)"], RED, W, below=True))
extra_s = (duo.titlu("SHORT — bear trail: exact aceeași serie, oglindită", color=RED)
+ scara(ch_s, LIN_S, EX_S, ORANGE)
+ duo.level(ch_s, SL_SHORT, ["stop 100.10 (pasul 4)"], RED, W, at_left=False)
+ duo.level(ch_s, E_S, ["intrare 99.60"], GREEN, W, below=False)
+ duo.level(ch_s, TP_S, ["TP1 99.10 = 1:1"], GREEN, W, below=True,
at_left=False))
svg, H, n = duo.build(
[("LONG", body_l, h_l, extra_l), ("SHORT", body_s, h_s, extra_s)],
["Serii construite, aceleași cifre ca în restul capitolului.",
"Scara portocalie e linia de trail, palier cu palier.",
"Panoul de jos e panoul de sus oglindit în jurul lui 100.00, calculat, "
"nu desenat din ochi."],
W)
duo.fara_preturi_straine(svg, [E_L, TP_L, SL_LONG, TRAIL_L, EXIT_L,
E_S, TP_S, SL_SHORT, TRAIL_S, EXIT_S, OGLINDA, 100.00])
OUT.write_text(svg, encoding="utf-8")
print(f"scris {OUT} ({W}x{H:.0f}), {n} etichete | LONG: intrare {E_L:.2f} SL {SL_LONG:.2f} "
f"TP1 {TP_L:.2f} la bara {TP_BAR_L}, trail {TRAIL_L:.2f}, ieșire bara {EX_L} la "
f"{EXIT_L:.2f} = {RR_L}R | SHORT (oglindit): intrare {E_S:.2f} SL {SL_SHORT:.2f} "
f"TP1 {TP_S:.2f}, trail {TRAIL_S:.2f}, ieșire {EXIT_S:.2f} = {RR_S}R")