Buy hammer: forma (patru candele cu aceeasi inaltime, DA/limita/NU), trend (aceeasi bara dupa scadere e hammer, dupa urcare e hanging man — verificat prin assert), locatie, trigger in trei panouri, stop, iesire, si oglinda pe short obtinuta prin oglindire bara cu bara. MBT-10: confluente si close peste pivotul daily. Doua serii partajate (bh_ansamblu si mbt_confluente expun serie()), ca sa nu existe doua variante ale aceluiasi trade. Capitolul se imparte in doua proceduri separate, nu una amestecata: partea A buy hammer in 5 pasi cu oglinda pe short, partea B MBT-10 in 5 pasi, cu nivelul 1 comun. Textul e neatins — agentul a atins pragul de context. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
115 lines
5.8 KiB
Python
115 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""MBT-10, pasul „unde": ideea de bottom cu confluențe (exemplu construit).
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
Rulare: python3 gen/strategii/hammer_mbt10_mbt_confluente.py
|
|
"""
|
|
import re
|
|
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
|
|
from pathlib import Path
|
|
from svg_candles import Arrow, Chart, Level, 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
|
|
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
|
|
CLOSE_I = 19 # bara care se închide peste pivotul daily
|
|
|
|
CLOSES = [96.00, 95.00, 94.20, 94.60, 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
|
|
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,
|
|
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)
|
|
# 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)
|
|
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}]"
|
|
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
|
|
# 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, \
|
|
"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"
|
|
prim_tp = next(i for i in range(CLOSE_I + 1, len(cds)) if cds[i].h >= TP)
|
|
assert prim_tp == 26, prim_tp
|
|
return cds
|
|
|
|
|
|
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),
|
|
],
|
|
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)",
|
|
)
|
|
svg = ch.render()
|
|
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),
|
|
]
|
|
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}); picioare {pct1}% / {pct2}% peste suport, R={R}")
|