"""Trinity — 3 stele vs. trei divergențe simultane.
Diagramă conceptuală pentru `summaries/08_ANALIZA_ZILNICA/11_selectia_simbolului.md`
(marcaj ``), §3 „Trinity și power — stelele".
Două panouri:
1. Trinity complet — relative strength, power și volum, toate în cadranul 1,
aceeași direcție => „3 stele cu plus".
2. Trei divergențe simultane (volum, RS, power) => setup de bottom, dar fără
trigger încă: „doar pe listă".
Nu e grafic de preț, deci NU folosește `svg_candles` / `pchart`: SVG-ul e
construit ca string, fără dependințe. Rulează:
.venv/bin/python gen/selectia/trinity.py
Scrie `gen/selectia/trinity.svg`.
Fiecare cifră și etichetă de aici există în textul din jurul marcajului sau în
citatele lui:
- „3 stele cu plus" / „3 stele" / cadranul 1 / relativ strength, power, volum:
`75_05052026.txt:101-106` și `82_24042026.txt:334-335`;
- cele trei divergențe simultane și așteptarea trigger-ului:
`98_30032026.txt:395-397`;
- „3 stele cu roșu" pe indice = short: `75_05052026.txt:101-106` și tabelul
Trinity DA/NU.
Textul nu leagă DA de verde și nici divergențele de vreo culoare, așa că nu am
folosit verde/semafor: roșu apare doar acolo unde sursa spune explicit „roșu".
"""
import html
from pathlib import Path
W, H = 700, 640
BLACK = "#000000"
GRAY = "#777777"
RED = "#c00"
BLUE = "#1a5fb4"
texts = [] # (x, y, text, size, weight, fill, w_est)
def add(x, y, s, size=13, weight="normal", fill=BLACK):
factor = 0.62 if weight == "bold" else 0.56
texts.append((x, y, s, size, weight, fill, len(s) * size * factor))
return x, y, s, size, weight, fill, len(s) * size * factor
def box(x, y, w, h):
return (
f''
)
parts = [
f'")
svg = "\n".join(parts) + "\n"
# ---------------------------------------------------------------- verificare
assert "filter=" not in svg and "gradient" not in svg, "fără umbre/gradienti"
boxes = []
for x, y, s, size, weight, fill, w in texts:
assert size >= 13, f"font sub 13px: {s!r} ({size})"
left, right = x - w / 2.0, x + w / 2.0
top, bottom = y - size * 0.78, y + size * 0.22
assert 0 <= left and right <= W, f"etichetă în afara panzei pe orizontală: {s!r}"
assert 0 <= top and bottom <= H, f"etichetă în afara panzei pe verticală: {s!r}"
boxes.append((left, right, top, bottom, s))
for i in range(len(boxes)):
for j in range(i + 1, len(boxes)):
l1, r1, t1, b1, s1 = boxes[i]
l2, r2, t2, b2, s2 = boxes[j]
if r1 > l2 and r2 > l1 and b1 > t2 and b2 > t1:
raise AssertionError(f"etichete suprapuse: {s1!r} / {s2!r}")
for required in ("3 stele", "cadranul 1", "Relative strength", "Power", "Volum",
"3 stele cu plus", "divergență", "trei divergențe simultane",
"setup de bottom", "trigger", "doar pe listă",
"3 stele cu roșu", "short"):
assert required in svg, f"lipsește din desen: {required!r}"
# fiecare din cele trei condiții apare o dată în panoul 1 și o dată în panoul 2
for word in ("Relative strength", "Power", "Volum"):
assert svg.count(f">{word}") == 2, f"{word!r} nu apare de două ori"
OUT = Path(__file__).with_suffix(".svg")
OUT.write_text(svg, encoding="utf-8")
print(f"scris {OUT} ({len(svg)} bytes, {len(texts)} etichete, {W}x{H}), verificare OK")