MODUL 5, lectia 5: strategia 8 DHRT

12 diagrame, audit curat. Patru lucruri prinse numai prin screenshot, nu de
audit: retestul desenat nu intra in consolidare desi eticheta spunea ca se
opreste peste jumatate; wedge-ul short desenat ca un canal paralel; umarul
drept de pe volum vizual egal cu cel stang; eticheta zonei de stop plutind
departe de banda. Assert-urile din generator au fost intarite pentru toate.

Singurul pret al cursului pe o eticheta e 51 (tinta XLF, "aproximativ la 51",
linia 285). Restul sunt exemple construite, declarate in titlu si in caption.

"T"-ul din DHRT ramane nerezolvat: autorul insusi spune ca nu mai stie de la
ce a zis. Nu a fost inventat.

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-02 00:34:49 +00:00
parent c739ce3126
commit 83788fc3c7
3 changed files with 3564 additions and 0 deletions

541
gen/strategia_8_dhrt.py Normal file
View File

@@ -0,0 +1,541 @@
"""Diagramele pentru summaries/06_MODUL_5/05_strategia_8_dhrt.md.
Toate graficele cu candele / intrare / stop / ținte se construiesc cu
svg_candles (o singură scară px/unitate pe desen), fiecare cifră din etichete
e verificată prin assert, apoi se substituie marcatorii <!--SVG:nume--> din .md.
Regula de cifre: pe etichete intră DOAR prețuri rostite în transcriere (51, la
XLF) sau prețuri din exemplul construit de mine, declarat ca atare în titlu și
în caption. Valorile derivate din geometria cursului (SL la 1/3, TP1 = R,
TP2 = proiecția gâtului) apar doar pe desenele construite, unde seria e a mea.
Cele două schițe fără candele (`hs_pe_volum`, `cadrane`) sunt scrise de mână.
Rulează: .venv/bin/python gen/strategia_8_dhrt.py
"""
import os
import re
import sys
sys.path.insert(0, "/workspace/atm-curs-dl")
from svg_candles import Chart, Level, Mark, MA, Zone, from_closes # noqa: E402
MD = ("/workspace/atm-curs-dl/summaries/06_MODUL_5/"
"05_strategia_8_dhrt.md")
SVG = {}
# ----------------------------------------------------------------- unelte mici
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 floor_lows(cds, a, b, price):
"""Scurtează fitilele de jos ale barelor a..b până la `price`.
Nu atinge corpurile: dacă un open sau close ar fi sub nivel, crapă. Lungimea
fitilului e oricum un parametru liber al desenului; aici o fixez ca mai
multe bare să se oprească exact pe nivelul pe care îl afirmă eticheta.
"""
for c in cds[a:b + 1]:
assert min(c.o, c.c) >= price, f"corpul barei trece sub {price}"
if c.l < price:
c.l = price
return price
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ă, verifică etichetele, salvează.
`distante` = numere cu două zecimale permise în etichete fără să fie
niveluri desenate (R-uri, înălțimi de pattern). `intregi` = întregi
rostiți în transcriere, permiși în etichete.
"""
svg = ch.render()
assert "\n\n" not in svg, f"{name}: linie goală în svg"
assert len(ch.caption) <= 118, f"{name}: caption de {len(ch.caption)} caractere"
desenate = ({f"{lv.price:.2f}" for lv in ch.levels}
| {f"{z.p_top:.2f}" for z in ch.zones if z.p_top is not None}
| {f"{z.p_bot:.2f}" for z in ch.zones if z.p_bot 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"
for m in re.finditer(
r"(?<![\d.\-/])(\d{2,3})(?![\d.])"
r"(?!\s*(?:candele|bare|săptămâni|luni|perioade|%))", 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"
assert ch._y(lv.price) < jos + 0.06 * (jos - sus), \
f"{name}: nivelul {lv.price} e lipit de marginea de jos"
SVG[name] = svg
print(f" {name}: {len(ch.candles)} bare, {len(ch.levels)} niveluri")
CONSTRUIT = ("Exemplu construit (fără ticker), la scară. Geometria e a cursului; "
"prețurile și R-urile sunt ale mele.")
# ===================================================== seria principală (HS răsturnat)
# O singură serie construită, folosită de harta, pasul 3 (stopul) și pasul 4
# (țintele), ca să nu se schimbe cifrele de la o secțiune la alta.
CL = (
[71.00, 69.00, 67.00, 65.00, 63.00, 61.00] # 0-5 downtrend anterior
+ [59.50, 58.80, 60.50, 62.00] # 6-9 umărul stâng
+ [62.80, 62.00, 63.00] # 10-12 gâtul, stânga (high 63.00)
+ [61.00, 58.00, 56.00, 54.00, 53.00, 52.30] # 13-18 căderea în cap
+ [54.00, 56.50, 58.50, 60.50, 62.00, 63.00] # 19-24 urcarea din cap
+ [62.30, 61.00, 59.30, 58.80, 59.60, 59.00] # 25-30 umărul drept
+ [59.10] # 31 doji
+ [65.00] # 32 breakout = intrare
+ [63.90, 64.60, 66.50, 69.00, 71.00] # 33-37 retest, apoi urcă
+ [73.00, 71.80, 74.00, 76.10, 77.50]) # 38-42 TP2, TP1, trail
WK = (
[(0.40, 0.40)] * 6
+ [(0.30, 0.30), (0.30, 0.30), (0.30, 0.30), (0.30, 0.30)]
+ [(0.20, 0.30), (0.30, 0.30), (0.00, 0.30)] # 12: high-ul gâtului stâng
+ [(0.30, 0.30)] * 5 + [(0.30, 0.30)]
+ [(0.30, 0.30)] * 5 + [(0.00, 0.30)] # 24: high-ul gâtului drept
+ [(0.30, 0.30), (0.30, 0.30), (0.30, 0.30), (0.30, 0.30),
(0.30, 0.30), (0.40, 0.30)]
+ [(0.90, 0.50)] # 31: fitile de doji
+ [(0.20, 0.20)] # 32: candela de breakout
+ [(0.40, 0.40)] * 5
+ [(0.40, 0.40)] * 5)
VL = vols(43, 46, 12, i27=56, i28=60, i29=64, i30=68, i31=74, i32=112,
i33=62, i34=66, i35=78, i36=84, i37=80, i39=86, i40=92)
CDS = from_closes(CL, wicks=WK, vols=VL, start=73.00)
CAP = lo(CDS, 13, 18) # low-ul capului
UMD = lo(CDS, 25, 31) # nivelul umărului drept
UMS = lo(CDS, 6, 9) # nivelul umărului stâng
H = round(UMD - CAP, 2) # înălțimea cap -> umăr drept
SL = round(CAP + H / 3, 2) # 1/3 de la cap: marginea de sus a treimii
E = CDS[32].c # intrarea, la close-ul candelei de breakout
R = round(E - SL, 2)
TP1 = round(E + R, 2)
GAT = round((hi(CDS, 12, 12) + hi(CDS, 24, 24)) / 2, 2) # media celor două vârfuri
H_HS = round(GAT - CAP, 2)
TP2 = round(GAT + H_HS, 2)
assert (CAP, UMD, UMS) == (52.00, 58.50, 58.50), (CAP, UMD, UMS)
assert H == 6.50, H
assert SL == 54.17 and CAP < SL < UMD, (CAP, SL, UMD)
assert abs(CDS[31].c - CDS[31].o) <= 0.15 * (CDS[31].h - CDS[31].l), \
"candela 31 nu e doji"
assert CDS[32].c > hi(CDS, 31, 31) and CDS[32].c > GAT, \
"candela de breakout trebuie să închidă peste doji ȘI peste gât"
assert lo(CDS, 33, 37) > SL, "retestul nu trebuie să atingă stopul"
assert hi(CDS, 38, 42) >= TP1 > TP2, \
"aici TP1 (=R) iese peste TP2 (proiecția gâtului) — exact cazul din lecție"
assert lo(CDS, 13, 18) < lo(CDS, 6, 9) and lo(CDS, 13, 18) < lo(CDS, 25, 31), \
"capul trebuie să fie mai jos decât ambii umeri"
assert VL[32] > max(VL[25:32]), "candela de breakout nu are volumul cel mai mare"
print(f"construit: cap {CAP} umeri {UMS}/{UMD} H {H} SL {SL} intrare {E}"
f" R {R} TP1 {TP1} gât {GAT} (h {H_HS}) TP2 {TP2}")
# ------------------------------------------------------------------- 1. harta
deco(Chart(
candles=CDS,
levels=[Level(SL, f"SL {SL:.2f}", "#c00", label_at="left"),
Level(E, f"intrare {E:.2f}", "#188a3e"),
Level(GAT, f"linia gâtului {GAT:.2f}", "#6a3d9a"),
Level(TP2, f"TP2 {TP2:.2f} = proiecția gâtului", "#1a5fb4",
label_at="left"),
Level(TP1, f"TP1 {TP1:.2f} = distanța stopului", "#1a5fb4")],
marks=[Mark(7, "umărul stâng", "#6a3d9a", "below", dy=14),
Mark(17, "capul", "#6a3d9a", "below", dy=16),
Mark(31, "doji", "#b06000", "below", dy=8),
Mark(32, "buy doji = trigger", "#188a3e", dy=-40),
Mark(34, "retest", "#b06000", "below", dy=22),
Mark(41, "apoi trail", "#1a5fb4", dy=-8)],
zones=[Zone(25, 31, "umărul drept", "#188a3e")],
mas=[MA(20, "#b06000", dash="4 3")],
scale=11.0, gap=15, body_w=9, left=58, width=700, top=46, vol_h=70,
vol_label="volum", title="DHRT, tot trade-ul — HS răsturnat (exemplu construit)",
caption=CONSTRUIT), "harta", distante=(R, H, H_HS))
# ===================================== 2. pasul 1, DA — capul în suport, umărul pe pivot
S_CL = (
[48.00, 46.50, 45.00, 43.50, 42.00] # 0-4 downtrend
+ [40.60, 40.10, 41.50, 43.00] # 5-8 umărul stâng
+ [43.60, 42.80, 43.50] # 9-11 gâtul
+ [41.50, 39.00, 37.50, 36.30] # 12-15 căderea în cap
+ [37.80, 39.50, 41.00, 42.60, 43.40] # 16-20 urcarea
+ [42.40, 41.20, 40.30, 40.10, 40.80, 40.40] # 21-26 umărul drept
+ [40.50, 44.20, 45.60, 47.00, 48.50]) # 27-31 doji, breakout, urcă
S_WK = ([(0.40, 0.40)] * 5
+ [(0.30, 0.30), (0.30, 0.10), (0.30, 0.10), (0.30, 0.30)]
+ [(0.30, 0.30), (0.30, 0.30), (0.50, 0.30)]
+ [(0.30, 0.30), (0.30, 0.30), (0.30, 0.30), (0.30, 0.30)]
+ [(0.30, 0.30)] * 4 + [(0.40, 0.30)]
+ [(0.30, 0.30), (0.30, 0.30), (0.30, 0.30), (0.30, 0.10),
(0.30, 0.10), (0.30, 0.30)]
+ [(0.70, 0.40)] + [(0.20, 0.20)] + [(0.40, 0.40)] * 3)
S_VL = vols(32, 44, 12, i23=54, i24=58, i25=62, i26=66, i27=70, i28=104, i29=84)
SC = from_closes(S_CL, wicks=S_WK, vols=S_VL, start=49.00)
SUP, PIV = lo(SC, 12, 15), lo(SC, 21, 27)
assert SUP == 36.00 and PIV == 40.00, (SUP, PIV)
assert PIV > SUP, "umărul drept trebuie să stea peste suportul capului"
assert abs(lo(SC, 5, 8) - PIV) <= 0.20, "umerii trebuie să fie aproximativ simetrici"
assert abs(SC[27].c - SC[27].o) <= 0.15 * (SC[27].h - SC[27].l), "bara 27 nu e doji"
assert SC[28].c > hi(SC, 27, 27) and SC[28].c > hi(SC, 9, 11), \
"breakout-ul trebuie să treacă peste doji și peste gât"
deco(Chart(
candles=SC,
levels=[Level(SUP, f"suport monthly {SUP:.2f}", "#b06000", label_at="left"),
Level(PIV, f"pivot monthly {PIV:.2f}", "#6a3d9a", label_at="left")],
marks=[Mark(6, "umărul stâng", "#6a3d9a", dy=-22),
Mark(14, "capul, în suport", "#b06000", "below", dy=16),
Mark(27, "doji", "#b06000", "below", dy=28),
Mark(28, "buy doji = trigger", "#188a3e", dy=-44)],
zones=[Zone(21, 27, "umărul drept, pullback pe pivot", "#188a3e")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=14.0, gap=17, body_w=9, left=58, width=700, top=46, vol_h=70,
vol_label="volum", title="Pasul 1, DA — capul în suport, umărul drept pe pivot",
caption="Exemplu construit (fără ticker), la scară. Volumul crește pe "
"ultimele bare ale umărului și explodează pe breakout."), "pas1_da")
# ======================================== 3. pasul 1, NU — triple bottom la al 4-lea test
N_CL = (
[38.00, 36.50, 35.00, 33.60, 32.40] # 0-4 downtrend
+ [31.10, 32.80, 34.00] # 5-7 piciorul 1
+ [33.00, 31.90, 31.20, 32.60, 33.80] # 8-12 piciorul 2
+ [32.90, 31.80, 31.10, 32.20, 33.20] # 13-17 piciorul 3
+ [32.40, 31.60, 31.00, 31.40, 30.20, 28.60, 27.00]) # 18-24 al 4-lea: rupe
N_WK = ([(0.40, 0.40)] * 5
+ [(0.30, 0.10), (0.30, 0.30), (0.30, 0.30)]
+ [(0.30, 0.30), (0.30, 0.30), (0.30, 0.10), (0.30, 0.30), (0.30, 0.30)]
+ [(0.30, 0.30), (0.30, 0.30), (0.30, 0.10), (0.30, 0.30), (0.30, 0.30)]
+ [(0.30, 0.30), (0.30, 0.30), (0.30, 0.20), (0.30, 0.30),
(0.30, 0.30), (0.30, 0.30), (0.30, 0.30)])
N_VL = vols(25, 54, 14, i5=74, i10=58, i15=46, i20=36, i21=40, i22=62, i23=70,
i24=76)
NC = from_closes(N_CL, wicks=N_WK, vols=N_VL, start=39.00)
BAZA = floor_lows(NC, 5, 17, 31.00)
assert lo(NC, 5, 17) == 31.00, lo(NC, 5, 17)
_pic = [min(c.c for c in NC[a:b + 1]) for a, b in ((5, 7), (8, 12), (13, 17))]
assert max(_pic) - min(_pic) <= 0.30, \
f"cele trei picioare trebuie să închidă aproximativ la același nivel: {_pic}"
assert lo(NC, 18, 24) < BAZA, "al 4-lea test trebuie să rupă baza"
assert N_VL[5] > N_VL[10] > N_VL[15] > N_VL[20], \
"volumul trebuie să scadă de la un picior la altul"
deco(Chart(
candles=NC,
levels=[Level(BAZA, f"baza testată de 3 ori: {BAZA:.2f}", "#c00")],
marks=[Mark(5, "1", "#6a3d9a", "below", dy=14),
Mark(10, "2", "#6a3d9a", "below", dy=14),
Mark(15, "3", "#6a3d9a", "below", dy=14),
Mark(20, "al 4-lea test: nu mai ține", "#c00", "below", dy=96),
Mark(8, "volumul scade la fiecare picior", "#c00", dy=-8)],
zones=[Zone(18, 24, "breakdown, nu breakout", "#c00")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=20.0, gap=19, body_w=9, left=58, width=700, top=46, vol_h=70,
label_gap=60,
vol_label="volum", title="Pasul 1, NU — triple bottom la al 4-lea test",
caption="Exemplu construit (fără ticker), la scară. Cu cât baza e retestată "
"mai des și volumul scade, cresc șansele să cadă."),
"pas1_nu")
# ========================================= 4. pasul 2, DA — trigger-ul din umărul drept
T_CL = ([55.00, 56.50, 58.00, 59.50, 61.00, 62.20, 63.00] # 0-6 urcarea din cap
+ [62.40, 61.30, 60.20, 59.40, 59.90, 59.20, 59.70,
59.10, 59.80, 59.30] # 7-16 consolidarea
+ [59.40] # 17 doji
+ [65.00] # 18 buy doji/breakout
+ [64.20, 65.80, 67.50, 69.00]) # 19-22 continuă
T_WK = ([(0.40, 0.40)] * 7
+ [(0.30, 0.30)] * 10
+ [(0.90, 0.70)] # 17 doji
+ [(0.20, 0.20)] # 18 breakout
+ [(0.40, 0.40)] * 4)
T_VL = vols(23, 44, 10, i4=78, i8=46, i9=42, i10=40, i11=44, i12=48, i13=52,
i14=58, i15=64, i16=70, i17=76, i18=118, i19=70, i20=84, i21=90)
TC = from_closes(T_CL, wicks=T_WK, vols=T_VL, start=54.00)
CONS_HI = hi(TC, 7, 17)
assert abs(TC[17].c - TC[17].o) <= 0.15 * (TC[17].h - TC[17].l), "bara 17 nu e doji"
assert TC[18].c > CONS_HI, "breakout-ul trebuie să închidă peste vârful consolidării"
assert T_VL[18] > T_VL[4], "volumul de breakout trebuie să treacă peste swing high-ul lui"
assert T_VL[10] < T_VL[13] < T_VL[16] < T_VL[17], "volumul nu e în acumulare"
deco(Chart(
candles=TC,
levels=[Level(CONS_HI, f"vârful consolidării {CONS_HI:.2f}", "#6a3d9a",
label_at="left")],
marks=[Mark(17, "doji: setup-ul", "#b06000", "below", dy=26),
Mark(18, "buy doji = trigger", "#188a3e", dy=-14),
Mark(11, "↓ volum în acumulare: bare tot mai mari", "#188a3e",
"below", dy=26),
Mark(4, "↓ swing high de volum", "#1a5fb4", "below", dy=70)],
zones=[Zone(7, 17, "umărul drept: 11 bare de consolidare", "#188a3e")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=16.0, gap=26, body_w=11, left=58, width=700, top=46, vol_h=80,
vol_label="volum", title="Pasul 2, DA — trigger valid din umărul drept",
caption="Exemplu construit (fără ticker). Volumul de breakout trece peste "
"swing high-ul anterior de volum."), "pas2_da")
# ========================================== 5. pasul 2, NU — volumul rupe în jos
X_CL = ([55.00, 56.50, 58.00, 59.50, 61.00, 62.20, 63.00]
+ [62.40, 61.30, 60.20, 59.40, 59.90, 59.20, 59.70,
59.10, 59.80, 59.30]
+ [59.40] # 17 același doji
+ [64.40] # 18 breakout, dar fără volum
+ [62.00, 60.00, 57.50, 55.00]) # 19-22 breakdown
X_WK = T_WK
X_VL = vols(23, 44, 10, i4=78, i8=52, i9=48, i10=40, i11=38, i12=34, i13=32,
i14=30, i15=28, i16=26, i17=24, i18=36, i19=54, i20=66, i21=74)
XC = from_closes(X_CL, wicks=X_WK, vols=X_VL, start=54.00)
assert abs(XC[17].c - XC[17].o) <= 0.15 * (XC[17].h - XC[17].l), "bara 17 nu e doji"
assert XC[18].c > hi(XC, 7, 17), "breakout-ul de preț există și aici"
assert X_VL[18] < X_VL[4], "volumul de breakout NU trebuie să treacă swing high-ul"
assert X_VL[17] == min(X_VL), "volumul minim trebuie să cadă pe doji"
assert XC[22].c < lo(XC, 7, 17), "după breakout-ul fals prețul rupe consolidarea"
deco(Chart(
candles=XC,
levels=[Level(lo(XC, 7, 17), f"baza {lo(XC, 7, 17):.2f}", "#c00",
label_at="left")],
marks=[Mark(17, "doji", "#b06000", "below", dy=26),
Mark(18, "închide peste consolidare, dar volumul e praf", "#c00", dy=-10),
Mark(12, "volumul face minime tot mai joase", "#c00", "below", dy=26),
Mark(22, "breakdown", "#c00", "below", dy=14)],
zones=[Zone(7, 17, "aceeași consolidare de 11 bare", "#c00")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=14.0, gap=26, body_w=11, left=58, width=700, top=46, vol_h=80,
vol_label="volum", title="Pasul 2, NU — breakout de preț fără breakout de volum",
caption="Exemplu construit (fără ticker). Prețul arată identic cu diagrama "
"de deasupra; diferă panoul de volum. False breakout."), "pas2_nu")
# ================================================== 6. pasul 3 — stopul, treimea de jos
deco(Chart(
candles=CDS[6:36],
levels=[Level(UMD, f"umăr drept {UMD:.2f}", "#6a3d9a"),
Level(CAP, f"cap {CAP:.2f} — baza lui H", "#6a3d9a",
label_at="left"),
Level(SL, f"SL minim {SL:.2f} = cap + H/3", "#c00"),
Level(E, f"intrare {E:.2f}; distanța până la SL e R", "#188a3e",
label_at="left")],
marks=[Mark(12, "capul", "#6a3d9a", "below", dy=16),
Mark(22, "banda roșie = treimea de jos din H", "#c00",
"below", dy=104)],
zones=[Zone(8, 27, "", "#c00", p_top=SL, p_bot=CAP)],
scale=13.0, gap=20, body_w=10, left=58, width=700, top=46,
title="Pasul 3, stopul — H de la cap la umărul drept, apoi o treime",
caption=CONSTRUIT), "pas3_stop", distante=(H, R))
# ========================================================= 7. pasul 4 — cele două ținte
deco(Chart(
candles=CDS[18:],
levels=[Level(SL, f"SL {SL:.2f}", "#c00", label_at="left"),
Level(E, f"intrare {E:.2f}", "#188a3e", label_at="left"),
Level(GAT, f"linia gâtului {GAT:.2f}, media celor două vârfuri",
"#6a3d9a", label_at="left"),
Level(TP2, f"TP2 {TP2:.2f} = gât + înălțimea HS", "#1a5fb4",
label_at="left"),
Level(TP1, f"TP1 {TP1:.2f} = intrare + R", "#1a5fb4",
label_at="left")],
marks=[Mark(14, "buy doji", "#188a3e", dy=-10)],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=12.0, gap=24, body_w=10, left=58, width=700, top=46,
title="Pasul 4, țintele — TP1 = R, TP2 = proiecția gâtului",
caption="Exemplu construit (fără ticker), la scară. Aici TP1 iese PESTE TP2; "
"ordinea lor nu e fixă."), "pas4_tinte", distante=(R, H_HS))
# ================================================ 8. retestul „locului crimei", DA
Y_CL = ([50.00, 51.20, 52.40, 53.00, 52.20, 53.40, 52.60, 53.20,
52.40, 53.00] # 0-9 consolidarea
+ [56.00] # 10 breakout
+ [54.60, 53.00, 52.70] # 11-13 retest în consolidare
+ [52.80] # 14 doji
+ [57.20, 58.80, 60.50, 62.00]) # 15-18 pleacă
Y_WK = ([(0.30, 0.30)] * 10 + [(0.20, 0.20)]
+ [(0.30, 0.30), (0.30, 0.30), (0.30, 0.30)]
+ [(0.60, 0.50)] + [(0.30, 0.30)] * 4)
Y_VL = vols(19, 44, 10, i10=96, i11=52, i12=48, i13=46, i14=56, i15=88, i16=82)
YC = from_closes(Y_CL, wicks=Y_WK, vols=Y_VL, start=49.00)
C_HI, C_LO = hi(YC, 0, 9), lo(YC, 0, 9)
JUM = round((C_HI + C_LO) / 2, 2)
assert YC[10].c > C_HI, "bara 10 trebuie să facă breakout peste consolidare"
assert JUM < lo(YC, 11, 14) < C_HI, \
"retestul trebuie să intre în consolidare, dar să se oprească peste jumătate"
assert YC[18].c > YC[10].c, "după retest prețul trebuie să plece mai sus"
deco(Chart(
candles=YC,
levels=[Level(C_HI, f"vârful consolidării {C_HI:.2f} = locul crimei", "#6a3d9a"),
Level(JUM, f"jumătatea consolidării {JUM:.2f}", "#b06000")],
marks=[Mark(10, "breakout", "#188a3e", dy=-10),
Mark(13, "retest, se oprește peste jumătate", "#188a3e", "below", dy=20),
Mark(14, "doji aici: a doua intrare", "#188a3e", "below", dy=38)],
zones=[Zone(0, 9, "consolidarea", "#6a3d9a")],
scale=22.0, gap=30, body_w=12, left=58, width=700, top=46, vol_h=70,
vol_label="volum", title="Retestul, DA — se oprește în jumătatea de sus",
caption="Exemplu construit (fără ticker). Volum mic pe retest, mare pe "
"repornire: nu vin vânzători noi."), "retest_da")
# ================================================ 9. retestul „locului crimei", NU
Z_CL = ([50.00, 51.20, 52.40, 53.00, 52.20, 53.40, 52.60, 53.20,
52.40, 53.00]
+ [56.00]
+ [54.80, 53.20, 51.80, 50.40] # 11-14 trece tot jos
+ [49.00, 47.60, 46.00, 44.50]) # 15-18 breakdown
Z_WK = ([(0.30, 0.30)] * 10 + [(0.20, 0.20)] + [(0.30, 0.30)] * 8)
Z_VL = vols(19, 44, 10, i10=96, i11=58, i12=64, i13=72, i14=80, i15=88, i16=94)
ZC = from_closes(Z_CL, wicks=Z_WK, vols=Z_VL, start=49.00)
assert hi(ZC, 0, 9) == C_HI and lo(ZC, 0, 9) == C_LO, \
"consolidarea trebuie să fie identică cu cea din diagrama DA"
assert ZC[10].c > C_HI, "și aici există breakout"
assert ZC[14].c < JUM and ZC[18].c < C_LO, "retestul trece sub bază: breakdown"
assert Z_VL[13] > Z_VL[11], "volumul crește pe coborâre — vin vânzători"
deco(Chart(
candles=ZC,
levels=[Level(C_HI, f"vârful consolidării {C_HI:.2f}", "#6a3d9a"),
Level(JUM, f"jumătatea consolidării {JUM:.2f}", "#b06000"),
Level(C_LO, f"baza {C_LO:.2f}", "#c00")],
marks=[Mark(10, "același breakout", "#188a3e", dy=-10),
Mark(13, "retestul trece sub jumătate", "#c00", "below", dy=52),
Mark(17, "volum în creștere pe coborâre", "#c00", "below", dy=16)],
zones=[Zone(0, 9, "aceeași consolidare", "#6a3d9a")],
scale=15.0, gap=30, body_w=12, left=58, width=700, top=46, vol_h=70,
vol_label="volum", title="Retestul, NU — trece sub jumătate și rupe baza",
caption="Exemplu construit (fără ticker). Același breakout; diferă cât de "
"adânc cade retestul și ce face volumul."),
"retest_nu")
# ================================================= 10. varianta short — ascending wedge
W_CL = ([52.10, 52.50, 52.90] # 0-2 uptrend anterior
+ [53.40, 52.80, 52.10] # 3-5 vârf 1, picior 1
+ [52.80, 53.40, 53.90, 53.20, 52.70] # 6-10 vârf 2, picior 2
+ [53.20, 53.70, 54.10, 53.60, 53.20] # 11-15 vârf 3, picior 3
+ [53.60, 53.95] # 16-17 ultimul test
+ [53.90] # 18 sell doji
+ [53.10, 52.50, 52.00, 51.50, 51.00, 50.90, 51.20]) # 19-25 cade spre 51
W_WK = ([(0.25, 0.25)] * 18 + [(0.55, 0.50)] + [(0.25, 0.25)] * 7)
W_VL = vols(26, 48, 10, i3=62, i8=50, i10=40, i12=36, i13=34, i15=30, i16=28,
i17=26, i18=30, i19=78, i20=86, i21=92, i22=96, i23=88)
WC = from_closes(W_CL, wicks=W_WK, vols=W_VL, start=51.80)
TINTA = 51.00
L1, L2, L3 = lo(WC, 4, 6), lo(WC, 9, 11), lo(WC, 14, 16)
H1, H2, H3 = hi(WC, 2, 4), hi(WC, 7, 9), hi(WC, 12, 14)
assert L1 < L2 < L3, f"minimele wedge-ului trebuie să urce: {L1} {L2} {L3}"
assert H1 < H2 < H3, f"maximele trebuie să urce și ele: {H1} {H2} {H3}"
assert (H1 - L1) > (H2 - L2) > (H3 - L3), \
f"wedge înseamnă convergență: {H1-L1:.2f} {H2-L2:.2f} {H3-L3:.2f}"
assert abs(WC[18].c - WC[18].o) <= 0.20 * (WC[18].h - WC[18].l), "bara 18 nu e doji"
assert WC[19].c < lo(WC, 17, 18), "sell doji-ul trebuie să rupă în jos"
assert lo(WC, 21, 25) <= TINTA, "seria trebuie să atingă ținta rostită, 51"
assert W_VL[17] == min(W_VL), "volumul trebuie să se stingă în vârful wedge-ului"
assert max(W_VL[19:23]) > max(W_VL[:19]), "volumul trebuie să explodeze pe coborâre"
print(f" wedge: picioare {L1}/{L2}/{L3} vârfuri {H1}/{H2}/{H3} "
f"deschideri {H1-L1:.2f}/{H2-L2:.2f}/{H3-L3:.2f}")
deco(Chart(
candles=WC,
levels=[Level(TINTA, "ținta rostită în lecție: 51", "#1a5fb4",
label_at="left")],
marks=[Mark(16, "volumul se stinge", "#c00", "below", dy=30),
Mark(18, "sell doji = trigger de short", "#c00", dy=-10),
Mark(23, "ținta atinsă", "#1a5fb4", "below", dy=16),
Mark(10, "minimele urcă mai repede decât maximele", "#c00",
"below", dy=40)],
zones=[Zone(2, 18, "", "#c00")],
mas=[MA(20, "#b06000", dash="4 3", text="SMA-20")],
scale=65.0, gap=23, body_w=10, left=58, width=700, top=46, vol_h=70,
vol_label="volum", title="Varianta short — XLF, ascending wedge",
caption="Al lui: ținta de 51 și patternul pe XLF. Barele sunt ale mele; "
"wedge-ul se îngustează, nu urcă paralel."),
"short_wedge", intregi=(51,))
# ============================================ 11. HS răsturnat și pe volum (schiță)
SVG["hs_pe_volum"] = """<svg viewBox="0 0 700 410" 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">Secretul: același HS răsturnat, de două ori — pe preț și pe volum</text>
<text x="20" y="44" fill="#555">Sus prețul, jos linia de trend a volumului. Când ambele desenează aceeași formă, setup-ul e mai tare.</text>
<rect x="20" y="60" width="660" height="150" fill="#fbfbfb" stroke="#ddd"/>
<text x="30" y="78" fill="#6a3d9a" style="font-weight:bold">PREȚ</text>
<polyline points="40,80 90,120 140,150 190,118 240,135 290,180 340,195 390,160 440,145 490,152 540,140 590,96 650,74" fill="none" stroke="#1a1a1a" stroke-width="2"/>
<line x1="150" y1="131" x2="610" y2="131" stroke="#6a3d9a" stroke-width="1.4" stroke-dasharray="4 3"/>
<text x="614" y="127" fill="#6a3d9a">linia gâtului</text>
<circle cx="140" cy="150" r="4" fill="#6a3d9a"/>
<text x="112" y="172" fill="#6a3d9a">umăr stâng</text>
<circle cx="340" cy="195" r="4" fill="#6a3d9a"/>
<text x="318" y="212" fill="#6a3d9a">cap</text>
<circle cx="490" cy="152" r="4" fill="#6a3d9a"/>
<text x="464" y="174" fill="#6a3d9a">umăr drept</text>
<text x="556" y="90" fill="#188a3e" style="font-weight:bold">breakout</text>
<rect x="20" y="226" width="660" height="150" fill="#fbfbfb" stroke="#ddd"/>
<text x="30" y="244" fill="#1a5fb4" style="font-weight:bold">VOLUM (linia de trend)</text>
<polyline points="40,268 90,292 140,322 190,296 240,308 290,336 340,352 390,322 440,292 490,298 540,264 590,248 650,236" fill="none" stroke="#1a5fb4" stroke-width="2"/>
<line x1="140" y1="322" x2="490" y2="322" stroke="#1a5fb4" stroke-width="1" stroke-dasharray="3 3"/>
<circle cx="140" cy="322" r="4" fill="#1a5fb4"/>
<text x="112" y="342" fill="#1a5fb4">umăr stâng</text>
<circle cx="340" cy="352" r="4" fill="#1a5fb4"/>
<text x="318" y="370" fill="#1a5fb4">cap</text>
<circle cx="490" cy="298" r="4" fill="#1a5fb4"/>
<text x="430" y="288" fill="#1a5fb4">umăr drept, mai sus decât cel stâng</text>
<text x="20" y="398" fill="#555">Umărul drept de pe volum mai sus decât cel stâng: cumpărătorii revin cu mai multă forță decât prima dată. Asta cauți.</text>
</svg>"""
# ================================================ 12. cadranele de filtru (schiță)
SVG["cadrane"] = """<svg viewBox="0 0 700 330" 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">„Cadran long" — cele două cadrane în care ai voie să iei trigger-ul</text>
<rect x="60" y="44" width="150" height="100" fill="#eef4ff" stroke="#1a5fb4"/>
<text x="70" y="68" fill="#1a5fb4" style="font-weight:bold">improving</text>
<text x="70" y="88" fill="#333">se îmbunătățește,</text>
<text x="70" y="106" fill="#333">încă sub piață</text>
<text x="70" y="130" fill="#188a3e" style="font-weight:bold">DA</text>
<rect x="210" y="44" width="150" height="100" fill="#e9f7ee" stroke="#188a3e"/>
<text x="220" y="68" fill="#188a3e" style="font-weight:bold">outperforming</text>
<text x="220" y="88" fill="#333">bate piața</text>
<text x="220" y="130" fill="#188a3e" style="font-weight:bold">DA</text>
<rect x="60" y="144" width="150" height="100" fill="#fdeeee" stroke="#c00"/>
<text x="70" y="168" fill="#c00" style="font-weight:bold">lagging</text>
<text x="70" y="188" fill="#333">rămâne în urmă</text>
<text x="70" y="230" fill="#c00" style="font-weight:bold">NU</text>
<rect x="210" y="144" width="150" height="100" fill="#fdeeee" stroke="#c00"/>
<text x="220" y="168" fill="#c00" style="font-weight:bold">weakening</text>
<text x="220" y="188" fill="#333">se deteriorează</text>
<text x="220" y="230" fill="#c00" style="font-weight:bold">NU</text>
<text x="60" y="266" fill="#555">slab ←</text>
<text x="330" y="266" fill="#555">→ puternic</text>
<text x="400" y="62" fill="#333" style="font-weight:bold">Ordinea de importanță, după autor</text>
<text x="400" y="86" fill="#555">1. volumul — oricare dintre cele două</text>
<text x="400" y="106" fill="#555">2. relative strength în cadran long</text>
<text x="400" y="126" fill="#555">3. power în cadran long</text>
<text x="400" y="156" fill="#333" style="font-weight:bold">Toate trei aliniate = Trinity</text>
<text x="400" y="178" fill="#555">Nu e obligatoriu: „nu poți să le ai</text>
<text x="400" y="196" fill="#555">chiar pe toate". Volumul singur e</text>
<text x="400" y="214" fill="#555">suficient ca filtru minim.</text>
<text x="20" y="296" fill="#555">Relative strength se citește față de SPY, deci are sens doar pe equities (acțiuni, ETF-uri de sector).</text>
<text x="20" y="316" fill="#555">Pe commodities schimbi reperul pe o clasă similară: petrol față de gaze, aur față de argint, grâu față de porumb.</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")