Files
atm-curs-dl/gen/strategii/hammer_mbt10_mbt_gapdown.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

199 lines
9.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""După gap down — primul MBT-10 te scoate, al doilea merge (exemplu construit).
Citește `gen/strategii/hammer_mbt10_mbt_gapdown.spec.txt`
(marcajul `<!-- DIAGRAMA: mbt_gapdown -->`, Partea B §2.3 Gotchas).
Serie continuă de 33 candele daily, construită din close-urile date în
specificație, cu open-ul fiecărei bare = close-ul precedentei (STYLE.md),
cu două excepții impuse de exemplu:
- bara 13 (ultima dinainte de gap): ca să iasă ȘI ``low[13] = 70.60``
(nivelul de închidere a gap-ului, cerut de assert 1 și 6) ȘI
``high[13] = 71.00`` (structura seriei, „de la ~71"), bara trebuie să
fie un doji ``o = c = 70.60``. De aceea am ridicat ``close[12]`` de la
69.80 (cât dă lista) la 70.60: altfel ``min(open,close)=69.80`` și
low-ul ar ieși 69.80, nu 70.60. Wu=0.40 => high 71.00, wd=0.00 => low
70.60. (Linia „Mecioni" cere wu=0.20 => high 70.80; am ales 71.00,
cifra din structura seriei și din textul „~71".)
- bara 14 (gap down): ``open[14] = 66.40``, NU close[13]=70.60 — singura
bară cu open diferit de close-ul precedent. O construim manual:
o=c=66.40, wu=0.30 => high 66.70, wd=0.30 => low 66.10.
Wick-urile speciale: bara 16 wd=0.20 (low 64.60), bara 18 wd=0.20 (low
63.20), bara 21 wd=1.60 (low 60.60 = noul low al coborârii, ca SL-ul 60.40 din
material să stea sub o structură desenată); restul (0.30, 0.40).
Rulează: python3 gen/strategii/hammer_mbt10_mbt_gapdown.py
Scrie: gen/strategii/hammer_mbt10_mbt_gapdown.svg
"""
import re
import sys
from pathlib import Path
sys.path.insert(0, "/workspace/atm-curs-dl")
sys.path.insert(0, "/workspace/atm-curs-dl/gen")
from eticheta_libera import eticheta_libera # noqa: E402
from svg_candles import Candle, Chart, Level, Mark, from_closes # noqa: E402
OUT = Path(__file__).resolve().parent / "hammer_mbt10_mbt_gapdown.svg"
GRAY, RED, GREEN, BLUE, ORANGE = "#777", "#c00", "#188a3e", "#1a5fb4", "#b06000"
# --- seria: 33 de close-uri, exact ca în specificație ------------------------
# Singura abatere: closes[12] 69.80 -> 70.60, ca bara 13 să poată avea
# low 70.60 (vezi docstring-ul).
closes = [
60.00, 60.80, 61.60, 62.50, 63.30, 64.20, 65.00, 65.80, 66.60, 67.40, # 0-9
68.20, 69.00, 70.60, 70.60, # 10-13
66.40, # 14 = bara de GAP DOWN (open impus 66.40, NU close[13])
65.50, # 15
64.80, # 16 = MBT-10 #1, închidere => intrare #1
64.20, # 17
63.40, # 18 = low 63.20 => stop #1
62.90, # 19
62.50, # 20
62.20, # 21 = MBT-10 #2, închidere => intrare #2
62.80, 63.60, 64.50, 65.50, 66.50, 67.50, 68.50, 69.50, # 22-29
70.60, # 30 = gap închis (TP)
70.90, # 31
70.50, # 32
]
assert len(closes) == 33, len(closes)
WICKS = [(0.30, 0.40)] * 33 # restul barelor
WICKS[13] = (0.40, 0.00) # high 71.00, low 70.60
WICKS[14] = (0.30, 0.30) # high 66.70, low 66.10 (bara de gap)
WICKS[16] = (0.30, 0.20) # low 64.60
WICKS[18] = (0.30, 0.20) # low 63.20
# bara lui MBT-10 #2 face și noul low al coborârii: flush la 60.60, închidere
# înapoi la 62.20. Fără el, SL-ul 60.40 din material (`mbt`:729-732) ar pluti
# sub orice structură desenată — exact reproșul din verificare.
WICKS[21] = (0.30, 1.60) # low 60.60 = noul low; SL 60.40 stă sub el
# Volume relative, alese de generator (materialul nu dă volum aici):
# în scădere pe piciorul coborârii după gap (14 -> 21), apoi recuperare.
vols = [
48, 46, 44, 45, 43, 42, 44, 41, 40, 42, # 0-9
43, 41, 46, 58, # 10-13
90, # 14 = gap down
76, 66, 57, 50, 45, 42, # 15-20
40, # 21 = MBT-10 #2 (minim)
46, 52, 58, 63, 68, 73, 78, 82, 86, 88, 80, # 22-32
]
assert len(vols) == 33, len(vols)
coborare = vols[14:22]
assert all(coborare[i] >= coborare[i + 1] for i in range(len(coborare) - 1)), \
f"volumul nu scade pe piciorul coborârii: {coborare}"
assert vols[-1] > vols[21], "volumul nu recuperează după bara 21"
cds = from_closes(closes, wicks=WICKS, vols=vols, start=60.00)
# bara de gap: open = 66.40, nu close[13] = 70.60
cds[14] = Candle(66.40, 66.70, 66.10, 66.40, vol=vols[14], color=RED)
# --- assert-urile din specificație -----------------------------------------
# 1. gap down real
assert abs(cds[14].o - 66.40) < 1e-9, cds[14].o
assert abs(cds[13].l - 70.60) < 1e-9, f"low[13]={cds[13].l} != 70.60"
assert abs(cds[13].c - 70.60) < 1e-9, cds[13].c
assert cds[14].o < cds[13].l and cds[14].h < cds[13].l, "gapul nu e real"
assert abs(cds[14].o - cds[13].c) > 1e-9, "open[14] nu e excepția de la serie"
# 2. #1
intrare1, sl1 = 64.80, 63.20
assert abs(cds[16].c - intrare1) < 1e-9, f"close[16]={cds[16].c} != 64.80"
assert abs(sl1 - 63.20) < 1e-9
assert min(c.l for c in cds[16:19]) <= sl1, "stopul #1 nu e atins"
assert cds[16].c > sl1, "intrarea #1 e sub stopul ei"
# 3. #2
intrare2, sl2 = 62.20, 60.40
assert abs(cds[21].c - intrare2) < 1e-9, f"close[21]={cds[21].c} != 62.20"
assert abs(sl2 - 60.40) < 1e-9
assert not any(c.l <= sl2 for c in cds[22:]), "un low atinge SL2 după bara 21"
# stopul #2 numește o structură: e sub cel mai jos low al coborârii de după gap
nou_low = min(c.l for c in cds[14:22])
assert abs(nou_low - cds[21].l) < 1e-9, "noul low nu e al barei lui MBT-10 #2"
assert sl2 < nou_low <= sl2 + 0.30, \
f"SL2 {sl2} nu stă chiar sub noul low {nou_low:.2f}: nu mai numește o structură"
assert nou_low < min(c.l for c in cds[14:21]), "low-ul barei 21 nu e cel mai jos"
# 4. riscuri
risc1 = intrare1 - sl1 # 1.60
risc2 = intrare2 - sl2 # 1.80
assert abs(risc1 - 1.60) < 1e-9 and abs(risc2 - 1.80) < 1e-9, (risc1, risc2)
# 5. TP = închiderea gap-ului
TP = 70.60
reward2 = TP - intrare2 # 8.40
assert abs(reward2 - 8.40) < 1e-9, reward2
assert round(reward2 / risc2, 1) == 4.7, round(reward2 / risc2, 1)
# 6. low[13] e nivelul de închidere a gap-ului și TP-ul e atins în urcare
assert abs(cds[13].l - TP) < 1e-9, "low[13] != 70.60 (nivelul gap-ului)"
assert max(c.h for c in cds[22:33]) >= TP, "TP 70.60 nu e atins după #2"
primul_tp = next(i for i in range(22, 33) if cds[i].h >= TP)
# 7. același risc în bani: mărimea #2 = mărimea #1 × (risc1 / risc2)
marime1 = 1.0
marime2 = marime1 * (risc1 / risc2)
assert abs(marime2 - 1.60 / 1.80) < 1e-9, marime2
print(f"gap {cds[13].l:.2f} -> {cds[14].o:.2f} "
f"#1 intrare {intrare1:.2f} SL {sl1:.2f} (risc {risc1:.2f}) "
f"#2 intrare {intrare2:.2f} SL {sl2:.2f} (risc {risc2:.2f}) "
f"TP {TP:.2f} = {reward2 / risc2:.1f}R "
f"atins la bara {primul_tp} (high {cds[primul_tp].h:.2f}) "
f"mărime #2 = {marime2:.3f} × mărime #1")
# --- desenul ----------------------------------------------------------------
ch = Chart(
candles=cds,
levels=[
# toate etichetele stau în dreapta (x > ultima candelă), fără suprapuneri
Level(intrare1, "#1 intrare 64.80", GRAY, label_at="right"),
Level(sl1, "#1 SL 63.20", GRAY, label_at="right"),
Level(intrare2, "#2 intrare 62.20", GRAY, label_at="right"),
Level(sl2, "#2 SL 60.40, sub noul low 60.60", GRAY, label_at="right"),
Level(TP, "TP 70.60 = 4.7R (gap închis)", BLUE, label_at="right"),
],
marks=[
# decalate pe verticală cât să nu atingă candelele din coborâre
Mark(14, "gap down", RED, "above", dy=-22),
Mark(16, "MBT-10 #1", GRAY, "above", dy=-25),
Mark(18, "stop #1 atins", RED, "below", dy=30),
Mark(21, "MBT-10 #2: flush la 60.60, închidere 62.20", GREEN, "below", dy=25),
],
scale=28.0, gap=15, body_w=9, left=44, width=820, vol_h=70,
vol_label="volum",
title="După gap down — primul MBT-10 te scoate, al doilea merge (exemplu construit)",
caption="",
)
svg = ch.render()
assert "<svg" in svg and "\n\n" not in svg, "linie goală în SVG"
eticheta_libera(svg, "mbt_gapdown",
{"MBT-10 #2: flush la 60.60, închidere 62.20",
"#2 SL 60.40, sub noul low 60.60", "stop #1 atins", "gap down",
"MBT-10 #1"}, rects=True, segmente=False)
# --- blocul de text de jos: cine are același risc + legenda -----------------
m = re.search(r'viewBox="0 0 (\d+) (\d+)"', svg)
W, H = int(m.group(1)), int(m.group(2))
linii = [
"MBT-10 #1: intrare 64.80 / SL 63.20 — risc 1R în bani",
"MBT-10 #2: intrare 62.20 / SL 60.40, sub noul low 60.60 — risc 1R în bani "
"(mărime ajustată)",
"Exemplu construit: #1 și #2 au același risc în bani; "
"#2 singur dă 4.7R.",
"De aceea mărimea se împarte pe 2-3 încercări.",
]
extra = 16 * len(linii) + 6
svg = svg.replace(f'viewBox="0 0 {W} {H}"', f'viewBox="0 0 {W} {H + extra}"')
svg = svg.replace("</svg>", "".join(
f'<text x="24" y="{H + 12 + 16 * i}" fill="#555">{t}</text>'
for i, t in enumerate(linii)) + "</svg>")
assert "\n\n" not in svg, "linie goală în SVG după legendă"
OUT.write_text(svg)
print(f"scris {OUT.relative_to('/workspace/atm-curs-dl')}")