Files
atm-curs-dl/gen/strategii/hammer_mbt10_mbt_confluente.py
Claude Agent f60d32cb34 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
2026-10-02 05:29:33 +00:00

142 lines
7.4 KiB
Python

#!/usr/bin/env python3
"""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.
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 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 = 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)
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, 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, 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)
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)
# bara de după vârf deschide chiar în el: fără fitil sus, ca vârful să
# rămână singurul maxim la 95.20
w[VARF + 1] = (0.00, 0.25)
cds = from_closes(CLOSES, wicks=w, vols=VOLS, start=96.60)
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}]"
# 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[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
assert round(cds[VARF].h, 2) == TP, cds[VARF].h
assert max(c.h for c in cds[VARF + 1:CLOSE_I]) < TP, \
"un maxim de după vârf trece peste țintă: ținta n-ar mai fi prima structură"
return cds
if __name__ == "__main__":
cds = serie()
vis = cds[:CLOSE_I] # contextul, fără bara de trigger
ch = Chart(
candles=vis,
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\" — 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"),
("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}"')
svg = svg.replace("</svg>", "".join(
f'<text x="24" y="{H + 10 + 16 * i}" fill="{c}">{t}</text>'
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}); teste {TESTE} pe {SUP_W}, R={R}")