"""Funnel-ul de selecție din `summaries/08_ANALIZA_ZILNICA/11_selectia_simbolului.md`. Fluxul din scanner, de sus în jos, așa cum îl spune documentul: scanner (multe semnale) -> sectorul care domină -> doar suport/pivot, după downtrend -> RS cadranul 1-2 -> relative volume peste 100% -> stele (Trinity) -> listă scurtă. SVG scris de mână (nu e grafic de preț, deci nu se folosește svg_candles). Fără dependențe: doar stdlib. Rulare: .venv/bin/python gen/selectia/funnel.py Scrie `gen/selectia/funnel.svg`. """ from pathlib import Path from xml.sax.saxutils import escape OUT = Path(__file__).resolve().parent / "funnel.svg" BLACK = "#000000" GRAY = "#777777" BLUE = "#1a5fb4" W = 700 TITLE_Y = 34 SUB_Y = 56 BAND_H = 58 GAP = 24 STEP = BAND_H + GAP TOP0 = 84 WIDTHS = [620, 566, 512, 458, 404, 350, 296] STAGES = [ ("Scanner — multe semnale", "zeci sau sute de semnale"), ("Sectorul care domină", "multe simboluri din același sector = rotație de bani"), ("Doar suport / pivot, după downtrend", "suport monthly / quarterly / anual sau pivot"), ("Relative strength: cadran 1-2", "doar cadranele 1 și 2, RS pozitiv"), ("Relative volume peste 100%", "candela de volum / media ultimelor 10 candele"), ("Stele (Trinity)", "3 stele: RS + power + volum, cadran 1"), ("Listă scurtă", "taie lista la câteva idei"), ] N_BANDS = len(STAGES) BANDS_BOTTOM = TOP0 + (N_BANDS - 1) * STEP + BAND_H FOOT_Y = BANDS_BOTTOM + 34 H = FOOT_Y + 96 def est_width(text, size, bold=False): """Lățime aproximativă pentru system-ui, folosită la verificarea suprapunerilor.""" factor = 0.62 if bold else 0.56 return len(text) * size * factor def txt(x, y, s, size=13, bold=False, fill=BLACK, anchor="middle"): weight = "700" if bold else "400" return ( f'{escape(s)}' ) def band(i): name, detail = STAGES[i] w = WIDTHS[i] x = (W - w) / 2 y = TOP0 + i * STEP parts = [ f'', txt(W / 2, y + 25, name, size=15, bold=True), txt(W / 2, y + 45, detail, size=13, fill=GRAY), ] return parts, (y, detail) def arrow(y): """Chevron în jos, în golul dintre două benzi.""" return ( f'' ) svg = [ f'', f'', txt(W / 2, TITLE_Y, "Funnel de selecție — fluxul din scanner", size=19, bold=True), txt(W / 2, SUB_Y, "selecția se face înainte de semnalul tehnic", size=13, fill=GRAY), ] labels = [] # (x_left, x_right, y_baseline, text) pentru verificarea suprapunerilor for i in range(N_BANDS): parts, (y, detail) = band(i) svg.extend(parts) w = WIDTHS[i] half = est_width(detail, 13) / 2 labels.append((W / 2 - half, W / 2 + half, y + 45, detail)) name = STAGES[i][0] halfn = est_width(name, 15, bold=True) / 2 labels.append((W / 2 - halfn, W / 2 + halfn, y + 25, name)) if i < N_BANDS - 1: svg.append(arrow(y + BAND_H + 6)) svg.append(txt(W / 2, FOOT_Y, "Sub 100% relative volume: 0.96 și 0.74 au fost respinse; el vrea peste 100%.", size=13, fill=GRAY)) svg.append(txt(W / 2, FOOT_Y + 20, "Neconfirmat: nu reiese din sesiuni dacă sub prag oprește orice intrare.", size=13, fill=GRAY)) svg.append(txt(W / 2, H - 52, "Cifre din text: peste 100%, 10 candele, 0.96 / 0.74, cadranele 1-2.", size=13, fill=GRAY)) svg.append(txt(W / 2, H - 32, "Sursa: 11_selectia_simbolului.md — fluxul din scanner.", size=13, fill=GRAY)) svg.append("") # ------------------------------------------------------------------ verificare for i, (name, detail) in enumerate(STAGES): w = WIDTHS[i] for s, size, bold in ((name, 15, True), (detail, 13, False)): ew = est_width(s, size, bold) assert ew <= w - 24, f"eticheta nu incape in banda {i}: {s!r} ({ew:.0f} > {w - 24})" assert ew <= W - 20, f"eticheta iese din panza: {s!r}" for k in range(N_BANDS): y0 = TOP0 + k * STEP assert 0 < y0 and y0 + BAND_H < H, "banda iese din viewBox" seen = [] for l, r, y, s in labels: assert 0 <= l and r <= W, f"eticheta iese din panza pe orizontala: {s!r} ({l:.0f},{r:.0f})" assert 0 <= y <= H, f"eticheta iese din panza pe verticala: {s!r}" for l2, r2, y2, s2 in seen: if abs(y - y2) < 14 and not (r < l2 or r2 < l): raise AssertionError(f"posibile etichete suprapuse: {s!r} / {s2!r}") seen.append((l, r, y, s)) OUT.write_text("\n".join(svg) + "\n", encoding="utf-8") print(f"scris {OUT} ({W}x{H}), {N_BANDS} trepte, verificare OK")