MODUL 5, lectia 4: strategia 7 MICI(S), actiuni individuale

11 diagrame, audit curat, generatorul are assert pe ce afirma fiecare eticheta
(inaltimea doji-ului, trigger-ul care inchide peste high, ladder-ul care se
umple sau nu, TP2 < TP1, trail-uri strict crescatoare).

Doua lecturi de semnalat, ambele cu citatul [sic] alaturi:
- TP2 e o tinta mai APROPIATA decat TP1, nu mai departata: e acelasi 1R
  recalculat pe pretul mediu dupa mediere. Fraza din transcriere e stricata
  ("bit, bich, TPU normal", linia 761-763), dar pasajul de dupa o clarifica.
- stopul 94 e "din ochi": 1/3 din 28 peste 86 ar da 95.33. Eticheta poarta
  cifra rostita, diferenta e spusa in text.

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-10-01 23:16:59 +00:00
parent 1a9a4a2a66
commit 13bf509339
3 changed files with 3123 additions and 0 deletions

455
gen/strategia_7_micis.py Normal file
View File

@@ -0,0 +1,455 @@
"""Diagramele pentru summaries/06_MODUL_5/04_strategia_7_micis.md.
Toate graficele de preț se construiesc cu svg_candles (o singură scară
px/unitate pe desen), fiecare cifră afirmată în etichetă e verificată prin
assert, apoi se substituie marcatorii <!--SVG:nume--> din fișierul .md.
Regula de cifre, cerută explicit: pe etichete intră DOAR prețuri rostite în
transcriere (157.47, 155.02, 86, 94, 133, 182, 48, 28, 217.02, 214.25, 108,
180) sau prețuri dintr-un exemplu construit de mine, declarat ca atare în
titlu. Valorile derivate (preț mediu, 1R) apar doar pe diagramele construite,
unde R-urile sunt ale mele.
Cele două schițe fără candele (`divergenta`, `flux`) sunt scrise de mână,
pentru că nu conțin candele, intrare, stop sau țintă.
Rulează: .venv/bin/python gen/strategia_7_micis.py
"""
import os
import re
import sys
sys.path.insert(0, "/workspace/atm-curs-dl")
from svg_candles import Chart, Level, Mark, MA, Zone, Arrow, from_closes # noqa: E402
MD = ("/workspace/atm-curs-dl/summaries/06_MODUL_5/"
"04_strategia_7_micis.md")
SVG = {}
# ----------------------------------------------------------------- unelte mici
def ramp(a, b, n):
"""n close-uri de la a (exclusiv) la b (inclusiv), în pași egali."""
return [round(a + (b - a) * k / n, 2) for k in range(1, n + 1)]
def vols(n, base=44, span=12, **over):
v = [float(base + ((i * 7) % span) - span // 2) for i in range(n)]
for k, x in over.items():
v[int(k[1:])] = float(x)
return v
def lo(cds, a, b):
return round(min(c.l for c in cds[a:b + 1]), 2)
def hi(cds, a, b):
return round(max(c.h for c in cds[a:b + 1]), 2)
def deco(ch, name, distante=(), intregi=()):
"""Randează graficul, verifică etichetele, salvează.
`distante` = numere cu două zecimale care au voie în etichete fără să fie
niveluri desenate (R-uri, înălțimi). `intregi` = numere întregi rostite
care au voie în etichete (86, 94, 133, 182, 28, 48, 108, 180).
"""
svg = ch.render()
assert "\n\n" not in svg, f"{name}: linie goală în svg"
assert len(ch.caption) <= 112, f"{name}: caption de {len(ch.caption)} caractere"
desenate = ({f"{lv.price:.2f}" for lv in ch.levels}
| {f"{a.price:.2f}" for a in ch.arrows if a.price is not None}
| {f"{d:.2f}" for d in distante})
permise_int = ({str(i) for i in intregi}
| {f"{lv.price:.0f}" for lv in ch.levels})
for t in re.findall(r"<text\b[^>]*>(.*?)</text>", svg, re.S):
plain = re.sub(r"<[^>]+>", "", t)
for m in re.finditer(r"\d+\.\d\d", plain):
assert m.group(0) in desenate, \
f"{name}: eticheta numește {m.group(0)}, care nu e un nivel desenat"
# întregii din etichete: doar niveluri desenate sau numere rostite.
# unitățile de numărătoare (bare, săptămâni) și SMA-ul nu sunt prețuri.
for m in re.finditer(
r"(?<![\d.\-])(\d{2,3})(?![\d.])"
r"(?!\s*(?:candele|bare|săptămâni|luni|perioade|mil))", plain):
assert m.group(1) in permise_int, \
f"{name}: eticheta numește întregul {m.group(1)}, nepermis"
sus = min(ch._y(c.h) for c in ch.candles)
jos = max(ch._y(c.l) for c in ch.candles)
for lv in ch.levels:
assert ch._y(lv.price) > sus - 0.06 * (jos - sus), \
f"{name}: nivelul {lv.price} e lipit de marginea de sus"
SVG[name] = svg
print(f" {name}: {len(ch.candles)} bare, {len(ch.levels)} niveluri")
CONSTRUIT = "Exemplu construit (fără ticker), la scară. R-urile sunt ale mele."
# =========================================================== seria construită
# Un singur trade construit, folosit de trei diagrame (harta, pasul 1, țintele),
# ca să nu se schimbe cifrele de la o secțiune la alta.
CL = ([64.00, 63.00, 62.00, 61.00, 58.50, 56.00, 54.00] # 0-6 context
+ [52.00, 50.00, 48.00, 45.50, 43.00, 41.50, 39.90] # 7-13 downtrend, 7 bare
+ [40.00] # 14 doji
+ [45.00] # 15 marubozu de trigger
+ [43.20, 42.60] # 16-17 pullback-ul
+ [43.60, 44.80, 46.00, 47.90, 49.20, 50.70] # 18-23 urcarea
+ [52.00, 51.30, 53.00, 54.50]) # 24-27 continuare
WK = ([(0.40, 0.40)] * 14
+ [(2.00, 1.90)] # 14 fitile de doji
+ [(0.00, 0.00)] # 15 marubozu curat
+ [(0.30, 0.20), (0.20, 0.30)]
+ [(0.35, 0.35)] * 10)
VL = vols(28, 46, 12, i11=58, i12=62, i13=66, i14=70, i15=96, i16=58, i17=52,
i18=60, i19=66, i20=72, i21=78, i22=70, i23=80)
CDS = from_closes(CL, wicks=WK, vols=VL, start=65.00)
DOJI_LO, DOJI_HI = lo(CDS, 14, 14), hi(CDS, 14, 14)
H_DOJI = round(DOJI_HI - DOJI_LO, 2) # 4.00
assert (DOJI_LO, DOJI_HI, H_DOJI) == (38.00, 42.00, 4.00), (DOJI_LO, DOJI_HI)
assert abs(CDS[14].c - CDS[14].o) <= 0.10 * H_DOJI, "candela 14 nu e doji"
assert CDS[15].c > DOJI_HI, "trigger-ul nu închide peste high-ul doji-ului"
assert lo(CDS, 7, 13) < lo(CDS, 0, 6), "downtrend-ul numărat nu coboară"
TRIG_HI, TRIG_LO = hi(CDS, 15, 15), lo(CDS, 15, 15)
H_TRIG = round(TRIG_HI - TRIG_LO, 2) # 5.00
E1 = CDS[15].c # 45.00, la close
E2 = round(TRIG_HI - H_TRIG / 3, 2) # 43.33, 1/3 din marubozu
E3 = round(TRIG_HI - H_TRIG / 2, 2) # 42.50, 1/2 din marubozu
SL = round(DOJI_LO + H_DOJI / 3, 2) # 39.33, 2/3 din doji
MED = round((E1 + E2 + E3) / 3, 2) # 43.61, prețul mediu
R1 = round(E1 - SL, 2)
R2 = round(MED - SL, 2)
TP1 = round(E1 + R1, 2)
TP2 = round(MED + R2, 2)
assert lo(CDS, 16, 16) <= E2 and lo(CDS, 17, 17) <= E3, "ladder-ul nu se umple"
assert lo(CDS, 16, 17) > SL, "pullback-ul atinge stopul"
assert hi(CDS, 21, 21) >= TP2 and hi(CDS, 23, 23) >= TP1, "țintele nu sunt atinse"
assert TP2 < TP1, "pe prețul mediu ținta de 1R vine mai jos, nu mai sus"
print(f"construit: doji {DOJI_LO}-{DOJI_HI} (h={H_DOJI}) intrări {E1}/{E2}/{E3}"
f" medie {MED} SL {SL} TP1 {TP1} ({R1}) TP2 {TP2} ({R2})")
# ---------------------------------------------------------------- 1. harta
deco(Chart(
candles=CDS,
levels=[Level(SL, f"SL {SL:.2f} = 2/3 din doji", "#c00", label_at="left"),
Level(E1, f"intrare 1/3 la close {E1:.2f}", "#188a3e"),
Level(E2, f"limit 1/3 la {E2:.2f}", "#188a3e", label_at="left"),
Level(E3, f"limit 1/3 la {E3:.2f}", "#188a3e", label_at="left"),
Level(MED, f"preț mediu {MED:.2f}", "#6a3d9a"),
Level(TP2, f"TP2 {TP2:.2f}", "#1a5fb4"),
Level(TP1, f"TP1 {TP1:.2f}", "#1a5fb4")],
marks=[Mark(14, "doji", "#b06000", "below", dy=14),
Mark(15, "buy doji", "#188a3e", dy=-6),
Mark(17, "se umplu limiturile", "#188a3e", "below", dy=44),
Mark(23, "ieși, nu aștepți", "#1a5fb4", dy=-8)],
zones=[Zone(7, 13, "downtrend 7 candele", "#c00"),
Zone(15, 17, "fereastra de intrare", "#188a3e")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=18.0, gap=17, body_w=9, left=52, width=700, vol_h=70,
vol_label="volum", title="MICIS, tot trade-ul — weekly (exemplu construit)",
caption=CONSTRUIT), "harta", distante=(R1, R2, H_DOJI))
# ------------------------------------------------- 2. pasul 1 — setup-ul DA
PIV = 36.00
cl2 = ([78.00, 76.50, 77.00, 75.00, 73.50, 74.00, 72.00, 70.00, 68.50, 67.00,
66.00] + CL[:15])
wk2 = [(0.50, 0.50)] * 11 + WK[:15]
vl2 = vols(26, 44, 12, i21=58, i22=62, i23=66, i24=70, i25=88)
cds2 = from_closes(cl2, wicks=wk2, vols=vl2, start=79.00)
assert lo(cds2, 25, 25) == DOJI_LO and hi(cds2, 25, 25) == DOJI_HI, "doji schimbat"
assert lo(cds2, 25, 25) > PIV, "doji-ul trebuie să se oprească pe pivot, nu sub el"
assert vl2[23] < vl2[24] < vl2[25], "volumul nu crește pe ultimele trei bare"
deco(Chart(
candles=cds2,
levels=[Level(PIV, f"pivot quarterly {PIV:.2f}", "#b06000", label_at="left"),
Level(DOJI_LO, f"low-ul doji-ului {DOJI_LO:.2f}", "#6a3d9a")],
marks=[Mark(25, "doji", "#b06000", dy=-18)],
zones=[Zone(18, 24, "downtrend 7 candele", "#c00")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=8.0, gap=17, body_w=9, left=52, width=700, vol_h=70,
vol_label="volum", title="Pasul 1, DA — doji weekly pe pivotul quarterly",
caption="Exemplu construit (fără ticker). Volumul crește pe ultimele trei "
"bare: asta e acumularea."), "pasul1_da")
# ------------------------------------------------- 3. pasul 1 — setup-ul NU
cl3 = (ramp(41.00, 47.00, 6) + [46.50, 47.50] + ramp(47.50, 53.00, 6)
+ [52.40, 53.20] + ramp(53.20, 59.00, 6) + [58.60, 59.40, 58.80]
+ [59.00] + [58.40, 57.00, 55.00])
wk3 = [(0.35, 0.35)] * 25 + [(1.60, 1.50)] + [(0.40, 0.40)] * 3
vl3 = vols(29, 48, 12, i22=38, i23=34, i24=30, i25=26, i26=34, i27=44, i28=52)
cds3 = from_closes(cl3, wicks=wk3, vols=vl3, start=40.00)
assert abs(cds3[25].c - cds3[25].o) <= 0.10 * (cds3[25].h - cds3[25].l), \
"candela 25 nu e doji"
assert cds3[25].c > cds3[0].c and hi(cds3, 25, 25) == hi(cds3, 0, 28), \
"doji-ul trebuie să cadă în vârful unui uptrend"
assert vl3[25] == min(vl3), "volumul trebuie să fie cel mai mic la doji"
deco(Chart(
candles=cds3,
marks=[Mark(25, "doji aici: după uptrend", "#c00", dy=-10),
Mark(22, "volum în scădere", "#c00", "below", dy=24),
Mark(28, "urmează corecția", "#c00", "below", dy=14),
Mark(12, "uptrend", "#188a3e", "below", dy=38)],
zones=[Zone(6, 24, "", "#188a3e")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=11.0, gap=17, body_w=9, left=52, width=700, top=64, vol_h=70,
vol_label="volum", title="Pasul 1, NU — același doji, context greșit",
caption="Exemplu construit (fără ticker), la scară. Doji-ul arată identic; "
"ce îl descalifică e ce e în stânga lui."), "pasul1_nu")
# ------------------------------------- 4. pasul 2 — ladder-ul umplut (JNJ)
J_CL = ([166.00, 164.50, 165.50, 163.00, 161.00, 162.00, 159.50, 157.00,
155.00, 153.00, 151.50, 150.00] # 0-11 downtrend
+ [150.12] # 12 doji
+ [157.47] # 13 marubozu, close = high
+ [155.60, 154.00] # 14-15 pullback
+ [155.50, 157.00, 158.60, 160.50, 162.00, 161.00, 163.50, 165.00,
166.50, 168.00])
J_WK = ([(0.60, 0.60)] * 12 + [(2.40, 2.60)] + [(0.00, 0.00)]
+ [(0.70, 0.70), (0.40, 0.40)] + [(0.60, 0.60)] * 10)
J_VL = vols(26, 44, 12, i12=58, i13=92, i14=54, i15=50, i16=58, i17=64, i18=70)
JC = from_closes(J_CL, wicks=J_WK, vols=J_VL, start=167.00)
J_E1 = JC[13].c
J_HI, J_LO = hi(JC, 13, 13), lo(JC, 13, 13)
J_E2 = round(J_HI - (J_HI - J_LO) / 3, 2)
J_E3 = round(J_HI - (J_HI - J_LO) / 2, 2)
assert J_E1 == 157.47 and J_HI == 157.47, "close-ul rostit e 157.47, pe high"
assert J_E2 == 155.02, f"1/3 din marubozu trebuie să cadă pe 155.02, nu {J_E2}"
assert JC[13].c > hi(JC, 12, 12), "trigger-ul nu închide peste high-ul doji-ului"
assert lo(JC, 14, 14) <= J_E2 and lo(JC, 15, 15) <= J_E3, "ladder-ul nu se umple"
deco(Chart(
candles=JC,
levels=[Level(J_E1, f"intrare 1/3 la close {J_E1:.2f}", "#188a3e"),
Level(J_E2, f"limit 1/3 la {J_E2:.2f} = 1/3 din marubozu", "#188a3e",
label_at="left"),
Level(J_E3, "limit 1/3 la 1/2 din marubozu", "#6a3d9a")],
marks=[Mark(12, "doji", "#b06000", "below", dy=14),
Mark(13, "marubozu de trigger", "#188a3e", dy=-26),
Mark(15, "pullback-ul umple ambele limituri", "#188a3e", "below", dy=38)],
scale=10.0, gap=17, body_w=9, left=58, width=700, vol_h=70,
vol_label="volum", title="Pasul 2, ladder umplut — JNJ weekly",
caption="Ale lui: close-ul 157.47 și limit-ul de 155.02; barele din jur "
"sunt reconstruite de mine."),
"pasul2_jnj", distante=(J_E3,))
# ------------------------------- 5. pasul 2 — ladder-ul neumplut (AMD 108→180)
A_CL = ([206.00, 198.00, 190.00, 182.00, 176.00, 168.00] # 0-5
+ [152.00, 146.00, 138.00, 130.00, 120.00, 112.00, 104.00, 98.00] # 6-13
+ [97.50] # 14 doji
+ [108.00] # 15 marubozu, close rostit
+ [116.00, 124.00, 121.00, 132.00, 141.00, 138.00, 150.00, 158.00,
166.00, 174.00, 180.00]) # 16-26 pleacă fără tine
A_WK = ([(2.00, 2.00)] * 6 + [(1.60, 1.60)] * 8 + [(7.50, 8.00)]
+ [(0.50, 0.50)] + [(1.60, 1.60)] * 11)
A_VL = vols(27, 44, 12, i14=58, i15=96, i16=78, i17=74, i18=62, i19=76, i22=80)
AC = from_closes(A_CL, wicks=A_WK, vols=A_VL, start=210.00)
A_E1 = AC[15].c
A_HI, A_LO = hi(AC, 15, 15), lo(AC, 15, 15)
A_E2 = round(A_HI - (A_HI - A_LO) / 3, 2)
assert A_E1 == 108.00, "close-ul rostit e 108"
assert hi(AC, 26, 26) >= 180.00, "seria trebuie să ajungă la 180, cât a rostit"
assert lo(AC, 16, 26) > A_E2, "ladder-ul NU trebuie să se umple pe acest desen"
deco(Chart(
candles=AC,
levels=[Level(A_E1, f"intrare 1/3 la close {A_E1:.2f}", "#188a3e"),
Level(A_E2, f"limit 1/3 la {A_E2:.2f} — niciodată atins", "#c00",
label_at="left"),
Level(180.00, "unde a ajuns: 180", "#1a5fb4")],
marks=[Mark(14, "doji", "#b06000", "below", dy=14),
Mark(15, "intri cu 1/3 și rămâi cu 1/3", "#188a3e", dy=-30)],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=2.3, gap=19, body_w=10, left=58, width=700, vol_h=70,
vol_label="volum", title="Pasul 2, ladder neumplut — AMD monthly",
caption="Ale lui: 108 (de unde a plecat) și 180 (unde a ajuns); restul e "
"reconstruit de mine."),
"pasul2_amd", intregi=(108, 180))
# -------------------------------------------- 6. pasul 3 — stopul (NVDA monthly)
N_CL = ([20.00, 23.50, 27.00, 25.00, 31.00, 38.00, 45.00, 42.00, 50.00, 55.00,
62.00, 75.00, 90.00, 108.00, 125.00, 138.00] # 0-15 uptrend lung
+ [150.00, 138.00, 126.00, 115.00, 101.00] # 16-20 downtrend, 5 bare
+ [100.50] # 21 doji
+ [133.00] # 22 marubozu de trigger
+ [141.00, 152.00, 164.00, 175.00, 182.00]) # 23-27 spre 182
N_WK = ([(1.50, 1.50)] * 16 + [(3.00, 3.00)] * 5 + [(13.00, 14.50)]
+ [(0.50, 1.50)] + [(2.00, 2.00)] * 5)
N_VL = vols(28, 46, 12, i19=66, i20=78, i21=84, i22=104, i23=86, i24=80)
NC = from_closes(N_CL, wicks=N_WK, vols=N_VL, start=19.00)
N_LO, N_HI = lo(NC, 21, 21), hi(NC, 21, 21)
assert (N_LO, round(N_HI - N_LO, 2)) == (86.00, 28.00), (N_LO, N_HI)
assert abs(NC[21].c - NC[21].o) <= 0.10 * 28.00, "candela 21 nu e doji"
assert NC[22].c == 133.00 and NC[22].c > N_HI, "trigger-ul închide la 133, peste doji"
assert hi(NC, 27, 27) >= 182.00, "seria trebuie să ajungă la 182"
assert round(133.00 + 48.00, 2) == 181.00, "133 + 48 = 181, el a rostit 182"
SL_23 = round(N_LO + 28.00 / 3, 2) # 95.33 strict; el a citit „pe la 94"
print(f" NVDA: 1/3 de la low = {SL_23} strict, rostit 94; "
f"distanța 133→86 = {(133 - 86) / 86 * 100:.1f}%")
deco(Chart(
candles=NC,
levels=[Level(86.00, "sub low-ul doji-ului: 86", "#c00", label_at="left"),
Level(94.00, "SL 2/3 din doji: 94", "#c00", label_at="left"),
Level(133.00, "intrare 1/3 la close: 133", "#188a3e"),
Level(182.00, "ținta rostită: 182", "#1a5fb4")],
marks=[Mark(21, "doji monthly, înălțime 28", "#b06000", "below", dy=16),
Mark(22, "marubozu de trigger", "#188a3e", dy=-70)],
zones=[Zone(16, 20, "downtrend 5 candele", "#c00")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=2.4, gap=19, body_w=10, left=58, width=700, top=60, vol_h=70,
vol_label="volum", title="Pasul 3, stopul — NVDA monthly",
caption="Ale lui: 86, 94, 133, 182, înălțimea de 28 și urcarea de 48; "
"barele din jur sunt ale mele."),
"pasul3_nvda", intregi=(86, 94, 133, 182, 28, 48))
# ------------------------------------------ 7. pasul 4 — cele două ținte, zoom
cl4 = CL[9:]
wk4 = WK[9:]
vl4 = VL[9:]
cds4 = from_closes(cl4, wicks=wk4, vols=vl4, start=CL[8])
assert lo(cds4, 5, 5) == DOJI_LO and cds4[6].c == E1, "zoom-ul mută seria"
deco(Chart(
candles=cds4,
levels=[Level(SL, f"SL {SL:.2f}", "#c00", label_at="left"),
Level(MED, f"preț mediu {MED:.2f}", "#6a3d9a"),
Level(E1, f"intrare 1 la {E1:.2f}", "#188a3e"),
Level(TP2, f"TP2 {TP2:.2f}", "#1a5fb4"),
Level(TP1, f"TP1 {TP1:.2f}", "#1a5fb4")],
arrows=[Arrow(10, f"TP2 = 1R pe medie ({R2:.2f})", price=TP2, where="left",
color="#1a5fb4", dx=-6),
Arrow(12, f"TP1 = 1R pe prima tranșă ({R1:.2f})", price=TP1,
where="above", color="#1a5fb4", dy=-10)],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=13.0, gap=28, body_w=14, left=60, width=700, top=56,
title="Pasul 4, cele două ținte — weekly (exemplu construit)",
caption="Mediind în jos, 1R se scurtează: TP2 vine înaintea lui TP1. "
"R-urile sunt ale mele."),
"pasul4_tinte", distante=(R1, R2))
# --------------------------------------------------- 8. pasul 5 — trail-ul
cl5 = (ramp(44.00, 50.00, 5) + [49.20, 48.60, 49.40] # 0-7 trail 1
+ ramp(49.40, 56.00, 5) + [55.00, 54.20, 55.40] # 8-15 trail 2
+ ramp(55.40, 62.00, 5) + [61.00, 60.20, 61.40] # 16-23 trail 3
+ ramp(61.40, 67.00, 4) + [66.20, 65.60]) # 24-29 trail 4
wk5 = [(0.40, 0.40)] * 30
vl5 = vols(30, 50, 12)
cds5 = from_closes(cl5, wicks=wk5, vols=vl5, start=43.00)
t1, t2, t3, t4 = (lo(cds5, 5, 7), lo(cds5, 13, 15), lo(cds5, 21, 23),
lo(cds5, 28, 29))
assert t1 < t2 < t3 < t4, (t1, t2, t3, t4)
deco(Chart(
candles=cds5,
levels=[Level(t1, f"trail 1: {t1:.2f}", "#c00", label_at="left"),
Level(t2, f"trail 2: {t2:.2f}", "#c00", label_at="left"),
Level(t3, f"trail 3: {t3:.2f}", "#c00"),
Level(t4, f"trail 4: {t4:.2f}", "#c00")],
marks=[Mark(6, "swing low", "#c00", "below", dy=14),
Mark(14, "swing low mai sus → muți stopul", "#c00", dy=-10)],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=7.0, gap=17, body_w=9, left=52, width=700, top=64, vol_h=70,
vol_label="volum",
title="Pasul 5, trail pe swing low — weekly (decizia a fost pe monthly)",
caption="Exemplu construit (fără ticker). Stopul urcă doar la un swing low "
"mai sus; nu coboară niciodată."), "pasul5_trail")
# ------------------------------------- 9. când nu merge (Tesla, 217.02/214.25)
T_CL = ([320.00, 312.00, 304.00, 298.00] # 0-3
+ [290.00, 282.00, 272.00, 262.00, 252.00, 244.00, 236.00, 230.00] # 4-11
+ [232.00] # 12 buy hammer
+ [228.00, 222.00, 216.00] # 13-15 scoate stopul
+ [225.00] # 16 al doilea semnal
+ [240.00, 252.00, 262.00, 272.00, 282.00, 290.00, 298.00] # 17-23
+ [295.00, 302.00]) # 24-25
T_WK = ([(3.00, 3.00)] * 12 + [(2.00, 12.98)]
+ [(2.00, 2.00), (2.00, 2.00), (1.00, 1.75)]
+ [(2.00, 2.00)] * 10)
T_VL = vols(26, 46, 12, i12=72, i15=78, i16=84, i17=88, i18=80)
TC = from_closes(T_CL, wicks=T_WK, vols=T_VL, start=326.00)
assert lo(TC, 12, 12) == 217.02, f"low-ul hammer-ului trebuie 217.02, e {lo(TC, 12, 12)}"
assert lo(TC, 13, 15) == 214.25, f"minimul următor trebuie 214.25, e {lo(TC, 13, 15)}"
assert 214.25 < 217.02, "al doilea minim e sub low-ul hammer-ului"
assert len(TC[17:24]) == 7, "urcarea rostită e de 7 săptămâni"
deco(Chart(
candles=TC,
levels=[Level(214.25, "minimul de după: 214.25", "#c00")],
marks=[Mark(12, "buy hammer — primul semnal", "#b06000", dy=-10),
Mark(17, "al doilea semnal, acesta merge", "#188a3e", dy=-10),
Mark(23, "7 săptămâni de urcare", "#188a3e", dy=-10)],
arrows=[Arrow(12, "low-ul hammer-ului: 217.02;\nstopul pus sub el a fost luat",
price=217.02, where="left", color="#b06000", dx=-10, dy=-26)],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=2.6, gap=19, body_w=10, left=58, width=700, vol_h=70,
vol_label="volum", title="Când nu merge — Tesla weekly",
caption="Ale lui: 217.02, 214.25 și cele 7 săptămâni de după al doilea "
"semnal; restul barelor e al meu."),
"nu_merge", intregi=())
# ------------------------------------------- 10. filtrul de volum (schiță)
SVG["divergenta"] = """<svg viewBox="0 0 700 370" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:700px;height:auto;font:12px sans-serif">
<text x="20" y="22" fill="#333" style="font-weight:bold">Filtrul de volum: divergență bull pe histograma instituțională</text>
<text x="20" y="42" fill="#666">Sus prețul, jos histograma. Cifrele de volum sunt citirile lui pe Ford; forma preț o desenez eu.</text>
<text x="20" y="74" fill="#555">PREȚ (weekly)</text>
<polyline points="90,96 160,130 230,170 300,142 370,186 440,150 510,118 580,96" fill="none" stroke="#1a1a1a" stroke-width="2"/>
<circle cx="230" cy="170" r="5" fill="#c00"/>
<circle cx="370" cy="186" r="5" fill="#c00"/>
<line x1="230" y1="170" x2="370" y2="186" stroke="#c00" stroke-width="1.4" stroke-dasharray="4 3"/>
<text x="196" y="192" fill="#c00">picior 1</text>
<text x="336" y="208" fill="#c00">picior 2, mai jos</text>
<text x="440" y="86" fill="#188a3e" style="font-weight:bold">și totuși urcă</text>
<text x="20" y="246" fill="#555">VOLUM INSTITUȚIONAL</text>
<line x1="90" y1="252" x2="660" y2="252" stroke="#888" stroke-width="1.2"/>
<text x="664" y="256" fill="#888" text-anchor="end">0</text>
<rect x="150" y="252" width="16" height="28" fill="#c00"/>
<rect x="222" y="252" width="16" height="72" fill="#c00"/>
<rect x="294" y="252" width="16" height="34" fill="#c00"/>
<rect x="362" y="252" width="16" height="50" fill="#c00"/>
<rect x="434" y="252" width="16" height="20" fill="#c00"/>
<rect x="500" y="232" width="16" height="20" fill="#188a3e"/>
<rect x="572" y="222" width="16" height="30" fill="#188a3e"/>
<text x="196" y="340" fill="#c00">minus 265 mil.</text>
<text x="336" y="318" fill="#188a3e">minus 243 mil. — mai sus</text>
<line x1="230" y1="324" x2="370" y2="302" stroke="#188a3e" stroke-width="1.4" stroke-dasharray="4 3"/>
<text x="20" y="364" fill="#555">Prețul face minim mai jos, histograma nu: cumpărătorii nu mai cedează. Asta e divergența bull care validează filtrul.</text>
</svg>"""
# ---------------------------------------- 11. rutina de scanare (schiță)
SVG["flux"] = """<svg viewBox="0 0 700 300" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:700px;height:auto;font:12px sans-serif">
<text x="20" y="22" fill="#333" style="font-weight:bold">Rutina: scanezi doji, aștepți cu radar screen-ul</text>
<rect x="20" y="44" width="200" height="56" fill="#eef4ff" stroke="#1a5fb4"/>
<text x="32" y="66" fill="#1a5fb4" style="font-weight:bold">1. Scanner, pe candelă închisă</text>
<text x="32" y="86" fill="#333">doar DOJI, nu buy doji</text>
<rect x="250" y="44" width="200" height="56" fill="#eef4ff" stroke="#1a5fb4"/>
<text x="262" y="66" fill="#1a5fb4" style="font-weight:bold">2. Lista, 3-400 de simboluri</text>
<text x="262" y="86" fill="#333">ținută 4 luni, într-un excel</text>
<rect x="480" y="44" width="200" height="56" fill="#eef4ff" stroke="#1a5fb4"/>
<text x="492" y="66" fill="#1a5fb4" style="font-weight:bold">3. Radar screen</text>
<text x="492" y="86" fill="#333">lista stă acolo și clipește</text>
<line x1="222" y1="72" x2="246" y2="72" stroke="#1a5fb4" stroke-width="1.6"/>
<line x1="452" y1="72" x2="476" y2="72" stroke="#1a5fb4" stroke-width="1.6"/>
<line x1="580" y1="102" x2="580" y2="128" stroke="#1a5fb4" stroke-width="1.6"/>
<rect x="480" y="130" width="200" height="56" fill="#e9f7ee" stroke="#188a3e"/>
<text x="492" y="152" fill="#188a3e" style="font-weight:bold">4. Clipește = buy doji</text>
<text x="492" y="172" fill="#333">îl vezi în timp ce se formează</text>
<text x="20" y="150" fill="#555">De ce în ordinea asta: scanner-ul vede doar candela închisă, deci</text>
<text x="20" y="170" fill="#555">buy doji-ul l-ai afla vineri la 23 sau în ultima zi a lunii, prea târziu.</text>
<text x="20" y="190" fill="#555">Radar screen-ul citește candela în formare, deci îl prinzi cu 2-3 zile</text>
<text x="20" y="210" fill="#555">înainte să se închidă săptămâna sau luna.</text>
<text x="20" y="246" fill="#333" style="font-weight:bold">Când scanezi</text>
<text x="20" y="266" fill="#555">Vineri seara, după închidere, pentru weekly. Cu 2-3 zile înainte de finalul lunii, pentru monthly.</text>
<text x="20" y="286" fill="#555">Doji-ul rămâne valabil ca sursă de buy doji 1-4 perioade, de aceea lista se ține patru luni.</text>
</svg>"""
# ---------------------------------------------------------------- substituire
if os.path.exists(MD):
with open(MD, encoding="utf-8") as f:
md = f.read()
lipsa = [n for n in SVG if f"<!--SVG:{n}-->" not in md]
assert not lipsa, f"marcatori lipsă în .md: {lipsa}"
for n, svg in SVG.items():
md = re.sub(rf"<!--SVG:{n}-->(\s*<svg\b[\s\S]*?</svg>)?",
lambda _m: f"<!--SVG:{n}-->\n{svg}", md, count=1)
with open(MD, "w", encoding="utf-8") as f:
f.write(md)
print(f"\n{len(SVG)} diagrame substituite in {MD}")
else:
print(f"\n{len(SVG)} diagrame generate; {MD} nu exista inca")