Nivelurile 1-2-3, cei 6 pasi cu diagrama fiecare, mini-glosar de 33 de termeni, oglinda pe short cu diagrama ei, checklist. Sursele in fise/07_mdsrt_surse.md. Capitolul avea TREI reguli numerice diferite in acelasi loc: stop fix pe low in ansamblu, 0.10 sub low in aplus si exemplu, plus doua reguli de intrare. Acum mdsrt_ansamblu.py tine seria si regulile, iar picior, trigger, stop, iesire si short le importa — nu mai pot diverge. Noi: zona (daily -> 60 min ca descompunere reala, 2 candele daily = 14 bare, cu caseta, ghidaje si pivotul pe ambele panouri), picior, trigger, stop, iesire, short (seria long rasturnata, deci fiecare cifra are perechea ei). Verificare numerica text-diagrama: trei nepotriviri reparate, inclusiv o cifra din proza care nu exista pe niciun desen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
97 lines
4.8 KiB
Python
97 lines
4.8 KiB
Python
"""MDSRT, Pasul 6 — ieșirea: TP1 la 1:1, breakeven, restul pe trail.
|
|
|
|
Aceeași serie canonică (importată din `mdsrt_ansamblu`), de la intrare
|
|
încolo: prima parte a poziției iese la ținta simetrică 1:1 (591.00), stopul
|
|
se mută la breakeven după ce prețul a trecut de jumătatea drumului până la
|
|
țintă, iar restul merge pe linia de trail — ultimul swing low — până la prima
|
|
închidere sub ea.
|
|
|
|
Din curs: ținta stabilită împreună cu stopul, simetric; trail pe Bull Trail
|
|
sau pe swing low, la alegerea traderului; trail-ul se evaluează pe candelă
|
|
închisă, nu în timpul barei. Numărul de tranșe NU e dat de curs —
|
|
transcrierea se întrerupe exact acolo.
|
|
|
|
Rulează: python3 gen/strategii/mdsrt_iesire.py
|
|
"""
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, "/workspace/atm-curs-dl")
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
from svg_candles import Chart, Level, Mark, Arrow, Zone # noqa: E402
|
|
from mdsrt_ansamblu import (serie, CONF, ENTRY, SL, R, TP1, EXIT_I, TRAIL, # noqa: E402
|
|
bull_trail)
|
|
|
|
OUT = Path(__file__).with_suffix(".svg")
|
|
GREEN, RED, BLUE, GRAY, ORANGE = "#188a3e", "#c00", "#1a5fb4", "#555", "#b06000"
|
|
W = 720
|
|
S = 14
|
|
|
|
cds = serie()[S:EXIT_I + 1]
|
|
cf, tp_i, ex_i = CONF - S, 22 - S, EXIT_I - S
|
|
BE = ENTRY # stopul mutat la prețul de intrare
|
|
half = round(ENTRY + R / 2, 2) # jumătatea drumului până la țintă
|
|
be_i = next(i for i in range(cf + 1, len(cds)) if cds[i].c > half)
|
|
|
|
# ----------------------------------------------------------------- assert-uri
|
|
assert cds[cf].c == ENTRY and round(ENTRY - SL, 2) == R
|
|
assert round(TP1 - ENTRY, 2) == R, "ținta nu e simetrică cu stopul"
|
|
assert cds[tp_i].h >= TP1 and max(c.h for c in cds[cf + 1:tp_i]) < TP1, "TP1 atins altundeva"
|
|
assert cds[be_i].c > half and all(c.c <= half for c in cds[cf + 1:be_i]), "breakeven greșit"
|
|
assert be_i < tp_i, "breakeven-ul ar veni după țintă"
|
|
# trail: ultimul swing low înaintea întoarcerii; ieșirea e prima închidere sub el
|
|
assert cds[ex_i].c < TRAIL and all(c.c > TRAIL for c in cds[ex_i - 2:ex_i])
|
|
r_exit = round((cds[ex_i].c - ENTRY) / R, 2)
|
|
assert r_exit == 2.75, r_exit
|
|
# scara: distanța intrare→TP1 e egală cu distanța intrare→SL, și în preț, și în px
|
|
print(f"ieșire: TP1 {TP1:.2f} la bara {tp_i + S}, breakeven de la bara {be_i + S} "
|
|
f"(peste {half:.2f}), trail {TRAIL:.2f}, ieșire {cds[ex_i].c:.2f} = {r_exit:.2f}R")
|
|
|
|
ch = Chart(
|
|
candles=cds,
|
|
levels=[
|
|
Level(TP1, f"TP1 {TP1:.2f} = 1:1", GREEN, "2 2",
|
|
label_at="left"),
|
|
Level(ENTRY, f"intrare {ENTRY:.2f} = breakeven", GRAY, "4 3",
|
|
label_at="left"),
|
|
Level(SL, f"SL inițial {SL:.2f} (risc {R:.2f} = 1R)", RED, "4 3", label_at="left"),
|
|
],
|
|
marks=[Mark(ex_i, f"ieșire {cds[ex_i].c:.2f} = {r_exit:.2f}R", GREEN, "above")],
|
|
zones=[Zone(be_i, tp_i, "de aici stopul stă la breakeven", ORANGE)],
|
|
arrows=[
|
|
Arrow(be_i, f"prețul a trecut de jumătatea drumului ({half:.2f}):\n"
|
|
f"muți stopul la {BE:.2f} — trade-ul nu mai poate pierde",
|
|
where="below", price=SL, color=ORANGE, dx=-40, dy=44),
|
|
Arrow(tp_i, f"ținta 1:1 atinsă: {TP1:.2f}\nrestul poziției rămâne pe trail",
|
|
where="above", color=GREEN, dx=90, dy=-30),
|
|
Arrow(ex_i, f"prima închidere sub linia de trail ({TRAIL:.2f}):\n"
|
|
f"ieși cu restul — se citește pe candelă închisă,\nnu în timpul barei",
|
|
where="below", price=cds[ex_i].c, color=BLUE, dx=-30, dy=64),
|
|
],
|
|
scale=56.0, gap=24, body_w=12, left=200, width=W, top=44,
|
|
title="Pasul 6 — ieșirea: ținta 1:1, breakeven, restul pe trail (SPY 5 min, construit)",
|
|
caption="Câte tranșe faci nu e dat de curs: acolo se întrerupe transcrierea.",
|
|
)
|
|
svg = ch.render()
|
|
|
|
# linia de trail: ultimul swing low de la fiecare pas, desenată ca scară
|
|
trail_pts = bull_trail(cds, cf)
|
|
assert trail_pts[-1][1] == TRAIL, (trail_pts[-1], TRAIL)
|
|
assert len(trail_pts) > 5, trail_pts
|
|
d = []
|
|
for k, (i, p) in enumerate(trail_pts):
|
|
x0, x1 = ch._cx(i) - ch.gap / 2, ch._cx(i) + ch.gap / 2
|
|
d.append(("M" if k == 0 else "L") + f"{x0:.1f},{ch._y(p):.1f}")
|
|
d.append(f"L{x1:.1f},{ch._y(p):.1f}")
|
|
trail_svg = (f'<path d="{" ".join(d)}" fill="none" stroke="{BLUE}" stroke-width="1.6" '
|
|
f'stroke-dasharray="5 3"/>')
|
|
i = svg.rindex("</svg>")
|
|
svg = svg[:i] + " " + trail_svg + "\n" + svg[i:]
|
|
assert "\n\n" not in svg, "linie goală în SVG"
|
|
H = float(re.search(r'viewBox="0 0 [\d.]+ ([\d.]+)"', svg).group(1))
|
|
for x, y in re.findall(r'<text x="([-\d.]+)" y="([-\d.]+)"', svg):
|
|
assert 0 <= float(x) <= W and 0 <= float(y) <= H, f"text în afara pânzei la ({x}, {y})"
|
|
OUT.write_text(svg, encoding="utf-8")
|
|
print(f"scris {OUT.name} ({W}x{H:.0f})")
|