#!/usr/bin/env python3 """ATMI — Pasul 6: ieșirea la +10 %, cash, apoi reinvestirea integrală. Nu e un grafic de preț: e ciclul banilor. Trei cicluri, fiecare cu aceeași regulă — ieși cu TOATĂ poziția la +10 %, banii stau în cash până la următorul trigger valid, iar acolo intră înapoi integral, plus contribuția nouă. Coloana din dreapta arată ce iese dacă reinvestești doar contribuțiile și lași profitul deoparte: aceeași sumă pusă, mai puțin la final. Contribuția de 600 $/trimestru e cifra cursului („1 unitate SPY"); ținta de +10 % e regula lui. Suma finală e calculată aici, nu preluată din backtest — backtest-ul cursului (~16.300 $ → ~52-53.000 $ în 20 de ani) are alt orizont și e citat în text, nu desenat. Rulează: python3 gen/strategii/atmi_reinvestire.py """ from pathlib import Path OUT = Path(__file__).with_suffix(".svg") W = 700 CONTRIB, TINTA = 600.0, 0.10 N = 3 GREEN, RED, BLUE, INK, GRAY, PURPLE = "#188a3e", "#c00", "#1a5fb4", "#333", "#777", "#7b2fbf" # --- cele două scenarii ---------------------------------------------------- cicluri, capital = [], 0.0 for i in range(N): intrat = round(capital + CONTRIB, 2) iesit = round(intrat * (1 + TINTA), 2) cicluri.append((i + 1, intrat, iesit)) capital = iesit fara = round(N * CONTRIB * (1 + TINTA), 2) # fiecare contribuție câștigă 10 % o dată pus = round(N * CONTRIB, 2) assert cicluri[0] == (1, 600.00, 660.00), cicluri[0] assert cicluri[1] == (2, 1260.00, 1386.00), cicluri[1] assert cicluri[2] == (3, 1986.00, 2184.60), cicluri[2] assert fara == 1980.00 and pus == 1800.00 CASTIG = round(cicluri[-1][2] - fara, 2) assert CASTIG == 204.60, CASTIG # fiecare ciclu intră cu exact ce a ieșit din precedentul plus contribuția for (_, intr, _), (_, _, ies) in zip(cicluri[1:], cicluri): assert round(intr - ies, 2) == CONTRIB assert all(round(ies / intr, 3) == 1.100 for _, intr, ies in cicluri) # --- desen ----------------------------------------------------------------- out, LABELS = [], [] BASE_Y = 250 # linia de zero a coloanelor PXPU = 0.072 # px per dolar COL_W, X0, STEP = 46, 60, 190 assert cicluri[-1][2] * PXPU < BASE_Y - 80, "coloana cea mai înaltă iese din desen" def text(x, y, s, fill=INK, anchor="start", bold=False, size=12): st = f"font-size:{size}px" + (";font-weight:bold" if bold else "") a = f' text-anchor="{anchor}"' if anchor != "start" else "" w = len(s) * (size * 0.52) x0 = x if anchor == "start" else (x - w / 2 if anchor == "middle" else x - w) assert 2 <= x0 and x0 + w <= W - 2, f"text iese din panză: {s!r} ({x0:.0f}..{x0 + w:.0f})" LABELS.append((x0, x0 + w, y, s)) out.append(f'{s}') def bar(x, val, color, label, sub): h = val * PXPU out.append(f'') text(x + COL_W / 2, BASE_Y - h - 8, label, fill=color, anchor="middle", bold=True, size=11) text(x + COL_W / 2, BASE_Y + 15, sub, fill=GRAY, anchor="middle", size=10) out.append('' '') text(20, 22, "Ciclul ATMI: ieși cu tot la +10 %, stai în cash, reintri cu tot plus contribuția", bold=True, size=13) text(20, 40, f"Contribuție {CONTRIB:.0f} $ la fiecare trigger valid; ținta +10 % pe poziție.", fill="#555", size=11) for i, (nr, intrat, iesit) in enumerate(cicluri): xa = X0 + i * STEP xb = xa + COL_W + 26 text(xa, 72, f"ciclul {nr}", fill=INK, bold=True, size=12) bar(xa, intrat, BLUE, f"{intrat:,.0f} $".replace(",", "."), "intri cu tot") bar(xb, iesit, GREEN, f"{iesit:,.2f} $".replace(",", "x").replace(".", ",").replace("x", "."), "ieși la +10 %") # săgeata dintre intrare și ieșire (ce face trade-ul) out.append(f'') if i + 1 < len(cicluri): # săgeata spre ciclul următor: cash + contribuție nouă xn = X0 + (i + 1) * STEP y = BASE_Y + 46 out.append(f'') text((xb + xn) / 2 + COL_W / 2, y + 16, f"cash, apoi + {CONTRIB:.0f} $ nou", fill=BLUE, anchor="middle", size=11, bold=True) out.append(f'') # comparația de la final yc = BASE_Y + 92 out.append(f'') text(34, yc, f"Ai pus în total {pus:,.0f} $".replace(",", ".") + ", în trei contribuții egale.", fill=INK, size=11, bold=True) text(34, yc + 17, f"Cu reinvestire integrală: " f"{cicluri[-1][2]:,.2f} $".replace(",", "x").replace(".", ",").replace("x", ".") + f" · dacă lași profitul deoparte: {fara:,.0f} $".replace(",", ".") + f" · diferența: {CASTIG:,.2f} $".replace(",", "x").replace(".", ",").replace("x", "."), fill=INK, size=11) text(34, yc + 34, "Completare proprie: cifrele astea sunt calculate pe trei cicluri, nu backtest-ul cursului.", fill=GRAY, size=10) H = yc + 56 for i in range(len(LABELS)): for j in range(i + 1, len(LABELS)): xa0, xa1, ya, sa = LABELS[i] xb0, xb1, yb_, sb = LABELS[j] assert not (abs(ya - yb_) < 12 and xa0 < xb1 - 4 and xb0 < xa1 - 4), \ f"etichete suprapuse: {sa!r} / {sb!r}" assert 0 < LABELS[i][2] < H, f"etichetă în afara înălțimii: {LABELS[i][3]!r}" svg = (f'\n ' + "\n ".join(out) + "\n") assert "\n\n" not in svg and ".md:" not in svg OUT.write_text(svg, encoding="utf-8") print(" | ".join(f"c{n}: {a:.0f} -> {b:.2f}" for n, a, b in cicluri) + f" | fără reinvestire {fara:.0f} | diferență {CASTIG:.2f} | scris {OUT.name} ({W}x{H:.0f})")