La mdsrt_aplus eticheta spunea "primul low 94.60" pentru o bara al carei low era 94.50. Reparatia a mutat low-ul, nu eticheta: regula capitolului numara piciorul dupa low, iar specul spune tot 94.60 - doar umbra de 0.10 o contrazicea. Nicio cifra tiparita nu se schimba, iar nivelul isi ia acum eticheta din date, cu assert, ca sa nu mai poata minti. Cele trei de la mp2 aveau toate aceeasi cauza fizica: text colorat peste un corp de candela de aceeasi culoare. Acolo caracterele nu se incaleca, dispar - "intrare 577.00" se citea "intrare 577. 0", "crossing" se citea "crossi g". VERDICT pe restul de ~94: nu merita un lot. Din 20 de suprapuneri vazute efectiv pe ecran, doar 3 schimbau ce citesti, si toate trei din cauza aia. Celelalte 17 - text peste fitil, peste linie de nivel, peste chenar, peste coada de sageata - raman lizibile, fiindca fundalul e o linie subtire, nu o suprafata plina. Filtrul util nu e tiparul geometric, ci: eticheta cu cifra, peste un <rect> de aceeasi culoare. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
118 lines
5.9 KiB
Python
118 lines
5.9 KiB
Python
"""MDSRT pe short — oglinda completă a trade-ului long.
|
||
|
||
Seria e exact seria canonică a capitolului, răsturnată în jurul unui preț
|
||
(p' = 690 − p): fiecare candelă verde devine roșie, fiecare low devine high.
|
||
Așa, orice regulă verificată pe long e verificată și aici, cu semnul schimbat
|
||
— și se vede că nu e „doar invers", ci un trade întreg.
|
||
|
||
ATENȚIE: varianta short a MDSRT NU e explicată în curs — transcrierea se
|
||
întrerupe înainte. Regulile de aici sunt reconstruite prin oglindire de
|
||
autorul sumarului, marcate ca atare, și se tratează ca ipoteză de testat.
|
||
|
||
Rulează: python3 gen/strategii/mdsrt_short.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 Candle, Chart, Level, Mark, Zone, Arrow # noqa: E402
|
||
sys.path.insert(0, "/workspace/atm-curs-dl/gen")
|
||
from eticheta_libera import eticheta_libera # noqa: E402
|
||
from mdsrt_ansamblu import (serie, SUPORT, LEG1, TRIG, CONF, EXIT_I, # noqa: E402
|
||
ENTRY, SL, R, TP1, MARJA, STOP_BARS)
|
||
|
||
OUT = Path(__file__).with_suffix(".svg")
|
||
GREEN, RED, BLUE, GRAY, ORANGE = "#188a3e", "#c00", "#1a5fb4", "#555", "#b06000"
|
||
W, K = 700, 690.0 # K = prețul în jurul căruia se răstoarnă seria
|
||
S = 6
|
||
|
||
|
||
def m(p):
|
||
return round(K - p, 2)
|
||
|
||
|
||
cds = [Candle(m(c.o), m(c.l), m(c.h), m(c.c), vol=c.vol) for c in serie()]
|
||
REZ = m(SUPORT) # rezistența / pivotul, sus
|
||
l1, l2, cf, ex = LEG1, TRIG, CONF, EXIT_I
|
||
leg1_h, leg2_h = cds[l1].h, cds[l2].h
|
||
entry = cds[cf].c
|
||
sl = round(leg2_h + MARJA, 2)
|
||
risk = round(sl - entry, 2)
|
||
tp1 = round(entry - risk, 2)
|
||
|
||
# ----------------------------------------------------------------- assert-uri
|
||
for i, c in enumerate(cds):
|
||
assert c.h >= max(c.o, c.c) and c.l <= min(c.o, c.c), i
|
||
if i:
|
||
assert abs(c.o - cds[i - 1].c) < 1e-9, f"open[{i}] != close[{i-1}]"
|
||
# 1. oglinda e exactă: fiecare cifră a trade-ului long are perechea ei
|
||
assert (REZ, leg1_h, leg2_h, entry, sl, tp1) == (100.00, 99.90, 100.50, 99.80, 100.60, 99.00), \
|
||
(REZ, leg1_h, leg2_h, entry, sl, tp1)
|
||
assert risk == R == 0.80
|
||
# 2. povestea: piciorul 1 nu trece de nivel, piciorul 2 îl rupe în sus și recade
|
||
assert leg1_h < REZ < leg2_h
|
||
assert cds[l2].c > REZ, "candela-trigger ar trebui să se închidă tot deasupra nivelului"
|
||
assert cds[cf].c < REZ, "candela de intrare nu se închide înapoi sub nivel"
|
||
# 3. intrarea rupe low-ul candelei-trigger, stopul e cu marja peste maximul ei
|
||
assert entry < cds[l2].l, (entry, cds[l2].l)
|
||
high4 = max(c.h for c in cds[cf - STOP_BARS + 1:cf + 1])
|
||
assert high4 == leg2_h and round(high4 + MARJA, 2) == sl
|
||
# 4. ținta e simetrică, atinsă la aceeași bară ca pe long
|
||
assert abs((sl - entry) - (entry - tp1)) < 1e-9
|
||
assert next(i for i in range(cf + 1, len(cds)) if cds[i].l <= tp1 + 1e-9) == 22
|
||
# 5. ieșirea pe bear trail, tot la 2.75R
|
||
r_exit = round((entry - cds[ex].c) / risk, 2)
|
||
assert r_exit == 2.75, r_exit
|
||
# 6. divergența, în oglindă: higher high pe preț, lower high pe indicator/volum
|
||
assert cds[l2].h > cds[l1].h and cds[l2].vol > cds[l1].vol
|
||
print(f"short: rezistență {REZ:.2f}, picior 1 {leg1_h:.2f}, picior 2 {leg2_h:.2f}, "
|
||
f"intrare {entry:.2f}, SL {sl:.2f} (risc {risk:.2f}), TP1 {tp1:.2f}, ieșire {r_exit:.2f}R")
|
||
|
||
ch = Chart(
|
||
candles=cds[S:ex + 1],
|
||
levels=[
|
||
Level(REZ, f"pivot daily {REZ:.2f} — zona, sus", BLUE, label_at="left"),
|
||
Level(sl, f"SL {sl:.2f} = {MARJA:.2f} peste piciorul 2", RED, "4 3"),
|
||
# eticheta coboară sub propria linie, în stânga: la dreapta, pe
|
||
# înălțimea ei, o tăia linia pivotului de 100.00 (0.20 mai sus)
|
||
Level(entry, f"intrare short {entry:.2f}", GREEN, "6 3",
|
||
label_at="left", label_dy=18),
|
||
Level(tp1, f"TP1 {tp1:.2f} = 1:1", GREEN, "2 2", label_at="left"),
|
||
],
|
||
marks=[Mark(ex - S, f"ieșire pe trail {cds[ex].c:.2f} = {r_exit:.2f}R", GREEN, "below")],
|
||
zones=[Zone(l2 - S, cf - S, "", RED)],
|
||
arrows=[
|
||
Arrow(l1 - S, f"piciorul 1: high {leg1_h:.2f}\nrezistența ține",
|
||
where="above", price=leg1_h, color=GRAY, dx=-30, dy=-30),
|
||
Arrow(l2 - S, f"piciorul 2: high {leg2_h:.2f} — rupe nivelul în sus\n"
|
||
f"și mătură stopurile celor intrați pe short,\ndar nu poate ține acolo",
|
||
where="above", price=leg2_h, color=RED, dx=60, dy=-16),
|
||
Arrow(cf - S, f"intri short la {entry:.2f}: close sub nivel și sub low-ul candelei-trigger\n"
|
||
f"cei prinși long vând ca să iasă — coborârea e bruscă",
|
||
where="below", color=GREEN, dx=20, dy=30),
|
||
],
|
||
scale=58.0, gap=18, body_w=10, left=176, width=W, top=64, vol_h=60,
|
||
vol_label="volum: la piciorul 2 volumul crește, prețul nu mai are cumpărători = divergență",
|
||
# titlul e scurt pe un singur rând: cu paranteza („serie construită prin
|
||
# răsturnarea exemplului long") se întindea până sub coada săgeții
|
||
# „piciorul 1", care îl traversa. Explicația a trecut în caption.
|
||
title="Oglinda pe short",
|
||
caption="Serie răsturnată din exemplul long; varianta short nu e explicată în curs.",
|
||
)
|
||
svg = ch.render()
|
||
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})"
|
||
# etichetele de nivel, verificate pe linii străine (min_px=2: fiecare stă la
|
||
# 6 px peste linia ei prin construcție)
|
||
eticheta_libera(svg, "short",
|
||
{f"pivot daily {REZ:.2f} — zona, sus",
|
||
f"SL {sl:.2f} = {MARJA:.2f} peste piciorul 2",
|
||
f"intrare short {entry:.2f}", f"TP1 {tp1:.2f} = 1:1"},
|
||
min_px=2.0, rects=True)
|
||
OUT.write_text(svg, encoding="utf-8")
|
||
print(f"scris {OUT.name} ({W}x{H:.0f})")
|