cele 7 diagrame din 11_selectia
Sunt diagrame conceptuale - funnel, bara de scor, matrice, cele patru cadrane, Trinity, sectoare - nu grafice de pret, deci nu trec prin svg_candles / pchart, care raman obligatorii doar pentru candele si entry/SL/TP. Agent nou, diagramist, cate unul per diagrama, fiecare cu generatorul lui in gen/selectia/; substitutia in .md o face gen/az_selectia.py, ca sa nu scrie sapte agenti in acelasi fisier. Regula de continut a agentului: fiecare cifra si eticheta trebuie sa existe in document sau in citate. Ce nu reiese din sursa e scris pe desen ca atare - ordinea celor 7 sectoare, ce se intampla sub 100% relative volume. Fara semafor rosu/verde, care nu e in sursa. Verificat cu ochii pe doua diagrame randate in browser. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
This commit is contained in:
158
gen/selectia/trinity.py
Normal file
158
gen/selectia/trinity.py
Normal file
@@ -0,0 +1,158 @@
|
||||
"""Trinity — 3 stele vs. trei divergențe simultane.
|
||||
|
||||
Diagramă conceptuală pentru `summaries/08_ANALIZA_ZILNICA/11_selectia_simbolului.md`
|
||||
(marcaj `<!--SVG:trinity-->`), §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'<rect x="{x}" y="{y}" width="{w}" height="{h}" fill="#ffffff" '
|
||||
f'stroke="{GRAY}" stroke-width="1.5"/>'
|
||||
)
|
||||
|
||||
|
||||
parts = [
|
||||
f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {W} {H}" '
|
||||
f'width="{W}" height="{H}" role="img" '
|
||||
f'aria-label="Trinity: relative strength, power și volum toate în cadranul 1 '
|
||||
f'înseamnă 3 stele; trei divergențe simultane pe volum, relative strength și '
|
||||
f'power sunt doar setup de bottom, fără trigger">',
|
||||
f'<rect x="0" y="0" width="{W}" height="{H}" fill="#ffffff"/>',
|
||||
]
|
||||
|
||||
# ---------------------------------------------------------------- titlu
|
||||
add(W / 2, 32, "Trinity — 3 stele", 20, "bold")
|
||||
add(W / 2, 56,
|
||||
"Relative strength, power și volum aliniate în aceeași direcție, în cadranul 1;",
|
||||
13, "normal", GRAY)
|
||||
add(W / 2, 74, "„3 stele cu plus” pe simbol.", 13, "normal", GRAY)
|
||||
|
||||
# ---------------------------------------------------------------- panoul 1
|
||||
P1_X, P1_Y, P1_W, P1_H = 40, 92, 620, 198
|
||||
parts.append(box(P1_X, P1_Y, P1_W, P1_H))
|
||||
add(W / 2, 118, "DA — Trinity complet: 3 stele cu plus", 16, "bold", BLUE)
|
||||
|
||||
COL_W, COL_H, COL_Y = 180, 96, 136
|
||||
COL_X = [60, 260, 460]
|
||||
CENTER = [x + COL_W / 2.0 for x in COL_X]
|
||||
COL_TITLES = ["Relative strength", "Power", "Volum"]
|
||||
|
||||
for cx, title in zip(CENTER, COL_TITLES):
|
||||
parts.append(box(cx - COL_W / 2.0, COL_Y, COL_W, COL_H))
|
||||
add(cx, COL_Y + 26, title, 15, "bold")
|
||||
add(cx, COL_Y + 56, "cadranul 1", 14, "bold", BLUE)
|
||||
|
||||
add(W / 2, 258, "toate trei: cadranul 1, aceeași direcție", 14, "bold")
|
||||
add(W / 2, 280, "→ 3 stele cu plus", 15, "bold", BLUE)
|
||||
|
||||
# ---------------------------------------------------------------- panoul 2
|
||||
P2_X, P2_Y, P2_W, P2_H = 40, 306, 620, 214
|
||||
parts.append(box(P2_X, P2_Y, P2_W, P2_H))
|
||||
add(W / 2, 332, "NU — trei divergențe simultane: nu sunt 3 stele", 16, "bold")
|
||||
|
||||
COL2_Y = 350
|
||||
COL2_TITLES = ["Volum", "Relative strength", "Power"]
|
||||
|
||||
for cx, title in zip(CENTER, COL2_TITLES):
|
||||
parts.append(box(cx - COL_W / 2.0, COL2_Y, COL_W, COL_H))
|
||||
add(cx, COL2_Y + 26, title, 15, "bold")
|
||||
add(cx, COL2_Y + 56, "divergență", 14, "bold", GRAY)
|
||||
|
||||
add(W / 2, 472,
|
||||
"setup de bottom: prețul e la fund, dar încă nu s-a întors", 14)
|
||||
add(W / 2, 496,
|
||||
"aștepți trigger-ul — deocamdată doar pe listă", 14, "bold", GRAY)
|
||||
|
||||
# ---------------------------------------------------------------- note + sursă
|
||||
add(W / 2, 548,
|
||||
"Trinity — NU și: două din trei aliniate, a treia în roșu;", 13, "normal", GRAY)
|
||||
add(W / 2, 566,
|
||||
"„3 stele cu roșu” pe indice = short, nu cumperi contra.", 13, "normal", RED)
|
||||
add(W / 2, 596,
|
||||
"Sursa: 11_selectia_simbolului.md §3 — 75_05052026.txt:101-106;", 13,
|
||||
"normal", GRAY)
|
||||
add(W / 2, 614,
|
||||
"82_24042026.txt:334-335; 98_30032026.txt:395-397.", 13, "normal", GRAY)
|
||||
|
||||
# ---------------------------------------------------------------- emitere
|
||||
for x, y, s, size, weight, fill, _ in texts:
|
||||
parts.append(
|
||||
f'<text x="{x:.1f}" y="{y:.1f}" font-size="{size}" '
|
||||
f'font-weight="{weight}" fill="{fill}" text-anchor="middle">'
|
||||
f'{html.escape(s, quote=False)}</text>'
|
||||
)
|
||||
parts.append("</svg>")
|
||||
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}</text>") == 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")
|
||||
Reference in New Issue
Block a user