17_STRATEGII/06_hammer_mbt10: toate cele 9 restante, plus cele 3 cosmetice

Cea mai grava, si cea care a cerut refacerea seriei: exemplul central de
MBT-10 era luat de pe 60 de minute si bagat in procedura de daily, cu barele
numite "zile", desi sursa spune explicit de ce nu merge pe daily. Pe langa
asta, suportul fusese schimbat din 88.00 (testat de trei ori, cu compresie,
cum e in sursa) in 87.50 cu un double bottom si o divergenta de volum
imprumutate din alt exemplu.

Seria e refacuta pe exemplul materialului, cu assert pe cele trei atingeri ale
lui 88.00 si pe compresia varfurilor. Adaosurile au fost scoase, nu doar
marcate: cu ele in desen, suportul din sursa n-ar fi avut sens. Aritmetica a
supravietuit neatinsa.

Restul: stopul de 60.40 sta acum sub o structura reala; pivotul daily nu mai e
o linie fixa peste tot graficul, ci un segment peste ziua intrarii; SL-ul de
pe LABU respecta regula proprie de 5 centi; citatul de la A2 nu mai e dat ca
al autorului; pragul de 1-2% isi spune originea (cursul da 0,5%, pe 60 min);
o singura conventie de distanta, impartirea la nivel; swing low definit la fel
in pas si in glosar.

eticheta_libera a prins 7 suprapuneri reale. La bh_aplus a trebuit rulat pe
fiecare panou separat: wrapper-ul le muta cu <g transform>, pe care unealta
nu-l citeste - de notat pentru data viitoare.

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 05:29:33 +00:00
parent 80624653dc
commit f60d32cb34
20 changed files with 1156 additions and 987 deletions

View File

@@ -1,53 +1,64 @@
#!/usr/bin/env python3
"""MBT-10, pasul „unde": ideea de bottom cu confluențe (exemplu construit).
"""MBT-10, pasul „unde": ideea de bottom, pe exemplul materialului.
Seria de aici e SURSA UNICĂ a trade-ului MBT-10 din Nivelul 2:
`hammer_mbt10_mbt_ppd`, `_mbt_stop` și `_mbt_iesire` importă `serie()` și
pornesc din aceleași bare. Nivelurile 89.90 (intrare la close), 87.30 (SL) și
95.20 (ținta, vârful de unde a pornit coborârea) sunt cifrele exemplului
construit din fișierul principal; suportul weekly 87.50 și pivotul daily
89.60 sunt puse de mine, ca acele cifre să aibă de unde ieși.
pornesc din aceleași bare.
Diagrama asta arată doar contextul: double bottom pe suportul weekly, cu
volum mai mic pe al doilea picior. Nicio intrare desenată — intrarea vine la
pasul următor.
Exemplul e al materialului (`08_ANALIZA_ZILNICA/02_mbt10.md:440-455`) și e pe
**60 de minute**, nu pe daily: suport weekly **88.00**, testat de **trei ori**,
cu vârfuri tot mai mici între teste (compresie); intrare **89.90** la close-ul
barei în MBT-10; **SL 87.30** sub suport; **țintă 95.20**, vârful de unde a
pornit coborârea. Materialul spune și de ce nu pe daily: „o bară daily în
suport weekly poate avea un low cu 2-3 % sub suport, deci stopul ar sta
departe".
Ale mele sunt doar forma exactă a barelor, volumul și pivotul daily 89.60 (pus
ca să aibă ce verifica pasul B3). Nu există aici nici double bottom, nici
divergență de volum: alea sunt din alt exemplu al materialului (gap up, cu
picioarele 32.10 / 30.90) și nu se fuzionează cu ăsta.
Rulare: python3 gen/strategii/hammer_mbt10_mbt_confluente.py
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
sys.path.insert(0, "/workspace/atm-curs-dl/gen")
from pathlib import Path
from svg_candles import Arrow, Chart, Level, Zone, from_closes
from eticheta_libera import eticheta_libera
from svg_candles import Chart, Level, Mark, Zone, from_closes
OUT = Path(__file__).with_suffix(".svg")
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
SUP_W, PPD = 87.50, 89.60 # suport weekly, pivotul daily
SUP_W, PPD = 88.00, 89.60 # suport weekly (materialul), pivotul daily (al meu)
INTRARE, SL, TP = 89.90, 87.30, 95.20
R = round(INTRARE - SL, 2)
FUND1, FUND2 = 10, 15 # cele două picioare ale double bottom-ului
TESTE = (9, 12, 15) # cele trei atingeri ale suportului weekly
VARFURI = (10, 13) # vârfurile dintre teste: tot mai mici (compresie)
VARF = 3 # ultimul maxim înainte de coborâre: high 95.20 = ținta
CLOSE_I = 19 # bara care se închide peste pivotul daily
BARE_PE_ZI = 7 # 60 de minute, sesiune US: 7 bare pe zi
ZI_INTRARE = (14, 20) # barele zilei în care vine trigger-ul
CLOSES = [96.00, 95.00, 94.20, 95.00, 93.10, 92.00, 91.20, 90.10, 89.00, # 0-8
88.20, 87.70, 88.40, 89.10, # 9-12
88.60, 88.00, 87.65, 88.30, # 13-16
88.90, 89.40, 89.90, # 17-19
90.60, 91.40, 92.20, 91.80, 93.00, 94.10, 95.40] # 20-26
88.20, 89.00, 88.60, # 9-11
88.20, 89.00, 88.50, # 12-14
88.20, 88.60, 89.00, 89.40, 89.90, # 15-19
90.60, 91.40, 92.20, 91.80, 93.00, 94.10, 95.40] # 20-26
VOLS = [60, 58, 55, 50, 62, 66, 70, 74, 80,
86, 94, 62, 58,
55, 60, 66, 54, # piciorul 2: volum vizibil mai mic
58, 62, 96,
86, 62, 58,
84, 60, 56,
82, 58, 62, 66, 96,
70, 66, 64, 58, 68, 72, 80]
def serie():
w = [(0.20, 0.25)] * len(CLOSES)
w[FUND1] = (0.20, 0.10) # low 87.60
w[FUND2] = (0.20, 0.10) # low 87.55
# barele imediat de după picioare pornesc din același preț: fără fitil lung
# în jos, altfel ele ar face minimul, nu picioarele
w[FUND1 + 1] = w[FUND2 + 1] = (0.20, 0.05)
for t in TESTE:
w[t] = (0.20, 0.20) # low exact pe 88.00: suportul ține, nu cedează
w[t + 1] = (0.20, 0.05) # bara de după pornește din 88.20: fără fitil lung în jos
w[VARFURI[0]] = (0.50, 0.05) # high 89.50
w[VARFURI[1]] = (0.10, 0.05) # high 89.10 — vârf mai mic
# bara 18 atinge pivotul intraday, dar se închide sub el: contraexemplul
# de la pasul cu condiția de preț
w[CLOSE_I - 1] = (0.30, 0.25)
@@ -58,20 +69,30 @@ def serie():
assert len(cds) == len(VOLS) == 27
for i in range(1, len(cds)):
assert abs(cds[i].o - cds[i - 1].c) < 1e-9, f"open[{i}] != close[{i-1}]"
l1, l2 = round(cds[FUND1].l, 2), round(cds[FUND2].l, 2)
assert (l1, l2) == (87.60, 87.55), (l1, l2)
assert abs(l1 - l2) <= 0.05 and l2 < l1, "double bottom: al doilea picior, puțin mai jos"
assert round(min(c.l for c in cds), 2) == l2, "cel mai jos low nu e al piciorului 2"
assert l2 > SUP_W > SL, "picioarele trebuie să stea peste suport, iar stopul sub el"
assert VOLS[FUND2] < VOLS[FUND1], "fără divergență de volum pe piciorul 2"
# de la al doilea picior încoace, nicio bară nu închide peste pivotul zilei
# suportul weekly e atins de exact trei ori și ține de fiecare dată
atingeri = [i for i, c in enumerate(cds) if round(c.l, 2) <= SUP_W]
assert atingeri == list(TESTE), atingeri
for t in TESTE:
assert round(cds[t].l, 2) == SUP_W, (t, cds[t].l)
assert SUP_W > SL, "stopul trebuie să stea sub suport"
# compresie: vârfurile dintre teste scad
v1, v2 = (round(cds[i].h, 2) for i in VARFURI)
assert v1 > v2, f"vârfurile dintre teste nu scad: {v1} > {v2}"
assert (v1, v2) == (89.50, 89.10), (v1, v2)
# de la primul test încoace, nicio bară nu închide peste pivotul zilei
# intrării — altfel trigger-ul ar fi venit mai devreme
assert max(c.c for c in cds[FUND2:CLOSE_I]) < PPD < cds[CLOSE_I].c, \
assert max(c.c for c in cds[TESTE[0]:CLOSE_I]) < PPD < cds[CLOSE_I].c, \
"o bară dinaintea trigger-ului închide deja peste pivotul daily"
assert round(cds[CLOSE_I].c, 2) == INTRARE
assert cds[CLOSE_I - 1].h > PPD > cds[CLOSE_I - 1].c, \
"bara 18 trebuie să atingă pivotul intraday, dar să închidă sub el"
assert min(c.l for c in cds[CLOSE_I:]) > SL, "stopul ar fi fost atins după intrare"
# trigger-ul și contraexemplul lui stau în aceeași zi: pe 60 de minute
# pivotul daily e un singur nivel pe toată ziua, dar se schimbă mâine
assert ZI_INTRARE[0] <= CLOSE_I - 1 and CLOSE_I <= ZI_INTRARE[1]
assert ZI_INTRARE[1] - ZI_INTRARE[0] + 1 == BARE_PE_ZI
assert all(i // BARE_PE_ZI == ZI_INTRARE[0] // BARE_PE_ZI
for i in range(*ZI_INTRARE)), "ziua intrării nu e un bloc de 7 bare"
prim_tp = next(i for i in range(CLOSE_I + 1, len(cds)) if cds[i].h >= TP)
assert prim_tp == 26, prim_tp
# ținta 95.20 nu e un număr ales: e high-ul ultimului maxim dinaintea coborârii
@@ -83,34 +104,32 @@ def serie():
if __name__ == "__main__":
cds = serie()
pct1 = round((cds[FUND1].l - SUP_W) / SUP_W * 100, 2)
pct2 = round((cds[FUND2].l - SUP_W) / SUP_W * 100, 2)
assert pct1 < 0.2 and pct2 < 0.2, (pct1, pct2)
vis = cds[:CLOSE_I] # contextul, fără bara de trigger
ch = Chart(
candles=vis,
levels=[Level(SUP_W, "suport weekly 87.50", BLUE, label_at="left")],
zones=[Zone(FUND1, FUND2, "double bottom: 87.60 și 87.55", ORANGE)],
arrows=[
Arrow(FUND1, "piciorul 1: low 87.60,\nla 0,11 % peste suport",
where="below", color=GREY, dx=-150, dy=26),
Arrow(FUND2, "piciorul 2: low 87.55, cu 5 cenți mai jos,\ndar cu volum mai mic decât "
"la piciorul 1 —\nvânzarea a slăbit (divergență de volum)",
where="below", color=RED, dx=-40, dy=64),
],
levels=[Level(SUP_W, "suport weekly 88.00", BLUE, label_at="left")],
zones=[Zone(TESTE[0], TESTE[-1], "", ORANGE)],
marks=[Mark(t, f"test {n}", ORANGE, "above", dy=-34)
for n, t in enumerate(TESTE, 1)],
scale=30.0, gap=22, body_w=12, left=54, width=700, vol_h=70, vol_label="volum",
title="MBT-10, pasul „unde\" — double bottom pe suportul weekly (exemplu construit)",
title="MBT-10, pasul „unde\" — suport weekly testat de trei ori, pe 60 de minute",
)
svg = ch.render()
eticheta_libera(svg, "mbt_confluente", {"test 1", "test 2", "test 3"}, rects=True)
m = re.search(r'viewBox="0 0 (\d+) (\d+)"', svg)
W, H = int(m.group(1)), int(m.group(2))
linii = [
("Aici nu intri încă: diagrama arată doar ideea de bottom. MBT-10 e ultima piesă, și "
"vine abia la close-ul unei bare.", "#333"),
("Cifrele 89.90 / 87.30 / 95.20 ale trade-ului sunt din exemplul construit al "
"materialului;", GREY),
("suportul weekly 87.50, pivotul daily 89.60 și structura barelor sunt ale mele.", GREY),
("Suportul 88.00 ține de trei ori, iar între teste vârfurile scad — 89.50, apoi "
"89.10: compresie.", "#333"),
("Exemplul e al materialului și e pe 60 de minute: suport 88.00, intrare 89.90, "
"SL 87.30, țintă 95.20.", GREY),
("Nu e double bottom și nu e divergență de volum — alea sunt din alt exemplu al lui "
"(gap up, picioarele 32.10 / 30.90).", GREY),
("Forma exactă a barelor și volumul sunt ale mele; la fel pivotul daily 89.60, pus ca "
"să aibă ce verifica pasul B3.", GREY),
]
add = 16 * len(linii) + 10
svg = svg.replace(f'viewBox="0 0 {W} {H}"', f'viewBox="0 0 {W} {H + add}"')
@@ -119,4 +138,4 @@ if __name__ == "__main__":
for i, (t, c) in enumerate(linii)) + "</svg>")
assert "\n\n" not in svg, "linie goală în SVG"
OUT.write_text(svg, encoding="utf-8")
print(f"scris {OUT.name} ({W}x{H + add}); picioare {pct1}% / {pct2}% peste suport, R={R}")
print(f"scris {OUT.name} ({W}x{H + add}); teste {TESTE} pe {SUP_W}, R={R}")