Cea mai grava, si cea care a cerut refacerea seriei: exemplul central de MBT-10 era luat de pe 60 de minute si bagat in procedura de daily, cu barele numite "zile", desi sursa spune explicit de ce nu merge pe daily. Pe langa asta, suportul fusese schimbat din 88.00 (testat de trei ori, cu compresie, cum e in sursa) in 87.50 cu un double bottom si o divergenta de volum imprumutate din alt exemplu. Seria e refacuta pe exemplul materialului, cu assert pe cele trei atingeri ale lui 88.00 si pe compresia varfurilor. Adaosurile au fost scoase, nu doar marcate: cu ele in desen, suportul din sursa n-ar fi avut sens. Aritmetica a supravietuit neatinsa. Restul: stopul de 60.40 sta acum sub o structura reala; pivotul daily nu mai e o linie fixa peste tot graficul, ci un segment peste ziua intrarii; SL-ul de pe LABU respecta regula proprie de 5 centi; citatul de la A2 nu mai e dat ca al autorului; pragul de 1-2% isi spune originea (cursul da 0,5%, pe 60 min); o singura conventie de distanta, impartirea la nivel; swing low definit la fel in pas si in glosar. eticheta_libera a prins 7 suprapuneri reale. La bh_aplus a trebuit rulat pe fiecare panou separat: wrapper-ul le muta cu <g transform>, pe care unealta nu-l citeste - de notat pentru data viitoare. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
96 lines
4.6 KiB
Python
96 lines
4.6 KiB
Python
#!/usr/bin/env python3
|
|
"""MBT-10 — stopul sub structură și mărimea poziției (60 de minute).
|
|
|
|
Zoom pe barele 8-21 din seria pasului „unde" (importată). Stopul 87.30 nu e
|
|
ales la distanță, ci sub suportul weekly 88.00, cel testat de trei ori —
|
|
amândouă cifrele sunt ale materialului. Riscul iese 2.60 $ pe acțiune, iar
|
|
mărimea din regula de 2 % pe același cont de 10.000 $ folosit în Partea A:
|
|
200 / 2.60 = 76 de acțiuni.
|
|
|
|
Rulare: python3 gen/strategii/hammer_mbt10_mbt_stop.py
|
|
"""
|
|
import re
|
|
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
|
|
sys.path.insert(0, "/workspace/atm-curs-dl/gen")
|
|
sys.path.insert(0, "/workspace/atm-curs-dl/gen/strategii")
|
|
from pathlib import Path
|
|
from eticheta_libera import eticheta_libera
|
|
from hammer_mbt10_mbt_confluente import (CLOSE_I, INTRARE, SL, SUP_W, TESTE,
|
|
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 = 8, 21
|
|
w = cds[I0:I1 + 1]
|
|
sh = lambda i: i - I0 # noqa: E731
|
|
RISC = round(INTRARE - SL, 2)
|
|
CONT, PROCENT = 10_000, 0.02
|
|
RISC_LEI = CONT * PROCENT
|
|
ACTIUNI = int(RISC_LEI // RISC)
|
|
|
|
# --- verificări -------------------------------------------------------------
|
|
assert RISC == 2.60, RISC
|
|
assert ACTIUNI == 76 and ACTIUNI * RISC <= RISC_LEI, (ACTIUNI, ACTIUNI * RISC)
|
|
assert SL < SUP_W <= min(cds[t].l for t in TESTE), \
|
|
"stopul trebuie să stea sub suport, iar suportul la sau sub cele trei teste"
|
|
assert SL < min(c.l for c in w), "linia stopului trebuie să stea sub toate fitilele"
|
|
assert round(cds[CLOSE_I].c, 2) == INTRARE
|
|
assert I0 <= TESTE[0] and TESTE[-1] <= I1 and CLOSE_I <= I1, \
|
|
"fereastra nu prinde tot ce trebuie"
|
|
|
|
ch = Chart(
|
|
candles=w,
|
|
levels=[Level(INTRARE, "intrare 89.90 (close-ul barei)", GREEN, label_at="right"),
|
|
Level(SUP_W, "suport weekly 88.00, testat de trei ori", BLUE),
|
|
Level(SL, "SL 87.30", RED, label_at="left")],
|
|
# fără etichetă pe zonă: eticheta ei cădea peste linia intrării, iar
|
|
# săgeata de mai jos spune deja ce e structura
|
|
zones=[Zone(sh(TESTE[0]), sh(TESTE[-1]), "", ORANGE)],
|
|
arrows=[
|
|
Arrow(sh(TESTE[-1]), "sub 87.30 nu mai ține suportul weekly:\nideea de la pasul 1 a murit,\nnu mai ai ce aștepta",
|
|
price=SL, where="below", color=RED, dx=-40, dy=34),
|
|
],
|
|
scale=40.0, gap=26, body_w=13, left=64, width=680, vol_h=0,
|
|
title="MBT-10 — stopul sub structură, pe 60 de minute",
|
|
)
|
|
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\.0" 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(w) - 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 = 2.60 $</text>')
|
|
linii = [
|
|
(f"Mărimea, cu aceeași regulă ca la buy hammer: 2 % dintr-un cont de 10.000 $ = 200 $;",
|
|
"#333"),
|
|
(f"200 / 2.60 = {RISC_LEI / RISC:.1f} → {ACTIUNI} de acțiuni, pierdere maximă "
|
|
f"{ACTIUNI * RISC:.2f} $.", "#333"),
|
|
("87.30 și suportul weekly 88.00 sunt cifrele materialului, pe exemplul lui de 60 de "
|
|
"minute —", GREY),
|
|
("nu marja mea de 5 cenți. Materialul nu dă niciun procent fix de stop pentru MBT-10:",
|
|
GREY),
|
|
("stopul numește structura de sub el.", GREY),
|
|
]
|
|
add = 16 * len(linii) + 10
|
|
svg = svg.replace(f'viewBox="0 0 {W} {H}"', f'viewBox="0 0 {W} {H + add}"')
|
|
# primul rând al unei săgeți e locul de care se prinde coada ei: acolo
|
|
# suprapunerea e prin construcție, nu o greșeală. Verificăm restul.
|
|
eticheta_libera(svg, "mbt_stop",
|
|
{"ideea de la pasul 1 a murit,", "nu mai ai ce aștepta"}, rects=True)
|
|
# etichetele de nivel stau lipite de linia lor prin construcție
|
|
eticheta_libera(svg, "mbt_stop",
|
|
{"intrare 89.90 (close-ul barei)", "suport weekly 88.00, testat de trei ori",
|
|
"SL 87.30"}, rects=True, segmente=False)
|
|
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 + add}); risc {RISC}, {ACTIUNI} acțiuni")
|