hammer_mbt10: noua diagrame noi (textul urmeaza)

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
This commit is contained in:
Claude Agent
2026-09-20 12:52:31 +00:00
parent 98ba05273b
commit 93e453f6fb
18 changed files with 1632 additions and 0 deletions

View File

@@ -0,0 +1,154 @@
#!/usr/bin/env python3
"""Ce e un hammer și ce nu — patru candele cu același high 63.30 și low 62.10.
Prima imagine a capitolului: cine o vede nu știe ce e un hammer, deci candela
A primește săgeți pe corp și pe fiecare fitil, iar C și D sunt contraexemple
cu aceeași înălțime. Zonă verde peste A și B, roșie peste C și D.
Desenat direct, nu cu `Chart`: fiecare etichetă trebuie să stea lipită sub
candela ei, pe 2-3 rânduri, plus săgeți cu text pe lateral.
Rulare: python3 gen/strategii/hammer_mbt10_bh_forma.py
"""
from pathlib import Path
OUT = Path(__file__).with_suffix(".svg")
GREEN, RED, GREY, BLUE = "#188a3e", "#c00", "#555", "#1a5fb4"
H, L = 63.30, 62.10
RNG = H - L # 1.20
PRAG_SUS = L + 2 / 3 * RNG # 62.90 — corpul trebuie să stea peste el
# (nume, o, h, l, c, verdict, rânduri de etichetă sub candelă)
CANDLES = [
("A", 63.05, H, L, 63.30, "DA", ["DA: corp 0.25,", "fitil jos 0.95 = 3,8x corpul"]),
("B", 62.90, H, L, 63.30, "DA", ["DA, la limită: corp 0.40,", "fitil jos 0.80 = exact 2x"]),
("C", 62.60, H, L, 63.30, "NU", ["NU: corp 0.70,", "fitil jos 0.50 = 0,7x corpul"]),
("D", 62.25, H, L, 62.45, "NU", ["NU: corpul e jos, fitilul", "lung e sus — alt pattern"]),
]
def masuri(o, h, l, c):
return abs(c - o), min(o, c) - l, h - max(o, c) # corp, fitil jos, fitil sus
# --- verificările -----------------------------------------------------------
M = {n: masuri(o, h, l, c) for n, o, h, l, c, *_ in CANDLES}
for n, o, h, l, c, *_ in CANDLES:
assert (h, l) == (H, L), (n, h, l) # 1 aceeași bară
assert [tuple(round(v, 2) for v in M[n]) for n in "ABCD"] == [ # 2 cifrele din etichete
(0.25, 0.95, 0.00), (0.40, 0.80, 0.00), (0.70, 0.50, 0.00), (0.20, 0.15, 0.85)], M
for n in "AB": # 3 A și B trec ambele reguli
corp, jos, _ = M[n]
o, c = [(o, c) for nn, o, _, _, c, *_ in CANDLES if nn == n][0]
assert jos >= 2 * corp - 1e-9, (n, jos, corp)
assert min(o, c) >= PRAG_SUS - 1e-9, (n, min(o, c), PRAG_SUS)
assert M["C"][1] < 2 * M["C"][0], "C ar trebui să pice pe regula fitilului" # 4
oD, cD = CANDLES[3][1], CANDLES[3][4]
assert max(oD, cD) < PRAG_SUS, "D ar trebui să pice pe regula treimii de sus" # 5
assert round(M["A"][1] / M["A"][0], 1) == 3.8 and round(M["B"][1] / M["B"][0], 1) == 2.0
assert round(M["C"][1] / M["C"][0], 1) == 0.7
# --- geometrie --------------------------------------------------------------
SCALE, TOP, W = 260, 210, 1000
XS = [350, 490, 690, 860]
BODY_W = 26
def y(p):
return TOP + (H - p) * SCALE
assert y(CANDLES[0][1]) > y(CANDLES[0][4]), "open A trebuie sub close A pe ecran"
out = []
t = out.append
def text(x, yy, s, color=GREY, anchor="start", bold=False, size=12):
style = f' style="font-weight:bold;font-size:{size}px"' if bold else (
f' style="font-size:{size}px"' if size != 12 else "")
t(f'<text x="{x:.1f}" y="{yy:.1f}" fill="{color}" text-anchor="{anchor}"{style}>{s}</text>')
def zone(x0, x1, y0, y1, label, color):
t(f'<rect x="{x0:.1f}" y="{y0:.1f}" width="{x1 - x0:.1f}" height="{y1 - y0:.1f}" '
f'fill="{color}" fill-opacity="0.10" stroke="{color}" stroke-width="1"/>')
text(x0 + 6, y0 - 7, label, color, bold=True)
def arrow(x1, y1, x2, y2, color, lines, anchor="start"):
d = max(((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5, 1e-9)
ux, uy = (x2 - x1) / d, (y2 - y1) / d
bx, by = x2 - 8 * ux, y2 - 8 * uy
t(f'<line x1="{x1:.1f}" y1="{y1:.1f}" x2="{bx:.1f}" y2="{by:.1f}" '
f'stroke="{color}" stroke-width="1.6"/>')
t(f'<polygon points="{x2:.1f},{y2:.1f} {bx - 4 * uy:.1f},{by + 4 * ux:.1f} '
f'{bx + 4 * uy:.1f},{by - 4 * ux:.1f}" fill="{color}"/>')
dx = -6 if anchor == "end" else (0 if anchor == "middle" else 6)
y0 = (y1 - 10 - 14 * (len(lines) - 1) if anchor == "middle"
else y1 + 4 - 14 * (len(lines) - 1) / 2)
for k, s in enumerate(lines):
text(x1 + dx, y0 + 14 * k, s, color, anchor, bold=(k == 0))
text(24, 30, "Ce e un hammer și ce nu — aceeași bară, 63.30 sus și 62.10 jos", "#333",
bold=True, size=14)
label_y0 = y(L) + 28
z_bot = label_y0 + 16 * 2 - 4
zone(XS[0] - 58, XS[1] + 66, y(H) - 30, z_bot, "hammer", GREEN)
zone(XS[2] - 60, XS[3] + 74, y(H) - 30, z_bot, "nu e hammer", RED)
for p in (H, L):
t(f'<line x1="{XS[0] - 100}" y1="{y(p):.1f}" x2="{W - 24}" y2="{y(p):.1f}" '
f'stroke="#bbb" stroke-dasharray="4 3"/>')
text(24, y(H) - 6, "cât de sus a urcat prețul: 63.30")
text(24, y(L) + 14, "cât de jos a coborât: 62.10")
# pragul treimii de sus: linia pe care corpul trebuie s-o depășească
t(f'<line x1="{XS[0] - 100}" y1="{y(PRAG_SUS):.1f}" x2="{W - 24}" y2="{y(PRAG_SUS):.1f}" '
f'stroke="{BLUE}" stroke-width="1.2" stroke-dasharray="2 3"/>')
text(24, y(PRAG_SUS) - 4, f"treimea de sus începe la {PRAG_SUS:.2f}", BLUE)
for (n, o, h, l, c, verdict, lines), x in zip(CANDLES, XS):
color = GREEN if c >= o else RED
vcol = GREEN if verdict == "DA" else RED
t(f'<line x1="{x}" y1="{y(h):.1f}" x2="{x}" y2="{y(l):.1f}" stroke="#1a1a1a" stroke-width="1.4"/>')
top, bot = y(max(o, c)), y(min(o, c))
t(f'<rect x="{x - BODY_W / 2:.1f}" y="{top:.1f}" width="{BODY_W}" '
f'height="{max(bot - top, 1.6):.1f}" fill="{color}"/>')
for k, s in enumerate(lines):
text(x, label_y0 + 16 * k, s, vcol, "middle", bold=(k == 0))
xA = XS[0]
arrow(xA - 60, y(63.10), xA - 15, y(63.17), BLUE, anchor="end",
lines=["corpul: mic și sus în bară",
"ziua s-a închis aproape de maxim —",
"cumpărătorii au ținut până la final"])
arrow(xA - 60, y(62.55), xA - 3, y(62.60), BLUE, anchor="end",
lines=["fitilul de jos, lung",
"vânzătorii au dus prețul până la 62.10,",
"dar cumpărătorii l-au adus înapoi sus"])
text(xA + 20, y(63.05) + 12, "open 63.05")
text(xA + 20, y(63.30) - 4, "close = high 63.30")
xC, xD = XS[2], XS[3]
arrow(xC + 34, y(H) - 112, xC + 14, y(62.95), RED,
lines=["corp prea gros", "fitilul de jos nu e nici cât corpul —", "nimeni n-a fost respins jos"])
arrow(xD, y(H) - 34, xD, y(63.24), RED, anchor="middle",
lines=["fitilul lung e sus, nu jos", "aici cumpărătorii au fost respinși;",
"e inverted hammer, alt pattern"])
cap_y = z_bot + 30
text(24, cap_y, "Hammer = fitilul de jos e cel puțin dublul corpului ȘI corpul stă în treimea "
"de sus a barei (aici peste 62.90).")
text(24, cap_y + 16, "Pragul „fitil ≥ 2x corpul\" e al cursului; „corpul în treimea de sus\" e "
"traducerea mea a lui „corp mic sus, fitil de sus aproape inexistent\".", GREY)
height = cap_y + 40
svg = (f'<svg viewBox="0 0 {W} {height:.0f}" xmlns="http://www.w3.org/2000/svg" '
f'style="width:100%;height:auto;font:12px sans-serif">\n '
+ "\n ".join(out) + "\n</svg>\n")
assert "\n\n" not in svg
OUT.write_text(svg, encoding="utf-8")
print(f"scris {OUT.name} ({W}x{height:.0f})")

View File

@@ -0,0 +1,53 @@
<svg viewBox="0 0 1000 648" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="24.0" y="30.0" fill="#333" text-anchor="start" style="font-weight:bold;font-size:14px">Ce e un hammer și ce nu — aceeași bară, 63.30 sus și 62.10 jos</text>
<rect x="292.0" y="180.0" width="264.0" height="398.0" fill="#188a3e" fill-opacity="0.10" stroke="#188a3e" stroke-width="1"/>
<text x="298.0" y="173.0" fill="#188a3e" text-anchor="start" style="font-weight:bold;font-size:12px">hammer</text>
<rect x="630.0" y="180.0" width="304.0" height="398.0" fill="#c00" fill-opacity="0.10" stroke="#c00" stroke-width="1"/>
<text x="636.0" y="173.0" fill="#c00" text-anchor="start" style="font-weight:bold;font-size:12px">nu e hammer</text>
<line x1="250" y1="210.0" x2="976" y2="210.0" stroke="#bbb" stroke-dasharray="4 3"/>
<line x1="250" y1="522.0" x2="976" y2="522.0" stroke="#bbb" stroke-dasharray="4 3"/>
<text x="24.0" y="204.0" fill="#555" text-anchor="start">cât de sus a urcat prețul: 63.30</text>
<text x="24.0" y="536.0" fill="#555" text-anchor="start">cât de jos a coborât: 62.10</text>
<line x1="250" y1="314.0" x2="976" y2="314.0" stroke="#1a5fb4" stroke-width="1.2" stroke-dasharray="2 3"/>
<text x="24.0" y="310.0" fill="#1a5fb4" text-anchor="start">treimea de sus începe la 62.90</text>
<line x1="350" y1="210.0" x2="350" y2="522.0" stroke="#1a1a1a" stroke-width="1.4"/>
<rect x="337.0" y="210.0" width="26" height="65.0" fill="#188a3e"/>
<text x="350.0" y="550.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold;font-size:12px">DA: corp 0.25,</text>
<text x="350.0" y="566.0" fill="#188a3e" text-anchor="middle">fitil jos 0.95 = 3,8x corpul</text>
<line x1="490" y1="210.0" x2="490" y2="522.0" stroke="#1a1a1a" stroke-width="1.4"/>
<rect x="477.0" y="210.0" width="26" height="104.0" fill="#188a3e"/>
<text x="490.0" y="550.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold;font-size:12px">DA, la limită: corp 0.40,</text>
<text x="490.0" y="566.0" fill="#188a3e" text-anchor="middle">fitil jos 0.80 = exact 2x</text>
<line x1="690" y1="210.0" x2="690" y2="522.0" stroke="#1a1a1a" stroke-width="1.4"/>
<rect x="677.0" y="210.0" width="26" height="182.0" fill="#188a3e"/>
<text x="690.0" y="550.0" fill="#c00" text-anchor="middle" style="font-weight:bold;font-size:12px">NU: corp 0.70,</text>
<text x="690.0" y="566.0" fill="#c00" text-anchor="middle">fitil jos 0.50 = 0,7x corpul</text>
<line x1="860" y1="210.0" x2="860" y2="522.0" stroke="#1a1a1a" stroke-width="1.4"/>
<rect x="847.0" y="431.0" width="26" height="52.0" fill="#188a3e"/>
<text x="860.0" y="550.0" fill="#c00" text-anchor="middle" style="font-weight:bold;font-size:12px">NU: corpul e jos, fitilul</text>
<text x="860.0" y="566.0" fill="#c00" text-anchor="middle">lung e sus — alt pattern</text>
<line x1="290.0" y1="262.0" x2="327.6" y2="246.8" stroke="#1a5fb4" stroke-width="1.6"/>
<polygon points="335.0,243.8 329.1,250.5 326.1,243.1" fill="#1a5fb4"/>
<text x="284.0" y="252.0" fill="#1a5fb4" text-anchor="end" style="font-weight:bold;font-size:12px">corpul: mic și sus în bară</text>
<text x="284.0" y="266.0" fill="#1a5fb4" text-anchor="end">ziua s-a închis aproape de maxim —</text>
<text x="284.0" y="280.0" fill="#1a5fb4" text-anchor="end">cumpărătorii au ținut până la final</text>
<line x1="290.0" y1="405.0" x2="339.2" y2="393.8" stroke="#1a5fb4" stroke-width="1.6"/>
<polygon points="347.0,392.0 340.1,397.7 338.3,389.9" fill="#1a5fb4"/>
<text x="284.0" y="395.0" fill="#1a5fb4" text-anchor="end" style="font-weight:bold;font-size:12px">fitilul de jos, lung</text>
<text x="284.0" y="409.0" fill="#1a5fb4" text-anchor="end">vânzătorii au dus prețul până la 62.10,</text>
<text x="284.0" y="423.0" fill="#1a5fb4" text-anchor="end">dar cumpărătorii l-au adus înapoi sus</text>
<text x="370.0" y="287.0" fill="#555" text-anchor="start">open 63.05</text>
<text x="370.0" y="206.0" fill="#555" text-anchor="start">close = high 63.30</text>
<line x1="724.0" y1="98.0" x2="704.8" y2="293.0" stroke="#c00" stroke-width="1.6"/>
<polygon points="704.0,301.0 700.8,292.6 708.8,293.4" fill="#c00"/>
<text x="730.0" y="88.0" fill="#c00" text-anchor="start" style="font-weight:bold;font-size:12px">corp prea gros</text>
<text x="730.0" y="102.0" fill="#c00" text-anchor="start">fitilul de jos nu e nici cât corpul —</text>
<text x="730.0" y="116.0" fill="#c00" text-anchor="start">nimeni n-a fost respins jos</text>
<line x1="860.0" y1="176.0" x2="860.0" y2="217.6" stroke="#c00" stroke-width="1.6"/>
<polygon points="860.0,225.6 856.0,217.6 864.0,217.6" fill="#c00"/>
<text x="860.0" y="138.0" fill="#c00" text-anchor="middle" style="font-weight:bold;font-size:12px">fitilul lung e sus, nu jos</text>
<text x="860.0" y="152.0" fill="#c00" text-anchor="middle">aici cumpărătorii au fost respinși;</text>
<text x="860.0" y="166.0" fill="#c00" text-anchor="middle">e inverted hammer, alt pattern</text>
<text x="24.0" y="608.0" fill="#555" text-anchor="start">Hammer = fitilul de jos e cel puțin dublul corpului ȘI corpul stă în treimea de sus a barei (aici peste 62.90).</text>
<text x="24.0" y="624.0" fill="#555" text-anchor="start">Pragul „fitil ≥ 2x corpul" e al cursului; „corpul în treimea de sus" e traducerea mea a lui „corp mic sus, fitil de sus aproape inexistent".</text>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""Buy hammer — ieșirea: jumătate la 1:1, restul pe trail sub swing low-uri.
Pornește din aceeași serie ca diagrama de ansamblu (barele 0-33, importate)
și îi adaugă o continuare construită (barele 34-40), pentru că seria de
ansamblu se oprește înainte ca trail-ul să apuce să urce de două ori.
Regula de trail desenată: stopul se mută sub ultimul swing low — cel mai jos
low al unui pullback, confirmat de două bare care nu-l rup. Ieși la prima
închidere sub linie.
Rulare: python3 gen/strategii/hammer_mbt10_bh_iesire.py
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
sys.path.insert(0, "/workspace/atm-curs-dl/gen/strategii")
from pathlib import Path
from hammer_mbt10_bh_ansamblu import serie
from svg_candles import Arrow, Candle, Chart, Level, Zone
OUT = Path(__file__).with_suffix(".svg")
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
INTRARE, SL, R = 63.35, 62.05, 1.30
TP1 = round(INTRARE + R, 2) # 64.65 — ținta 1:1 a strategiei MBP
TP2R = round(INTRARE + 2 * R, 2) # 65.95 — ținta din exemplul lecției
cds_all, hammer, conf = serie()
conf.note = "" # nota e a diagramei de ansamblu; aici ar sta peste legendă
# continuarea construită: un pullback, o urcare, al doilea pullback, ieșirea
CONT = [Candle(*b) for b in [
(65.60, 66.10, 65.45, 65.95), # 34
(65.95, 66.80, 65.85, 66.60), # 35
(66.60, 66.90, 66.20, 66.35), # 36
(66.35, 66.55, 66.00, 66.45), # 37 -> swing low 66.00
(66.45, 67.30, 66.35, 67.10), # 38
(67.10, 67.60, 66.90, 67.30), # 39
(67.30, 67.40, 65.80, 65.90), # 40 -> close sub trail: ieși
]]
full = cds_all + CONT
assert abs(CONT[0].o - cds_all[-1].c) < 1e-9, "continuarea nu pornește din close-ul barei 33"
for i, c in enumerate(full):
assert c.l <= min(c.o, c.c) and c.h >= max(c.o, c.c), f"bara {i}: h/l nu cuprind o/c"
def swing_lows(cds, start):
"""Cel mai jos low al unui pullback, confirmat de două bare care nu-l rup."""
out = []
for i in range(start, len(cds) - 2):
if (cds[i].l < cds[i - 1].l and cds[i + 1].l >= cds[i].l and cds[i + 2].l >= cds[i].l):
out.append((i, round(cds[i].l, 2)))
return out
CONF_I = 20
sw = swing_lows(full, CONF_I + 1)
trepte, iesire = [], None
t = None
for i in range(CONF_I + 1, len(full)):
if t is not None and full[i].c < t:
iesire = i
break
nou = [p for j, p in sw if j + 2 <= i]
if nou and (t is None or nou[-1] > t):
t = nou[-1]
trepte.append((i, t))
# --- verificări -------------------------------------------------------------
assert round(full[CONF_I].c, 2) == INTRARE, "intrarea nu e close-ul barei 20"
prim_tp1 = next(i for i in range(CONF_I + 1, len(full)) if full[i].h >= TP1)
prim_2r = next(i for i in range(CONF_I + 1, len(full)) if full[i].h >= TP2R)
assert (prim_tp1, prim_2r) == (23, 28), (prim_tp1, prim_2r)
assert round(TP1 - INTRARE, 2) == R and round(TP2R - INTRARE, 2) == 2 * R
assert trepte == [(23, 63.05), (34, 65.10), (39, 66.00)], trepte
assert all(b[1] > a[1] for a, b in zip(trepte, trepte[1:])), "trail-ul trebuie doar să urce"
assert iesire == 40 and abs(full[40].c - 65.90) < 1e-9, iesire
assert trepte[0][1] > SL, "prima treaptă nu îmbunătățește stopul inițial"
assert trepte[-1][1] > INTRARE, "ultima treaptă de trail e sub intrare: n-ar proteja profitul"
R_IES = round((full[iesire].c - INTRARE) / R, 2)
assert R_IES == 1.96, R_IES
assert min(c.l for c in full[CONF_I:]) > SL, "stopul inițial n-ar fi fost atins în fereastră"
I0 = 16
w = full[I0:]
sh = lambda i: i - I0 # noqa: E731 index în fereastră
ch = Chart(
candles=w,
levels=[Level(TP2R, "65.95 = 2R — ținta din exemplul lecției", BLUE),
Level(TP1, "64.65 = 1:1 — prima jumătate", GREEN),
Level(INTRARE, "intrare 63.35", GREY, label_at="left"),
Level(SL, "SL inițial 62.05", RED, label_at="left")],
zones=[Zone(sh(30), sh(34), "pullback", ORANGE), Zone(sh(36), sh(38), "", ORANGE)],
arrows=[
Arrow(sh(23), "prima jumătate iese la 64.65:\nexact cât ai riscat (1R)",
price=TP1, where="above", color=GREEN, dx=-150, dy=-40),
Arrow(sh(40), "a doua jumătate iese la 65.90 (+1,96R):\nprima închidere sub linia de trail",
where="below", color=RED, dx=-250, dy=54),
],
scale=34.0, gap=16, body_w=9, left=48, width=700, vol_h=0, top=58,
title="Buy hammer — ieșirea (daily, ticker ilustrativ XYZ; barele de după 33 sunt construite)",
)
svg = ch.render()
m = re.search(r'viewBox="0 0 (\d+) (\d+)"', svg)
W, H = int(m.group(1)), int(m.group(2))
OFF = (float(re.search(r'<line x1="24" y1="([\d.]+)"', svg).group(1)) - ch._y(ch.levels[0].price))
Y = lambda p: ch._y(p) + OFF # noqa: E731
pts, etichete = [], []
for k, (i, t) in enumerate(trepte):
x_de_la = ch._cx(sh(i)) - 6
x_pana = ch._cx(sh(trepte[k + 1][0])) - 6 if k + 1 < len(trepte) else ch._cx(sh(iesire)) + 6
if pts:
pts.append(f"{x_de_la:.1f},{Y(t):.1f}")
pts += [f"{x_de_la:.1f},{Y(t):.1f}", f"{x_pana:.1f},{Y(t):.1f}"]
if k == 0: # o singură etichetă: cifrele treptelor sunt în legendă
etichete.append(f'<text x="{x_de_la + 4:.1f}" y="{Y(t) + 16:.1f}" fill="{ORANGE}" '
f'style="font-weight:bold">linia de trail</text>')
extra_svg = (f'<polyline points="{" ".join(pts)}" fill="none" stroke="{ORANGE}" '
f'stroke-width="2"/>' + "".join(etichete))
linii = [
("Trail-ul urcă doar sub un swing low nou — 63.05, apoi 65.10, apoi 66.00 — și nu coboară "
"niciodată; ieși la prima închidere sub el.", "#333"),
("Lecția de pattern nu dă o țintă proprie — 1:1 vine de la strategia MBP, iar 2R e ținta "
"exemplului din lecție. Continuarea barelor e construită.", 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>", extra_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}); TP1 la bara {prim_tp1}, 2R la {prim_2r}, "
f"trail {trepte}, ieșire bara {iesire} @ {full[iesire].c:.2f} = +{R_IES}R")

View File

@@ -0,0 +1,72 @@
<svg viewBox="0 0 785 434" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="24" y="72" fill="#333" style="font-weight:bold">Buy hammer — ieșirea (daily, ticker ilustrativ XYZ; barele de după 33 sunt construite)</text>
<rect x="348.4" y="114.5" width="83.0" height="58.5" fill="#b06000" fill-opacity="0.08" stroke="#b06000" stroke-width="1"/>
<text x="348.4" y="109.5" fill="#b06000" style="font-weight:bold">pullback</text>
<rect x="444.4" y="82.2" width="51.0" height="60.2" fill="#b06000" fill-opacity="0.08" stroke="#b06000" stroke-width="1"/>
<line x1="24" y1="136.1" x2="771" y2="136.1" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="757" y="130.1" fill="#1a5fb4" text-anchor="end">65.95 = 2R — ținta din exemplul lecției</text>
<line x1="24" y1="180.3" x2="771" y2="180.3" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="757" y="174.3" fill="#188a3e" text-anchor="end">64.65 = 1:1 — prima jumătate</text>
<line x1="24" y1="224.5" x2="771" y2="224.5" stroke="#555" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="30" y="218.5" fill="#555">intrare 63.35</text>
<line x1="24" y1="268.7" x2="771" y2="268.7" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="30" y="262.7" fill="#c00">SL inițial 62.05</text>
<line x1="133.9" y1="190.5" x2="133.9" y2="233.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="129.4" y="199.0" width="9" height="23.8" fill="#c00"/>
<line x1="149.9" y1="204.1" x2="149.9" y2="233.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="145.4" y="212.6" width="9" height="10.2" fill="#188a3e"/>
<line x1="165.9" y1="204.1" x2="165.9" y2="244.9" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="161.4" y="212.6" width="9" height="22.1" fill="#c00"/>
<line x1="181.9" y1="226.2" x2="181.9" y2="267.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="177.4" y="226.2" width="9" height="8.5" fill="#188a3e"/>
<line x1="197.9" y1="219.4" x2="197.9" y2="231.3" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="193.4" y="224.5" width="9" height="1.7" fill="#188a3e"/>
<line x1="213.9" y1="200.7" x2="213.9" y2="234.7" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="209.4" y="209.2" width="9" height="15.3" fill="#188a3e"/>
<line x1="229.9" y1="187.1" x2="229.9" y2="219.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="225.4" y="195.6" width="9" height="13.6" fill="#188a3e"/>
<line x1="245.9" y1="173.5" x2="245.9" y2="205.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="241.4" y="182.0" width="9" height="13.6" fill="#188a3e"/>
<line x1="261.9" y1="173.5" x2="261.9" y2="199.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="257.4" y="182.0" width="9" height="6.8" fill="#c00"/>
<line x1="277.9" y1="163.3" x2="277.9" y2="199.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="273.4" y="171.8" width="9" height="17.0" fill="#188a3e"/>
<line x1="293.9" y1="153.1" x2="293.9" y2="182.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="289.4" y="161.6" width="9" height="10.2" fill="#188a3e"/>
<line x1="309.9" y1="142.9" x2="309.9" y2="171.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="305.4" y="151.4" width="9" height="10.2" fill="#188a3e"/>
<line x1="325.9" y1="132.7" x2="325.9" y2="161.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="321.4" y="141.2" width="9" height="10.2" fill="#188a3e"/>
<line x1="341.9" y1="122.5" x2="341.9" y2="151.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="337.4" y="131.0" width="9" height="10.2" fill="#188a3e"/>
<line x1="357.9" y1="122.5" x2="357.9" y2="144.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="353.4" y="131.0" width="9" height="3.4" fill="#c00"/>
<line x1="373.9" y1="125.9" x2="373.9" y2="154.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="369.4" y="134.4" width="9" height="10.2" fill="#c00"/>
<line x1="389.9" y1="136.1" x2="389.9" y2="165.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="385.4" y="144.6" width="9" height="10.2" fill="#c00"/>
<line x1="405.9" y1="139.5" x2="405.9" y2="165.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="401.4" y="148.0" width="9" height="6.8" fill="#188a3e"/>
<line x1="421.9" y1="131.0" x2="421.9" y2="153.1" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="417.4" y="136.1" width="9" height="11.9" fill="#188a3e"/>
<line x1="437.9" y1="107.2" x2="437.9" y2="139.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="433.4" y="114.0" width="9" height="22.1" fill="#188a3e"/>
<line x1="453.9" y1="103.8" x2="453.9" y2="127.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="449.4" y="114.0" width="9" height="8.5" fill="#c00"/>
<line x1="469.9" y1="115.7" x2="469.9" y2="134.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="465.4" y="119.1" width="9" height="3.4" fill="#188a3e"/>
<line x1="485.9" y1="90.2" x2="485.9" y2="122.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="481.4" y="97.0" width="9" height="22.1" fill="#188a3e"/>
<line x1="501.9" y1="80.0" x2="501.9" y2="103.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="497.4" y="90.2" width="9" height="6.8" fill="#188a3e"/>
<line x1="517.9" y1="86.8" x2="517.9" y2="141.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="513.4" y="90.2" width="9" height="47.6" fill="#c00"/>
<line x1="95.9" y1="110.3" x2="238.6" y2="173.1" stroke="#188a3e" stroke-width="1.8"/>
<polygon points="245.9,176.3 237.0,176.7 240.2,169.4" fill="#188a3e"/>
<text x="95.9" y="91.3" fill="#188a3e" text-anchor="middle" style="font-weight:bold">prima jumătate iese la 64.65:</text>
<text x="95.9" y="105.3" fill="#188a3e" text-anchor="middle" style="font-weight:bold">exact cât ai riscat (1R)</text>
<line x1="267.9" y1="329.0" x2="511.5" y2="149.9" stroke="#c00" stroke-width="1.8"/>
<polygon points="517.9,145.2 513.8,153.2 509.1,146.7" fill="#c00"/>
<text x="267.9" y="343.0" fill="#c00" text-anchor="middle" style="font-weight:bold">a doua jumătate iese la 65.90 (+1,96R):</text>
<text x="267.9" y="357.0" fill="#c00" text-anchor="middle" style="font-weight:bold">prima închidere sub linia de trail</text>
<polyline points="154.0,234.7 330.0,234.7 330.0,165.0 330.0,165.0 410.0,165.0 410.0,134.4 410.0,134.4 438.0,134.4" fill="none" stroke="#b06000" stroke-width="2"/><text x="158.0" y="250.7" fill="#b06000" style="font-weight:bold">linia de trail</text><text x="24" y="402" fill="#333">Trail-ul urcă doar sub un swing low nou — 63.05, apoi 65.10, apoi 66.00 — și nu coboară niciodată; ieși la prima închidere sub el.</text><text x="24" y="418" fill="#555">Lecția de pattern nu dă o țintă proprie — 1:1 vine de la strategia MBP, iar 2R e ținta exemplului din lecție. Continuarea barelor e construită.</text></svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""Buy hammer — locația: hammer la un nivel major vs. hammer în mijlocul range-ului.
Două panouri alăturate cu ACEEAȘI serie de 12 bare, pe aceeași scară și
aceeași axă de preț (candelele stau la aceleași y). Stânga: suport monthly
62.00, la 0,16 % sub low-ul hammer-ului. Dreapta: cel mai apropiat nivel de
sub el e la 58.00, adică un gol de 7,07 %. Nivelurile se desenează de mână,
cu coordonate absolute (liniile din Chart pornesc de la x=24 și ar trece
peste panoul vecin).
Rulare: python3 gen/strategii/hammer_mbt10_bh_locatie.py
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
from pathlib import Path
from svg_candles import Arrow, Chart, Mark, from_closes
OUT = Path(__file__).with_suffix(".svg")
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
CLOSES = [65.40, 64.90, 64.40, 64.70, 64.00, 63.50, 63.05,
63.30, # 7 = hammer: o 63.05, h = c 63.30, l 62.10
63.35, # 8 = confirmare, close peste high-ul hammer-ului
63.80, 64.20, 64.60]
wicks = [(0.15, 0.15)] * len(CLOSES)
wicks[7] = (0.00, 0.95)
cds = from_closes(CLOSES, wicks=wicks, start=65.90)
ham = cds[7]
SUP_DA, SUP_NU, REZ_NU = 62.00, 58.00, 67.00
# --- verificări -------------------------------------------------------------
for i in range(1, len(cds)):
assert abs(cds[i].o - cds[i - 1].c) < 1e-9, f"open[{i}] != close[{i-1}]"
assert (round(ham.h, 2), round(ham.l, 2), round(ham.c, 2)) == (63.30, 62.10, 63.30)
corp, jos = ham.c - ham.o, ham.o - ham.l
assert jos >= 2 * corp, "bara 7 nu e hammer"
assert cds[8].c > ham.h, "bara 8 nu confirmă"
d_da = round((ham.l - SUP_DA) / SUP_DA * 100, 2)
assert d_da == 0.16 and d_da <= 2, d_da
d_nu = round((ham.l - SUP_NU) / SUP_NU * 100, 2)
assert d_nu == 7.07 and d_nu > 2, d_nu
d_rez = round((REZ_NU - ham.h) / ham.h * 100, 2)
assert d_rez == 5.85 and d_rez > 2, d_rez
assert not any(SUP_NU < p < REZ_NU for p in (SUP_NU, REZ_NU) if False)
# --- layout -----------------------------------------------------------------
W, PW = 760, 350
PX = [24, 24 + PW + 28]
SCALE, TOP = 34.0, 96
ARR = {
PX[0]: Arrow(4, "suport monthly: nivel urmărit de mulți —\naici au cumpărători motiv să apară",
price=SUP_DA, where="below", color=BLUE, dx=30, dy=22),
PX[1]: Arrow(7, "aceeași formă, dar nimic sub ea:\nfitilul n-a fost oprit de un nivel,\nci s-a oprit singur",
where="below", color=RED, dx=70, dy=30),
}
charts = []
for px in PX:
ch = Chart(candles=cds,
marks=[Mark(7, "hammer 63.30 / 62.10", ORANGE, "above", dy=-16)],
arrows=[ARR[px]],
scale=SCALE, gap=17, body_w=10, left=px + 34, width=px + PW, top=TOP)
body = ch._render()
assert f'viewBox="0 0 {px + PW} ' in body, f"panoul {px}: textul unei săgeți iese"
assert (ch.top, ch.left) == (TOP, px + 34), "Chart a mutat graficul: panourile s-ar dezalinia"
charts.append((ch, body.split(">", 1)[1].rsplit("</svg>", 1)[0].strip()))
(ch_da, body_da), (ch_nu, body_nu) = charts
assert ch_da.scale == ch_nu.scale and ch_da._pmax == ch_nu._pmax, "scări diferite"
y = ch_da._y
def level(px, price, text, color, below=False):
yy = y(price)
ty, anchor, tx = (yy + 14, "end", px + PW - 4) if below else (yy - 6, "end", px + PW - 4)
return [f'<line x1="{px}" y1="{yy:.1f}" x2="{px + PW}" y2="{yy:.1f}" stroke="{color}" '
f'stroke-width="1.5" stroke-dasharray="4 3"/>',
f'<text x="{tx}" y="{ty:.1f}" fill="{color}" text-anchor="{anchor}">{text}</text>']
def zone(px, p_top, p_bot, label, color, label_at_bottom=False):
y0, y1 = y(p_top), y(p_bot)
ly, anchor, lx = ((y1 - 12, "start", px + 8) if label_at_bottom
else (y0 - 6, "end", px + PW - 4))
return [f'<rect x="{px}" y="{y0:.1f}" width="{PW}" height="{y1 - y0:.1f}" fill="{color}" '
f'fill-opacity="0.12" stroke="{color}" stroke-width="1"/>',
f'<text x="{lx}" y="{ly:.1f}" fill="{color}" text-anchor="{anchor}" '
f'style="font-weight:bold">{label}</text>']
PCT_DA, PCT_NU = f"{d_da:.2f}".replace(".", ","), f"{d_nu:.2f}".replace(".", ",")
y_bot = y(SUP_NU)
parts = [
f'<svg viewBox="0 0 {W} {y_bot + 66:.0f}" xmlns="http://www.w3.org/2000/svg" '
f'style="width:100%;height:auto;font:12px sans-serif">',
'<text x="24" y="22" fill="#333" style="font-weight:bold">Hammer la un nivel vs. hammer '
'în mijlocul range-ului — daily, exemplu construit</text>',
f'<text x="{PX[0]}" y="48" fill="{GREEN}" style="font-weight:bold">DA — hammer pe suportul '
'monthly</text>',
f'<text x="{PX[1]}" y="48" fill="{RED}" style="font-weight:bold">NU — hammer în mijlocul '
'range-ului</text>',
f'<line x1="{PX[1] - 14}" y1="36" x2="{PX[1] - 14}" y2="{y_bot + 10:.0f}" stroke="#ccc"/>',
*zone(PX[0], ham.l, SUP_DA, f"low-ul hammer-ului: {ham.l:.2f}", GREEN),
*zone(PX[1], ham.l, SUP_NU, f"low-ul hammer-ului: {ham.l:.2f}", RED),
f'<text x="{PX[0] + PW - 4}" y="{y(SUP_DA) + 34:.1f}" fill="{GREEN}" text-anchor="end" '
f'style="font-weight:bold">de la {ham.l:.2f} la {SUP_DA:.2f} = {PCT_DA} % — la nivel</text>',
f'<text x="{PX[1] + 8}" y="{y(SUP_NU) - 12:.1f}" fill="{RED}" style="font-weight:bold">'
f'de la {ham.l:.2f} la {SUP_NU:.2f} = gol de {PCT_NU} % — hammer în aer</text>',
*level(PX[0], SUP_DA, "suport monthly 62.00", BLUE, below=True),
*level(PX[1], REZ_NU, "rezistența range-ului 67.00", BLUE, below=True),
*level(PX[1], SUP_NU, "baza range-ului 58.00", BLUE, below=True),
body_da, body_nu,
f'<text x="24" y="{y_bot + 34:.0f}" fill="{GREY}">Completare proprie: materialul cere '
'„un nivel major (weekly / monthly / quarterly), nu mijlocul range-ului", dar nu dă un prag '
'numeric.</text>',
f'<text x="24" y="{y_bot + 52:.0f}" fill="{GREY}">Pragul de 1-2 % e împrumutat de la buy '
f'doji, ca să ai ce măsura: aici {PCT_DA} % în stânga, {PCT_NU} % în dreapta.</text>',
"</svg>",
]
svg = "\n ".join(parts).replace("\n </svg>", "\n</svg>")
assert "\n\n" not in svg, "linie goală în SVG"
for m in re.finditer(r'<text x="([\d.]+)"[^>]*>(.*?)</text>', body_da):
assert float(m.group(1)) < PX[1] - 14, f"text din DA trece în NU: {m.group(2)}"
OUT.write_text(svg, encoding="utf-8")
print(f"scris {OUT.name} ({W}x{y_bot + 66:.0f}); DA {d_da}% NU {d_nu}% (rezistență {d_rez}%)")

View File

@@ -0,0 +1,79 @@
<svg viewBox="0 0 760 436" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="24" y="22" fill="#333" style="font-weight:bold">Hammer la un nivel vs. hammer în mijlocul range-ului — daily, exemplu construit</text>
<text x="24" y="48" fill="#188a3e" style="font-weight:bold">DA — hammer pe suportul monthly</text>
<text x="402" y="48" fill="#c00" style="font-weight:bold">NU — hammer în mijlocul range-ului</text>
<line x1="388" y1="36" x2="388" y2="380" stroke="#ccc"/>
<rect x="24" y="230.3" width="350" height="3.4" fill="#188a3e" fill-opacity="0.12" stroke="#188a3e" stroke-width="1"/>
<text x="370" y="224.3" fill="#188a3e" text-anchor="end" style="font-weight:bold">low-ul hammer-ului: 62.10</text>
<rect x="402" y="230.3" width="350" height="139.4" fill="#c00" fill-opacity="0.12" stroke="#c00" stroke-width="1"/>
<text x="748" y="224.3" fill="#c00" text-anchor="end" style="font-weight:bold">low-ul hammer-ului: 62.10</text>
<text x="370" y="267.7" fill="#188a3e" text-anchor="end" style="font-weight:bold">de la 62.10 la 62.00 = 0,16 % — la nivel</text>
<text x="410" y="357.7" fill="#c00" style="font-weight:bold">de la 62.10 la 58.00 = gol de 7,07 % — hammer în aer</text>
<line x1="24" y1="233.7" x2="374" y2="233.7" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="370" y="247.7" fill="#1a5fb4" text-anchor="end">suport monthly 62.00</text>
<line x1="402" y1="63.7" x2="752" y2="63.7" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="748" y="77.7" fill="#1a5fb4" text-anchor="end">rezistența range-ului 67.00</text>
<line x1="402" y1="369.7" x2="752" y2="369.7" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="748" y="383.7" fill="#1a5fb4" text-anchor="end">baza range-ului 58.00</text>
<line x1="58.0" y1="96.0" x2="58.0" y2="123.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="53.0" y="101.1" width="10" height="17.0" fill="#c00"/>
<line x1="75.0" y1="113.0" x2="75.0" y2="140.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="70.0" y="118.1" width="10" height="17.0" fill="#c00"/>
<line x1="92.0" y1="130.0" x2="92.0" y2="157.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="87.0" y="135.1" width="10" height="17.0" fill="#c00"/>
<line x1="109.0" y1="136.8" x2="109.0" y2="157.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="104.0" y="141.9" width="10" height="10.2" fill="#188a3e"/>
<line x1="126.0" y1="136.8" x2="126.0" y2="170.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="121.0" y="141.9" width="10" height="23.8" fill="#c00"/>
<line x1="143.0" y1="160.6" x2="143.0" y2="187.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="138.0" y="165.7" width="10" height="17.0" fill="#c00"/>
<line x1="160.0" y1="177.6" x2="160.0" y2="203.1" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="155.0" y="182.7" width="10" height="15.3" fill="#c00"/>
<line x1="177.0" y1="189.5" x2="177.0" y2="230.3" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="172.0" y="189.5" width="10" height="8.5" fill="#188a3e"/>
<line x1="194.0" y1="182.7" x2="194.0" y2="194.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="189.0" y="187.8" width="10" height="1.7" fill="#188a3e"/>
<line x1="211.0" y1="167.4" x2="211.0" y2="192.9" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="206.0" y="172.5" width="10" height="15.3" fill="#188a3e"/>
<line x1="228.0" y1="153.8" x2="228.0" y2="177.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="223.0" y="158.9" width="10" height="13.6" fill="#188a3e"/>
<line x1="245.0" y1="140.2" x2="245.0" y2="164.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="240.0" y="145.3" width="10" height="13.6" fill="#188a3e"/>
<text x="177.0" y="163.5" fill="#b06000" text-anchor="middle" style="font-weight:bold">hammer 63.30 / 62.10</text>
<line x1="156.0" y1="285.7" x2="130.2" y2="244.5" stroke="#1a5fb4" stroke-width="1.8"/>
<polygon points="126.0,237.7 133.6,242.4 126.8,246.6" fill="#1a5fb4"/>
<text x="156.0" y="299.7" fill="#1a5fb4" text-anchor="middle" style="font-weight:bold">suport monthly: nivel urmărit de mulți —</text>
<text x="156.0" y="313.7" fill="#1a5fb4" text-anchor="middle" style="font-weight:bold">aici au cumpărători motiv să apară</text>
<line x1="436.0" y1="96.0" x2="436.0" y2="123.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="431.0" y="101.1" width="10" height="17.0" fill="#c00"/>
<line x1="453.0" y1="113.0" x2="453.0" y2="140.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="448.0" y="118.1" width="10" height="17.0" fill="#c00"/>
<line x1="470.0" y1="130.0" x2="470.0" y2="157.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="465.0" y="135.1" width="10" height="17.0" fill="#c00"/>
<line x1="487.0" y1="136.8" x2="487.0" y2="157.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="482.0" y="141.9" width="10" height="10.2" fill="#188a3e"/>
<line x1="504.0" y1="136.8" x2="504.0" y2="170.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="499.0" y="141.9" width="10" height="23.8" fill="#c00"/>
<line x1="521.0" y1="160.6" x2="521.0" y2="187.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="516.0" y="165.7" width="10" height="17.0" fill="#c00"/>
<line x1="538.0" y1="177.6" x2="538.0" y2="203.1" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="533.0" y="182.7" width="10" height="15.3" fill="#c00"/>
<line x1="555.0" y1="189.5" x2="555.0" y2="230.3" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="550.0" y="189.5" width="10" height="8.5" fill="#188a3e"/>
<line x1="572.0" y1="182.7" x2="572.0" y2="194.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="567.0" y="187.8" width="10" height="1.7" fill="#188a3e"/>
<line x1="589.0" y1="167.4" x2="589.0" y2="192.9" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="584.0" y="172.5" width="10" height="15.3" fill="#188a3e"/>
<line x1="606.0" y1="153.8" x2="606.0" y2="177.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="601.0" y="158.9" width="10" height="13.6" fill="#188a3e"/>
<line x1="623.0" y1="140.2" x2="623.0" y2="164.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="618.0" y="145.3" width="10" height="13.6" fill="#188a3e"/>
<text x="555.0" y="163.5" fill="#b06000" text-anchor="middle" style="font-weight:bold">hammer 63.30 / 62.10</text>
<line x1="625.0" y1="290.3" x2="561.2" y2="239.3" stroke="#c00" stroke-width="1.8"/>
<polygon points="555.0,234.3 563.7,236.2 558.7,242.4" fill="#c00"/>
<text x="625.0" y="304.3" fill="#c00" text-anchor="middle" style="font-weight:bold">aceeași formă, dar nimic sub ea:</text>
<text x="625.0" y="318.3" fill="#c00" text-anchor="middle" style="font-weight:bold">fitilul n-a fost oprit de un nivel,</text>
<text x="625.0" y="332.3" fill="#c00" text-anchor="middle" style="font-weight:bold">ci s-a oprit singur</text>
<text x="24" y="404" fill="#555">Completare proprie: materialul cere „un nivel major (weekly / monthly / quarterly), nu mijlocul range-ului", dar nu dă un prag numeric.</text>
<text x="24" y="422" fill="#555">Pragul de 1-2 % e împrumutat de la buy doji, ca să ai ce măsura: aici 0,16 % în stânga, 7,07 % în dreapta.</text>
</svg>

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Sell hammer — oglinda pe short a trade-ului din Partea A.
Seria e chiar trade-ul long, oglindit în jurul lui K = 162.30: fiecare preț
p devine K - p, iar fitilele se inversează. Așa, hammer-ul 63.30 / 62.10
devine 99.00 / 100.20, intrarea 63.35 devine 98.95, stopul 62.05 devine
100.25 și ținta 65.95 devine 96.35 — riscul rămâne exact 1.30, deci cele
două diagrame nu se pot contrazice la cifre. Oglindirea e verificată bară
cu bară prin assert.
Rulare: python3 gen/strategii/hammer_mbt10_bh_sell.py
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
sys.path.insert(0, "/workspace/atm-curs-dl/gen/strategii")
from pathlib import Path
from hammer_mbt10_bh_ansamblu import serie
from svg_candles import Arrow, Candle, Chart, Level
OUT = Path(__file__).with_suffix(".svg")
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
K = 162.30
lung, ham_l, conf_l = serie()
conf_l.note = ""
cds = [Candle(K - c.o, K - c.l, K - c.h, K - c.c, vol=c.vol) for c in lung]
ham, conf = cds[19], cds[20]
INTRARE, SL, TP = round(K - 63.35, 2), round(K - 62.05, 2), round(K - 65.95, 2)
R = round(SL - INTRARE, 2)
# --- verificări -------------------------------------------------------------
for i, (a, b) in enumerate(zip(lung, cds)):
assert abs(b.o - (K - a.o)) < 1e-9 and abs(b.c - (K - a.c)) < 1e-9, i
assert abs(b.h - (K - a.l)) < 1e-9 and abs(b.l - (K - a.h)) < 1e-9, f"bara {i}: fitil neoglindit"
assert b.l <= min(b.o, b.c) and b.h >= max(b.o, b.c), f"bara {i}: h/l nu cuprind o/c"
for i in range(1, len(cds)):
assert abs(cds[i].o - cds[i - 1].c) < 1e-9, f"open[{i}] != close[{i-1}]"
assert (round(ham.l, 2), round(ham.h, 2)) == (99.00, 100.20), ham
corp, sus = ham.o - ham.c, ham.h - ham.o
assert sus >= 2 * corp, "bara 19 nu e sell hammer (fitilul de sus sub dublul corpului)"
assert abs(ham.l - ham.c) < 1e-9, "corpul nu se sprijină pe low: fitil de jos inexistent"
assert cds[18].c > cds[0].c + 8, "urcarea dinainte nu se vede"
assert conf.c < ham.l and round(conf.c, 2) == INTRARE, "confirmarea nu închide sub low-ul lui"
assert round(SL, 2) == round(ham.h + 0.05, 2), "SL nu e la 5 cenți peste high-ul sell hammer-ului"
assert R == 1.30 and round(INTRARE - TP, 2) == 2 * R, (R, TP)
assert TP < INTRARE < SL, "ordinea nivelurilor e greșită pe short"
prim_tp = next(i for i in range(21, len(cds)) if cds[i].l <= TP)
assert prim_tp == 28, prim_tp
assert max(c.h for c in cds[21:prim_tp + 1]) < SL, "stopul ar fi fost atins înainte de țintă"
ch = Chart(
candles=cds,
levels=[Level(SL, "SL 100.25 — peste high-ul sell hammer-ului", RED),
Level(INTRARE, "intrare short 98.95", GREEN, label_at="left"),
Level(TP, "TP 96.35 = 2R", BLUE)],
arrows=[
Arrow(19, "sell hammer 99.00 / 100.20:\ncorp mic jos, fitil lung în sus",
where="left", color=ORANGE, dx=-8, dy=-30),
Arrow(20, "close 98.95, sub low-ul lui 99.00:\naici vinzi în lipsă",
where="below", color=GREEN, dx=-120, dy=40),
Arrow(prim_tp, "ținta 96.35: aceeași distanță\nca la long, dar în jos",
price=TP, where="below", color=BLUE, dx=-60, dy=30),
],
scale=32.0, gap=15, body_w=9, left=44, width=720, top=56, vol_h=70, vol_label="volum",
title="Sell hammer — oglinda pe short (daily, 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 = [
("Totul e întors: urcare înainte, corp mic jos și fitil lung în sus, intrarea la o "
"închidere SUB", "#333"),
("low-ul candelei, stopul PESTE high-ul ei, ținta la aceeași distanță în jos.", "#333"),
("Completare proprie: cursul numește Sell Hammer ca simetric al lui Buy Hammer, dar "
"nu-i scrie", GREY),
("regulile separat. Seria e trade-ul long oglindit, deci riscul e tot 1.30.", 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}); intrare {INTRARE} SL {SL} TP {TP} R {R}, "
f"țintă atinsă la bara {prim_tp}")

View File

@@ -0,0 +1,125 @@
<svg viewBox="0 0 720 621" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="24" y="70" fill="#333" style="font-weight:bold">Sell hammer — oglinda pe short (daily, exemplu construit)</text>
<line x1="24" y1="78.0" x2="706" y2="78.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="692" y="72.0" fill="#c00" text-anchor="end">SL 100.25 — peste high-ul sell hammer-ului</text>
<line x1="24" y1="119.6" x2="706" y2="119.6" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="30" y="113.6" fill="#188a3e">intrare short 98.95</text>
<line x1="24" y1="202.8" x2="706" y2="202.8" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="692" y="196.8" fill="#1a5fb4" text-anchor="end">TP 96.35 = 2R</text>
<line x1="44.0" y1="386.8" x2="44.0" y2="404.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="39.5" y="396.4" width="9" height="1.6" fill="#188a3e"/>
<line x1="59.0" y1="361.2" x2="59.0" y2="404.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="54.5" y="370.8" width="9" height="25.6" fill="#188a3e"/>
<line x1="74.0" y1="361.2" x2="74.0" y2="388.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="69.5" y="370.8" width="9" height="9.6" fill="#c00"/>
<line x1="89.0" y1="335.6" x2="89.0" y2="388.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="84.5" y="345.2" width="9" height="35.2" fill="#188a3e"/>
<line x1="104.0" y1="310.0" x2="104.0" y2="353.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="99.5" y="319.6" width="9" height="25.6" fill="#188a3e"/>
<line x1="119.0" y1="310.0" x2="119.0" y2="340.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="114.5" y="319.6" width="9" height="12.8" fill="#c00"/>
<line x1="134.0" y1="287.6" x2="134.0" y2="340.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="129.5" y="297.2" width="9" height="35.2" fill="#188a3e"/>
<line x1="149.0" y1="262.0" x2="149.0" y2="305.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="144.5" y="271.6" width="9" height="25.6" fill="#188a3e"/>
<line x1="164.0" y1="262.0" x2="164.0" y2="289.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="159.5" y="271.6" width="9" height="9.6" fill="#c00"/>
<line x1="179.0" y1="236.4" x2="179.0" y2="289.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="174.5" y="246.0" width="9" height="35.2" fill="#188a3e"/>
<line x1="194.0" y1="210.8" x2="194.0" y2="254.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="189.5" y="220.4" width="9" height="25.6" fill="#188a3e"/>
<line x1="209.0" y1="210.8" x2="209.0" y2="238.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="204.5" y="220.4" width="9" height="9.6" fill="#c00"/>
<line x1="224.0" y1="185.2" x2="224.0" y2="238.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="219.5" y="194.8" width="9" height="35.2" fill="#188a3e"/>
<line x1="239.0" y1="159.6" x2="239.0" y2="202.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="234.5" y="169.2" width="9" height="25.6" fill="#188a3e"/>
<line x1="254.0" y1="159.6" x2="254.0" y2="186.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="249.5" y="169.2" width="9" height="9.6" fill="#c00"/>
<line x1="269.0" y1="134.0" x2="269.0" y2="186.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="264.5" y="143.6" width="9" height="35.2" fill="#188a3e"/>
<line x1="284.0" y1="111.6" x2="284.0" y2="151.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="279.5" y="121.2" width="9" height="22.4" fill="#188a3e"/>
<line x1="299.0" y1="111.6" x2="299.0" y2="138.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="294.5" y="121.2" width="9" height="9.6" fill="#c00"/>
<line x1="314.0" y1="100.4" x2="314.0" y2="138.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="309.5" y="110.0" width="9" height="20.8" fill="#188a3e"/>
<line x1="329.0" y1="79.6" x2="329.0" y2="118.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="324.5" y="110.0" width="9" height="8.0" fill="#c00"/>
<line x1="344.0" y1="113.2" x2="344.0" y2="124.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="339.5" y="118.0" width="9" height="1.6" fill="#c00"/>
<line x1="359.0" y1="110.0" x2="359.0" y2="142.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="354.5" y="119.6" width="9" height="14.4" fill="#c00"/>
<line x1="374.0" y1="124.4" x2="374.0" y2="154.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="369.5" y="134.0" width="9" height="12.8" fill="#c00"/>
<line x1="389.0" y1="137.2" x2="389.0" y2="167.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="384.5" y="146.8" width="9" height="12.8" fill="#c00"/>
<line x1="404.0" y1="143.6" x2="404.0" y2="167.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="399.5" y="153.2" width="9" height="6.4" fill="#188a3e"/>
<line x1="419.0" y1="143.6" x2="419.0" y2="177.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="414.5" y="153.2" width="9" height="16.0" fill="#c00"/>
<line x1="434.0" y1="159.6" x2="434.0" y2="186.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="429.5" y="169.2" width="9" height="9.6" fill="#c00"/>
<line x1="449.0" y1="169.2" x2="449.0" y2="196.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="444.5" y="178.8" width="9" height="9.6" fill="#c00"/>
<line x1="464.0" y1="178.8" x2="464.0" y2="206.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="459.5" y="188.4" width="9" height="9.6" fill="#c00"/>
<line x1="479.0" y1="188.4" x2="479.0" y2="215.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="474.5" y="198.0" width="9" height="9.6" fill="#c00"/>
<line x1="494.0" y1="194.8" x2="494.0" y2="215.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="489.5" y="204.4" width="9" height="3.2" fill="#188a3e"/>
<line x1="509.0" y1="185.2" x2="509.0" y2="212.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="504.5" y="194.8" width="9" height="9.6" fill="#188a3e"/>
<line x1="524.0" y1="175.6" x2="524.0" y2="202.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="519.5" y="185.2" width="9" height="9.6" fill="#188a3e"/>
<line x1="539.0" y1="175.6" x2="539.0" y2="199.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="534.5" y="185.2" width="9" height="6.4" fill="#c00"/>
<line x1="24" y1="521.4" x2="706" y2="521.4" stroke="#888"/>
<rect x="39.5" y="484.6" width="9" height="36.8" fill="#188a3e" opacity="0.55"/>
<rect x="54.5" y="486.0" width="9" height="35.4" fill="#188a3e" opacity="0.55"/>
<rect x="69.5" y="486.8" width="9" height="34.6" fill="#c00" opacity="0.55"/>
<rect x="84.5" y="487.5" width="9" height="33.9" fill="#188a3e" opacity="0.55"/>
<rect x="99.5" y="488.2" width="9" height="33.2" fill="#188a3e" opacity="0.55"/>
<rect x="114.5" y="487.5" width="9" height="33.9" fill="#c00" opacity="0.55"/>
<rect x="129.5" y="489.0" width="9" height="32.4" fill="#188a3e" opacity="0.55"/>
<rect x="144.5" y="489.7" width="9" height="31.7" fill="#188a3e" opacity="0.55"/>
<rect x="159.5" y="488.2" width="9" height="33.2" fill="#c00" opacity="0.55"/>
<rect x="174.5" y="490.5" width="9" height="30.9" fill="#188a3e" opacity="0.55"/>
<rect x="189.5" y="491.2" width="9" height="30.2" fill="#188a3e" opacity="0.55"/>
<rect x="204.5" y="489.7" width="9" height="31.7" fill="#c00" opacity="0.55"/>
<rect x="219.5" y="491.9" width="9" height="29.5" fill="#188a3e" opacity="0.55"/>
<rect x="234.5" y="492.7" width="9" height="28.7" fill="#188a3e" opacity="0.55"/>
<rect x="249.5" y="491.2" width="9" height="30.2" fill="#c00" opacity="0.55"/>
<rect x="264.5" y="493.4" width="9" height="28.0" fill="#188a3e" opacity="0.55"/>
<rect x="279.5" y="494.1" width="9" height="27.3" fill="#188a3e" opacity="0.55"/>
<rect x="294.5" y="492.7" width="9" height="28.7" fill="#c00" opacity="0.55"/>
<rect x="309.5" y="480.9" width="9" height="40.5" fill="#188a3e" opacity="0.55"/>
<rect x="324.5" y="455.1" width="9" height="66.3" fill="#c00" opacity="0.55"/>
<rect x="339.5" y="451.4" width="9" height="70.0" fill="#c00" opacity="0.55"/>
<rect x="354.5" y="478.7" width="9" height="42.7" fill="#c00" opacity="0.55"/>
<rect x="369.5" y="480.9" width="9" height="40.5" fill="#c00" opacity="0.55"/>
<rect x="384.5" y="482.3" width="9" height="39.1" fill="#c00" opacity="0.55"/>
<rect x="399.5" y="484.6" width="9" height="36.8" fill="#188a3e" opacity="0.55"/>
<rect x="414.5" y="483.1" width="9" height="38.3" fill="#c00" opacity="0.55"/>
<rect x="429.5" y="481.6" width="9" height="39.8" fill="#c00" opacity="0.55"/>
<rect x="444.5" y="480.1" width="9" height="41.3" fill="#c00" opacity="0.55"/>
<rect x="459.5" y="477.2" width="9" height="44.2" fill="#c00" opacity="0.55"/>
<rect x="474.5" y="474.2" width="9" height="47.2" fill="#c00" opacity="0.55"/>
<rect x="489.5" y="478.7" width="9" height="42.7" fill="#188a3e" opacity="0.55"/>
<rect x="504.5" y="480.9" width="9" height="40.5" fill="#188a3e" opacity="0.55"/>
<rect x="519.5" y="483.1" width="9" height="38.3" fill="#188a3e" opacity="0.55"/>
<rect x="534.5" y="484.6" width="9" height="36.8" fill="#c00" opacity="0.55"/>
<text x="24" y="445.4" fill="#555">volum</text>
<line x1="282.5" y1="88.0" x2="314.2" y2="113.0" stroke="#b06000" stroke-width="1.8"/>
<polygon points="320.5,118.0 311.7,116.2 316.7,109.9" fill="#b06000"/>
<text x="278.5" y="85.0" fill="#b06000" text-anchor="end" style="font-weight:bold">sell hammer 99.00 / 100.20:</text>
<text x="278.5" y="99.0" fill="#b06000" text-anchor="end" style="font-weight:bold">corp mic jos, fitil lung în sus</text>
<line x1="224.0" y1="388.4" x2="340.6" y2="135.7" stroke="#188a3e" stroke-width="1.8"/>
<polygon points="344.0,128.4 344.3,137.3 337.0,134.0" fill="#188a3e"/>
<text x="224.0" y="402.4" fill="#188a3e" text-anchor="middle" style="font-weight:bold">close 98.95, sub low-ul lui 99.00:</text>
<text x="224.0" y="416.4" fill="#188a3e" text-anchor="middle" style="font-weight:bold">aici vinzi în lipsă</text>
<line x1="404.0" y1="262.8" x2="458.2" y2="212.3" stroke="#1a5fb4" stroke-width="1.8"/>
<polygon points="464.0,206.8 460.9,215.2 455.4,209.3" fill="#1a5fb4"/>
<text x="404.0" y="276.8" fill="#1a5fb4" text-anchor="middle" style="font-weight:bold">ținta 96.35: aceeași distanță</text>
<text x="404.0" y="290.8" fill="#1a5fb4" text-anchor="middle" style="font-weight:bold">ca la long, dar în jos</text>
<text x="24" y="557" fill="#333">Totul e întors: urcare înainte, corp mic jos și fitil lung în sus, intrarea la o închidere SUB</text><text x="24" y="573" fill="#333">low-ul candelei, stopul PESTE high-ul ei, ținta la aceeași distanță în jos.</text><text x="24" y="589" fill="#555">Completare proprie: cursul numește Sell Hammer ca simetric al lui Buy Hammer, dar nu-i scrie</text><text x="24" y="605" fill="#555">regulile separat. Seria e trade-ul long oglindit, deci riscul e tot 1.30.</text></svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python3
"""Buy hammer — unde stă stopul și câte acțiuni cumperi (același trade XYZ).
Zoom pe barele 14-27 din seria diagramei de ansamblu (importată, ca să nu
existe două variante ale aceluiași trade). Arată: SL 62.05, cu 5 cenți sub
low-ul hammer-ului, paranteza de risc 1.30 $/acțiune și, sub grafic, calculul
de mărime al lecției: 2 % dintr-un cont de 10.000 $ = 200 $; 200 / 1.30 = 153
de acțiuni.
Rulare: python3 gen/strategii/hammer_mbt10_bh_stop.py
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
sys.path.insert(0, "/workspace/atm-curs-dl/gen/strategii")
from pathlib import Path
from hammer_mbt10_bh_ansamblu import serie
from svg_candles import Arrow, Chart, Level, Zone
OUT = Path(__file__).with_suffix(".svg")
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
I0, I1 = 14, 27 # fereastra desenată din seria completă
cds_all, hammer, conf = serie()
cds = cds_all[I0:I1 + 1]
HAM, CONF = 19 - I0, 20 - I0 # indicii hammer / confirmare în fereastră
INTRARE, SL = 63.35, 62.05
RISC = round(INTRARE - SL, 2)
CONT, PROCENT = 10_000, 0.02
RISC_LEI = CONT * PROCENT
ACTIUNI = int(RISC_LEI // RISC)
# --- verificări -------------------------------------------------------------
assert cds[HAM] is hammer and cds[CONF] is conf, "fereastra nu prinde hammer-ul și confirmarea"
assert round(SL, 2) == round(hammer.l - 0.05, 2), "SL nu e la 5 cenți sub low-ul hammer-ului"
assert round(conf.c, 2) == INTRARE and conf.c > hammer.h, "intrarea nu e close-ul confirmării"
assert RISC == 1.30, RISC
assert RISC_LEI == 200 and ACTIUNI == 153, (RISC_LEI, ACTIUNI)
assert min(c.l for c in cds) == hammer.l, "în fereastră, cel mai jos low nu e al hammer-ului"
assert SL < min(c.l for c in cds), "linia stopului trebuie să stea sub toate fitilele"
# pierderea maximă planificată încape în regula de 2 %
assert ACTIUNI * RISC <= RISC_LEI, "pierderea planificată depășește 2 % din cont"
ch = Chart(
candles=cds,
levels=[Level(INTRARE, "intrare 63.35 (close-ul confirmării)", GREEN, label_at="left"),
Level(SL, "SL 62.05", RED, label_at="left")],
zones=[Zone(HAM, CONF, "cele două bare care dau stopul", ORANGE)],
arrows=[
Arrow(HAM, "low-ul hammer-ului: 62.10\nsub el, cererea care a făcut\nfitilul nu mai există",
where="below", price=hammer.l, color=BLUE, dx=-176, dy=26),
Arrow(CONF, "riscul e distanța intrare - SL:\n63.35 - 62.05 = 1.30 $ pe acțiune",
where="above", color=GREY, dx=186, dy=-4),
],
scale=44.0, gap=26, body_w=13, left=64, width=680, vol_h=0,
title="Buy hammer — stopul și mărimea poziției (daily, ticker ilustrativ XYZ)",
)
svg = ch.render()
m = re.search(r'viewBox="0 0 (\d+) (\d+)"', svg)
W, H = int(m.group(1)), int(m.group(2))
# paranteza de risc, desenată de mână: stop -> intrare, cu textul în dreapta
OFF = (float(re.search(r'<line x1="24" y1="([\d.]+)"', svg).group(1)) - ch._y(ch.levels[0].price))
y_in, y_sl = ch._y(INTRARE) + OFF, ch._y(SL) + OFF
xp = ch._cx(len(cds) - 2)
brk = (f'<polyline points="{xp - 6:.1f},{y_in:.1f} {xp:.1f},{y_in:.1f} {xp:.1f},{y_sl:.1f} '
f'{xp - 6:.1f},{y_sl:.1f}" fill="none" stroke="{RED}" stroke-width="1.5"/>'
f'<text x="{xp + 6:.1f}" y="{(y_in + y_sl) / 2 + 4:.1f}" fill="{RED}" '
f'style="font-weight:bold">1R = 1.30 $</text>')
linii = [
("Mărimea poziției, cu cifrele lecției: 2 % dintr-un cont de 10.000 $ = 200 $ de risc.", "#333"),
(f"200 $ / 1.30 $ pe acțiune = {200 / RISC:.1f} → {ACTIUNI} de acțiuni (rotunjit în jos); "
f"pierderea maximă {ACTIUNI * RISC:.2f} $.", "#333"),
("Cei 5 cenți de sub low sunt marja folosită în tot capitolul pe exemplele construite de "
"mine; unde cifra vine din material, e spusă acolo.", GREY),
]
extra = 16 * len(linii) + 10
svg = svg.replace(f'viewBox="0 0 {W} {H}"', f'viewBox="0 0 {W} {H + extra}"')
svg = svg.replace("</svg>", brk + "".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 + extra}); risc {RISC}, {ACTIUNI} acțiuni")

View File

@@ -0,0 +1,47 @@
<svg viewBox="0 0 754 447" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="24" y="70" fill="#333" style="font-weight:bold">Buy hammer — stopul și mărimea poziției (daily, ticker ilustrativ XYZ)</text>
<rect x="257.3" y="169.0" width="49.0" height="77.6" fill="#b06000" fill-opacity="0.08" stroke="#b06000" stroke-width="1"/>
<text x="257.3" y="95.4" fill="#b06000" style="font-weight:bold">cele două bare care dau stopul</text>
<line x1="24" y1="183.6" x2="740" y2="183.6" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="30" y="177.6" fill="#188a3e">intrare 63.35 (close-ul confirmării)</text>
<line x1="24" y1="240.8" x2="740" y2="240.8" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="30" y="234.8" fill="#c00">SL 62.05</text>
<line x1="138.8" y1="91.2" x2="138.8" y2="128.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="132.3" y="102.2" width="13" height="13.2" fill="#188a3e"/>
<line x1="164.8" y1="91.2" x2="164.8" y2="163.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="158.3" y="102.2" width="13" height="48.4" fill="#c00"/>
<line x1="190.8" y1="139.6" x2="190.8" y2="194.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="184.3" y="150.6" width="13" height="30.8" fill="#c00"/>
<line x1="216.8" y1="157.2" x2="216.8" y2="194.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="210.3" y="168.2" width="13" height="13.2" fill="#188a3e"/>
<line x1="242.8" y1="157.2" x2="242.8" y2="210.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="236.3" y="168.2" width="13" height="28.6" fill="#c00"/>
<line x1="268.8" y1="185.8" x2="268.8" y2="238.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="262.3" y="185.8" width="13" height="11.0" fill="#188a3e"/>
<line x1="294.8" y1="177.0" x2="294.8" y2="192.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="288.3" y="183.6" width="13" height="2.2" fill="#188a3e"/>
<line x1="320.8" y1="152.8" x2="320.8" y2="196.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="314.3" y="163.8" width="13" height="19.8" fill="#188a3e"/>
<line x1="346.8" y1="135.2" x2="346.8" y2="177.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="340.3" y="146.2" width="13" height="17.6" fill="#188a3e"/>
<line x1="372.8" y1="117.6" x2="372.8" y2="159.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="366.3" y="128.6" width="13" height="17.6" fill="#188a3e"/>
<line x1="398.8" y1="117.6" x2="398.8" y2="150.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="392.3" y="128.6" width="13" height="8.8" fill="#c00"/>
<line x1="424.8" y1="104.4" x2="424.8" y2="150.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="418.3" y="115.4" width="13" height="22.0" fill="#188a3e"/>
<line x1="450.8" y1="91.2" x2="450.8" y2="128.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="444.3" y="102.2" width="13" height="13.2" fill="#188a3e"/>
<line x1="476.8" y1="78.0" x2="476.8" y2="115.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="470.3" y="89.0" width="13" height="13.2" fill="#188a3e"/>
<line x1="92.8" y1="294.6" x2="261.1" y2="244.9" stroke="#1a5fb4" stroke-width="1.8"/>
<polygon points="268.8,242.6 262.3,248.7 260.0,241.0" fill="#1a5fb4"/>
<text x="92.8" y="308.6" fill="#1a5fb4" text-anchor="middle" style="font-weight:bold">low-ul hammer-ului: 62.10</text>
<text x="92.8" y="322.6" fill="#1a5fb4" text-anchor="middle" style="font-weight:bold">sub el, cererea care a făcut</text>
<text x="92.8" y="336.6" fill="#1a5fb4" text-anchor="middle" style="font-weight:bold">fitilul nu mai există</text>
<line x1="480.8" y1="66.0" x2="301.7" y2="169.0" stroke="#555" stroke-width="1.8"/>
<polygon points="294.8,173.0 299.7,165.5 303.7,172.5" fill="#555"/>
<text x="480.8" y="47.0" fill="#555" text-anchor="middle" style="font-weight:bold">riscul e distanța intrare - SL:</text>
<text x="480.8" y="61.0" fill="#555" text-anchor="middle" style="font-weight:bold">63.35 - 62.05 = 1.30 $ pe acțiune</text>
<text x="24" y="367.6" fill="#188a3e">bara 20: confirmare — close 63.35 peste high-ul hammer-ului 63.30 (intrare)</text>
<polyline points="370.0,183.6 376.0,183.6 376.0,240.8 370.0,240.8" fill="none" stroke="#c00" stroke-width="1.5"/><text x="382.0" y="216.2" fill="#c00" style="font-weight:bold">1R = 1.30 $</text><text x="24" y="399" fill="#333">Mărimea poziției, cu cifrele lecției: 2 % dintr-un cont de 10.000 $ = 200 $ de risc.</text><text x="24" y="415" fill="#333">200 $ / 1.30 $ pe acțiune = 153.8 → 153 de acțiuni (rotunjit în jos); pierderea maximă 198.90 $.</text><text x="24" y="431" fill="#555">Cei 5 cenți de sub low sunt marja folosită în tot capitolul pe exemplele construite de mine; unde cifra vine din material, e spusă acolo.</text></svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,99 @@
#!/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, 34
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="24" fill="#333" style="font-weight:bold">'
'Aceeași candelă, două contexte — daily, exemplu construit</text>',
f'<text x="{PX[0]}" y="48" fill="{GREEN}" style="font-weight:bold">'
'DA — după o scădere: hammer</text>',
f'<text x="{PX[1]}" y="48" fill="{RED}" style="font-weight:bold">'
'NU — după o urcare: hanging man</text>',
f'<line x1="{PX[1] - 10}" y1="40" 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})")

View File

@@ -0,0 +1,76 @@
<svg viewBox="0 0 780 509" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="24" y="24" fill="#333" style="font-weight:bold">Aceeași candelă, două contexte — daily, exemplu construit</text>
<text x="24" y="48" fill="#188a3e" style="font-weight:bold">DA — după o scădere: hammer</text>
<text x="402" y="48" fill="#c00" style="font-weight:bold">NU — după o urcare: hanging man</text>
<line x1="392" y1="40" x2="392" y2="463" stroke="#ccc"/>
<g transform="translate(0,34)"><rect x="59.0" y="96.0" width="214.0" height="162.9" fill="#c00" fill-opacity="0.08" stroke="#c00" stroke-width="1"/>
<text x="59.0" y="91.0" fill="#c00" style="font-weight:bold">scădere de 9 candele</text>
<line x1="70.0" y1="104.0" x2="70.0" y2="122.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="64.0" y="107.9" width="12" height="10.4" fill="#c00"/>
<line x1="94.0" y1="114.4" x2="94.0" y2="143.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="88.0" y="118.3" width="12" height="20.8" fill="#c00"/>
<line x1="118.0" y1="135.2" x2="118.0" y2="161.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="112.0" y="139.1" width="12" height="18.2" fill="#c00"/>
<line x1="142.0" y1="145.6" x2="142.0" y2="161.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="136.0" y="149.5" width="12" height="7.8" fill="#188a3e"/>
<line x1="166.0" y1="145.6" x2="166.0" y2="184.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="160.0" y="149.5" width="12" height="31.2" fill="#c00"/>
<line x1="190.0" y1="176.8" x2="190.0" y2="202.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="184.0" y="180.7" width="12" height="18.2" fill="#c00"/>
<line x1="214.0" y1="189.8" x2="214.0" y2="202.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="208.0" y="193.7" width="12" height="5.2" fill="#188a3e"/>
<line x1="238.0" y1="189.8" x2="238.0" y2="221.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="232.0" y="193.7" width="12" height="23.4" fill="#c00"/>
<line x1="262.0" y1="213.2" x2="262.0" y2="250.9" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="256.0" y="217.1" width="12" height="29.9" fill="#c00"/>
<line x1="286.0" y1="240.5" x2="286.0" y2="271.7" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="280.0" y="240.5" width="12" height="6.5" fill="#188a3e"/>
<line x1="310.0" y1="235.3" x2="310.0" y2="244.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="304.0" y="239.2" width="12" height="1.6" fill="#188a3e"/>
<line x1="334.0" y1="223.6" x2="334.0" y2="243.1" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="328.0" y="227.5" width="12" height="11.7" fill="#188a3e"/>
<line x1="216.0" y1="335.7" x2="279.9" y2="280.9" stroke="#b06000" stroke-width="1.8"/>
<polygon points="286.0,275.7 282.5,283.9 277.3,277.9" fill="#b06000"/>
<text x="216.0" y="349.7" fill="#b06000" text-anchor="middle" style="font-weight:bold">hammer 63.30 / 62.10: prețul a fost dus la 62.10</text>
<text x="216.0" y="363.7" fill="#b06000" text-anchor="middle" style="font-weight:bold">și readus sus, la 63.30</text>
<line x1="214.0" y1="82.4" x2="305.7" y2="224.6" stroke="#188a3e" stroke-width="1.8"/>
<polygon points="310.0,231.3 302.3,226.7 309.0,222.4" fill="#188a3e"/>
<text x="214.0" y="63.4" fill="#188a3e" text-anchor="middle" style="font-weight:bold">close 63.35, peste high-ul hammer-ului:</text>
<text x="214.0" y="77.4" fill="#188a3e" text-anchor="middle" style="font-weight:bold">semnalul e valid, aici intri</text></g>
<g transform="translate(0,34)"><rect x="437.0" y="102.5" width="214.0" height="165.5" fill="#188a3e" fill-opacity="0.08" stroke="#188a3e" stroke-width="1"/>
<text x="437.0" y="97.5" fill="#188a3e" style="font-weight:bold">urcare de 9 candele</text>
<line x1="448.0" y1="241.8" x2="448.0" y2="260.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="442.0" y="245.7" width="12" height="10.4" fill="#188a3e"/>
<line x1="472.0" y1="223.6" x2="472.0" y2="249.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="466.0" y="227.5" width="12" height="18.2" fill="#188a3e"/>
<line x1="496.0" y1="205.4" x2="496.0" y2="231.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="490.0" y="209.3" width="12" height="18.2" fill="#188a3e"/>
<line x1="520.0" y1="205.4" x2="520.0" y2="218.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="514.0" y="209.3" width="12" height="5.2" fill="#c00"/>
<line x1="544.0" y1="182.0" x2="544.0" y2="218.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="538.0" y="185.9" width="12" height="28.6" fill="#188a3e"/>
<line x1="568.0" y1="163.8" x2="568.0" y2="189.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="562.0" y="167.7" width="12" height="18.2" fill="#188a3e"/>
<line x1="592.0" y1="143.0" x2="592.0" y2="171.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="586.0" y="146.9" width="12" height="20.8" fill="#188a3e"/>
<line x1="616.0" y1="127.4" x2="616.0" y2="150.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="610.0" y="131.3" width="12" height="15.6" fill="#188a3e"/>
<line x1="640.0" y1="110.5" x2="640.0" y2="135.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="634.0" y="114.4" width="12" height="16.9" fill="#188a3e"/>
<line x1="664.0" y1="107.9" x2="664.0" y2="139.1" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="658.0" y="107.9" width="12" height="6.5" fill="#188a3e"/>
<line x1="688.0" y1="104.0" x2="688.0" y2="145.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="682.0" y="107.9" width="12" height="33.8" fill="#c00"/>
<line x1="712.0" y1="137.8" x2="712.0" y2="161.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="706.0" y="141.7" width="12" height="15.6" fill="#c00"/>
<line x1="414.0" y1="366.0" x2="658.0" y2="148.4" stroke="#c00" stroke-width="1.8"/>
<polygon points="664.0,143.1 660.7,151.4 655.4,145.4" fill="#c00"/>
<text x="414.0" y="380.0" fill="#c00" text-anchor="middle" style="font-weight:bold">aceeași candelă 63.30 / 62.10, dar după o urcare:</text>
<text x="414.0" y="394.0" fill="#c00" text-anchor="middle" style="font-weight:bold">se numește hanging man și avertizează de scădere</text>
<line x1="618.0" y1="56.0" x2="681.2" y2="95.7" stroke="#c00" stroke-width="1.8"/>
<polygon points="688.0,100.0 679.1,99.1 683.4,92.4" fill="#c00"/>
<text x="618.0" y="37.0" fill="#c00" text-anchor="middle" style="font-weight:bold">close 62.00, sub low-ul ei: scăderea</text>
<text x="618.0" y="51.0" fill="#c00" text-anchor="middle" style="font-weight:bold">începe — nu era semnal de cumpărare</text></g>
<text x="24" y="483" fill="#555">Forma nu spune nimic singură: hammer-ul e pattern de întoarcere doar după o scădere. Aceeași bară după o urcare</text>
<text x="24" y="499" fill="#555">e hanging man și are sensul opus. Prețurile sunt construite; regula de context e a cursului.</text>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,104 @@
#!/usr/bin/env python3
"""Trigger-ul buy hammer: un singur DA și două feluri de NU.
Trei panouri cu ACELEAȘI șase bare (scădere + hammer 63.30 / 62.10) și cu o
singură bară diferită la final — candela următoare. Axa de preț e comună:
toate trei folosesc același `pmax`, verificat prin assert, deci liniile
63.30 și 62.10 cad la același y pe toate panourile.
Rulare: python3 gen/strategii/hammer_mbt10_bh_trigger.py
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
from pathlib import Path
from svg_candles import Arrow, Chart, from_closes
OUT = Path(__file__).with_suffix(".svg")
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
BAZA = [65.20, 64.60, 64.10, 63.60, 63.05, 63.30] # 5 = hammer
H_HAM, L_HAM = 63.30, 62.10
ULTIMA = {"DA": 63.35, "DEVREME": 63.20, "MORT": 62.00}
def serie(ultim):
closes = BAZA + [ultim]
w = [(0.15, 0.15)] * len(closes)
w[5] = (0.00, 0.95)
return from_closes(closes, wicks=w, start=65.70)
S = {k: serie(v) for k, v in ULTIMA.items()}
# --- verificări -------------------------------------------------------------
for k, cds in S.items():
for i in range(1, len(cds)):
assert abs(cds[i].o - cds[i - 1].c) < 1e-9, f"{k}: open[{i}] != close[{i-1}]"
h = cds[5]
assert (round(h.h, 2), round(h.l, 2)) == (H_HAM, L_HAM), (k, h)
assert (h.o - h.l) >= 2 * (h.c - h.o), f"{k}: bara 5 nu e hammer"
assert [round(c.c, 2) for c in cds[:6]] == BAZA, k
assert S["DA"][6].c > H_HAM, "DA: candela următoare nu închide peste high"
assert L_HAM <= S["DEVREME"][6].c <= H_HAM, "DEVREME: închiderea trebuie între low și high"
assert S["MORT"][6].c < L_HAM, "MORT: candela următoare nu închide sub low"
# --- layout -----------------------------------------------------------------
W, PW = 760, 240
PX = [12, 12 + PW + 14, 12 + 2 * (PW + 14)]
SCALE, TOP, SHIFT = 46.0, 96, 30
CFG = [
("DA", PX[0], GREEN, "DA — închide peste high",
Arrow(6, "close 63.35, peste 63.30:\naici intri", where="above", color=GREEN, dx=-70, dy=-18)),
("DEVREME", PX[1], RED, "NU — încă sub high",
Arrow(6, "close 63.20, sub 63.30:\nnu s-a întâmplat nimic,\naștepți mai departe",
where="above", color=RED, dx=-78, dy=-18)),
("MORT", PX[2], RED, "NU — închide sub low",
Arrow(6, "close 62.00, sub 62.10:\nvânzătorii au dus prețul\nsub fitil — setup mort",
where="below", color=RED, dx=-84, dy=26)),
]
bodies, inalt, charts = [], [], {}
for k, px, col, _, arr in CFG:
ch = Chart(candles=S[k], arrows=[arr], scale=SCALE, gap=20, body_w=11,
left=px + 46, width=px + PW, top=TOP)
body = ch._render()
assert f'viewBox="0 0 {px + PW} ' in body, f"panoul {k}: textul iese din cadru"
assert (ch.top, ch.left) == (TOP, px + 46), f"panoul {k}: Chart a mutat graficul"
charts[k] = ch
inalt.append(float(re.search(r'viewBox="0 0 [\d.]+ ([\d.]+)"', body).group(1)))
bodies.append(f'<g transform="translate(0,{SHIFT})">'
+ body.split(">", 1)[1].rsplit("</svg>", 1)[0].strip() + '</g>')
pmax = {k: c._pmax for k, c in charts.items()}
assert len(set(pmax.values())) == 1, f"panourile n-au aceeași axă: {pmax}"
y = lambda p: charts["DA"]._y(p) + SHIFT # noqa: E731
H = int(max(inalt)) + SHIFT + 44
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="12" y="20" fill="#333" style="font-weight:bold">Trigger-ul: contează unde se '
'închide candela următoare — daily, exemplu construit</text>',
]
for (k, px, col, titlu, _), corp in zip(CFG, bodies):
parts.append(f'<text x="{px}" y="{40}" fill="{col}" style="font-weight:bold">{titlu}</text>')
for p, c, txt in ((H_HAM, ORANGE, "high 63.30"), (L_HAM, BLUE, "low 62.10")):
yy = y(p)
parts.append(f'<line x1="{px}" y1="{yy:.1f}" x2="{px + PW}" y2="{yy:.1f}" '
f'stroke="{c}" stroke-width="1.3" stroke-dasharray="4 3"/>')
parts.append(f'<text x="{px + PW - 2}" y="{yy - 5:.1f}" fill="{c}" text-anchor="end">'
f'{txt}</text>')
parts.append(corp)
for px in PX[1:]:
parts.append(f'<line x1="{px - 7}" y1="34" x2="{px - 7}" y2="{H - 40}" stroke="#ccc"/>')
parts += [
f'<text x="12" y="{H - 22}" fill="{GREY}">Regula e a lecției de pattern: intri la close-ul '
'candelei următoare, dacă acea închidere e peste high-ul hammer-ului. O atingere</text>',
f'<text x="12" y="{H - 6}" fill="{GREY}">intraday peste 63.30, urmată de o închidere sub el, '
'nu e trigger. Prețurile sunt construite.</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})")

View File

@@ -0,0 +1,78 @@
<svg viewBox="0 0 760 487" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="12" y="20" fill="#333" style="font-weight:bold">Trigger-ul: contează unde se închide candela următoare — daily, exemplu construit</text>
<text x="12" y="40" fill="#188a3e" style="font-weight:bold">DA — închide peste high</text>
<line x1="12" y1="243.3" x2="252" y2="243.3" stroke="#b06000" stroke-width="1.3" stroke-dasharray="4 3"/>
<text x="250" y="238.3" fill="#b06000" text-anchor="end">high 63.30</text>
<line x1="12" y1="298.5" x2="252" y2="298.5" stroke="#1a5fb4" stroke-width="1.3" stroke-dasharray="4 3"/>
<text x="250" y="293.5" fill="#1a5fb4" text-anchor="end">low 62.10</text>
<g transform="translate(0,30)"><line x1="58.0" y1="96.0" x2="58.0" y2="132.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="52.5" y="102.9" width="11" height="23.0" fill="#c00"/>
<line x1="78.0" y1="119.0" x2="78.0" y2="160.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="72.5" y="125.9" width="11" height="27.6" fill="#c00"/>
<line x1="98.0" y1="146.6" x2="98.0" y2="183.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="92.5" y="153.5" width="11" height="23.0" fill="#c00"/>
<line x1="118.0" y1="169.6" x2="118.0" y2="206.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="112.5" y="176.5" width="11" height="23.0" fill="#c00"/>
<line x1="138.0" y1="192.6" x2="138.0" y2="231.7" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="132.5" y="199.5" width="11" height="25.3" fill="#c00"/>
<line x1="158.0" y1="213.3" x2="158.0" y2="268.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="152.5" y="213.3" width="11" height="11.5" fill="#188a3e"/>
<line x1="178.0" y1="204.1" x2="178.0" y2="220.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="172.5" y="211.0" width="11" height="2.3" fill="#188a3e"/>
<line x1="108.0" y1="70.0" x2="174.2" y2="193.1" stroke="#188a3e" stroke-width="1.8"/>
<polygon points="178.0,200.1 170.7,195.0 177.7,191.2" fill="#188a3e"/>
<text x="108.0" y="51.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">close 63.35, peste 63.30:</text>
<text x="108.0" y="65.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">aici intri</text></g>
<text x="266" y="40" fill="#c00" style="font-weight:bold">NU — încă sub high</text>
<line x1="266" y1="243.3" x2="506" y2="243.3" stroke="#b06000" stroke-width="1.3" stroke-dasharray="4 3"/>
<text x="504" y="238.3" fill="#b06000" text-anchor="end">high 63.30</text>
<line x1="266" y1="298.5" x2="506" y2="298.5" stroke="#1a5fb4" stroke-width="1.3" stroke-dasharray="4 3"/>
<text x="504" y="293.5" fill="#1a5fb4" text-anchor="end">low 62.10</text>
<g transform="translate(0,30)"><line x1="312.0" y1="96.0" x2="312.0" y2="132.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="306.5" y="102.9" width="11" height="23.0" fill="#c00"/>
<line x1="332.0" y1="119.0" x2="332.0" y2="160.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="326.5" y="125.9" width="11" height="27.6" fill="#c00"/>
<line x1="352.0" y1="146.6" x2="352.0" y2="183.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="346.5" y="153.5" width="11" height="23.0" fill="#c00"/>
<line x1="372.0" y1="169.6" x2="372.0" y2="206.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="366.5" y="176.5" width="11" height="23.0" fill="#c00"/>
<line x1="392.0" y1="192.6" x2="392.0" y2="231.7" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="386.5" y="199.5" width="11" height="25.3" fill="#c00"/>
<line x1="412.0" y1="213.3" x2="412.0" y2="268.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="406.5" y="213.3" width="11" height="11.5" fill="#188a3e"/>
<line x1="432.0" y1="206.4" x2="432.0" y2="224.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="426.5" y="213.3" width="11" height="4.6" fill="#c00"/>
<line x1="354.0" y1="70.0" x2="427.9" y2="195.5" stroke="#c00" stroke-width="1.8"/>
<polygon points="432.0,202.4 424.5,197.5 431.4,193.5" fill="#c00"/>
<text x="354.0" y="37.0" fill="#c00" text-anchor="middle" style="font-weight:bold">close 63.20, sub 63.30:</text>
<text x="354.0" y="51.0" fill="#c00" text-anchor="middle" style="font-weight:bold">nu s-a întâmplat nimic,</text>
<text x="354.0" y="65.0" fill="#c00" text-anchor="middle" style="font-weight:bold">aștepți mai departe</text></g>
<text x="520" y="40" fill="#c00" style="font-weight:bold">NU — închide sub low</text>
<line x1="520" y1="243.3" x2="760" y2="243.3" stroke="#b06000" stroke-width="1.3" stroke-dasharray="4 3"/>
<text x="758" y="238.3" fill="#b06000" text-anchor="end">high 63.30</text>
<line x1="520" y1="298.5" x2="760" y2="298.5" stroke="#1a5fb4" stroke-width="1.3" stroke-dasharray="4 3"/>
<text x="758" y="293.5" fill="#1a5fb4" text-anchor="end">low 62.10</text>
<g transform="translate(0,30)"><line x1="566.0" y1="96.0" x2="566.0" y2="132.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="560.5" y="102.9" width="11" height="23.0" fill="#c00"/>
<line x1="586.0" y1="119.0" x2="586.0" y2="160.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="580.5" y="125.9" width="11" height="27.6" fill="#c00"/>
<line x1="606.0" y1="146.6" x2="606.0" y2="183.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="600.5" y="153.5" width="11" height="23.0" fill="#c00"/>
<line x1="626.0" y1="169.6" x2="626.0" y2="206.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="620.5" y="176.5" width="11" height="23.0" fill="#c00"/>
<line x1="646.0" y1="192.6" x2="646.0" y2="231.7" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="640.5" y="199.5" width="11" height="25.3" fill="#c00"/>
<line x1="666.0" y1="213.3" x2="666.0" y2="268.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="660.5" y="213.3" width="11" height="11.5" fill="#188a3e"/>
<line x1="686.0" y1="206.4" x2="686.0" y2="280.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="680.5" y="213.3" width="11" height="59.8" fill="#c00"/>
<line x1="602.0" y1="336.0" x2="679.2" y2="288.2" stroke="#c00" stroke-width="1.8"/>
<polygon points="686.0,284.0 681.3,291.6 677.1,284.8" fill="#c00"/>
<text x="602.0" y="350.0" fill="#c00" text-anchor="middle" style="font-weight:bold">close 62.00, sub 62.10:</text>
<text x="602.0" y="364.0" fill="#c00" text-anchor="middle" style="font-weight:bold">vânzătorii au dus prețul</text>
<text x="602.0" y="378.0" fill="#c00" text-anchor="middle" style="font-weight:bold">sub fitil — setup mort</text></g>
<line x1="259" y1="34" x2="259" y2="447" stroke="#ccc"/>
<line x1="513" y1="34" x2="513" y2="447" stroke="#ccc"/>
<text x="12" y="465" fill="#555">Regula e a lecției de pattern: intri la close-ul candelei următoare, dacă acea închidere e peste high-ul hammer-ului. O atingere</text>
<text x="12" y="481" fill="#555">intraday peste 63.30, urmată de o închidere sub el, nu e trigger. Prețurile sunt construite.</text>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,114 @@
#!/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}")

View File

@@ -0,0 +1,75 @@
<svg viewBox="0 0 700 658" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="24" y="48" fill="#333" style="font-weight:bold">MBT-10, pasul „unde" — double bottom pe suportul weekly (exemplu construit)</text>
<rect x="263.0" y="273.0" width="132.0" height="68.5" fill="#b06000" fill-opacity="0.08" stroke="#b06000" stroke-width="1"/>
<text x="263.0" y="268.0" fill="#b06000" style="font-weight:bold">double bottom: 87.60 și 87.55</text>
<line x1="24" y1="335.0" x2="686" y2="335.0" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="30" y="329.0" fill="#1a5fb4">suport weekly 87.50</text>
<line x1="54.0" y1="56.0" x2="54.0" y2="87.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="48.0" y="62.0" width="12" height="18.0" fill="#c00"/>
<line x1="76.0" y1="74.0" x2="76.0" y2="117.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="70.0" y="80.0" width="12" height="30.0" fill="#c00"/>
<line x1="98.0" y1="104.0" x2="98.0" y2="141.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="92.0" y="110.0" width="12" height="24.0" fill="#c00"/>
<line x1="120.0" y1="116.0" x2="120.0" y2="141.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="114.0" y="122.0" width="12" height="12.0" fill="#188a3e"/>
<line x1="142.0" y1="116.0" x2="142.0" y2="174.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="136.0" y="122.0" width="12" height="45.0" fill="#c00"/>
<line x1="164.0" y1="161.0" x2="164.0" y2="207.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="158.0" y="167.0" width="12" height="33.0" fill="#c00"/>
<line x1="186.0" y1="194.0" x2="186.0" y2="231.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="180.0" y="200.0" width="12" height="24.0" fill="#c00"/>
<line x1="208.0" y1="218.0" x2="208.0" y2="264.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="202.0" y="224.0" width="12" height="33.0" fill="#c00"/>
<line x1="230.0" y1="251.0" x2="230.0" y2="297.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="224.0" y="257.0" width="12" height="33.0" fill="#c00"/>
<line x1="252.0" y1="284.0" x2="252.0" y2="321.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="246.0" y="290.0" width="12" height="24.0" fill="#c00"/>
<line x1="274.0" y1="308.0" x2="274.0" y2="332.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="268.0" y="314.0" width="12" height="15.0" fill="#c00"/>
<line x1="296.0" y1="302.0" x2="296.0" y2="330.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="290.0" y="308.0" width="12" height="21.0" fill="#188a3e"/>
<line x1="318.0" y1="281.0" x2="318.0" y2="315.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="312.0" y="287.0" width="12" height="21.0" fill="#188a3e"/>
<line x1="340.0" y1="281.0" x2="340.0" y2="309.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="334.0" y="287.0" width="12" height="15.0" fill="#c00"/>
<line x1="362.0" y1="296.0" x2="362.0" y2="327.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="356.0" y="302.0" width="12" height="18.0" fill="#c00"/>
<line x1="384.0" y1="314.0" x2="384.0" y2="333.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="378.0" y="320.0" width="12" height="10.5" fill="#c00"/>
<line x1="406.0" y1="305.0" x2="406.0" y2="332.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="400.0" y="311.0" width="12" height="19.5" fill="#188a3e"/>
<line x1="428.0" y1="287.0" x2="428.0" y2="318.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="422.0" y="293.0" width="12" height="18.0" fill="#188a3e"/>
<line x1="450.0" y1="269.0" x2="450.0" y2="300.5" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="444.0" y="278.0" width="12" height="15.0" fill="#188a3e"/>
<line x1="24" y1="574.5" x2="686" y2="574.5" stroke="#888"/>
<rect x="48.0" y="529.8" width="12" height="44.7" fill="#c00" opacity="0.55"/>
<rect x="70.0" y="531.3" width="12" height="43.2" fill="#c00" opacity="0.55"/>
<rect x="92.0" y="533.5" width="12" height="41.0" fill="#c00" opacity="0.55"/>
<rect x="114.0" y="537.3" width="12" height="37.2" fill="#188a3e" opacity="0.55"/>
<rect x="136.0" y="528.3" width="12" height="46.2" fill="#c00" opacity="0.55"/>
<rect x="158.0" y="525.4" width="12" height="49.1" fill="#c00" opacity="0.55"/>
<rect x="180.0" y="522.4" width="12" height="52.1" fill="#c00" opacity="0.55"/>
<rect x="202.0" y="519.4" width="12" height="55.1" fill="#c00" opacity="0.55"/>
<rect x="224.0" y="514.9" width="12" height="59.6" fill="#c00" opacity="0.55"/>
<rect x="246.0" y="510.5" width="12" height="64.0" fill="#c00" opacity="0.55"/>
<rect x="268.0" y="504.5" width="12" height="70.0" fill="#c00" opacity="0.55"/>
<rect x="290.0" y="528.3" width="12" height="46.2" fill="#188a3e" opacity="0.55"/>
<rect x="312.0" y="531.3" width="12" height="43.2" fill="#188a3e" opacity="0.55"/>
<rect x="334.0" y="533.5" width="12" height="41.0" fill="#c00" opacity="0.55"/>
<rect x="356.0" y="529.8" width="12" height="44.7" fill="#c00" opacity="0.55"/>
<rect x="378.0" y="525.4" width="12" height="49.1" fill="#c00" opacity="0.55"/>
<rect x="400.0" y="534.3" width="12" height="40.2" fill="#188a3e" opacity="0.55"/>
<rect x="422.0" y="531.3" width="12" height="43.2" fill="#188a3e" opacity="0.55"/>
<rect x="444.0" y="528.3" width="12" height="46.2" fill="#188a3e" opacity="0.55"/>
<text x="24" y="498.5" fill="#555">volum</text>
<line x1="124.0" y1="388.0" x2="266.4" y2="338.6" stroke="#555" stroke-width="1.8"/>
<polygon points="274.0,336.0 267.8,342.4 265.1,334.8" fill="#555"/>
<text x="124.0" y="402.0" fill="#555" text-anchor="middle" style="font-weight:bold">piciorul 1: low 87.60,</text>
<text x="124.0" y="416.0" fill="#555" text-anchor="middle" style="font-weight:bold">la 0,11 % peste suport</text>
<line x1="344.0" y1="427.5" x2="380.8" y2="344.8" stroke="#c00" stroke-width="1.8"/>
<polygon points="384.0,337.5 384.4,346.4 377.1,343.2" fill="#c00"/>
<text x="344.0" y="441.5" fill="#c00" text-anchor="middle" style="font-weight:bold">piciorul 2: low 87.55, cu 5 cenți mai jos,</text>
<text x="344.0" y="455.5" fill="#c00" text-anchor="middle" style="font-weight:bold">dar cu volum mai mic decât la piciorul 1 —</text>
<text x="344.0" y="469.5" fill="#c00" text-anchor="middle" style="font-weight:bold">vânzarea a slăbit (divergență de volum)</text>
<text x="24" y="610" fill="#333">Aici nu intri încă: diagrama arată doar ideea de bottom. MBT-10 e ultima piesă, și vine abia la close-ul unei bare.</text><text x="24" y="626" fill="#555">Cifrele 89.90 / 87.30 / 95.20 ale trade-ului sunt din exemplul construit al materialului;</text><text x="24" y="642" fill="#555">suportul weekly 87.50, pivotul daily 89.60 și structura barelor sunt ale mele.</text></svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""MBT-10 — singura bucată reconstituibilă: close peste pivotul daily.
Aceleași bare ca la pasul „unde" (importate din `hammer_mbt10_mbt_confluente`),
tăiate în jurul trigger-ului. Bara 18 atinge pivotul 89.60 în timpul zilei,
dar se închide sub el: nu e semnal. Bara 19 se închide la 89.90, peste pivot:
aici intri, la close.
Rulare: python3 gen/strategii/hammer_mbt10_mbt_ppd.py
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
sys.path.insert(0, "/workspace/atm-curs-dl/gen/strategii")
from pathlib import Path
from hammer_mbt10_mbt_confluente import CLOSE_I, INTRARE, PPD, SUP_W, serie
from svg_candles import Arrow, Chart, Level, Zone
OUT = Path(__file__).with_suffix(".svg")
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
cds = serie()
I0, I1 = 9, 22
w = cds[I0:I1 + 1]
sh = lambda i: i - I0 # noqa: E731
NU, DA = CLOSE_I - 1, CLOSE_I
assert cds[NU].h > PPD > cds[NU].c, "bara 18 nu mai e contraexemplul așteptat"
assert cds[DA].c > PPD and round(cds[DA].c, 2) == INTRARE
assert 0 <= sh(NU) < len(w) and sh(DA) < len(w), "fereastra nu prinde cele două bare"
assert max(c.c for c in cds[I0:DA]) < PPD, "o bară din fereastră închide deja peste pivot"
ch = Chart(
candles=w,
levels=[Level(PPD, "pivotul daily 89.60", BLUE),
Level(SUP_W, "suport weekly 87.50", GREY, label_at="left")],
zones=[Zone(sh(NU), sh(DA), "cele două zile care se compară", ORANGE)],
arrows=[
Arrow(sh(NU), "a atins 89.70 în timpul zilei,\ndar s-a închis la 89.40, sub pivot:\nnu e semnal",
where="below", color=RED, dx=-190, dy=40),
Arrow(sh(DA), "s-a închis la 89.90, peste pivot:\naici intri, la close-ul zilei",
where="above", color=GREEN, dx=-70, dy=-20),
],
scale=44.0, gap=26, body_w=13, left=64, width=680, vol_h=60, vol_label="volum",
title="MBT-10 — condiția de preț: close peste pivotul daily (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 = [
("Pivotul daily se recalculează în fiecare zi din maximul, minimul și închiderea zilei "
"precedente;", "#333"),
("linia desenată e valoarea din ziua intrării, 89.60, nu un nivel fix.", "#333"),
("Asta e tot ce se poate verifica din MBT-10 fără indicatorul proprietar — „prima "
"componentă\" din el,", GREY),
("cum îi spune materialul; restul formulei nu e publicat nicăieri.", 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})")

View File

@@ -0,0 +1,62 @@
<svg viewBox="0 0 686 554" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
<text x="24" y="48" fill="#333" style="font-weight:bold">MBT-10 — condiția de preț: close peste pivotul daily (exemplu construit)</text>
<rect x="293.0" y="149.2" width="49.0" height="79.8" fill="#b06000" fill-opacity="0.08" stroke="#b06000" stroke-width="1"/>
<text x="293.0" y="47.0" fill="#b06000" style="font-weight:bold">cele două zile care se compară</text>
<line x1="24" y1="179.2" x2="672" y2="179.2" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="658" y="173.2" fill="#1a5fb4" text-anchor="end">pivotul daily 89.60</text>
<line x1="24" y1="271.6" x2="672" y2="271.6" stroke="#555" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="30" y="265.6" fill="#555">suport weekly 87.50</text>
<line x1="70.5" y1="196.8" x2="70.5" y2="251.8" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="64.0" y="205.6" width="13" height="35.2" fill="#c00"/>
<line x1="96.5" y1="232.0" x2="96.5" y2="267.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="90.0" y="240.8" width="13" height="22.0" fill="#c00"/>
<line x1="122.5" y1="223.2" x2="122.5" y2="265.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="116.0" y="232.0" width="13" height="30.8" fill="#188a3e"/>
<line x1="148.5" y1="192.4" x2="148.5" y2="243.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="142.0" y="201.2" width="13" height="30.8" fill="#188a3e"/>
<line x1="174.5" y1="192.4" x2="174.5" y2="234.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="168.0" y="201.2" width="13" height="22.0" fill="#c00"/>
<line x1="200.5" y1="214.4" x2="200.5" y2="260.6" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="194.0" y="223.2" width="13" height="26.4" fill="#c00"/>
<line x1="226.5" y1="240.8" x2="226.5" y2="269.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="220.0" y="249.6" width="13" height="15.4" fill="#c00"/>
<line x1="252.5" y1="227.6" x2="252.5" y2="267.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="246.0" y="236.4" width="13" height="28.6" fill="#188a3e"/>
<line x1="278.5" y1="201.2" x2="278.5" y2="247.4" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="272.0" y="210.0" width="13" height="26.4" fill="#188a3e"/>
<line x1="304.5" y1="174.8" x2="304.5" y2="221.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="298.0" y="188.0" width="13" height="22.0" fill="#188a3e"/>
<line x1="330.5" y1="157.2" x2="330.5" y2="199.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="324.0" y="166.0" width="13" height="22.0" fill="#188a3e"/>
<line x1="356.5" y1="126.4" x2="356.5" y2="177.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="350.0" y="135.2" width="13" height="30.8" fill="#188a3e"/>
<line x1="382.5" y1="91.2" x2="382.5" y2="146.2" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="376.0" y="100.0" width="13" height="35.2" fill="#188a3e"/>
<line x1="408.5" y1="56.0" x2="408.5" y2="111.0" stroke="#1a1a1a" stroke-width="1.2"/>
<rect x="402.0" y="64.8" width="13" height="35.2" fill="#188a3e"/>
<line x1="24" y1="454.4" x2="672" y2="454.4" stroke="#888"/>
<rect x="64.0" y="400.6" width="13" height="53.8" fill="#c00" opacity="0.55"/>
<rect x="90.0" y="395.6" width="13" height="58.8" fill="#c00" opacity="0.55"/>
<rect x="116.0" y="415.6" width="13" height="38.8" fill="#188a3e" opacity="0.55"/>
<rect x="142.0" y="418.1" width="13" height="36.2" fill="#188a3e" opacity="0.55"/>
<rect x="168.0" y="420.0" width="13" height="34.4" fill="#c00" opacity="0.55"/>
<rect x="194.0" y="416.9" width="13" height="37.5" fill="#c00" opacity="0.55"/>
<rect x="220.0" y="413.1" width="13" height="41.2" fill="#c00" opacity="0.55"/>
<rect x="246.0" y="420.6" width="13" height="33.8" fill="#188a3e" opacity="0.55"/>
<rect x="272.0" y="418.1" width="13" height="36.2" fill="#188a3e" opacity="0.55"/>
<rect x="298.0" y="415.6" width="13" height="38.8" fill="#188a3e" opacity="0.55"/>
<rect x="324.0" y="394.4" width="13" height="60.0" fill="#188a3e" opacity="0.55"/>
<rect x="350.0" y="410.6" width="13" height="43.8" fill="#188a3e" opacity="0.55"/>
<rect x="376.0" y="413.1" width="13" height="41.2" fill="#188a3e" opacity="0.55"/>
<rect x="402.0" y="414.4" width="13" height="40.0" fill="#188a3e" opacity="0.55"/>
<text x="24" y="388.4" fill="#555">volum</text>
<line x1="114.5" y1="317.4" x2="297.3" y2="228.5" stroke="#c00" stroke-width="1.8"/>
<polygon points="304.5,225.0 299.1,232.1 295.6,224.9" fill="#c00"/>
<text x="114.5" y="331.4" fill="#c00" text-anchor="middle" style="font-weight:bold">a atins 89.70 în timpul zilei,</text>
<text x="114.5" y="345.4" fill="#c00" text-anchor="middle" style="font-weight:bold">dar s-a închis la 89.40, sub pivot:</text>
<text x="114.5" y="359.4" fill="#c00" text-anchor="middle" style="font-weight:bold">nu e semnal</text>
<line x1="260.5" y1="98.4" x2="324.2" y2="148.3" stroke="#188a3e" stroke-width="1.8"/>
<polygon points="330.5,153.2 321.7,151.4 326.7,145.1" fill="#188a3e"/>
<text x="260.5" y="79.4" fill="#188a3e" text-anchor="middle" style="font-weight:bold">s-a închis la 89.90, peste pivot:</text>
<text x="260.5" y="93.4" fill="#188a3e" text-anchor="middle" style="font-weight:bold">aici intri, la close-ul zilei</text>
<text x="24" y="490" fill="#333">Pivotul daily se recalculează în fiecare zi din maximul, minimul și închiderea zilei precedente;</text><text x="24" y="506" fill="#333">linia desenată e valoarea din ziua intrării, 89.60, nu un nivel fix.</text><text x="24" y="522" fill="#555">Asta e tot ce se poate verifica din MBT-10 fără indicatorul proprietar — „prima componentă" din el,</text><text x="24" y="538" fill="#555">cum îi spune materialul; restul formulei nu e publicat nicăieri.</text></svg>

After

Width:  |  Height:  |  Size: 5.7 KiB