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:
@@ -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}")
|
||||
|
||||
Reference in New Issue
Block a user