Files
atm-curs-dl/gen/strategii/hammer_mbt10_harta.py
Claude Agent a7785740cc 06_hammer_mbt10: capitol reconstruit dupa sablon
Doua proceduri complet separate, nu una amestecata, pentru ca se fac
altfel: buy hammer e pattern public, desenabil si exersabil retroactiv;
MBT-10 e cutie neagra din care se poate reface o singura conditie.
Nivelul 1 le pune fata in fata, ca cititorul sa stie din prima de ce nu
le poate trata la fel. Cate 5 pasi fiecare, oglinda pe short la hammer,
checklist dublu. Sursele in fise/06_hammer_mbt10_surse.md.

Zece diagrame noi: hammer-ul nu era definit vizual nicaieri, iar hanging
man era doar text — acum e aceeasi bara in doua contexte, cu assert ca e
identica. Cele 7 vechi si-au pierdut trimiterile fisier:linie din
legende; toate le aveau.

Doua serii partajate (bh_ansamblu si mbt_confluente expun serie()), deci
un trade nu poate avea doua variante. Oglinda pe short e trade-ul long
oglindit in jurul lui K=162.30, deci riscul ramane 1.30 in ambele.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
2026-09-20 13:05:41 +00:00

267 lines
11 KiB
Python

#!/usr/bin/env python3
"""Hartă de orientare: buy hammer (public) vs. MBT-10 (cutie neagră), același
trigger de bottom.
Pentru `strategii/06_hammer_mbt10.md`, marcajul `<!-- DIAGRAMA: harta -->`.
Nu e grafic de preț (spec: TIP CONCEPT, CHEIE harta) — SVG scris de mână,
doar stdlib; nu se folosește svg_candles / pchart.
Ce arată (toate citatele și trimiterile vin din spec, nu se inventează):
- bara comună de sus: setup-urile de fond spun UNDE, trigger-ul de candelă
spune CÂND (`02_mbt10.md:9-11`, `43-49`);
- două cutii alăturate: BUY HAMMER (pattern standard, public) și MBT-10
(cutie neagră, indicator proprietar), fiecare cu regulile ei și cu
trimiterile de rigoare;
- săgeata de jos spre caseta finală: ce rămâne utilizabil pe BVB.
Verdictele de BVB din cutii sunt judecata mea (secțiunea Transfer), marcate
ca atare în legendă, exact cum cere specul.
Rulare: python3 gen/strategii/hammer_mbt10_harta.py -> hammer_mbt10_harta.svg
"""
from pathlib import Path
from xml.sax.saxutils import escape
OUT = Path(__file__).with_suffix(".svg")
W, H = 700, 610
BLACK, GRAY, BLUE, GREEN, RED, ORANGE, WHITE = (
"#000000", "#777777", "#1a5fb4", "#188a3e", "#c00", "#b06000", "#ffffff")
BORDER = "#333333"
# ---------------------------------------------------------------- geometrie
BAR_X0, BAR_X1, BAR_Y, BAR_H = 40.0, 660.0, 82.0, 76.0
BOX_W = 302.0
BOX_LX, BOX_RX, BOX_Y = 40.0, 358.0, 190.0
BOX_H = 256.0
PAD = 16.0
ROW0 = BOX_Y + 56.0 # baseline-ul primei reguli
ROW_H = 52.0
VERDICT_SEP = BOX_Y + 216.0
VERDICT_Y = VERDICT_SEP + 26.0
BUS_Y = 460.0 # linia orizontală de unire a celor două cutii
TRI_TIP = 500.0
FINAL_X0, FINAL_Y, FINAL_W, FINAL_H = 110.0, 500.0, 480.0, 56.0
TEXTS = [] # (x, y, text, size, weight, anchor) pentru verificare
def txt(x, y, s, size=13, weight="400", fill=BLACK, anchor="middle"):
TEXTS.append((x, y, s, size, weight, anchor))
return (
f'<text x="{x:.1f}" y="{y:.1f}" font-size="{size}" font-weight="{weight}" '
f'fill="{fill}" text-anchor="{anchor}">{escape(s)}</text>'
)
def line(x1, y1, x2, y2, stroke=GRAY, width=1.0, dash=None):
d = f' stroke-dasharray="{dash}"' if dash else ""
return (f'<line x1="{x1:.1f}" y1="{y1:.1f}" x2="{x2:.1f}" y2="{y2:.1f}" '
f'stroke="{stroke}" stroke-width="{width}"{d}/>')
def rect(x, y, w, h, fill=WHITE, stroke=GRAY, width=1.2):
return (f'<rect x="{x:.1f}" y="{y:.1f}" width="{w:.1f}" height="{h:.1f}" '
f'rx="8" fill="{fill}" stroke="{stroke}" stroke-width="{width}"/>')
def box(bx, title, title_fill, rows, verdict, verdict_fill, fill):
"""O cutie cu chenar: titlu, reguli (linii + trimitere), verdict."""
x = bx + PAD
area = BOX_W - 2 * PAD
out = [rect(bx, BOX_Y, BOX_W, BOX_H, fill=fill, stroke=title_fill, width=1.4)]
out.append(txt(x, BOX_Y + 26, title, 15, "700", title_fill, "start"))
out.append(line(bx + PAD, BOX_Y + 38, bx + BOX_W - PAD, BOX_Y + 38,
title_fill, 1.0))
for i, (mains, ref) in enumerate(rows):
top = ROW0 + i * ROW_H
for k, m in enumerate(mains):
out.append(txt(x, top + 14 + k * 17, m, 13, "400", BLACK, "start"))
if ref is not None:
out.append(txt(x, top + 48, ref, 13, "400", GRAY, "start"))
out.append(line(bx + PAD, VERDICT_SEP, bx + BOX_W - PAD, VERDICT_SEP,
verdict_fill, 1.2))
out.append(txt(x, VERDICT_Y, verdict, 13, "700", verdict_fill, "start"))
return out, area
def build():
p = [
f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {W} {H}" '
f'width="{W}" height="{H}" role="img" '
f'aria-label="Harta capitolului: acelasi trigger de bottom, doua naturi '
f'- buy hammer, pattern standard public, si MBT-10, cutie neagra cu '
f'indicator proprietar">',
'<g font-family="system-ui, sans-serif">',
f'<rect x="0" y="0" width="{W}" height="{H}" fill="{WHITE}"/>',
txt(W / 2, 34, "Același trigger de bottom, două naturi", 19, "700", BLACK),
txt(W / 2, 58, "buy hammer (public) vs. MBT-10 (cutie neagră)",
14, "400", GRAY),
]
# ------- zona 1: bara comună
p.append(rect(BAR_X0, BAR_Y, BAR_X1 - BAR_X0, BAR_H, fill="#f2f4f7",
stroke=GRAY, width=1.2))
p.append(txt(BAR_X0 + PAD, BAR_Y + 26, "Trigger de bottom: unde + când",
15, "700", BLUE, "start"))
p.append(txt(BAR_X0 + PAD, BAR_Y + 48,
"Setup-urile de fond — suport, locul crimei, double bottom, buy "
"doji,", 13, "400", BLACK, "start"))
p.append(txt(BAR_X0 + PAD, BAR_Y + 66,
"divergență de volum — spun UNDE. Trigger-ul de candelă spune "
"CÂND.", 13, "400", BLACK, "start"))
p.append(txt(BAR_X1 - PAD, BAR_Y + 26, "",
13, "400", GRAY, "end"))
# ------- conector bară -> cutii (un cot, fără săgeți redundante)
lx = BOX_LX + BOX_W / 2
rx = BOX_RX + BOX_W / 2
p.append(line(W / 2, BAR_Y + BAR_H, W / 2, 172.0, GRAY, 1.2))
p.append(line(lx, 172.0, rx, 172.0, GRAY, 1.2))
p.append(line(lx, 172.0, lx, BOX_Y, GRAY, 1.2))
p.append(line(rx, 172.0, rx, BOX_Y, GRAY, 1.2))
# ------- zona 2: cele două cutii
left_rows = [
(['„formă de candelă + downtrend”'], ""),
(['„trigger: close peste', 'high-ul hammer-ului”'],
""),
(['„fără niciun indicator proprietar”'], None),
]
right_rows = [
(['„formula nu e publică nicăieri”'], ""),
(['„reconstituibil doar:', 'close peste pivotul daily”'],
""),
(['„scanner + indicator proprietar”'], ""),
]
left_svg, left_area = box(
BOX_LX, "BUY HAMMER — pattern standard", BLUE, left_rows,
"„pe BVB: se poate rula long-only”", GREEN, "#eef4fd")
right_svg, right_area = box(
BOX_RX, "MBT-10 — cutie neagră", BORDER, right_rows,
"„pe BVB: nu, ca sistem”", RED, "#f5f5f5")
p += left_svg + right_svg
# ------- zona 3: ambele cutii -> caseta finală
p.append(line(lx, BOX_Y + BOX_H, lx, BUS_Y, GRAY, 1.2))
p.append(line(rx, BOX_Y + BOX_H, rx, BUS_Y, GRAY, 1.2))
p.append(line(lx, BUS_Y, rx, BUS_Y, GRAY, 1.2))
p.append(line(W / 2, BUS_Y, W / 2, TRI_TIP - 11, GRAY, 1.4))
p.append(f'<polygon points="{W/2:.1f},{TRI_TIP:.1f} '
f'{W/2-6:.1f},{TRI_TIP-11:.1f} {W/2+6:.1f},{TRI_TIP-11:.1f}" '
f'fill="{GRAY}"/>')
p.append(rect(FINAL_X0, FINAL_Y, FINAL_W, FINAL_H, fill="#fdf0e0",
stroke=ORANGE, width=1.6))
p.append(txt(W / 2, FINAL_Y + 24,
"Ce rămâne pe BVB: hammer la un nivel major", 14, "700",
BLACK))
p.append(txt(W / 2, FINAL_Y + 44, "+ close peste PPD", 14, "700", BLACK))
# ------- legendă
p.append(txt(W / 2, 578,
"Regulile = materialul cursului (cu trimiteri); verdictul de "
"BVB = judecata mea", 13, "400", GRAY))
p.append(txt(W / 2, 596, "din secțiunea Transfer.", 13, "400", GRAY))
p.append('</g></svg>')
return "\n".join(p) + "\n", left_area, right_area
# ---------------------------------------------------------------- verificare
def est_w(s, size, weight):
factor = 0.62 if weight == "700" else 0.56
return len(s) * size * factor
def box_of(x, y):
for bx in (BOX_LX, BOX_RX):
if bx <= x <= bx + BOX_W and BOX_Y <= y <= BOX_Y + BOX_H:
return bx
return None
def verify(svg, left_area, right_area):
# 1. geometrie: zonele nu se calcă
assert BAR_Y + BAR_H < BOX_Y, "bara comună intră în cutii"
assert BOX_Y + BOX_H < BUS_Y < TRI_TIP <= FINAL_Y, "săgeata nu are loc"
assert FINAL_Y + FINAL_H < 578, "caseta finală intră în legendă"
assert left_area == right_area == BOX_W - 2 * PAD
# 2. toate textele în panză
for x, y, s, size, weight, anchor in TEXTS:
ew = est_w(s, size, weight)
left = x - ew if anchor == "end" else (x - ew / 2 if anchor == "middle" else x)
right = left + ew
assert -2 <= left and right <= W + 2, f"text în afara panzei: {s!r}"
assert 0 <= y <= H, f"text în afara înălțimii: {s!r} (y={y})"
# 3. texte care nu se suprapun
for i in range(len(TEXTS)):
xi, yi, si, szi, wi, ai = TEXTS[i]
we = est_w(si, szi, wi)
li = xi - we if ai == "end" else (xi - we / 2 if ai == "middle" else xi)
ri = li + we
for j in range(i + 1, len(TEXTS)):
xj, yj, sj, szj, wj, aj = TEXTS[j]
wej = est_w(sj, szj, wj)
lj = xj - wej if aj == "end" else (xj - wej / 2 if aj == "middle" else xj)
rj = lj + wej
if abs(yi - yj) < 13 and li < rj - 4 and lj < ri - 4:
raise AssertionError(f"texte suprapuse: {si!r} / {sj!r}")
# 4. textele din cutii încap în cutii
for x, y, s, size, weight, anchor in TEXTS:
b = box_of(x, y)
if b is not None:
ew = est_w(s, size, weight)
assert x + ew <= b + BOX_W - PAD + 1, f"text iese din cutie: {s!r}"
# 5. verdictul e sub linia lui de separare
assert VERDICT_SEP < VERDICT_Y < BOX_Y + BOX_H
# 6. conținutul obligatoriu din spec
for cheie in (
"Trigger de bottom: unde + când",
"Setup-urile de fond — suport, locul crimei, double bottom, buy doji,",
"divergență de volum — spun UNDE. Trigger-ul de candelă spune CÂND.",
"",
"BUY HAMMER — pattern standard",
"„formă de candelă + downtrend”",
"",
"„trigger: close peste",
"high-ul hammer-ului”",
"",
"„fără niciun indicator proprietar”",
"„pe BVB: se poate rula long-only”",
"MBT-10 — cutie neagră",
"„formula nu e publică nicăieri”",
"",
"„reconstituibil doar:",
"close peste pivotul daily”",
"",
"„scanner + indicator proprietar”",
"",
"„pe BVB: nu, ca sistem”",
"Ce rămâne pe BVB: hammer la un nivel major",
"+ close peste PPD",
"verdictul de BVB = judecata mea",
"din secțiunea Transfer.",
):
assert cheie in svg, f"lipsește din desen: {cheie!r}"
# 7. fără axe de preț / candele / cifre inventate
for interzis in ("candela", "SL ", "intrare ", "TP1", "TP2", "$", "USD"):
assert interzis not in svg, f"nu ar trebui să apară preț: {interzis!r}"
return True
SVG, LEFT_AREA, RIGHT_AREA = build()
assert verify(SVG, LEFT_AREA, RIGHT_AREA), "verificare eșuată"
OUT.write_text(SVG, encoding="utf-8")
print(f"scris {OUT} ({W}x{H}), verificare OK: {len(TEXTS)} etichete, "
f"cutii {BOX_W:g}x{BOX_H:g} la {BOX_LX:g}/{BOX_RX:g}")