atmi: diagramele refacute, cinci noi, si fisa de surse

Noi: pivoti (PPQ/SQ calculati din trimestrul precedent, cu formula pe
desen), perechi_tf (weekly -> daily ca descompunere reala, cu caseta,
ghidaje si PPQ pe ambele panouri), trigger (BIM apoi verde, fata de
verde inainte de BIM — cutitul in cadere), risc (ce inseamna "fara
stop": 24 de bare sub apa, -20 % pe pozitie), reinvestire (ciclul
banilor pe trei cicluri).

aplus devine corectie: diagrama arata un prag de corectie, nu un setup
A+, si numele vechi trimitea la altceva.

Trei bug-uri reale: exemplul era etichetat weekly cu 20 de bare, dar
textul spunea "un an mai tarziu" — trecut pe monthly cu assert pe numarul
de luni; ansamblul avea o trimitere fisier:linie desenata in SVG; si
benzile PPQ/SQ erau inversate ca sens, cu SQ fix pe intrare.

PPQ 95.80 si SQ 90.80 sunt completare proprie — cursul spune explicit ca
nu da valorile; derivate cu formula standard, cu assert.

Textul capitolului e neatins — agentul a atins pragul de context.

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:46:38 +00:00
parent 0ed607134d
commit c08c857274
25 changed files with 2133 additions and 623 deletions

View File

@@ -1,6 +1,6 @@
"""ATMI — aceeași corecție: 4.0 % (DA) vs. 3.9 % (NU; cursul zice „3.93 %").
Citește specificația `gen/strategii/atmi_aplus.spec.txt`.
Citește specificația `gen/strategii/atmi_corectie.spec.txt`.
O singură serie de 32 de candele daily (open-ul fiecărei bare = close-ul
precedentei, deci seria e continuă), care urmează calea DA: urcare la swing
@@ -19,6 +19,7 @@ sys.path.insert(0, "/workspace/atm-curs-dl")
from svg_candles import Chart, Level, Mark, from_closes # noqa: E402
GRAY, RED, GREEN, BLUE, ORANGE, INK = "#777", "#c00", "#188a3e", "#1a5fb4", "#b06000", "#333"
PURPLE = "#7b2fbf"
# --- seria: 32 de close-uri, structura din specificație ----------------------
# 0-11 urcare 90.00 -> 100.00 (swing high la bara 11)
@@ -38,7 +39,7 @@ assert len(closes) == 32
# wick-uri (sus, jos): implicite (0.25, 0.30), cu excepțiile care fixează nivelurile
wicks = [(0.25, 0.30)] * 32
wicks[11] = (0.00, 0.30) # swing high: high = close = 100.00
wicks[18] = (0.20, 0.45) # BIM: codiță lungă în jos (hammer)
wicks[18] = (0.20, 0.43) # BIM: codiță lungă în jos, fundul la 95.55
wicks[19] = (0.20, 0.15) # candela de intrare
wicks[31] = (0.00, 0.30) # TP: high = close = 105.60
@@ -115,7 +116,7 @@ ch = Chart(
Mark(BIM_I, "BIM", GREEN, "above", dy=-2),
Mark(ENTRY_I, "candelă verde → trigger", GREEN, "below", dy=20),
],
scale=18.0, gap=16, body_w=9, left=44, width=680, vol_h=70,
scale=21.0, gap=16, body_w=9, left=44, width=680, vol_h=70,
vol_label="volum", title="SPY — daily: aceeași corecție, 4.0 % (DA) vs. 3.9 % (NU)",
caption="Calea DA (candele): 4.0 % la 96.00. Calea NU (punctat): 3.9 % („3.93 %” în curs) — fără intrare.",
)
@@ -123,9 +124,14 @@ svg = ch.render()
# --- elemente suplimentare, pe coordonatele graficului -----------------------
x0, x1 = 24, ch.width - 14
band_top, band_bot = ch._y(96.40), ch._y(95.40)
PPQ = 95.80 # pivotul trimestrial, calculat în atmi_pivoti.py
FUND = round(min(c.l for c in cds[12:20]), 2)
assert FUND == 95.55, FUND
assert PPQ - 0.30 <= FUND <= PPQ + 0.30, "fundul căii DA nu cade în banda PPQ"
assert NU_STOP >= PPQ + 0.30, "calea NU ar coborî în zona de cumpărare"
band_top, band_bot = ch._y(PPQ + 0.30), ch._y(PPQ - 0.30)
band = (f'<rect x="{x0}" y="{band_top:.1f}" width="{x1 - x0}" height="{band_bot - band_top:.1f}" '
f'fill="{GRAY}" opacity="0.10"/>')
f'fill="{PURPLE}" opacity="0.12"/>')
nu_line = ('<polyline points="' + " ".join(f"{ch._cx(i):.1f},{ch._y(p):.1f}" for i, p in nu_pts) + '" '
f'fill="none" stroke="{RED}" stroke-width="1.8" stroke-dasharray="5 4"/>')
@@ -135,15 +141,15 @@ nu_hline = (f'<line x1="24" y1="{ch._y(NU_STOP):.1f}" x2="{ch.width - 14}" y2="{
# punctul de oprire al traseului NU (96.10, strict deasupra pragului de 4 %)
stop_dot = (f'<circle cx="{ch._cx(17):.1f}" cy="{ch._y(NU_STOP):.1f}" r="3.5" fill="{RED}"/>')
# eticheta traseului NU, sub linia 96.10 (nu se suprapune cu eticheta verde de 96.00)
nu_lab = (f'<text x="{ch.width - 28}" y="{ch._y(NU_STOP) + 12:.1f}" fill="{RED}" text-anchor="end">'
f'96.10 = 3.9 % — NU, sub prag</text>')
nu_lab = (f'<text x="30" y="{ch._y(NU_STOP) - 8:.1f}" fill="{RED}">'
f'{NU_STOP:.2f} = 3.9 % — NU, sub prag</text>')
# eticheta zonei quarterly, sub banda (fără cifre: cursul nu le dă)
zone_lab = (f'<text x="{ch.width - 28}" y="{ch._y(95.40) + 13:.1f}" fill="{GRAY}" text-anchor="end">'
f'zonă quarterly</text>')
zone_lab = (f'<text x="30" y="{ch._y(PPQ - 0.30) + 34:.1f}" fill="{PURPLE}">'
f'zona PPQ {PPQ:.2f} — aici cumperi</text>')
# legende scurte ale celor două trasee
da_lab = (f'<text x="24" y="{ch._y(98.50):.1f}" fill="{GREEN}" '
da_lab = (f'<text x="24" y="{ch._y(97.60):.1f}" fill="{GREEN}" '
f'style="font-weight:bold">calea DA (candelele)</text>')
nu_leg = (f'<text x="{ch._cx(25):.1f}" y="{ch._y(94.45) + 16:.1f}" fill="{RED}" '
nu_leg = (f'<text x="{ch._cx(25):.1f}" y="{ch._y(94.45) + 30:.1f}" fill="{RED}" '
f'style="font-weight:bold">calea NU (continuă în jos)</text>')
overlay = [nu_line, nu_hline, stop_dot, nu_lab, zone_lab, da_lab, nu_leg]
@@ -151,8 +157,9 @@ svg = svg.replace(">", ">\n " + band, 1) # ban
svg = svg.replace("\n</svg>", "\n " + "\n ".join(overlay) + "\n</svg>") # traseele, peste
assert "\n\n" not in svg, "linie goală în SVG"
assert ".md:" not in svg, "trimitere fișier:linie în SVG"
assert "</svg>" in svg and "stroke-dasharray=\"5 4\"" in svg, "traseul NU nu a fost inserat"
with open("/workspace/atm-curs-dl/gen/strategii/atmi_aplus.svg", "w") as f:
with open("/workspace/atm-curs-dl/gen/strategii/atmi_corectie.svg", "w") as f:
f.write(svg)
print("scris gen/strategii/atmi_aplus.svg")
print("scris gen/strategii/atmi_corectie.svg")