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
100 lines
4.8 KiB
Python
100 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Aceeași candelă, două contexte: hammer (după scădere) vs. hanging man (după urcare).
|
|
|
|
Două panouri alăturate, aceeași scară px/unitate. Bara 9 e IDENTICĂ în ambele
|
|
(o 63.05, h = c 63.30, l 62.10) — verificat prin assert; ce diferă e ce s-a
|
|
întâmplat înaintea ei. Panourile nu împart axa de preț: seriile trăiesc în
|
|
zone de preț diferite, iar comparația cerută aici e de context, nu de nivel.
|
|
|
|
Rulare: python3 gen/strategii/hammer_mbt10_bh_trend.py
|
|
"""
|
|
import re
|
|
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
|
|
from pathlib import Path
|
|
from svg_candles import Arrow, Chart, Zone, from_closes
|
|
|
|
OUT = Path(__file__).with_suffix(".svg")
|
|
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
|
|
|
|
HAM = (63.05, 63.30, 62.10, 63.30) # o, h, l, c — bara 9, în ambele panouri
|
|
|
|
JOS = [68.00, 67.20, 66.50, 66.80, 65.60, 64.90, 65.10, 64.20, 63.05,
|
|
63.30, 63.35, 63.80]
|
|
SUS = [58.00, 58.70, 59.40, 59.20, 60.30, 61.00, 61.80, 62.40, 63.05,
|
|
63.30, 62.00, 61.40]
|
|
|
|
|
|
def serie(closes):
|
|
w = [(0.15, 0.15)] * len(closes)
|
|
w[9] = (0.00, 0.95) # bara-hammer: high = close, fitil jos 0.95
|
|
return from_closes(closes, wicks=w, start=closes[0] + (0.4 if closes[0] > 60 else -0.4))
|
|
|
|
|
|
L, R = serie(JOS), serie(SUS)
|
|
|
|
# --- verificări -------------------------------------------------------------
|
|
for s, nume in ((L, "stânga"), (R, "dreapta")):
|
|
for i in range(1, len(s)):
|
|
assert abs(s[i].o - s[i - 1].c) < 1e-9, f"{nume}: open[{i}] != close[{i-1}]"
|
|
b = s[9]
|
|
assert (round(b.o, 2), round(b.h, 2), round(b.l, 2), round(b.c, 2)) == HAM, (nume, b)
|
|
assert (L[9].o, L[9].h, L[9].l, L[9].c) == (R[9].o, R[9].h, R[9].l, R[9].c), \
|
|
"bara 9 trebuie să fie identică în ambele panouri"
|
|
corp, jos = HAM[3] - HAM[0], HAM[0] - HAM[2]
|
|
assert jos >= 2 * corp, "bara 9 nu trece regula de formă"
|
|
assert L[8].c < L[0].c - 4, "stânga: scăderea nu se vede"
|
|
assert R[8].c > R[0].c + 4, "dreapta: urcarea nu se vede"
|
|
assert L[10].c > L[9].h, "stânga: bara 10 nu confirmă peste high-ul hammer-ului"
|
|
assert R[10].c < R[9].l, "dreapta: bara 10 nu închide sub low-ul candelei"
|
|
|
|
# --- desen ------------------------------------------------------------------
|
|
W, PW = 780, 358
|
|
PX = [24, 24 + PW + 20]
|
|
SCALE, TOP, SHIFT = 26.0, 104, 60
|
|
|
|
panels, inalt = [], []
|
|
for px, cds, (zt, zc), arr in (
|
|
(PX[0], L, ("scădere de 9 candele", RED),
|
|
[Arrow(9, "hammer 63.30 / 62.10: prețul a fost dus la 62.10\nși readus sus, la 63.30",
|
|
where="below", color=ORANGE, dx=-70, dy=34),
|
|
Arrow(10, "close 63.35, peste high-ul hammer-ului:\nsemnalul e valid, aici intri",
|
|
where="above", color=GREEN, dx=-96, dy=-24)]),
|
|
(PX[1], R, ("urcare de 9 candele", GREEN),
|
|
[Arrow(9, "aceeași candelă 63.30 / 62.10, dar după o urcare:\nse numește hanging man și avertizează de scădere",
|
|
where="below", color=RED, dx=-250, dy=98),
|
|
Arrow(10, "close 62.00, sub low-ul ei: scăderea\nîncepe — nu era semnal de cumpărare",
|
|
where="above", color=RED, dx=-70, dy=-18)]),
|
|
):
|
|
ch = Chart(candles=cds, arrows=arr,
|
|
zones=[Zone(0, 8, zt, zc)],
|
|
scale=SCALE, gap=24, body_w=12, left=px + 46, width=px + PW, top=TOP)
|
|
body = ch._render()
|
|
assert f'viewBox="0 0 {px + PW} ' in body, f"panoul {px}: ceva iese din cadru"
|
|
assert ch.scale == SCALE
|
|
corp_panou = body.split(">", 1)[1].rsplit("</svg>", 1)[0].strip()
|
|
panels.append(f'<g transform="translate(0,{SHIFT})">{corp_panou}</g>')
|
|
inalt.append(float(re.search(r'viewBox="0 0 [\d.]+ ([\d.]+)"', body).group(1)))
|
|
|
|
H = int(max(inalt)) + SHIFT + 46
|
|
parts = [
|
|
f'<svg viewBox="0 0 {W} {H}" xmlns="http://www.w3.org/2000/svg" '
|
|
f'style="width:100%;height:auto;font:12px sans-serif">',
|
|
'<text x="24" y="20" fill="#333" style="font-weight:bold">'
|
|
'Aceeași candelă, două contexte — daily, exemplu construit</text>',
|
|
f'<text x="{PX[0]}" y="42" fill="{GREEN}" style="font-weight:bold">'
|
|
'DA — după o scădere: hammer</text>',
|
|
f'<text x="{PX[1]}" y="42" fill="{RED}" style="font-weight:bold">'
|
|
'NU — după o urcare: hanging man</text>',
|
|
f'<line x1="{PX[1] - 10}" y1="48" x2="{PX[1] - 10}" y2="{H - 46}" stroke="#ccc"/>',
|
|
*panels,
|
|
f'<text x="24" y="{H - 26}" fill="{GREY}">Forma nu spune nimic singură: hammer-ul '
|
|
'e pattern de întoarcere doar după o scădere. Aceeași bară după o urcare</text>',
|
|
f'<text x="24" y="{H - 10}" fill="{GREY}">e hanging man și are sensul opus. '
|
|
'Prețurile sunt construite; regula de context e a cursului.</text>',
|
|
"</svg>",
|
|
]
|
|
svg = "\n ".join(parts).replace("\n </svg>", "\n</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})")
|