selectia: diagramele refacute dupa sablon (textul urmeaza)

Agentul a atins pragul de context dupa diagrame; capitolul 04_selectia
e inca in formatul vechi si se reia separat.

Ce s-a schimbat: ansamblul nu mai arata ULTA mergand la TP2 — ULTA pica
chiar filtrul de selectie (RVOL 0.61 si 5.01 % de suport), deci nu putea
fi exemplul-vitrina; acum arata doar ce citeste selectia, cu granita
"aici se termina selectia" marcata. Funnel-ul trece de la 8 trepte la 6,
aliniat cu pasii nivelului 2, si fiecare treapta spune de ce. Cadranele
primesc mini-histograme RS, ca sa se recunoasca dintr-un desen, nu
dintr-o propozitie. Trimiterile fisier:linie sunt scoase de pe desene.

Noi: univers (pragurile de pret si volum), sectoare (dominantul din cele
11), proximitate (banda de 3 % peste suportul monthly, cu observatia ca
nu e pragul de 1-2 % din Buy Doji — masoara altceva).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
This commit is contained in:
Claude Agent
2026-09-20 12:43:12 +00:00
parent 63c01b5ee9
commit f1033a916c
19 changed files with 1407 additions and 670 deletions

View File

@@ -15,7 +15,7 @@ import sys
from pathlib import Path
sys.path.insert(0, "/workspace/atm-curs-dl")
from svg_candles import Candle, Chart, Level, Mark, MA, from_closes # noqa: E402
from svg_candles import Candle, Chart, Level, Arrow, Zone, MA, from_closes # noqa: E402
OUT = Path(__file__).resolve().parent / "selectia_exemplu.svg"
@@ -107,26 +107,33 @@ levels = [
Level(72.00, "TP 72.00", GREEN, label_at="left"),
]
marks = [
Mark(10, "gap down, open 79.20", "#333", "above", dy=-16),
Mark(12, "sell doji close 78.60", RED, "above", dy=-4),
Mark(13, "intrare short 78.10", GREEN, "below", dy=26),
Mark(10, "RVOL 200%", RED, "below", dy=12),
zones = [
Zone(10, 13, "ce l-a scos în față din cele 16 rezultate", RED, p_top=80.4),
]
arrows = [
Arrow(10, f"gap down: deschide la {cds[10].o:.2f}, mult sub\n"
f"închiderea de ieri — vânzare, nu pauză",
where="above", color=RED, dx=-160, dy=32),
Arrow(12, "sell doji close 78.60: vânzătorii și cumpărătorii la egalitate,\nîncă nu e semnal",
where="below", price=77.6, color="#333", dx=-120, dy=70),
Arrow(13, "aici ar intra strategia de intrare, nu selecția:\nînchidere sub low-ul doji-ului",
where="right", price=78.10, color=GREEN, dx=40, dy=110),
]
title = "HIG — daily (Sell Doji + Bear Reversal, RVOL 200%)"
caption = ("RVOL 200% si simbolul sunt reale (04_MODUL_3/01:196-199). Toate "
"nivelurile de preț (79.20 / 78.60 / 78.10 / 82.00 / 72.00) sunt "
"construite in sumarul 04_MODUL_3/01:293-296, nu date de curs; "
"structura barelor e construita, la scara.")
caption = ("Ale cursului: simbolul HIG, semnalul Sell Doji + Bear Reversal și RVOL-ul de 200 %, "
"cel mai mare din cele 16 rezultate ale scanerului. Nivelurile de preț "
"(79.20 / 78.60 / 78.10 / 82.00 / 72.00) și structura barelor sunt construite, la scară: "
"cursul nu dă cifre pentru HIG.")
ch = Chart(
candles=cds, levels=levels, marks=marks,
candles=cds, levels=levels, zones=zones, arrows=arrows,
mas=[MA(20, ORANGE, dash="4 3", text="SMA-20")],
scale=16.0, gap=15, body_w=9, left=44, width=640, vol_h=70,
vol_label="volum",
title="", # titlul se injecteaza sus, ca sa nu se suprapuna
caption=caption, # cu eticheta nivelului "rezistenta 84.50" (stanga)
title=title,
caption=caption,
)
svg = ch.render()
@@ -137,14 +144,28 @@ px_reward = ys[72.00] - ys[78.10]
assert px_risc > 0 and px_reward > 0
assert abs(px_risc / px_reward - risc / reward) < 1e-9, "SL/TP la scara gresita"
# ---------------------------------------------------------------- titlu injectat
m_svg = re.search(r"<svg[^>]*>", svg)
assert m_svg, "tag <svg> lipsa"
svg = svg.replace(
m_svg.group(0),
m_svg.group(0) + f'\n <text x="24" y="16" fill="#333" style="font-weight:bold">{title}</text>',
1,
)
# ---------------------------------------------------------------- RVOL, pe panoul de volum
# RVOL e o afirmație despre volum, deci eticheta stă pe panoul de volum, nu în
# cel de preț: linia întreruptă e media seriei, iar bara 10 e de două ori cât ea.
m_vb = re.search(r'<line x1="24" y1="([\d.]+)" x2="[\d.]+" y2="[\d.]+" stroke="#888"/>', svg)
assert m_vb, "nu gasesc linia de baza a panoului de volum"
vol_base = float(m_vb.group(1))
vmax = max(VOLS)
y_media = vol_base - media_vol / vmax * 70.0 # vol_h = 70
y_bara = vol_base - VOLS[10] / vmax * 70.0
assert abs((vol_base - y_bara) / (vol_base - y_media) - 2.0) < 1e-9, \
"bara de RVOL nu e de doua ori media, desenata"
m_w = re.search(r'viewBox="0 0 (\d+) ', svg)
assert m_w
w_svg = int(m_w.group(1))
vol_note = (f'<line x1="24" y1="{y_media:.1f}" x2="{w_svg - 14}" y2="{y_media:.1f}" '
f'stroke="{GRAY}" stroke-width="1.2" stroke-dasharray="4 3"/>'
f'<text x="{w_svg - 16}" y="{y_media - 4:.1f}" fill="{GRAY}" text-anchor="end">'
f'media volumului pe serie</text>'
f'<text x="92" y="{y_bara - 5:.1f}" fill="{RED}" style="font-weight:bold">'
f'ziua gap-ului: de {VOLS[10] / media_vol:.0f} ori media (RVOL 200 %) — '
f'se vinde dublu față de o zi normală</text>')
svg = svg.replace(m_vb.group(0), m_vb.group(0) + vol_note, 1)
# ---------------------------------------------------------------- caption pe randuri
def _wrap(text: str, max_chars: int) -> list[str]: