m2d: diagramele refacute; ansamblul primeste corespondenta de TF
Ansamblul arata acum 15 min si 3 min ca descompunere reala (k=5, cu assert), cu caseta punctata, ghidaje si nivelul comun legat prin conector — sablonul din buy_doji_perechi_tf. Noi, pentru pasii care nu aveau diagrama: directie (15 min ramane in Buy vs. se inchide Sell), trigger (bara inchisa peste capat vs. atinsa doar cu fitilul, plus al doilea semnal marcat "nu mai intri"), stop (cele 4 bare si alternativa 2xATR, cu cifrele SPY din curs), iesire (TP1 plus bull trail, long si short, oglinda calculata nu desenata din ochi). Secventa era din polilinii desenate de mana — rescrisa pe serie. Stopul e fix pe extrema celor 4 bare, fara marja: asa spune cursul aici, spre deosebire de 01_buy_doji. Diferenta trebuie spusa in text. Textul capitolului 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
@@ -1,136 +1,390 @@
|
||||
"""Diagrama de ansamblu M2D (strategii/03_m2d.md, marcajul `ansamblu`).
|
||||
#!/usr/bin/env python3
|
||||
"""M2D — tot trade-ul, pe perechea 15 min → 3 min, cu lupă.
|
||||
|
||||
„Setup M2D LONG complet pe TF mic (3 min), cu TF mare (15 min) în Buy":
|
||||
urcare -> pullback (M = Sell Momentum) -> trigger (A = primul Buy) -> intrare
|
||||
-> SL de 4 candele -> TP1 la 1:1 -> continuare -> vârf -> ieșire pe bull trail.
|
||||
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: ansamblu -->`.
|
||||
|
||||
Toate close-urile, wick-urile, volumele și nivelurile vin din
|
||||
`gen/strategii/m2d_ansamblu.spec.txt`. Seria e construită (exemplu generic,
|
||||
fără ticker), la scara 1.00 $ risc / 2.2R randament — nu e un trade real.
|
||||
Tiparul e cel din `buy_doji_perechi_tf.py`: panoul din dreapta NU e o serie
|
||||
care vine după cea din stânga — e **descompunerea reală** a ultimelor 4
|
||||
candele de 15 minute. O candelă de 15 min = k = 5 candele de 3 min, cu
|
||||
open, close, max(high) și min(low) care coincid, verificat bară cu bară.
|
||||
|
||||
Rulează:
|
||||
python3 gen/strategii/m2d_ansamblu.py
|
||||
Scrie lângă el `m2d_ansamblu.svg`.
|
||||
Sursa de adevăr e seria fină (`FINE`, 3 min). Candelele de 15 min din zona
|
||||
mărită se CALCULEAZĂ din ea prin agregare; barele de dinainte (`BASE`) sunt
|
||||
date separat și se leagă de lupă prin close == open.
|
||||
|
||||
Toate cifrele din desen ies din serii. Regula de stop din tot capitolul:
|
||||
stopul stă FIX pe extrema ultimelor 4 candele de pe TF mic, fără marjă.
|
||||
|
||||
Rulare: python3 gen/strategii/m2d_ansamblu.py
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, "/workspace/atm-curs-dl")
|
||||
from svg_candles import Chart, Level, Mark, MA, from_closes # noqa: E402
|
||||
OUT = Path(__file__).with_suffix(".svg")
|
||||
W = 720
|
||||
K = 5 # 5 candele de 3 min într-una de 15 min
|
||||
NZ = 4 # câte candele de 15 min sunt mărite
|
||||
STOP_BARS = 4 # stopul = extrema ultimelor 4 bare de pe TF mic
|
||||
PULLBACK_N = 9 # barele 0..8 = pullback-ul (M)
|
||||
TRIG = 9 # bara de trigger (A) pe TF mic
|
||||
|
||||
OUT = Path(__file__).resolve().parent / "m2d_ansamblu.svg"
|
||||
|
||||
GRAY, RED, GREEN, BLUE, ORANGE = "#777", "#c00", "#188a3e", "#1a5fb4", "#b06000"
|
||||
|
||||
# ---------------------------------------------------------------- seria (32 bare)
|
||||
CLOSES = [
|
||||
96.8, 97.2, 97.7, 98.1, 98.6, 99.1, 99.5, 100.0, # 0-7 urcare
|
||||
99.8, 99.4, 99.0, 99.2, 98.9, 99.15, 99.3, # 8-14 pullback (M)
|
||||
99.8, 100.2, # 15-16 trigger (A)
|
||||
100.7, 101.2, 101.6, 102.0, 102.4, 102.7, 103.0, # 17-23 continuare
|
||||
103.3, 103.1, 102.8, 102.7, 102.9, 102.5, 102.2, 102.0, # 24-31 vârf + violare
|
||||
]
|
||||
assert len(CLOSES) == 32, len(CLOSES)
|
||||
|
||||
# fitile (sus, jos); jos mai mari pe 10-12, ca minimul de 4 candele (11:15) să
|
||||
# fie clar sub intrare, la exact 98.80 (candela 12).
|
||||
WICKS = (
|
||||
[(0.15, 0.10)] * 8 # 0-7
|
||||
+ [(0.10, 0.15), (0.10, 0.20), (0.10, 0.15), # 8-10
|
||||
(0.10, 0.15), (0.10, 0.10), (0.10, 0.05), (0.10, 0.10)] # 11-14
|
||||
+ [(0.15, 0.10), (0.15, 0.10)] # 15-16
|
||||
+ [(0.15, 0.10)] * 7 # 17-23
|
||||
+ [(0.20, 0.10), (0.10, 0.15), (0.10, 0.15), (0.12, 0.15), # 24-27
|
||||
(0.10, 0.15), (0.10, 0.15), (0.10, 0.15), (0.10, 0.20)] # 28-31
|
||||
)
|
||||
assert len(WICKS) == 32, len(WICKS)
|
||||
|
||||
VOLS = (
|
||||
[62, 66, 60, 68, 64, 70, 66, 74] # 0-7 trend
|
||||
+ [44, 40, 38, 36, 34, 33, 35] # 8-14 pullback mic
|
||||
+ [82, 88] # 15-16 trigger
|
||||
+ [72, 70, 74, 68, 72, 66, 70] # 17-23 trend
|
||||
+ [76, 64, 60, 58, 62, 56, 54, 66] # 24-31 vârf + ieșire
|
||||
)
|
||||
assert len(VOLS) == 32, len(VOLS)
|
||||
|
||||
cds = from_closes(CLOSES, wicks=WICKS, vols=VOLS, start=96.4)
|
||||
|
||||
# ---------------------------------------------------------------- assert-urile din spec
|
||||
entry = cds[15].c # 1. intrarea = close-ul trigger-ului
|
||||
SL = min(c.l for c in cds[11:15]) # 2. minimul ultimelor 4 dinainte
|
||||
TP1 = entry + (entry - SL) # 4. TP1 exact 1:1
|
||||
|
||||
assert entry == round(cds[15].c, 2), (entry, cds[15].c)
|
||||
assert SL == min(c.l for c in cds[11:15]), SL
|
||||
assert SL < entry, (SL, entry)
|
||||
assert abs(TP1 - (entry + (entry - SL))) < 1e-6
|
||||
for a, b in zip(cds, cds[1:]): # 5. serie continuă, fără goluri
|
||||
assert a.c == b.o, (a.c, b.o)
|
||||
assert cds[15].c > cds[14].c # 6. trigger în sus după pullback
|
||||
assert any(c.c < c.o for c in cds[8:15]) # 7. pullback = Sell
|
||||
assert any(c.c > c.o for c in cds[0:8]) # context în sus
|
||||
exit_price = cds[31].c
|
||||
assert exit_price > entry # 8. ieșirea e peste intrare
|
||||
|
||||
# bull trail = low-ul ultimei candele care a închis peste high-ul precedentei
|
||||
qual = [i for i in range(1, 31) if cds[i].c > cds[i - 1].h]
|
||||
assert qual and qual[-1] == 24, qual
|
||||
bull = cds[24].l
|
||||
assert cds[31].c < bull, (cds[31].c, bull) # finala închide sub linie = ieșire aici
|
||||
|
||||
r_mult = (exit_price - entry) / (entry - SL) # 9. R-ul afișat
|
||||
assert round(r_mult, 1) == 2.2, r_mult
|
||||
|
||||
# ---------------------------------------------------------------- niveluri, etichete, marks
|
||||
levels = [
|
||||
Level(entry, f"intrare {entry:.2f}", GREEN, label_at="left"),
|
||||
Level(SL, f"SL {SL:.2f} (4 candele)", RED, label_at="right"),
|
||||
Level(TP1, f"TP1 {TP1:.2f} = 1:1", BLUE, label_at="right"),
|
||||
]
|
||||
assert [round(lv.price, 2) for lv in levels] == [99.80, 98.80, 100.80]
|
||||
|
||||
exit_text = f"ieșire {exit_price:.2f} pe bull trail ({r_mult:.1f}R)"
|
||||
assert f"{r_mult:.1f}R" in exit_text
|
||||
|
||||
marks = [
|
||||
Mark(0, "TF mare (15 min) în Buy", BLUE, "above", dy=-227),
|
||||
Mark(11, "M: Sell Momentum (pullback)", RED, "below"),
|
||||
Mark(15, "A: primul Buy = trigger", GREEN, "above", dy=-122),
|
||||
# „vârf" stă sub candela 24: deasupra ei, orice text de la y-ul vârfului se
|
||||
# calcă pe titlul din stânga-sus (ambele pornesc din `top`).
|
||||
Mark(24, "vârf 103.30", GRAY, "below", dy=25),
|
||||
Mark(31, "close sub bull trail = ieși", RED, "below", dy=55),
|
||||
Mark(31, exit_text, RED, "below", dy=73),
|
||||
# --- seria fină (3 min), 20 de bare: (open, high, low, close) --------------
|
||||
FINE = [
|
||||
(100.60, 100.70, 100.40, 100.45), (100.45, 100.50, 100.25, 100.30),
|
||||
(100.30, 100.35, 100.15, 100.20), (100.20, 100.25, 100.05, 100.10),
|
||||
(100.10, 100.15, 100.00, 100.05), (100.05, 100.10, 99.95, 100.00),
|
||||
(100.00, 100.05, 99.92, 99.95), (99.95, 100.00, 99.90, 99.98),
|
||||
(99.98, 100.08, 99.94, 100.02), # 8: capătul pullback-ului
|
||||
(100.02, 100.45, 100.00, 100.40), # 9: A = trigger, intri
|
||||
(100.40, 100.60, 100.35, 100.55), (100.55, 100.75, 100.50, 100.70),
|
||||
(100.70, 101.00, 100.65, 100.95), # 12: TP1 atins
|
||||
(100.95, 101.10, 100.88, 101.05), (101.05, 101.15, 100.95, 101.00),
|
||||
(101.00, 101.40, 100.95, 101.35), (101.35, 101.55, 101.25, 101.45),
|
||||
(101.45, 101.50, 101.20, 101.25),
|
||||
(101.25, 101.30, 101.05, 101.10), # 18: close sub trail = ieși
|
||||
(101.10, 101.15, 100.90, 100.95),
|
||||
]
|
||||
|
||||
caption = (f"Serie construită (32 bare, 3 min). R = ({exit_price:.2f} − {entry:.2f}) / "
|
||||
f"{entry - SL:.2f} = {r_mult:.1f}R.")
|
||||
assert f"{r_mult:.1f}R" in caption
|
||||
# --- barele de 15 min dinaintea lupei; ultima poartă semnalul Buy Momentum --
|
||||
BASE = [
|
||||
(98.00, 98.35, 97.85, 98.25), (98.25, 98.70, 98.15, 98.60),
|
||||
(98.60, 99.10, 98.50, 99.00), (99.00, 99.45, 98.90, 99.30),
|
||||
(99.30, 99.95, 99.20, 99.85),
|
||||
(99.85, 100.75, 99.80, 100.60), # 5: Buy Momentum pe 15 min
|
||||
]
|
||||
SIG_B = 5 # candela de 15 min cu semnalul
|
||||
|
||||
ch = Chart(
|
||||
candles=cds, levels=levels, marks=marks,
|
||||
mas=[MA(20, ORANGE, dash="4 3", text="SMA-20")],
|
||||
scale=52.0, gap=16, body_w=9, left=44, width=720, vol_h=70,
|
||||
vol_label="volum",
|
||||
title="Simbol construit — 3 min (TF mare 15 min în Buy)",
|
||||
caption=caption,
|
||||
)
|
||||
svg = ch.render()
|
||||
|
||||
# bull trail: nu e un `Level` (spec-ul cere exact trei niveluri), deci se
|
||||
# injectează ca linie separată, la aceeași scară (`ch._y`).
|
||||
yb = ch._y(bull)
|
||||
bull_layer = (
|
||||
f'<line x1="24" y1="{yb:.1f}" x2="{ch.width - 14}" y2="{yb:.1f}" '
|
||||
f'stroke="{ORANGE}" stroke-width="1.5" stroke-dasharray="2 3"/>'
|
||||
f'<text x="{ch.width - 28}" y="{yb - 6:.1f}" fill="{ORANGE}" '
|
||||
f'text-anchor="end">bull trail {bull:.2f}</text>'
|
||||
)
|
||||
i = svg.index(">") + 1
|
||||
svg = svg[:i] + "\n " + bull_layer + svg[i:]
|
||||
def aggregate(fine, k, n):
|
||||
out_ = []
|
||||
for j in range(n):
|
||||
part = fine[j * k:(j + 1) * k]
|
||||
out_.append((part[0][0], max(b[1] for b in part),
|
||||
min(b[2] for b in part), part[-1][3]))
|
||||
return out_
|
||||
|
||||
assert svg.count("\n\n") == 0, "linie goală în SVG rupe blocul din markdown"
|
||||
OUT.write_text(svg)
|
||||
print(f"scris {OUT.name}: {len(cds)} candele, intrare {entry:.2f}, SL {SL:.2f}, "
|
||||
f"TP1 {TP1:.2f}, ieșire {exit_price:.2f} = {r_mult:.1f}R, bull trail {bull:.2f}")
|
||||
|
||||
def eq(a, b):
|
||||
return abs(a - b) < 0.005
|
||||
|
||||
|
||||
ZOOM = aggregate(FINE, K, NZ)
|
||||
BIG = BASE + ZOOM
|
||||
|
||||
# ---------------------------------------------------------------- verificări
|
||||
for name, bars in (("15 min", BIG), ("3 min", FINE)):
|
||||
for i, (o, h, l, c) in enumerate(bars):
|
||||
assert h >= max(o, c) and l <= min(o, c), f"{name}[{i}]: high/low incoerent"
|
||||
if i:
|
||||
assert eq(o, bars[i - 1][3]), f"{name}[{i}]: open != close precedent"
|
||||
assert len(FINE) == K * NZ, len(FINE)
|
||||
|
||||
# (1) unde cad granițele candelelor de 15 min peste poveste — exact ce spune
|
||||
# textul capitolului, și poate fi fals
|
||||
span = len({i // K for i in range(PULLBACK_N)})
|
||||
assert span == 2, f"pullback-ul se întinde peste {span} candele de 15 min, nu 2"
|
||||
trig_big = TRIG // K
|
||||
assert trig_big == 1, f"trigger-ul cade în candela mare {trig_big}"
|
||||
assert eq(FINE[0][0], BASE[SIG_B][3]), "open-ul primei bare fine != close-ul semnalului"
|
||||
|
||||
# (2) pullback-ul (M): coboară, dar NU rupe low-ul candelei de 15 min din care
|
||||
# a pornit mișcarea — definiția ancorată din mini-glosar
|
||||
PULL = FINE[:PULLBACK_N]
|
||||
ref_low = BASE[SIG_B][2]
|
||||
pull_low = min(b[2] for b in PULL)
|
||||
assert PULL[0][3] > PULL[-1][3], "pullback-ul nu coboară"
|
||||
assert pull_low > ref_low, f"pullback-ul rupe low-ul de referință ({pull_low} <= {ref_low})"
|
||||
|
||||
# (3) trigger-ul (A). Săgeata vine dintr-un indicator proprietar, deci forma
|
||||
# ei pe desen e construită de mine: bara de trigger e PRIMA din pullback
|
||||
# care se închide peste high-urile ultimelor LOOK bare. Verific că e
|
||||
# într-adevăr prima — altfel desenul ar contrazice regula „primul semnal".
|
||||
LOOK = 3
|
||||
|
||||
|
||||
def rupe(i):
|
||||
return i >= LOOK and FINE[i][3] > max(b[1] for b in FINE[i - LOOK:i])
|
||||
|
||||
|
||||
assert rupe(TRIG), "bara de trigger nu rupe high-urile barelor dinainte"
|
||||
assert not any(rupe(i) for i in range(LOOK, TRIG)), \
|
||||
"o bară dinaintea trigger-ului rupea deja — nu mai e primul semnal"
|
||||
|
||||
# (4) trade-ul
|
||||
ENTRY = FINE[TRIG][3]
|
||||
SL = min(b[2] for b in FINE[TRIG - STOP_BARS + 1:TRIG + 1])
|
||||
RISK = round(ENTRY - SL, 2)
|
||||
TP1 = round(ENTRY + RISK, 2)
|
||||
assert eq(SL, pull_low), "stopul nu e minimul pullback-ului"
|
||||
assert eq(SL, min(b[2] for b in FINE)), "stopul nu e minimul zonei mărite"
|
||||
TP_BAR = next(i for i in range(TRIG + 1, len(FINE)) if FINE[i][1] >= TP1 - 1e-9)
|
||||
assert TP_BAR == 12, TP_BAR
|
||||
|
||||
# (5) bull trail: low-ul ultimei bare care s-a închis peste high-ul precedentei;
|
||||
# ieșirea = prima bară care se ÎNCHIDE sub linie
|
||||
trail, EXIT_BAR = None, None
|
||||
for i in range(1, len(FINE)):
|
||||
if trail is not None and FINE[i][3] < trail:
|
||||
EXIT_BAR = i
|
||||
break
|
||||
if i > TRIG and FINE[i][3] > FINE[i - 1][1]:
|
||||
trail = FINE[i][2]
|
||||
TRAIL = trail
|
||||
EXIT_BAR = EXIT_BAR if EXIT_BAR is not None else len(FINE) - 1
|
||||
EXIT = FINE[EXIT_BAR][3]
|
||||
assert (TRAIL, EXIT_BAR) == (101.25, 18), (TRAIL, EXIT_BAR)
|
||||
assert EXIT > ENTRY, "ieșirea pe trail e sub intrare"
|
||||
R = (EXIT - ENTRY) / RISK
|
||||
assert round(R, 1) == 1.4, R
|
||||
# wick-uri sub linie nu scot: bara 17 coboară sub trail, dar se închide deasupra
|
||||
assert FINE[17][2] < TRAIL <= FINE[17][3], "bara 17 nu mai ilustrează wick sub trail"
|
||||
|
||||
LEVEL = BASE[SIG_B][3] # nivelul comun celor două panouri
|
||||
assert eq(LEVEL, FINE[0][0])
|
||||
|
||||
# ---------------------------------------------------------------- desen
|
||||
GREEN, RED, INK, BLUE, GRAY = "#188a3e", "#c00", "#333", "#1a5fb4", "#888"
|
||||
LINK, CYAN = "#aaa", "#0891b2"
|
||||
PLOT_H = 168
|
||||
BX0, BGAP, BW = 104, 15, 9
|
||||
SX0, SGAP, SW = 372, 11, 7
|
||||
FRAME_L = SX0 - 8
|
||||
COL_X = 600
|
||||
MIDX = FRAME_L - 20
|
||||
PAD = 0.06
|
||||
|
||||
out, LABELS = [], []
|
||||
|
||||
|
||||
def text(x, y, s, fill=INK, anchor="start", bold=False, size=12):
|
||||
st = [f"font-size:{size}px"] + (["font-weight:bold"] if bold else [])
|
||||
a = f' text-anchor="{anchor}"' if anchor != "start" else ""
|
||||
w = len(s) * (5.7 if size >= 12 else size * 0.5)
|
||||
x0 = x if anchor == "start" else (x - w / 2 if anchor == "middle" else x - w)
|
||||
assert 4 <= x0 and x0 + w <= W - 4, f"text iese din viewBox: {s!r} ({x0:.0f}..{x0 + w:.0f})"
|
||||
LABELS.append((x0, x0 + w, y, s))
|
||||
out.append(f'<text x="{x:.1f}" y="{y:.1f}" fill="{fill}"{a} '
|
||||
f'style="{";".join(st)}">{s}</text>')
|
||||
|
||||
|
||||
def hline(x1, x2, y, color, dash, width=1.5):
|
||||
out.append(f'<line x1="{x1:.1f}" y1="{y:.1f}" x2="{x2:.1f}" y2="{y:.1f}" '
|
||||
f'stroke="{color}" stroke-width="{width}" stroke-dasharray="{dash}"/>')
|
||||
|
||||
|
||||
def line(x1, y1, x2, y2, color, dash="", width=1.2, marker=""):
|
||||
d = f' stroke-dasharray="{dash}"' if dash else ""
|
||||
m = f' marker-end="url(#{marker})"' if marker else ""
|
||||
out.append(f'<line x1="{x1:.1f}" y1="{y1:.1f}" x2="{x2:.1f}" y2="{y2:.1f}" '
|
||||
f'stroke="{color}" stroke-width="{width}"{d}{m}/>')
|
||||
|
||||
|
||||
def rect(x0_, y0_, x1, y1, color, fill_op=0.10, dash=""):
|
||||
d = f' stroke-dasharray="{dash}"' if dash else ""
|
||||
out.append(f'<rect x="{x0_:.1f}" y="{y0_:.1f}" width="{x1 - x0_:.1f}" '
|
||||
f'height="{y1 - y0_:.1f}" fill="{color}" fill-opacity="{fill_op}" '
|
||||
f'stroke="{color}" stroke-width="1.2"{d}/>')
|
||||
|
||||
|
||||
def candles(bars, x0, gap, yf, bw):
|
||||
for i, (o, h, l, c) in enumerate(bars):
|
||||
cx = x0 + i * gap
|
||||
color = GREEN if c >= o else RED
|
||||
line(cx, yf(h), cx, yf(l), "#1a1a1a", width=1.2)
|
||||
top_ = yf(max(o, c))
|
||||
hh = max(yf(min(o, c)) - top_, 1.6)
|
||||
out.append(f'<rect x="{cx - bw / 2:.1f}" y="{top_:.1f}" width="{bw}" '
|
||||
f'height="{hh:.1f}" fill="{color}"/>')
|
||||
|
||||
|
||||
def stack(items, x_line):
|
||||
y_prev = None
|
||||
for y, lines, fill in sorted(items, key=lambda t: t[0]):
|
||||
y_lab = y if y_prev is None or y >= y_prev + 16 else y_prev + 16
|
||||
if y_lab - y > 2:
|
||||
out.append(f'<path d="M{x_line + 2:.1f},{y - 4:.1f} H{x_line + 7:.1f} '
|
||||
f'L{COL_X - 4:.1f},{y_lab - 4:.1f}" fill="none" stroke="{fill}" '
|
||||
f'stroke-width="0.8" stroke-opacity="0.8"/>')
|
||||
else:
|
||||
line(x_line + 2, y - 4, COL_X - 4, y_lab - 4, fill, width=0.8)
|
||||
for j, s in enumerate(lines):
|
||||
text(COL_X, y_lab + j * 14, s, fill=fill, size=10)
|
||||
y_prev = y_lab + (len(lines) - 1) * 14
|
||||
|
||||
|
||||
def seg_dist(p, a, b):
|
||||
(px, py), (ax, ay), (bx, by) = p, a, b
|
||||
dx, dy = bx - ax, by - ay
|
||||
t = 0.0 if dx == dy == 0 else max(0.0, min(1.0, ((px - ax) * dx + (py - ay) * dy)
|
||||
/ (dx * dx + dy * dy)))
|
||||
return ((px - ax - t * dx) ** 2 + (py - ay - t * dy) ** 2) ** 0.5
|
||||
|
||||
|
||||
out.append('<defs><marker id="pt" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" '
|
||||
'markerHeight="7" orient="auto"><path d="M0,0 L10,5 L0,10 z" fill="#c00"/></marker>'
|
||||
'<marker id="pt-o" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" '
|
||||
'markerHeight="7" orient="auto"><path d="M0,0 L10,5 L0,10 z" fill="#b06000"/></marker>'
|
||||
'</defs>')
|
||||
text(20, 24, "M2D long, tot trade-ul: 15 min dă direcția, 3 min dă intrarea",
|
||||
bold=True, size=14)
|
||||
text(20, 42, "Graficul din dreapta nu e altă bucată de piață: e aceeași, mărită. "
|
||||
"O candelă de 15 min = 5 candele de 3 min.", fill="#555", size=11)
|
||||
|
||||
top = 80
|
||||
text(20, top - 12, "15 min: direcția", fill="#555", size=11)
|
||||
text(FRAME_L, top - 12, f"3 min: descompunerea ultimelor {NZ} candele de 15 min",
|
||||
fill="#555", size=11)
|
||||
|
||||
zlo_, zhi_ = SL, max(b[1] for b in FINE)
|
||||
pad = PAD * (zhi_ - zlo_)
|
||||
lo, hi = zlo_ - pad, zhi_ + pad
|
||||
|
||||
bmax = max(b[1] for b in BIG)
|
||||
bmin = min(min(b[2] for b in BIG), lo)
|
||||
bs, ss = PLOT_H / (bmax - bmin), PLOT_H / (hi - lo)
|
||||
yb = lambda p: top + (bmax - p) * bs # noqa: E731
|
||||
ys = lambda p: top + (hi - p) * ss # noqa: E731
|
||||
|
||||
# ---- panoul de 15 min ------------------------------------------------------
|
||||
sx_a, sx_b = BX0 + SIG_B * BGAP - 8, BX0 + SIG_B * BGAP + 8
|
||||
rect(sx_a, yb(BASE[SIG_B][1]) - 5, sx_b, yb(BASE[SIG_B][2]) + 5, CYAN)
|
||||
line(BX0 + SIG_B * BGAP, yb(BASE[SIG_B][2]) + 6, BX0 + SIG_B * BGAP, top + PLOT_H + 12,
|
||||
CYAN, width=1)
|
||||
text(BX0 + SIG_B * BGAP - 30, top + PLOT_H + 26, "Buy Momentum pe 15 min:",
|
||||
fill=CYAN, anchor="middle", bold=True, size=11)
|
||||
text(BX0 + SIG_B * BGAP - 30, top + PLOT_H + 39, "de aici ai voie doar long",
|
||||
fill=CYAN, anchor="middle", size=11)
|
||||
|
||||
# caseta de lupă peste exact candelele de 15 min care se sparg în dreapta
|
||||
lx0, lx1 = BX0 + len(BASE) * BGAP - 7, BX0 + (len(BIG) - 1) * BGAP + 8
|
||||
ly0, ly1 = yb(hi), yb(lo)
|
||||
rect(lx0, ly0, lx1, ly1, BLUE, fill_op=0.06, dash="4 3")
|
||||
|
||||
# minimul de referință al pullback-ului: trăiește pe TF-ul mare (pe panoul mic
|
||||
# e sub scară), deci se marchează aici și se trimite acolo din etichetă
|
||||
hline(BX0 - 14, lx1, yb(ref_low), "#555", "2 3", width=1.2)
|
||||
text(24, yb(ref_low) + 12, "minimul din care a pornit", fill="#555", size=10)
|
||||
text(24, yb(ref_low) + 26, f"mișcarea: {ref_low:.2f}", fill="#555", size=10)
|
||||
|
||||
hline(BX0 - 14, lx1, yb(LEVEL), LINK, "3 3", width=1.0)
|
||||
candles(BIG, BX0, BGAP, yb, BW)
|
||||
|
||||
# ---- ghidajele de lupă -----------------------------------------------------
|
||||
guides = [((lx1, ly0), (FRAME_L, top)), ((lx1, ly1), (FRAME_L, top + PLOT_H))]
|
||||
for a_, b_ in guides:
|
||||
line(a_[0], a_[1], b_[0], b_[1], BLUE, dash="5 3", width=1.1)
|
||||
|
||||
# ---- nivelul comun: conector între panouri, numărul scris o singură dată ---
|
||||
ycb, ycs = yb(LEVEL), ys(LEVEL)
|
||||
|
||||
|
||||
def clearance(mx):
|
||||
conn = [((lx1, ycb), (mx, ycb)), ((mx, ycb), (mx, ycs)), ((mx, ycs), (FRAME_L, ycs))]
|
||||
pts = [(sx + (ex - sx) * t / 24, sy + (ey - sy) * t / 24)
|
||||
for (sx, sy), (ex, ey) in conn for t in range(25)]
|
||||
return min(seg_dist(q, ga, gb) for q in pts if q[0] >= lx1 + 10 for ga, gb in guides)
|
||||
|
||||
|
||||
mid = max(range(int(lx1) + 14, int(FRAME_L) - 13), key=clearance)
|
||||
dmin = clearance(mid)
|
||||
assert dmin > 10, f"conectorul trece la {dmin:.1f} px de un ghidaj"
|
||||
out.append(f'<path d="M{lx1:.1f},{ycb:.1f} H{mid:.1f} V{ycs:.1f} H{FRAME_L:.1f}" '
|
||||
f'fill="none" stroke="{LINK}" stroke-width="1.0" stroke-dasharray="3 3"/>')
|
||||
tx = min(mid + 5, FRAME_L - 60)
|
||||
text(tx, (ycb + ycs) / 2 + 4, f"{LEVEL:.2f}", fill="#777", size=10)
|
||||
text(tx, (ycb + ycs) / 2 + 17, "același preț", fill="#999", size=10)
|
||||
|
||||
# ---- panoul de 3 min -------------------------------------------------------
|
||||
y_e, y_sl, y_tp, y_tr = ys(ENTRY), ys(SL), ys(TP1), ys(TRAIL)
|
||||
assert abs((y_sl - y_e) / (y_e - y_tp) - 1) < 1e-6, "SL-intrare != intrare-TP1 în px"
|
||||
assert top + PLOT_H - y_sl > 6, "linia de stop e lipită de marginea cadrului"
|
||||
frame_r = SX0 + (len(FINE) - 1) * SGAP + 8
|
||||
rect(FRAME_L, top, frame_r, top + PLOT_H, BLUE, fill_op=0.03)
|
||||
|
||||
# zona de evidențiere peste pullback + trigger: acolo se decide intrarea
|
||||
zx0 = SX0 - 7
|
||||
zx1 = SX0 + TRIG * SGAP + 7
|
||||
rect(zx0, ys(max(b[1] for b in FINE[:TRIG + 1])) - 5, zx1, ys(SL) + 5, GREEN)
|
||||
|
||||
hline(FRAME_L, frame_r, ycs, LINK, "3 3", width=1.0)
|
||||
hline(FRAME_L, frame_r, y_tp, GREEN, "2 3")
|
||||
hline(FRAME_L, frame_r, y_e, GREEN, "6 3")
|
||||
hline(FRAME_L, frame_r, y_sl, RED, "6 3")
|
||||
hline(FRAME_L, frame_r, y_tr, "#b06000", "2 2", width=1.2)
|
||||
candles(FINE, SX0, SGAP, ys, SW)
|
||||
|
||||
stack([(y_tp + 4, [f"TP1 {TP1:.2f} = 1:1", "iese prima tranșă"], GREEN),
|
||||
(y_tr + 4, [f"bull trail {TRAIL:.2f}", "urcă, nu coboară"], "#b06000"),
|
||||
(y_e + 4, [f"intrare {ENTRY:.2f}", "close-ul trigger-ului"], GREEN),
|
||||
(y_sl + 4, [f"stop {SL:.2f}", f"minimul a {STOP_BARS} bare"], RED)],
|
||||
frame_r)
|
||||
|
||||
# paranteza pullback-ului, sub cadru
|
||||
pxa, pxb = SX0 - 5, SX0 + (PULLBACK_N - 1) * SGAP + 5
|
||||
out.append(f'<path d="M{pxa:.1f},{top + PLOT_H + 2:.1f} V{top + PLOT_H + 8:.1f} '
|
||||
f'H{pxb:.1f} V{top + PLOT_H + 2:.1f}" fill="none" stroke="{RED}" stroke-width="1"/>')
|
||||
text((pxa + pxb) / 2, top + PLOT_H + 22, f"M: pullback, {PULLBACK_N} bare",
|
||||
fill=RED, anchor="middle", bold=True, size=11)
|
||||
text((pxa + pxb) / 2, top + PLOT_H + 36, "fără să rupă minimul",
|
||||
fill=RED, anchor="middle", size=11)
|
||||
|
||||
# ieșirea: săgeată în sus spre bara 18, cu explicația sub cadru, la dreapta
|
||||
exx = SX0 + EXIT_BAR * SGAP
|
||||
line(exx, top + PLOT_H + 14, exx, ys(FINE[EXIT_BAR][2]) + 5, "#b06000",
|
||||
dash="3 3", width=1.1, marker="pt-o")
|
||||
text(frame_r, top + PLOT_H + 22, "close sub trail",
|
||||
fill="#b06000", anchor="end", bold=True, size=11)
|
||||
text(frame_r, top + PLOT_H + 36, f"ieșire {EXIT:.2f} = {R:.1f}R",
|
||||
fill="#b06000", anchor="end", size=11)
|
||||
|
||||
# trigger-ul: săgeată în sus spre bara 9, cu explicația dedesubt
|
||||
tgx = SX0 + TRIG * SGAP
|
||||
line(tgx, top + PLOT_H + 50, tgx, ys(FINE[TRIG][2]) + 5, GREEN, width=1.6, marker="pt")
|
||||
text(pxa, top + PLOT_H + 58, "A: primul Buy după pullback — aici intri,",
|
||||
fill=GREEN, bold=True, size=11)
|
||||
text(pxa, top + PLOT_H + 72, "pentru că 15 min e încă în Buy.", fill=GREEN, size=11)
|
||||
text(pxa, top + PLOT_H + 86, "Wick-urile nu contează: se citește close-ul.",
|
||||
fill="#555", size=11)
|
||||
|
||||
LAB_N = len(LABELS) # etichetele de pe panouri; ce urmează e subsol
|
||||
H = top + PLOT_H + 108
|
||||
text(20, H - 6, f"Serie construită, fără ticker. Risc = {ENTRY:.2f} − {SL:.2f} = {RISK:.2f}; "
|
||||
f"TP1 la aceeași distanță în sus; ieșirea pe trail la {R:.1f}R.",
|
||||
fill="#555", size=11)
|
||||
H += 12
|
||||
|
||||
# ---- prețul fiecărui panou rămâne pe panoul lui ---------------------------
|
||||
COMUNE = {round(LEVEL, 2)}
|
||||
MARE = {"ref_low": ref_low}
|
||||
MIC = {k_: v for k_, v in (("entry", ENTRY), ("sl", SL), ("tp", TP1), ("trail", TRAIL))
|
||||
if round(v, 2) not in COMUNE}
|
||||
for x0_, _x1, _y, s_ in LABELS[:LAB_N]:
|
||||
rau = MARE if x0_ >= MIDX else MIC
|
||||
for kk, v in rau.items():
|
||||
assert f"{v:.2f}" not in s_, \
|
||||
f"eticheta {s_!r} de pe panoul {'mic' if x0_ >= MIDX else 'mare'} " \
|
||||
f"conține prețul {kk}={v:.2f} al celuilalt panou"
|
||||
cx_ = [x0_ for x0_, _x1, _y, s_ in LABELS[:LAB_N] if f"{LEVEL:.2f}" in s_]
|
||||
assert len(cx_) == 1 and lx1 < cx_[0] < FRAME_L, \
|
||||
f"{LEVEL:.2f} nu e scris exact o dată, în cotul conectorului ({cx_})"
|
||||
for nume, v in (("intrarea", ENTRY), ("stopul", SL), ("TP1", TP1), ("trail-ul", TRAIL)):
|
||||
assert any(f"{v:.2f}" in s_ and x0_ >= MIDX for x0_, _x1, _y, s_ in LABELS[:LAB_N]), \
|
||||
f"{nume} nu apare pe panoul mic"
|
||||
|
||||
for a in range(len(LABELS)):
|
||||
assert 0 < LABELS[a][2] < H, f"etichetă în afara înălțimii: {LABELS[a][3]!r}"
|
||||
for b in range(a + 1, len(LABELS)):
|
||||
xa0, xa1, ya_, sa = LABELS[a]
|
||||
xb0, xb1, yb_, sb = LABELS[b]
|
||||
assert not (abs(ya_ - yb_) < 13 and xa0 < xb1 - 4 and xb0 < xa1 - 4), \
|
||||
f"etichete suprapuse: {sa!r} / {sb!r}"
|
||||
|
||||
svg = (f'<svg viewBox="0 0 {W} {H:.0f}" xmlns="http://www.w3.org/2000/svg" '
|
||||
f'style="width:100%;height:auto;font:12px sans-serif">\n ' + "\n ".join(out) + "\n</svg>")
|
||||
assert "\n\n" not in svg
|
||||
assert ".md:" not in svg, "trimiteri la surse în SVG"
|
||||
OUT.write_text(svg, encoding="utf-8")
|
||||
print(f"scris {OUT} ({W}x{H:.0f}) | 15 min: {len(BIG)} candele, lupă pe ultimele {NZ} "
|
||||
f"= {len(FINE)} bare de 3 min | nivel comun {LEVEL:.2f} | "
|
||||
f"intrare {ENTRY:.2f} SL {SL:.2f} risc {RISK:.2f} TP1 {TP1:.2f} la bara {TP_BAR} | "
|
||||
f"trail {TRAIL:.2f}, ieșire bara {EXIT_BAR} la {EXIT:.2f} = {R:.2f}R | "
|
||||
f"pullback peste {span} candele de 15 min, trigger în candela mare {trig_big}")
|
||||
|
||||
@@ -1,117 +1,111 @@
|
||||
<svg viewBox="0 0 720 568" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<line x1="24" y1="87.2" x2="706" y2="87.2" stroke="#b06000" stroke-width="1.5" stroke-dasharray="2 3"/><text x="692" y="81.2" fill="#b06000" text-anchor="end">bull trail 102.90</text>
|
||||
<text x="24" y="48" fill="#333" style="font-weight:bold">Simbol construit — 3 min (TF mare 15 min în Buy)</text>
|
||||
<line x1="24" y1="248.4" x2="706" y2="248.4" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="30" y="242.4" fill="#188a3e">intrare 99.80</text>
|
||||
<line x1="24" y1="300.4" x2="706" y2="300.4" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="692" y="294.4" fill="#c00" text-anchor="end">SL 98.80 (4 candele)</text>
|
||||
<line x1="24" y1="196.4" x2="706" y2="196.4" stroke="#1a5fb4" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="692" y="190.4" fill="#1a5fb4" text-anchor="end">TP1 100.80 = 1:1</text>
|
||||
<polyline points="348.0,276.3 364.0,262.8 380.0,249.3 396.0,236.3 412.0,223.6 428.0,211.3 444.0,200.9 460.0,192.4 476.0,185.3 492.0,177.3 508.0,169.2 524.0,160.9 540.0,153.6" fill="none" stroke="#b06000" stroke-width="1.5" stroke-dasharray="4 3"/>
|
||||
<text x="546" y="148" fill="#b06000">SMA-20</text>
|
||||
<line x1="44.0" y1="396.6" x2="44.0" y2="430.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="39.5" y="404.4" width="9" height="20.8" fill="#188a3e"/>
|
||||
<line x1="60.0" y1="375.8" x2="60.0" y2="409.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="55.5" y="383.6" width="9" height="20.8" fill="#188a3e"/>
|
||||
<line x1="76.0" y1="349.8" x2="76.0" y2="388.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="71.5" y="357.6" width="9" height="26.0" fill="#188a3e"/>
|
||||
<line x1="92.0" y1="329.0" x2="92.0" y2="362.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="87.5" y="336.8" width="9" height="20.8" fill="#188a3e"/>
|
||||
<line x1="108.0" y1="303.0" x2="108.0" y2="342.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="103.5" y="310.8" width="9" height="26.0" fill="#188a3e"/>
|
||||
<line x1="124.0" y1="277.0" x2="124.0" y2="316.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="119.5" y="284.8" width="9" height="26.0" fill="#188a3e"/>
|
||||
<line x1="140.0" y1="256.2" x2="140.0" y2="290.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="135.5" y="264.0" width="9" height="20.8" fill="#188a3e"/>
|
||||
<line x1="156.0" y1="230.2" x2="156.0" y2="269.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="151.5" y="238.0" width="9" height="26.0" fill="#188a3e"/>
|
||||
<line x1="172.0" y1="232.8" x2="172.0" y2="256.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="167.5" y="238.0" width="9" height="10.4" fill="#c00"/>
|
||||
<line x1="188.0" y1="243.2" x2="188.0" y2="279.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="183.5" y="248.4" width="9" height="20.8" fill="#c00"/>
|
||||
<line x1="204.0" y1="264.0" x2="204.0" y2="297.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="199.5" y="269.2" width="9" height="20.8" fill="#c00"/>
|
||||
<line x1="220.0" y1="274.4" x2="220.0" y2="297.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="215.5" y="279.6" width="9" height="10.4" fill="#188a3e"/>
|
||||
<line x1="236.0" y1="274.4" x2="236.0" y2="300.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="231.5" y="279.6" width="9" height="15.6" fill="#c00"/>
|
||||
<line x1="252.0" y1="277.0" x2="252.0" y2="297.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="247.5" y="282.2" width="9" height="13.0" fill="#188a3e"/>
|
||||
<line x1="268.0" y1="269.2" x2="268.0" y2="287.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="263.5" y="274.4" width="9" height="7.8" fill="#188a3e"/>
|
||||
<line x1="284.0" y1="240.6" x2="284.0" y2="279.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="279.5" y="248.4" width="9" height="26.0" fill="#188a3e"/>
|
||||
<line x1="300.0" y1="219.8" x2="300.0" y2="253.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="295.5" y="227.6" width="9" height="20.8" fill="#188a3e"/>
|
||||
<line x1="316.0" y1="193.8" x2="316.0" y2="232.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="311.5" y="201.6" width="9" height="26.0" fill="#188a3e"/>
|
||||
<line x1="332.0" y1="167.8" x2="332.0" y2="206.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="327.5" y="175.6" width="9" height="26.0" fill="#188a3e"/>
|
||||
<line x1="348.0" y1="147.0" x2="348.0" y2="180.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="343.5" y="154.8" width="9" height="20.8" fill="#188a3e"/>
|
||||
<line x1="364.0" y1="126.2" x2="364.0" y2="160.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="359.5" y="134.0" width="9" height="20.8" fill="#188a3e"/>
|
||||
<line x1="380.0" y1="105.4" x2="380.0" y2="139.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="375.5" y="113.2" width="9" height="20.8" fill="#188a3e"/>
|
||||
<line x1="396.0" y1="89.8" x2="396.0" y2="118.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="391.5" y="97.6" width="9" height="15.6" fill="#188a3e"/>
|
||||
<line x1="412.0" y1="74.2" x2="412.0" y2="102.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="407.5" y="82.0" width="9" height="15.6" fill="#188a3e"/>
|
||||
<line x1="428.0" y1="56.0" x2="428.0" y2="87.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="423.5" y="66.4" width="9" height="15.6" fill="#188a3e"/>
|
||||
<line x1="444.0" y1="61.2" x2="444.0" y2="84.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="439.5" y="66.4" width="9" height="10.4" fill="#c00"/>
|
||||
<line x1="460.0" y1="71.6" x2="460.0" y2="100.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="455.5" y="76.8" width="9" height="15.6" fill="#c00"/>
|
||||
<line x1="476.0" y1="86.2" x2="476.0" y2="105.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="471.5" y="92.4" width="9" height="5.2" fill="#c00"/>
|
||||
<line x1="492.0" y1="82.0" x2="492.0" y2="105.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="487.5" y="87.2" width="9" height="10.4" fill="#188a3e"/>
|
||||
<line x1="508.0" y1="82.0" x2="508.0" y2="115.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="503.5" y="87.2" width="9" height="20.8" fill="#c00"/>
|
||||
<line x1="524.0" y1="102.8" x2="524.0" y2="131.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="519.5" y="108.0" width="9" height="15.6" fill="#c00"/>
|
||||
<line x1="540.0" y1="118.4" x2="540.0" y2="144.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="535.5" y="123.6" width="9" height="10.4" fill="#c00"/>
|
||||
<line x1="24" y1="526.4" x2="706" y2="526.4" stroke="#888"/>
|
||||
<rect x="39.5" y="477.1" width="9" height="49.3" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="55.5" y="473.9" width="9" height="52.5" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="71.5" y="478.7" width="9" height="47.7" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="87.5" y="472.3" width="9" height="54.1" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="103.5" y="475.5" width="9" height="50.9" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="119.5" y="470.7" width="9" height="55.7" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="135.5" y="473.9" width="9" height="52.5" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="151.5" y="467.5" width="9" height="58.9" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="167.5" y="491.4" width="9" height="35.0" fill="#c00" opacity="0.55"/>
|
||||
<rect x="183.5" y="494.6" width="9" height="31.8" fill="#c00" opacity="0.55"/>
|
||||
<rect x="199.5" y="496.2" width="9" height="30.2" fill="#c00" opacity="0.55"/>
|
||||
<rect x="215.5" y="497.8" width="9" height="28.6" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="231.5" y="499.4" width="9" height="27.0" fill="#c00" opacity="0.55"/>
|
||||
<rect x="247.5" y="500.1" width="9" height="26.2" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="263.5" y="498.6" width="9" height="27.8" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="279.5" y="461.2" width="9" height="65.2" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="295.5" y="456.4" width="9" height="70.0" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="311.5" y="469.1" width="9" height="57.3" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="327.5" y="470.7" width="9" height="55.7" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="343.5" y="467.5" width="9" height="58.9" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="359.5" y="472.3" width="9" height="54.1" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="375.5" y="469.1" width="9" height="57.3" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="391.5" y="473.9" width="9" height="52.5" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="407.5" y="470.7" width="9" height="55.7" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="423.5" y="465.9" width="9" height="60.5" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="439.5" y="475.5" width="9" height="50.9" fill="#c00" opacity="0.55"/>
|
||||
<rect x="455.5" y="478.7" width="9" height="47.7" fill="#c00" opacity="0.55"/>
|
||||
<rect x="471.5" y="480.3" width="9" height="46.1" fill="#c00" opacity="0.55"/>
|
||||
<rect x="487.5" y="477.1" width="9" height="49.3" fill="#188a3e" opacity="0.55"/>
|
||||
<rect x="503.5" y="481.9" width="9" height="44.5" fill="#c00" opacity="0.55"/>
|
||||
<rect x="519.5" y="483.4" width="9" height="43.0" fill="#c00" opacity="0.55"/>
|
||||
<rect x="535.5" y="473.9" width="9" height="52.5" fill="#c00" opacity="0.55"/>
|
||||
<text x="24" y="450.4" fill="#555">volum</text>
|
||||
<text x="32.0" y="159.6" fill="#1a5fb4" text-anchor="start" style="font-weight:bold">TF mare (15 min) în Buy</text>
|
||||
<text x="220.0" y="317.8" fill="#c00" text-anchor="middle" style="font-weight:bold">M: Sell Momentum (pullback)</text>
|
||||
<text x="284.0" y="108.6" fill="#188a3e" text-anchor="middle" style="font-weight:bold">A: primul Buy = trigger</text>
|
||||
<text x="428.0" y="132.2" fill="#777" text-anchor="middle" style="font-weight:bold">vârf 103.30</text>
|
||||
<text x="540.0" y="219.4" fill="#c00" text-anchor="middle" style="font-weight:bold">close sub bull trail = ieși</text>
|
||||
<text x="540.0" y="237.4" fill="#c00" text-anchor="middle" style="font-weight:bold">ieșire 102.00 pe bull trail (2.2R)</text>
|
||||
<text x="24" y="556" fill="#555">Serie construită (32 bare, 3 min). R = (102.00 − 99.80) / 1.00 = 2.2R.</text>
|
||||
<svg viewBox="0 0 720 368" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<defs><marker id="pt" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0 L10,5 L0,10 z" fill="#c00"/></marker><marker id="pt-o" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0 L10,5 L0,10 z" fill="#b06000"/></marker></defs>
|
||||
<text x="20.0" y="24.0" fill="#333" style="font-size:14px;font-weight:bold">M2D long, tot trade-ul: 15 min dă direcția, 3 min dă intrarea</text>
|
||||
<text x="20.0" y="42.0" fill="#555" style="font-size:11px">Graficul din dreapta nu e altă bucată de piață: e aceeași, mărită. O candelă de 15 min = 5 candele de 3 min.</text>
|
||||
<text x="20.0" y="68.0" fill="#555" style="font-size:11px">15 min: direcția</text>
|
||||
<text x="364.0" y="68.0" fill="#555" style="font-size:11px">3 min: descompunerea ultimelor 4 candele de 15 min</text>
|
||||
<rect x="171.0" y="111.3" width="16.0" height="53.1" fill="#0891b2" fill-opacity="0.1" stroke="#0891b2" stroke-width="1.2"/>
|
||||
<line x1="179.0" y1="165.5" x2="179.0" y2="260.0" stroke="#0891b2" stroke-width="1"/>
|
||||
<text x="149.0" y="274.0" fill="#0891b2" text-anchor="middle" style="font-size:11px;font-weight:bold">Buy Momentum pe 15 min:</text>
|
||||
<text x="149.0" y="287.0" fill="#0891b2" text-anchor="middle" style="font-size:11px">de aici ai voie doar long</text>
|
||||
<rect x="187.0" y="75.5" width="60.0" height="83.9" fill="#1a5fb4" fill-opacity="0.06" stroke="#1a5fb4" stroke-width="1.2" stroke-dasharray="4 3"/>
|
||||
<line x1="90.0" y1="159.5" x2="247.0" y2="159.5" stroke="#555" stroke-width="1.2" stroke-dasharray="2 3"/>
|
||||
<text x="24.0" y="171.5" fill="#555" style="font-size:10px">minimul din care a pornit</text>
|
||||
<text x="24.0" y="185.5" fill="#555" style="font-size:10px">mișcarea: 99.80</text>
|
||||
<line x1="90.0" y1="123.1" x2="247.0" y2="123.1" stroke="#aaa" stroke-width="1.0" stroke-dasharray="3 3"/>
|
||||
<line x1="104.0" y1="225.3" x2="104.0" y2="248.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="99.5" y="229.8" width="9" height="11.4" fill="#188a3e"/>
|
||||
<line x1="119.0" y1="209.4" x2="119.0" y2="234.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="114.5" y="213.9" width="9" height="15.9" fill="#188a3e"/>
|
||||
<line x1="134.0" y1="191.2" x2="134.0" y2="218.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="129.5" y="195.8" width="9" height="18.2" fill="#188a3e"/>
|
||||
<line x1="149.0" y1="175.4" x2="149.0" y2="200.3" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="144.5" y="182.2" width="9" height="13.6" fill="#188a3e"/>
|
||||
<line x1="164.0" y1="152.6" x2="164.0" y2="186.7" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="159.5" y="157.2" width="9" height="25.0" fill="#188a3e"/>
|
||||
<line x1="179.0" y1="116.3" x2="179.0" y2="159.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="174.5" y="123.1" width="9" height="34.1" fill="#188a3e"/>
|
||||
<line x1="194.0" y1="118.6" x2="194.0" y2="150.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="189.5" y="123.1" width="9" height="25.0" fill="#c00"/>
|
||||
<line x1="209.0" y1="129.9" x2="209.0" y2="154.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="204.5" y="132.2" width="9" height="15.9" fill="#188a3e"/>
|
||||
<line x1="224.0" y1="98.2" x2="224.0" y2="134.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="219.5" y="105.0" width="9" height="27.2" fill="#188a3e"/>
|
||||
<line x1="239.0" y1="80.0" x2="239.0" y2="109.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="234.5" y="105.0" width="9" height="2.3" fill="#c00"/>
|
||||
<line x1="247.0" y1="75.5" x2="364.0" y2="80.0" stroke="#1a5fb4" stroke-width="1.1" stroke-dasharray="5 3"/>
|
||||
<line x1="247.0" y1="159.4" x2="364.0" y2="248.0" stroke="#1a5fb4" stroke-width="1.1" stroke-dasharray="5 3"/>
|
||||
<path d="M247.0,123.1 H350.0 V175.4 H364.0" fill="none" stroke="#aaa" stroke-width="1.0" stroke-dasharray="3 3"/>
|
||||
<text x="304.0" y="153.2" fill="#777" style="font-size:10px">100.60</text>
|
||||
<text x="304.0" y="166.2" fill="#999" style="font-size:10px">același preț</text>
|
||||
<rect x="364.0" y="80.0" width="225.0" height="168.0" fill="#1a5fb4" fill-opacity="0.03" stroke="#1a5fb4" stroke-width="1.2"/>
|
||||
<rect x="365.0" y="161.3" width="113.0" height="82.7" fill="#188a3e" fill-opacity="0.1" stroke="#188a3e" stroke-width="1.2"/>
|
||||
<line x1="364.0" y1="175.4" x2="589.0" y2="175.4" stroke="#aaa" stroke-width="1.0" stroke-dasharray="3 3"/>
|
||||
<line x1="364.0" y1="148.1" x2="589.0" y2="148.1" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="2 3"/>
|
||||
<line x1="364.0" y1="193.5" x2="589.0" y2="193.5" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="6 3"/>
|
||||
<line x1="364.0" y1="239.0" x2="589.0" y2="239.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="6 3"/>
|
||||
<line x1="364.0" y1="116.3" x2="589.0" y2="116.3" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/>
|
||||
<line x1="372.0" y1="166.3" x2="372.0" y2="193.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="368.5" y="175.4" width="7" height="13.6" fill="#c00"/>
|
||||
<line x1="383.0" y1="184.5" x2="383.0" y2="207.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="379.5" y="189.0" width="7" height="13.6" fill="#c00"/>
|
||||
<line x1="394.0" y1="198.1" x2="394.0" y2="216.3" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="390.5" y="202.6" width="7" height="9.1" fill="#c00"/>
|
||||
<line x1="405.0" y1="207.2" x2="405.0" y2="225.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="401.5" y="211.7" width="7" height="9.1" fill="#c00"/>
|
||||
<line x1="416.0" y1="216.3" x2="416.0" y2="229.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="412.5" y="220.8" width="7" height="4.5" fill="#c00"/>
|
||||
<line x1="427.0" y1="220.8" x2="427.0" y2="234.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="423.5" y="225.4" width="7" height="4.5" fill="#c00"/>
|
||||
<line x1="438.0" y1="225.4" x2="438.0" y2="237.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="434.5" y="229.9" width="7" height="4.5" fill="#c00"/>
|
||||
<line x1="449.0" y1="229.9" x2="449.0" y2="239.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="445.5" y="231.7" width="7" height="2.7" fill="#188a3e"/>
|
||||
<line x1="460.0" y1="222.6" x2="460.0" y2="235.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="456.5" y="228.1" width="7" height="3.6" fill="#188a3e"/>
|
||||
<line x1="471.0" y1="189.0" x2="471.0" y2="229.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="467.5" y="193.5" width="7" height="34.5" fill="#188a3e"/>
|
||||
<line x1="482.0" y1="175.4" x2="482.0" y2="198.1" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="478.5" y="179.9" width="7" height="13.6" fill="#188a3e"/>
|
||||
<line x1="493.0" y1="161.7" x2="493.0" y2="184.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="489.5" y="166.3" width="7" height="13.6" fill="#188a3e"/>
|
||||
<line x1="504.0" y1="139.0" x2="504.0" y2="170.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="500.5" y="143.5" width="7" height="22.7" fill="#188a3e"/>
|
||||
<line x1="515.0" y1="129.9" x2="515.0" y2="149.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="511.5" y="134.5" width="7" height="9.1" fill="#188a3e"/>
|
||||
<line x1="526.0" y1="125.4" x2="526.0" y2="143.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="522.5" y="134.5" width="7" height="4.5" fill="#c00"/>
|
||||
<line x1="537.0" y1="102.6" x2="537.0" y2="143.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="533.5" y="107.2" width="7" height="31.8" fill="#188a3e"/>
|
||||
<line x1="548.0" y1="89.0" x2="548.0" y2="116.3" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="544.5" y="98.1" width="7" height="9.1" fill="#188a3e"/>
|
||||
<line x1="559.0" y1="93.5" x2="559.0" y2="120.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="555.5" y="98.1" width="7" height="18.2" fill="#c00"/>
|
||||
<line x1="570.0" y1="111.7" x2="570.0" y2="134.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="566.5" y="116.3" width="7" height="13.6" fill="#c00"/>
|
||||
<line x1="581.0" y1="125.4" x2="581.0" y2="148.1" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="577.5" y="129.9" width="7" height="13.6" fill="#c00"/>
|
||||
<line x1="591.0" y1="116.3" x2="596.0" y2="116.3" stroke="#b06000" stroke-width="0.8"/>
|
||||
<text x="600.0" y="120.3" fill="#b06000" style="font-size:10px">bull trail 101.25</text>
|
||||
<text x="600.0" y="134.3" fill="#b06000" style="font-size:10px">urcă, nu coboară</text>
|
||||
<line x1="591.0" y1="148.1" x2="596.0" y2="148.1" stroke="#188a3e" stroke-width="0.8"/>
|
||||
<text x="600.0" y="152.1" fill="#188a3e" style="font-size:10px">TP1 100.90 = 1:1</text>
|
||||
<text x="600.0" y="166.1" fill="#188a3e" style="font-size:10px">iese prima tranșă</text>
|
||||
<line x1="591.0" y1="193.5" x2="596.0" y2="193.5" stroke="#188a3e" stroke-width="0.8"/>
|
||||
<text x="600.0" y="197.5" fill="#188a3e" style="font-size:10px">intrare 100.40</text>
|
||||
<text x="600.0" y="211.5" fill="#188a3e" style="font-size:10px">close-ul trigger-ului</text>
|
||||
<line x1="591.0" y1="239.0" x2="596.0" y2="239.0" stroke="#c00" stroke-width="0.8"/>
|
||||
<text x="600.0" y="243.0" fill="#c00" style="font-size:10px">stop 99.90</text>
|
||||
<text x="600.0" y="257.0" fill="#c00" style="font-size:10px">minimul a 4 bare</text>
|
||||
<path d="M367.0,250.0 V256.0 H465.0 V250.0" fill="none" stroke="#c00" stroke-width="1"/>
|
||||
<text x="416.0" y="270.0" fill="#c00" text-anchor="middle" style="font-size:11px;font-weight:bold">M: pullback, 9 bare</text>
|
||||
<text x="416.0" y="284.0" fill="#c00" text-anchor="middle" style="font-size:11px">fără să rupă minimul</text>
|
||||
<line x1="570.0" y1="262.0" x2="570.0" y2="139.5" stroke="#b06000" stroke-width="1.1" stroke-dasharray="3 3" marker-end="url(#pt-o)"/>
|
||||
<text x="589.0" y="270.0" fill="#b06000" text-anchor="end" style="font-size:11px;font-weight:bold">close sub trail</text>
|
||||
<text x="589.0" y="284.0" fill="#b06000" text-anchor="end" style="font-size:11px">ieșire 101.10 = 1.4R</text>
|
||||
<line x1="471.0" y1="298.0" x2="471.0" y2="234.9" stroke="#188a3e" stroke-width="1.6" marker-end="url(#pt)"/>
|
||||
<text x="367.0" y="306.0" fill="#188a3e" style="font-size:11px;font-weight:bold">A: primul Buy după pullback — aici intri,</text>
|
||||
<text x="367.0" y="320.0" fill="#188a3e" style="font-size:11px">pentru că 15 min e încă în Buy.</text>
|
||||
<text x="367.0" y="334.0" fill="#555" style="font-size:11px">Wick-urile nu contează: se citește close-ul.</text>
|
||||
<text x="20.0" y="350.0" fill="#555" style="font-size:11px">Serie construită, fără ticker. Risc = 100.40 − 99.90 = 0.50; TP1 la aceeași distanță în sus; ieșirea pe trail la 1.4R.</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 10 KiB |
114
gen/strategii/m2d_directie.py
Normal file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
"""M2D, pasul 1 — direcția o dă TF-ul mare: DA (rămâne în Buy) vs. NU (se închide Sell).
|
||||
|
||||
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: directie -->`.
|
||||
|
||||
Ambele panouri sunt graficul de 15 minute al aceluiași exemplu construit ca în
|
||||
diagrama de ansamblu — primele 6 candele sunt identice, deci cifrele din
|
||||
capitol nu se bat cap în cap de la o diagramă la alta.
|
||||
|
||||
Sus: pullback-ul de pe 3 min lasă pe 15 min o candelă roșie, dar indicatorul
|
||||
nu dă Sell și candela nu se închide sub nivelul semnalului — setup-ul long
|
||||
trăiește. Jos: candela de 15 min se ÎNCHIDE Sell — setup-ul long e anulat.
|
||||
|
||||
Rulare: python3 gen/strategii/m2d_directie.py
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, "/workspace/atm-curs-dl")
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from svg_candles import Arrow, Candle, Chart, Mark # noqa: E402
|
||||
import m2d_duo as duo # noqa: E402
|
||||
|
||||
OUT = Path(__file__).with_suffix(".svg")
|
||||
W, SCALE, GAP, LEFT = 680, 46.0, 46, 74
|
||||
GREEN, RED, BLUE, CYAN, GREY = "#188a3e", "#c00", "#1a5fb4", "#0891b2", "#555"
|
||||
|
||||
# --- aceleași candele de 15 min ca în diagrama de ansamblu -----------------
|
||||
BASE = [(98.00, 98.35, 97.85, 98.25), (98.25, 98.70, 98.15, 98.60),
|
||||
(98.60, 99.10, 98.50, 99.00), (99.00, 99.45, 98.90, 99.30),
|
||||
(99.30, 99.95, 99.20, 99.85),
|
||||
(99.85, 100.75, 99.80, 100.60)] # 5: Buy Momentum pe 15 min
|
||||
DA = BASE + [(100.60, 100.70, 100.00, 100.05), # 6: roșie, dar nu Sell
|
||||
(100.05, 100.45, 99.90, 100.40), # 7: aici cade trigger-ul de pe 3 min
|
||||
(100.40, 101.15, 100.35, 101.00)]
|
||||
NU = BASE + [(100.60, 100.70, 100.00, 100.05),
|
||||
(100.05, 100.10, 99.20, 99.30), # 7: se ÎNCHIDE Sell — setup anulat
|
||||
(99.30, 99.40, 98.60, 98.75)]
|
||||
SIG = 5
|
||||
|
||||
# ---------------------------------------------------------------- verificări
|
||||
for nume, bars in (("DA", DA), ("NU", NU)):
|
||||
for i, (o, h, l, c) in enumerate(bars):
|
||||
assert h >= max(o, c) and l <= min(o, c), f"{nume}[{i}]: high/low incoerent"
|
||||
if i:
|
||||
assert abs(o - bars[i - 1][3]) < 1e-9, f"{nume}[{i}]: open != close precedent"
|
||||
assert DA[:SIG + 2] == NU[:SIG + 2], "panourile nu pornesc din aceeași serie"
|
||||
|
||||
SEMNAL = BASE[SIG][3] # 100.60 — același nivel ca în diagrama de ansamblu
|
||||
REF_LOW = BASE[SIG][2] # 99.80 — minimul din care a pornit mișcarea
|
||||
assert BASE[SIG][3] > BASE[SIG][0], "candela de semnal nu e verde"
|
||||
|
||||
# DA: nicio candelă de după semnal nu se închide sub minimul de referință
|
||||
assert all(b[3] > REF_LOW for b in DA[SIG + 1:]), "DA: o candelă închide sub referință"
|
||||
assert DA[6][3] < DA[6][0], "DA: candela 6 ar trebui să fie roșie (pullback pe 3 min)"
|
||||
assert DA[6][3] > REF_LOW, "DA: candela roșie rupe deja referința"
|
||||
# NU: exact una rupe — a șaptea, care se închide sub minimul de referință
|
||||
rupe = [i for i, b in enumerate(NU) if i > SIG and b[3] < REF_LOW]
|
||||
assert rupe == [7, 8], rupe
|
||||
assert NU[7][3] < NU[7][0] and NU[7][3] < REF_LOW, "NU: candela 7 nu se închide Sell"
|
||||
|
||||
|
||||
def chart(bars, marks, arrows, extra_h=0.0):
|
||||
return Chart(candles=[Candle(*b) for b in bars], marks=marks, arrows=arrows,
|
||||
scale=SCALE, gap=GAP, body_w=15, left=LEFT, width=W, top=64,
|
||||
label_gap=34 + extra_h)
|
||||
|
||||
|
||||
TITLU_DA = "DA — 15 min e încă în Buy când vine trigger-ul de pe 3 min"
|
||||
TITLU_NU = "NU — 15 min s-a închis Sell: setup-ul long e anulat"
|
||||
|
||||
ch_da = chart(
|
||||
DA,
|
||||
[],
|
||||
[Arrow(SIG, "Buy Momentum pe 15 min:\nde aici ai voie doar long",
|
||||
where="below", color=CYAN, dx=-60, dy=54),
|
||||
Arrow(6, "candelă roșie pe 15 min, dar close-ul\nrămâne peste 99.80: pullback, nu întoarcere",
|
||||
where="below", color=GREY, dx=-30, dy=26),
|
||||
Arrow(7, "aici cade trigger-ul de pe 3 min",
|
||||
where="above", color=GREEN, dx=-24, dy=18)])
|
||||
ch_nu = chart(
|
||||
NU,
|
||||
[],
|
||||
[Arrow(SIG, "Buy Momentum pe 15 min:\nde aici ai voie doar long",
|
||||
where="below", color=CYAN, dx=-60, dy=54),
|
||||
Arrow(7, "close 99.30, sub 99.80: direcția mare\ns-a răsucit — nu mai intri long",
|
||||
where="below", color=RED, dx=-40, dy=20),
|
||||
Arrow(8, "de aici cauți short, nu long", where="below", color=RED, dx=-120, dy=82)])
|
||||
|
||||
body_da, h_da = duo.panel(ch_da, W)
|
||||
body_nu, h_nu = duo.panel(ch_nu, W)
|
||||
|
||||
extra_da = (duo.titlu(TITLU_DA, color=GREEN)
|
||||
+ duo.zone(ch_da, SIG, 7, "zona în care ai voie long", GREEN, pad=20, lift=26)
|
||||
+ duo.level(ch_da, SEMNAL, ["close-ul candelei de semnal 100.60"], CYAN, W,
|
||||
below=False, at_left=False)
|
||||
+ duo.level(ch_da, REF_LOW, ["minimul din care a pornit mișcarea 99.80"],
|
||||
GREY, W, below=True, dash="2 3"))
|
||||
extra_nu = (duo.titlu(TITLU_NU, color=RED)
|
||||
+ duo.zone(ch_nu, 7, 8, "setup anulat", RED, pad=20)
|
||||
+ duo.level(ch_nu, SEMNAL, ["close-ul candelei de semnal 100.60"], CYAN, W,
|
||||
below=False, at_left=False)
|
||||
+ duo.level(ch_nu, REF_LOW, ["minimul din care a pornit mișcarea 99.80"],
|
||||
GREY, W, below=True, dash="2 3"))
|
||||
|
||||
svg, H, n = duo.build(
|
||||
[("DA", body_da, h_da, extra_da), ("NU", body_nu, h_nu, extra_nu)],
|
||||
["Același grafic de 15 minute ca în diagrama de ansamblu; serie construită, fără ticker.",
|
||||
"Pe 15 min se citește DIRECȚIA, nu intrarea. Intrarea vine de pe 3 min (pasul 3)."],
|
||||
W)
|
||||
duo.fara_preturi_straine(svg, [SEMNAL, REF_LOW, NU[7][3]])
|
||||
OUT.write_text(svg, encoding="utf-8")
|
||||
print(f"scris {OUT} ({W}x{H:.0f}), {n} etichete | semnal {SEMNAL:.2f}, referință {REF_LOW:.2f} | "
|
||||
f"DA: ultima închidere {DA[-1][3]:.2f} | NU: candela 7 închide {NU[7][3]:.2f}")
|
||||
66
gen/strategii/m2d_directie.svg
Normal file
@@ -0,0 +1,66 @@
|
||||
<svg viewBox="0 0 680 681" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<g transform="translate(0,0)"><text x="24" y="22" fill="#188a3e" style="font-weight:bold">DA — 15 min e încă în Buy când vine trigger-ul de pe 3 min</text><rect x="284.0" y="48.4" width="132.0" height="85.7" fill="#188a3e" fill-opacity="0.12" stroke="#188a3e" stroke-width="1"/><text x="290.0" y="41.4" fill="#188a3e" style="font-weight:bold">zona în care ai voie long</text><line x1="24" y1="89.3" x2="666" y2="89.3" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="83.3" fill="#0891b2" text-anchor="end" style="font-weight:bold">close-ul candelei de semnal 100.60</text><line x1="24" y1="126.1" x2="666" y2="126.1" stroke="#555" stroke-width="1.5" stroke-dasharray="2 3"/><text x="30" y="147.1" fill="#555" text-anchor="start" style="font-weight:bold">minimul din care a pornit mișcarea 99.80</text>
|
||||
<line x1="74.0" y1="192.8" x2="74.0" y2="215.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="66.5" y="197.4" width="15" height="11.5" fill="#188a3e"/>
|
||||
<line x1="120.0" y1="176.7" x2="120.0" y2="202.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="112.5" y="181.3" width="15" height="16.1" fill="#188a3e"/>
|
||||
<line x1="166.0" y1="158.3" x2="166.0" y2="185.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="158.5" y="162.9" width="15" height="18.4" fill="#188a3e"/>
|
||||
<line x1="212.0" y1="142.2" x2="212.0" y2="167.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="204.5" y="149.1" width="15" height="13.8" fill="#188a3e"/>
|
||||
<line x1="258.0" y1="119.2" x2="258.0" y2="153.7" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="250.5" y="123.8" width="15" height="25.3" fill="#188a3e"/>
|
||||
<line x1="304.0" y1="82.4" x2="304.0" y2="126.1" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="296.5" y="89.3" width="15" height="34.5" fill="#188a3e"/>
|
||||
<line x1="350.0" y1="84.7" x2="350.0" y2="116.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="342.5" y="89.3" width="15" height="25.3" fill="#c00"/>
|
||||
<line x1="396.0" y1="96.2" x2="396.0" y2="121.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="388.5" y="98.5" width="15" height="16.1" fill="#188a3e"/>
|
||||
<line x1="442.0" y1="64.0" x2="442.0" y2="100.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="434.5" y="70.9" width="15" height="27.6" fill="#188a3e"/>
|
||||
<line x1="244.0" y1="247.9" x2="300.4" y2="137.2" stroke="#0891b2" stroke-width="1.8"/>
|
||||
<polygon points="304.0,130.1 303.9,139.0 296.8,135.4" fill="#0891b2"/>
|
||||
<text x="244.0" y="261.9" fill="#0891b2" text-anchor="middle" style="font-weight:bold">Buy Momentum pe 15 min:</text>
|
||||
<text x="244.0" y="275.9" fill="#0891b2" text-anchor="middle" style="font-weight:bold">de aici ai voie doar long</text>
|
||||
<line x1="320.0" y1="201.5" x2="347.2" y2="128.4" stroke="#555" stroke-width="1.8"/>
|
||||
<polygon points="350.0,120.9 351.0,129.8 343.5,127.0" fill="#555"/>
|
||||
<text x="320.0" y="215.5" fill="#555" text-anchor="middle" style="font-weight:bold">candelă roșie pe 15 min, dar close-ul</text>
|
||||
<text x="320.0" y="229.5" fill="#555" text-anchor="middle" style="font-weight:bold">rămâne peste 99.80: pullback, nu întoarcere</text>
|
||||
<line x1="372.0" y1="74.0" x2="389.6" y2="87.4" stroke="#188a3e" stroke-width="1.8"/>
|
||||
<polygon points="396.0,92.2 387.2,90.6 392.0,84.2" fill="#188a3e"/>
|
||||
<text x="372.0" y="69.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">aici cade trigger-ul de pe 3 min</text>
|
||||
</g>
|
||||
<g transform="translate(0,311)"><text x="24" y="22" fill="#c00" style="font-weight:bold">NU — 15 min s-a închis Sell: setup-ul long e anulat</text><rect x="376.0" y="85.9" width="86.0" height="85.0" fill="#c00" fill-opacity="0.12" stroke="#c00" stroke-width="1"/><text x="382.0" y="78.9" fill="#c00" style="font-weight:bold">setup anulat</text><line x1="24" y1="70.9" x2="666" y2="70.9" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="64.9" fill="#0891b2" text-anchor="end" style="font-weight:bold">close-ul candelei de semnal 100.60</text><line x1="24" y1="107.7" x2="666" y2="107.7" stroke="#555" stroke-width="1.5" stroke-dasharray="2 3"/><text x="30" y="128.7" fill="#555" text-anchor="start" style="font-weight:bold">minimul din care a pornit mișcarea 99.80</text>
|
||||
<line x1="74.0" y1="174.4" x2="74.0" y2="197.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="66.5" y="179.0" width="15" height="11.5" fill="#188a3e"/>
|
||||
<line x1="120.0" y1="158.3" x2="120.0" y2="183.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="112.5" y="162.9" width="15" height="16.1" fill="#188a3e"/>
|
||||
<line x1="166.0" y1="139.9" x2="166.0" y2="167.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="158.5" y="144.5" width="15" height="18.4" fill="#188a3e"/>
|
||||
<line x1="212.0" y1="123.8" x2="212.0" y2="149.1" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="204.5" y="130.7" width="15" height="13.8" fill="#188a3e"/>
|
||||
<line x1="258.0" y1="100.8" x2="258.0" y2="135.3" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="250.5" y="105.4" width="15" height="25.3" fill="#188a3e"/>
|
||||
<line x1="304.0" y1="64.0" x2="304.0" y2="107.7" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="296.5" y="70.9" width="15" height="34.5" fill="#188a3e"/>
|
||||
<line x1="350.0" y1="66.3" x2="350.0" y2="98.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="342.5" y="70.9" width="15" height="25.3" fill="#c00"/>
|
||||
<line x1="396.0" y1="93.9" x2="396.0" y2="135.3" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="388.5" y="96.2" width="15" height="34.5" fill="#c00"/>
|
||||
<line x1="442.0" y1="126.1" x2="442.0" y2="162.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="434.5" y="130.7" width="15" height="25.3" fill="#c00"/>
|
||||
<line x1="244.0" y1="229.5" x2="300.4" y2="118.8" stroke="#0891b2" stroke-width="1.8"/>
|
||||
<polygon points="304.0,111.7 303.9,120.6 296.8,117.0" fill="#0891b2"/>
|
||||
<text x="244.0" y="243.5" fill="#0891b2" text-anchor="middle" style="font-weight:bold">Buy Momentum pe 15 min:</text>
|
||||
<text x="244.0" y="257.5" fill="#0891b2" text-anchor="middle" style="font-weight:bold">de aici ai voie doar long</text>
|
||||
<line x1="356.0" y1="190.9" x2="391.1" y2="145.6" stroke="#c00" stroke-width="1.8"/>
|
||||
<polygon points="396.0,139.3 394.3,148.1 387.9,143.2" fill="#c00"/>
|
||||
<text x="356.0" y="204.9" fill="#c00" text-anchor="middle" style="font-weight:bold">close 99.30, sub 99.80: direcția mare</text>
|
||||
<text x="356.0" y="218.9" fill="#c00" text-anchor="middle" style="font-weight:bold">s-a răsucit — nu mai intri long</text>
|
||||
<line x1="322.0" y1="274.9" x2="436.1" y2="172.3" stroke="#c00" stroke-width="1.8"/>
|
||||
<polygon points="442.0,166.9 438.7,175.2 433.4,169.3" fill="#c00"/>
|
||||
<text x="322.0" y="288.9" fill="#c00" text-anchor="middle" style="font-weight:bold">de aici cauți short, nu long</text>
|
||||
</g>
|
||||
<text x="24" y="641" fill="#555">Același grafic de 15 minute ca în diagrama de ansamblu; serie construită, fără ticker.</text>
|
||||
<text x="24" y="658" fill="#555">Pe 15 min se citește DIRECȚIA, nu intrarea. Intrarea vine de pe 3 min (pasul 3).</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
124
gen/strategii/m2d_duo.py
Normal file
@@ -0,0 +1,124 @@
|
||||
"""Ajutor comun pentru diagramele capitolului M2D cu două panouri (DA / NU).
|
||||
|
||||
Tiparul e cel din `buy_doji_fereastra.py`: două `Chart`-uri desenate cu
|
||||
`_render()` și puse unul sub altul într-un singur SVG, plus verificarea că
|
||||
nicio etichetă nu iese din pânză și că nicio pereche de etichete de pe
|
||||
ACELAȘI panou nu se suprapune. E scos aici ca să nu fie copiat în patru
|
||||
generatoare; nu are alt rol.
|
||||
|
||||
Nu se rulează singur: îl importă `m2d_directie.py`, `m2d_secventa.py`,
|
||||
`m2d_trigger.py`, `m2d_stop.py`, `m2d_iesire.py`.
|
||||
"""
|
||||
import re
|
||||
|
||||
TEXT = re.compile(r'<text x="([-\d.]+)" y="([-\d.]+)"([^>]*)>(.*?)</text>', re.S)
|
||||
GREY = "#555"
|
||||
|
||||
|
||||
def panel(ch, width):
|
||||
"""Corpul SVG al unui Chart, fără <svg>, plus înălțimea lui.
|
||||
|
||||
`_render()`, nu `render()`: al doilea restaurează top/left după desen,
|
||||
iar liniile desenate de mână ar cădea deplasate față de corp.
|
||||
"""
|
||||
svg = ch._render()
|
||||
m = re.search(r'viewBox="0 0 ([\d.]+) ([\d.]+)"', svg)
|
||||
assert m, "viewBox lipsă"
|
||||
assert float(m.group(1)) == width, f"textul unei săgeți iese din {width}px"
|
||||
return svg[svg.index(">") + 1:svg.rindex("</svg>")], float(m.group(2))
|
||||
|
||||
|
||||
def level(ch, price, lines, color, width, below=False, at_left=True, dash="4 3"):
|
||||
"""Linie punctată pe toată lățimea + etichetă, desenată de mână.
|
||||
|
||||
Eticheta din `Level` stă lipită de linie și cade peste candelele care o
|
||||
traversează; aici o pun în marginea liberă a panoului.
|
||||
"""
|
||||
y = ch._y(price)
|
||||
out = [f'<line x1="24" y1="{y:.1f}" x2="{width - 14}" y2="{y:.1f}" stroke="{color}" '
|
||||
f'stroke-width="1.5" stroke-dasharray="{dash}"/>']
|
||||
for k, s in enumerate(lines):
|
||||
ty = (y + 21 + 14 * k) if below else (y - 6 - 14 * (len(lines) - 1 - k))
|
||||
tx, anchor = (30, "start") if at_left else (width - 24, "end")
|
||||
out.append(f'<text x="{tx}" y="{ty:.1f}" fill="{color}" text-anchor="{anchor}" '
|
||||
f'style="font-weight:bold">{s}</text>')
|
||||
return out
|
||||
|
||||
|
||||
def zone(ch, i0, i1, label, color, lift=0.0, pad=16):
|
||||
"""Dreptunghi de evidențiere peste candelele i0..i1, cu eticheta deasupra."""
|
||||
cds = ch.candles[i0:i1 + 1]
|
||||
x0, x1 = ch._cx(i0) - pad, ch._cx(i1) + pad
|
||||
y0 = ch._y(max(c.h for c in cds)) - 8 - lift
|
||||
y1 = ch._y(min(c.l for c in cds)) + 8
|
||||
out = [f'<rect x="{x0:.1f}" y="{y0:.1f}" width="{x1 - x0:.1f}" height="{y1 - y0:.1f}" '
|
||||
f'fill="{color}" fill-opacity="0.12" stroke="{color}" stroke-width="1"/>']
|
||||
if label:
|
||||
out.append(f'<text x="{x0 + 6:.1f}" y="{y0 - 7:.1f}" fill="{color}" '
|
||||
f'style="font-weight:bold">{label}</text>')
|
||||
return out
|
||||
|
||||
|
||||
def titlu(s, y=22, color="#333", x=24):
|
||||
"""Titlul panoului, desenat de mână.
|
||||
|
||||
`Chart(title=...)` îl pune la `top - 8`, adică la 7 px de eticheta unei
|
||||
zone desenate la `y(pmax) - 15` — se calcă mereu, indiferent de `top`.
|
||||
"""
|
||||
return [f'<text x="{x}" y="{y}" fill="{color}" style="font-weight:bold">{s}</text>']
|
||||
|
||||
|
||||
def _texts(body, y_off, tag):
|
||||
out = []
|
||||
for m in TEXT.finditer(body):
|
||||
x, y = float(m.group(1)), float(m.group(2)) + y_off
|
||||
attrs, s = m.group(3), m.group(4)
|
||||
anchor = ("end" if 'text-anchor="end"' in attrs
|
||||
else "middle" if 'text-anchor="middle"' in attrs else "start")
|
||||
w = len(s) * 12 * (0.62 if "bold" in attrs else 0.52)
|
||||
left = x - w if anchor == "end" else (x - w / 2 if anchor == "middle" else x)
|
||||
out.append((left, left + w, y, s, tag))
|
||||
return out
|
||||
|
||||
|
||||
def build(panels, captions, width, vgap=0):
|
||||
"""`panels` = listă de (eticheta panoului, corp SVG, înălțime, extra).
|
||||
|
||||
Întoarce SVG-ul întreg, după ce verifică etichetele.
|
||||
"""
|
||||
parts = [f'<svg viewBox="0 0 {width} {{H}}" xmlns="http://www.w3.org/2000/svg" '
|
||||
f'style="width:100%;height:auto;font:12px sans-serif">']
|
||||
labels, off = [], 0.0
|
||||
for tag, body, h, extra in panels:
|
||||
parts.append(f'<g transform="translate(0,{off:.0f})">{"".join(extra)}{body}</g>')
|
||||
labels += _texts(body + "".join(extra), off, tag)
|
||||
off += h + vgap
|
||||
cap_top = off + 6
|
||||
for i, c in enumerate(captions):
|
||||
assert "<" not in c
|
||||
parts.append(f'<text x="24" y="{cap_top + 17 * i:.0f}" fill="{GREY}">{c}</text>')
|
||||
labels.append((24, 24 + len(c) * 6.3, cap_top + 17 * i, c, "cap"))
|
||||
H = cap_top + 17 * len(captions) + 6
|
||||
parts.append("</svg>")
|
||||
svg = "\n ".join(parts).replace("{H}", f"{H:.0f}")
|
||||
assert "\n\n" not in svg, "linie goală în SVG"
|
||||
assert ".md:" not in svg, "trimitere fișier:linie în SVG"
|
||||
|
||||
for left, right, y, s, tag in labels:
|
||||
assert left >= -2 and right <= width + 2, f"[{tag}] text iese din pânză: {s!r}"
|
||||
assert 0 <= y <= H, f"[{tag}] text în afara înălțimii: {s!r} (y={y:.0f})"
|
||||
for i in range(len(labels)):
|
||||
li, ri, yi, si, ti = labels[i]
|
||||
for j in range(i + 1, len(labels)):
|
||||
lj, rj, yj, sj, tj = labels[j]
|
||||
if ti == tj and abs(yi - yj) < 12 and li < rj - 4 and lj < ri - 4:
|
||||
raise AssertionError(f"[{ti}] texte suprapuse: {si!r} / {sj!r}")
|
||||
return svg, H, len(labels)
|
||||
|
||||
|
||||
def fara_preturi_straine(svg, permise):
|
||||
"""Nicio etichetă nu numește un `\\d+\\.\\d\\d` care nu e un nivel desenat."""
|
||||
gasite = {float(x) for x in re.findall(r"\d+\.\d\d", " ".join(
|
||||
m.group(4) for m in TEXT.finditer(svg)))}
|
||||
strain = {g for g in gasite if not any(abs(g - p) < 0.005 for p in permise)}
|
||||
assert not strain, f"prețuri în etichete care nu sunt niveluri desenate: {sorted(strain)}"
|
||||
169
gen/strategii/m2d_iesire.py
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python3
|
||||
"""M2D, pasul 5 — ieșirea: TP1 la 1:1 și restul pe trail, long și short.
|
||||
|
||||
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: iesire -->`.
|
||||
|
||||
Sus, LONG: barele de după trigger din seria de 3 minute a diagramei de
|
||||
ansamblu. Prima tranșă iese la TP1 = 1:1. Restul merge pe bull trail: linia
|
||||
sare pe low-ul fiecărei bare care se ÎNCHIDE peste high-ul precedentei și nu
|
||||
coboară niciodată. Ieșirea vine la prima bară care se închide sub linie —
|
||||
fitilul de dedesubt al barei dinainte nu scoate pe nimeni.
|
||||
|
||||
Jos, SHORT: exact aceeași serie oglindită în jurul lui 100.00 (p' = 200 − p),
|
||||
deci bear trail-ul e construit de același cod, doar cu semnele întoarse.
|
||||
Oglinda e calculată, nu desenată din ochi.
|
||||
|
||||
Rulare: python3 gen/strategii/m2d_iesire.py
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, "/workspace/atm-curs-dl")
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from svg_candles import Arrow, Candle, Chart # noqa: E402
|
||||
import m2d_duo as duo # noqa: E402
|
||||
|
||||
OUT = Path(__file__).with_suffix(".svg")
|
||||
W, SCALE, GAP, LEFT = 680, 150.0, 40, 66
|
||||
GREEN, RED, ORANGE, GREY = "#188a3e", "#c00", "#b06000", "#555"
|
||||
OGLINDA = 200.0 # axa de oglindire: p' = OGLINDA − p
|
||||
|
||||
LONG = [(99.98, 100.08, 99.94, 100.02),
|
||||
(100.02, 100.45, 100.00, 100.40), # 1: trigger, intrare
|
||||
(100.40, 100.60, 100.35, 100.55), (100.55, 100.75, 100.50, 100.70),
|
||||
(100.70, 101.00, 100.65, 100.95), # 4: TP1 atins
|
||||
(100.95, 101.10, 100.88, 101.05), (101.05, 101.15, 100.95, 101.00),
|
||||
(101.00, 101.40, 100.95, 101.35), (101.35, 101.55, 101.25, 101.45),
|
||||
(101.45, 101.50, 101.20, 101.25), # 9: fitil sub linie, close peste
|
||||
(101.25, 101.30, 101.05, 101.10), # 10: close sub linie = ieși
|
||||
(101.10, 101.15, 100.90, 100.95)]
|
||||
TRIG, SL_LONG = 1, 99.90 # stopul vine din pasul 4
|
||||
|
||||
SHORT = [(OGLINDA - o, OGLINDA - l, OGLINDA - h, OGLINDA - c) for o, h, l, c in LONG]
|
||||
SL_SHORT = OGLINDA - SL_LONG
|
||||
|
||||
|
||||
def trepte(bars, trig, sus):
|
||||
"""Linia de trail, bară cu bară, de la trigger încolo.
|
||||
|
||||
sus=True: bull trail — sare pe low-ul barei care se ÎNCHIDE peste high-ul
|
||||
precedentei. sus=False: bear trail — pe high-ul barei care se închide sub
|
||||
low-ul precedentei. `None` cât timp linia nu există încă.
|
||||
"""
|
||||
linie, out, iesire = None, [], None
|
||||
for i, (o, h, l, c) in enumerate(bars):
|
||||
if i > trig and linie is not None and ((c < linie) if sus else (c > linie)):
|
||||
iesire = i
|
||||
out.append(linie)
|
||||
break
|
||||
if i > trig:
|
||||
p = bars[i - 1]
|
||||
if (c > p[1]) if sus else (c < p[2]):
|
||||
linie = l if sus else h
|
||||
out.append(linie)
|
||||
return out + [linie] * (len(bars) - len(out)), iesire
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- verificări
|
||||
for nume, bars in (("LONG", LONG), ("SHORT", SHORT)):
|
||||
for i, (o, h, l, c) in enumerate(bars):
|
||||
assert h >= max(o, c) and l <= min(o, c), f"{nume}[{i}]: high/low incoerent"
|
||||
if i:
|
||||
assert abs(o - bars[i - 1][3]) < 1e-9, f"{nume}[{i}]: open != close precedent"
|
||||
|
||||
E_L, E_S = LONG[TRIG][3], SHORT[TRIG][3]
|
||||
R_L, R_S = round(E_L - SL_LONG, 2), round(SL_SHORT - E_S, 2)
|
||||
TP_L, TP_S = round(E_L + R_L, 2), round(E_S - R_S, 2)
|
||||
assert (E_L, R_L, TP_L) == (100.40, 0.50, 100.90), (E_L, R_L, TP_L)
|
||||
assert (E_S, R_S, TP_S) == (99.60, 0.50, 99.10), (E_S, R_S, TP_S)
|
||||
assert abs((OGLINDA - E_L) - E_S) < 1e-9 and abs((OGLINDA - TP_L) - TP_S) < 1e-9, \
|
||||
"oglinda nu e exactă"
|
||||
|
||||
TP_BAR_L = next(i for i in range(TRIG + 1, len(LONG)) if LONG[i][1] >= TP_L - 1e-9)
|
||||
TP_BAR_S = next(i for i in range(TRIG + 1, len(SHORT)) if SHORT[i][2] <= TP_S + 1e-9)
|
||||
assert TP_BAR_L == TP_BAR_S == 4, (TP_BAR_L, TP_BAR_S)
|
||||
|
||||
LIN_L, EX_L = trepte(LONG, TRIG, True)
|
||||
LIN_S, EX_S = trepte(SHORT, TRIG, False)
|
||||
assert EX_L == EX_S == 10, (EX_L, EX_S)
|
||||
TRAIL_L, TRAIL_S = LIN_L[EX_L], LIN_S[EX_S]
|
||||
assert (TRAIL_L, TRAIL_S) == (101.25, 98.75), (TRAIL_L, TRAIL_S)
|
||||
assert abs((OGLINDA - TRAIL_L) - TRAIL_S) < 1e-9, "trail-ul oglindit nu se potrivește"
|
||||
# linia urcă (long) / coboară (short) și nu se întoarce niciodată
|
||||
pas_l = [v for v in LIN_L[:EX_L + 1] if v is not None]
|
||||
pas_s = [v for v in LIN_S[:EX_S + 1] if v is not None]
|
||||
assert all(b >= a for a, b in zip(pas_l, pas_l[1:])), "bull trail-ul coboară"
|
||||
assert all(b <= a for a, b in zip(pas_s, pas_s[1:])), "bear trail-ul urcă"
|
||||
# bara 9: fitilul trece de linie, close-ul nu — deci nu scoate
|
||||
assert LONG[9][2] < TRAIL_L <= LONG[9][3], "bara 9 nu mai ilustrează fitilul sub linie"
|
||||
assert SHORT[9][1] > TRAIL_S >= SHORT[9][3], "oglinda barei 9 nu ține"
|
||||
EXIT_L, EXIT_S = LONG[EX_L][3], SHORT[EX_S][3]
|
||||
RR_L = round((EXIT_L - E_L) / R_L, 1)
|
||||
RR_S = round((E_S - EXIT_S) / R_S, 1)
|
||||
assert RR_L == RR_S == 1.4, (RR_L, RR_S)
|
||||
|
||||
|
||||
def chart(bars, arrows, top=70):
|
||||
return Chart(candles=[Candle(*b) for b in bars], arrows=arrows, scale=SCALE,
|
||||
gap=GAP, body_w=14, left=LEFT, width=W, top=top)
|
||||
|
||||
|
||||
def scara(ch, linie, pana_la, color):
|
||||
"""Linia de trail desenată ca scară: un palier pe fiecare bară."""
|
||||
seg, prev = [], None
|
||||
for i, v in enumerate(linie[:pana_la + 1]):
|
||||
if v is None:
|
||||
continue
|
||||
y, x0, x1 = ch._y(v), ch._cx(i) - GAP / 2, ch._cx(i) + GAP / 2
|
||||
seg.append(f'<line x1="{x0:.1f}" y1="{y:.1f}" x2="{x1:.1f}" y2="{y:.1f}" '
|
||||
f'stroke="{color}" stroke-width="2"/>')
|
||||
if prev is not None and abs(prev - v) > 1e-9:
|
||||
seg.append(f'<line x1="{x0:.1f}" y1="{ch._y(prev):.1f}" x2="{x0:.1f}" '
|
||||
f'y2="{y:.1f}" stroke="{color}" stroke-width="1.2" '
|
||||
f'stroke-dasharray="2 2"/>')
|
||||
prev = v
|
||||
return seg
|
||||
|
||||
|
||||
ch_l = chart(LONG, [
|
||||
Arrow(TP_BAR_L, "prima tranșă iese aici, la TP1",
|
||||
where="above", color=GREEN, dx=-60, dy=-8),
|
||||
Arrow(9, "fitilul trece sub linie, close-ul nu:\nnu ieși pe fitil",
|
||||
where="below", color=GREY, dx=-30, dy=86),
|
||||
Arrow(EX_L, "prima bară ÎNCHISĂ sub linie:\niese restul poziției, 1.4R",
|
||||
where="below", color=ORANGE, dx=-20, dy=18)])
|
||||
ch_s = chart(SHORT, [
|
||||
Arrow(TP_BAR_S, "prima tranșă iese aici, la TP1",
|
||||
where="below", color=GREEN, dx=-60, dy=20),
|
||||
Arrow(EX_S, "prima bară ÎNCHISĂ peste linie:\niese restul poziției, 1.4R",
|
||||
where="above", color=ORANGE, dx=-20, dy=-8)])
|
||||
|
||||
body_l, h_l = duo.panel(ch_l, W)
|
||||
body_s, h_s = duo.panel(ch_s, W)
|
||||
|
||||
extra_l = (duo.titlu("LONG — bull trail: linia urcă, nu coboară", color=GREEN)
|
||||
+ scara(ch_l, LIN_L, EX_L, ORANGE)
|
||||
+ duo.level(ch_l, TP_L, ["TP1 100.90 = 1:1"], GREEN, W, at_left=False)
|
||||
+ duo.level(ch_l, E_L, ["intrare 100.40"], GREEN, W, below=True, at_left=False)
|
||||
+ duo.level(ch_l, SL_LONG, ["stop 99.90 (pasul 4)"], RED, W, below=True))
|
||||
extra_s = (duo.titlu("SHORT — bear trail: exact aceeași serie, oglindită", color=RED)
|
||||
+ scara(ch_s, LIN_S, EX_S, ORANGE)
|
||||
+ duo.level(ch_s, SL_SHORT, ["stop 100.10 (pasul 4)"], RED, W, at_left=False)
|
||||
+ duo.level(ch_s, E_S, ["intrare 99.60"], GREEN, W, below=False)
|
||||
+ duo.level(ch_s, TP_S, ["TP1 99.10 = 1:1"], GREEN, W, below=True,
|
||||
at_left=False))
|
||||
|
||||
svg, H, n = duo.build(
|
||||
[("LONG", body_l, h_l, extra_l), ("SHORT", body_s, h_s, extra_s)],
|
||||
["Serii construite, aceleași cifre ca în restul capitolului.",
|
||||
"Scara portocalie e linia de trail, palier cu palier.",
|
||||
"Panoul de jos e panoul de sus oglindit în jurul lui 100.00, calculat, "
|
||||
"nu desenat din ochi."],
|
||||
W)
|
||||
duo.fara_preturi_straine(svg, [E_L, TP_L, SL_LONG, TRAIL_L, EXIT_L,
|
||||
E_S, TP_S, SL_SHORT, TRAIL_S, EXIT_S, OGLINDA, 100.00])
|
||||
OUT.write_text(svg, encoding="utf-8")
|
||||
print(f"scris {OUT} ({W}x{H:.0f}), {n} etichete | LONG: intrare {E_L:.2f} SL {SL_LONG:.2f} "
|
||||
f"TP1 {TP_L:.2f} la bara {TP_BAR_L}, trail {TRAIL_L:.2f}, ieșire bara {EX_L} la "
|
||||
f"{EXIT_L:.2f} = {RR_L}R | SHORT (oglindit): intrare {E_S:.2f} SL {SL_SHORT:.2f} "
|
||||
f"TP1 {TP_S:.2f}, trail {TRAIL_S:.2f}, ieșire {EXIT_S:.2f} = {RR_S}R")
|
||||
75
gen/strategii/m2d_iesire.svg
Normal file
@@ -0,0 +1,75 @@
|
||||
<svg viewBox="0 0 680 737" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<g transform="translate(0,0)"><text x="24" y="22" fill="#188a3e" style="font-weight:bold">LONG — bull trail: linia urcă, nu coboară</text><line x1="126.0" y1="250.0" x2="166.0" y2="250.0" stroke="#b06000" stroke-width="2"/><line x1="166.0" y1="227.5" x2="206.0" y2="227.5" stroke="#b06000" stroke-width="2"/><line x1="166.0" y1="250.0" x2="166.0" y2="227.5" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="206.0" y1="205.0" x2="246.0" y2="205.0" stroke="#b06000" stroke-width="2"/><line x1="206.0" y1="227.5" x2="206.0" y2="205.0" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="246.0" y1="170.5" x2="286.0" y2="170.5" stroke="#b06000" stroke-width="2"/><line x1="246.0" y1="205.0" x2="246.0" y2="170.5" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="286.0" y1="170.5" x2="326.0" y2="170.5" stroke="#b06000" stroke-width="2"/><line x1="326.0" y1="160.0" x2="366.0" y2="160.0" stroke="#b06000" stroke-width="2"/><line x1="326.0" y1="170.5" x2="326.0" y2="160.0" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="366.0" y1="115.0" x2="406.0" y2="115.0" stroke="#b06000" stroke-width="2"/><line x1="366.0" y1="160.0" x2="366.0" y2="115.0" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="406.0" y1="115.0" x2="446.0" y2="115.0" stroke="#b06000" stroke-width="2"/><line x1="446.0" y1="115.0" x2="486.0" y2="115.0" stroke="#b06000" stroke-width="2"/><line x1="24" y1="167.5" x2="666" y2="167.5" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="161.5" fill="#188a3e" text-anchor="end" style="font-weight:bold">TP1 100.90 = 1:1</text><line x1="24" y1="242.5" x2="666" y2="242.5" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="263.5" fill="#188a3e" text-anchor="end" style="font-weight:bold">intrare 100.40</text><line x1="24" y1="317.5" x2="666" y2="317.5" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/><text x="30" y="338.5" fill="#c00" text-anchor="start" style="font-weight:bold">stop 99.90 (pasul 4)</text>
|
||||
<line x1="66.0" y1="290.5" x2="66.0" y2="311.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="59.0" y="299.5" width="14" height="6.0" fill="#188a3e"/>
|
||||
<line x1="106.0" y1="235.0" x2="106.0" y2="302.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="99.0" y="242.5" width="14" height="57.0" fill="#188a3e"/>
|
||||
<line x1="146.0" y1="212.5" x2="146.0" y2="250.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="139.0" y="220.0" width="14" height="22.5" fill="#188a3e"/>
|
||||
<line x1="186.0" y1="190.0" x2="186.0" y2="227.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="179.0" y="197.5" width="14" height="22.5" fill="#188a3e"/>
|
||||
<line x1="226.0" y1="152.5" x2="226.0" y2="205.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="219.0" y="160.0" width="14" height="37.5" fill="#188a3e"/>
|
||||
<line x1="266.0" y1="137.5" x2="266.0" y2="170.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="259.0" y="145.0" width="14" height="15.0" fill="#188a3e"/>
|
||||
<line x1="306.0" y1="130.0" x2="306.0" y2="160.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="299.0" y="145.0" width="14" height="7.5" fill="#c00"/>
|
||||
<line x1="346.0" y1="92.5" x2="346.0" y2="160.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="339.0" y="100.0" width="14" height="52.5" fill="#188a3e"/>
|
||||
<line x1="386.0" y1="70.0" x2="386.0" y2="115.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="379.0" y="85.0" width="14" height="15.0" fill="#188a3e"/>
|
||||
<line x1="426.0" y1="77.5" x2="426.0" y2="122.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="419.0" y="85.0" width="14" height="30.0" fill="#c00"/>
|
||||
<line x1="466.0" y1="107.5" x2="466.0" y2="145.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="459.0" y="115.0" width="14" height="22.5" fill="#c00"/>
|
||||
<line x1="506.0" y1="130.0" x2="506.0" y2="167.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="499.0" y="137.5" width="14" height="22.5" fill="#c00"/>
|
||||
<line x1="166.0" y1="114.5" x2="219.0" y2="144.6" stroke="#188a3e" stroke-width="1.8"/>
|
||||
<polygon points="226.0,148.5 217.1,148.0 221.0,141.1" fill="#188a3e"/>
|
||||
<text x="166.0" y="109.5" fill="#188a3e" text-anchor="middle" style="font-weight:bold">prima tranșă iese aici, la TP1</text>
|
||||
<line x1="396.0" y1="261.5" x2="424.3" y2="134.3" stroke="#555" stroke-width="1.8"/>
|
||||
<polygon points="426.0,126.5 428.2,135.2 420.4,133.4" fill="#555"/>
|
||||
<text x="396.0" y="275.5" fill="#555" text-anchor="middle" style="font-weight:bold">fitilul trece sub linie, close-ul nu:</text>
|
||||
<text x="396.0" y="289.5" fill="#555" text-anchor="middle" style="font-weight:bold">nu ieși pe fitil</text>
|
||||
<line x1="446.0" y1="193.5" x2="462.7" y2="156.3" stroke="#b06000" stroke-width="1.8"/>
|
||||
<polygon points="466.0,149.0 466.4,157.9 459.1,154.7" fill="#b06000"/>
|
||||
<text x="446.0" y="207.5" fill="#b06000" text-anchor="middle" style="font-weight:bold">prima bară ÎNCHISĂ sub linie:</text>
|
||||
<text x="446.0" y="221.5" fill="#b06000" text-anchor="middle" style="font-weight:bold">iese restul poziției, 1.4R</text>
|
||||
</g>
|
||||
<g transform="translate(0,337)"><text x="24" y="22" fill="#c00" style="font-weight:bold">SHORT — bear trail: exact aceeași serie, oglindită</text><line x1="126.0" y1="131.5" x2="166.0" y2="131.5" stroke="#b06000" stroke-width="2"/><line x1="166.0" y1="154.0" x2="206.0" y2="154.0" stroke="#b06000" stroke-width="2"/><line x1="166.0" y1="131.5" x2="166.0" y2="154.0" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="206.0" y1="176.5" x2="246.0" y2="176.5" stroke="#b06000" stroke-width="2"/><line x1="206.0" y1="154.0" x2="206.0" y2="176.5" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="246.0" y1="211.0" x2="286.0" y2="211.0" stroke="#b06000" stroke-width="2"/><line x1="246.0" y1="176.5" x2="246.0" y2="211.0" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="286.0" y1="211.0" x2="326.0" y2="211.0" stroke="#b06000" stroke-width="2"/><line x1="326.0" y1="221.5" x2="366.0" y2="221.5" stroke="#b06000" stroke-width="2"/><line x1="326.0" y1="211.0" x2="326.0" y2="221.5" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="366.0" y1="266.5" x2="406.0" y2="266.5" stroke="#b06000" stroke-width="2"/><line x1="366.0" y1="221.5" x2="366.0" y2="266.5" stroke="#b06000" stroke-width="1.2" stroke-dasharray="2 2"/><line x1="406.0" y1="266.5" x2="446.0" y2="266.5" stroke="#b06000" stroke-width="2"/><line x1="446.0" y1="266.5" x2="486.0" y2="266.5" stroke="#b06000" stroke-width="2"/><line x1="24" y1="64.0" x2="666" y2="64.0" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="58.0" fill="#c00" text-anchor="end" style="font-weight:bold">stop 100.10 (pasul 4)</text><line x1="24" y1="139.0" x2="666" y2="139.0" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/><text x="30" y="133.0" fill="#188a3e" text-anchor="start" style="font-weight:bold">intrare 99.60</text><line x1="24" y1="214.0" x2="666" y2="214.0" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="235.0" fill="#188a3e" text-anchor="end" style="font-weight:bold">TP1 99.10 = 1:1</text>
|
||||
<line x1="66.0" y1="70.0" x2="66.0" y2="91.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="59.0" y="76.0" width="14" height="6.0" fill="#c00"/>
|
||||
<line x1="106.0" y1="79.0" x2="106.0" y2="146.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="99.0" y="82.0" width="14" height="57.0" fill="#c00"/>
|
||||
<line x1="146.0" y1="131.5" x2="146.0" y2="169.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="139.0" y="139.0" width="14" height="22.5" fill="#c00"/>
|
||||
<line x1="186.0" y1="154.0" x2="186.0" y2="191.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="179.0" y="161.5" width="14" height="22.5" fill="#c00"/>
|
||||
<line x1="226.0" y1="176.5" x2="226.0" y2="229.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="219.0" y="184.0" width="14" height="37.5" fill="#c00"/>
|
||||
<line x1="266.0" y1="211.0" x2="266.0" y2="244.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="259.0" y="221.5" width="14" height="15.0" fill="#c00"/>
|
||||
<line x1="306.0" y1="221.5" x2="306.0" y2="251.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="299.0" y="229.0" width="14" height="7.5" fill="#188a3e"/>
|
||||
<line x1="346.0" y1="221.5" x2="346.0" y2="289.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="339.0" y="229.0" width="14" height="52.5" fill="#c00"/>
|
||||
<line x1="386.0" y1="266.5" x2="386.0" y2="311.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="379.0" y="281.5" width="14" height="15.0" fill="#c00"/>
|
||||
<line x1="426.0" y1="259.0" x2="426.0" y2="304.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="419.0" y="266.5" width="14" height="30.0" fill="#188a3e"/>
|
||||
<line x1="466.0" y1="236.5" x2="466.0" y2="274.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="459.0" y="244.0" width="14" height="22.5" fill="#188a3e"/>
|
||||
<line x1="506.0" y1="214.0" x2="506.0" y2="251.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="499.0" y="221.5" width="14" height="22.5" fill="#188a3e"/>
|
||||
<line x1="166.0" y1="279.0" x2="219.7" y2="237.9" stroke="#188a3e" stroke-width="1.8"/>
|
||||
<polygon points="226.0,233.0 222.1,241.0 217.2,234.7" fill="#188a3e"/>
|
||||
<text x="166.0" y="293.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">prima tranșă iese aici, la TP1</text>
|
||||
<line x1="446.0" y1="198.0" x2="462.0" y2="225.6" stroke="#b06000" stroke-width="1.8"/>
|
||||
<polygon points="466.0,232.5 458.5,227.6 465.4,223.6" fill="#b06000"/>
|
||||
<text x="446.0" y="179.0" fill="#b06000" text-anchor="middle" style="font-weight:bold">prima bară ÎNCHISĂ peste linie:</text>
|
||||
<text x="446.0" y="193.0" fill="#b06000" text-anchor="middle" style="font-weight:bold">iese restul poziției, 1.4R</text>
|
||||
</g>
|
||||
<text x="24" y="680" fill="#555">Serii construite, aceleași cifre ca în restul capitolului.</text>
|
||||
<text x="24" y="697" fill="#555">Scara portocalie e linia de trail, palier cu palier.</text>
|
||||
<text x="24" y="714" fill="#555">Panoul de jos e panoul de sus oglindit în jurul lui 100.00, calculat, nu desenat din ochi.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
@@ -1,268 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Secvența M → A a strategiei M2D — schemă conceptuală pe două panouri.
|
||||
"""M2D, pasul 2 — pullback-ul (M) pe TF mic: DA (există) vs. NU (lipsește).
|
||||
|
||||
Pentru `strategii/03_m2d.md`, marcajul `<!-- DIAGRAMA: secventa -->`.
|
||||
Nu e grafic de preț (spec: „schemă pe două panouri, nu candele de trade”):
|
||||
SVG scris de mână, doar stdlib — nu se folosește svg_candles / pchart.
|
||||
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: secventa -->`.
|
||||
|
||||
Ce arată (toate etichetele vin din spec; nicio cifră de preț nu se inventează):
|
||||
- panoul de sus, LONG: pe TF mare (15 min) polilinia urcă și „rămâne în Buy pe
|
||||
tot parcursul”; pe TF mic (3 min) urcă → pullback (M: Sell Momentum) → urcă
|
||||
peste vârful anterior (A: Buy Momentum — TRIGGER, intri long);
|
||||
- panoul de jos, SHORT: oglindit — TF mare coboară („rămâne în Sell”), TF mic
|
||||
coboară → pullback în sus (M: Buy Momentum) → coboară sub minimul anterior
|
||||
(A: Sell Momentum — TRIGGER, intri short);
|
||||
- două linii verticale punctate leagă momentul M și momentul A de rândul de sus
|
||||
(verificarea că TF mare rămâne în aceeași direcție);
|
||||
- textul de subsol: „Secvența contează, nu starea...”.
|
||||
Panoul de sus e chiar graficul de 3 minute din diagrama de ansamblu, primele
|
||||
13 bare — aceleași cifre în tot capitolul. Panoul de jos pornește din același
|
||||
preț, dar urcă fără să se oprească: nu există pullback, deci nu există setup
|
||||
M2D, oricât de frumoasă ar fi mișcarea.
|
||||
|
||||
Rulare: python3 gen/strategii/m2d_secventa.py -> gen/strategii/m2d_secventa.svg
|
||||
Definiția pe care o susține desenul: pullback = revenire scurtă contra
|
||||
direcției mari care NU rupe minimul din care a pornit mișcarea. Minimul acela
|
||||
e low-ul candelei de 15 min care a dat semnalul (99.80) și e desenat pe
|
||||
ambele panouri.
|
||||
|
||||
Rulare: python3 gen/strategii/m2d_secventa.py
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from xml.sax.saxutils import escape
|
||||
|
||||
sys.path.insert(0, "/workspace/atm-curs-dl")
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from svg_candles import Arrow, Candle, Chart # noqa: E402
|
||||
import m2d_duo as duo # noqa: E402
|
||||
|
||||
OUT = Path(__file__).with_suffix(".svg")
|
||||
W, SCALE, GAP, LEFT = 680, 108.0, 32, 66
|
||||
GREEN, RED, BLUE, CYAN, GREY = "#188a3e", "#c00", "#1a5fb4", "#0891b2", "#555"
|
||||
|
||||
W, H = 700, 780
|
||||
BLACK, GRAY, RED, GREEN, BLUE, CYAN, WHITE = (
|
||||
"#000000", "#777777", "#c00", "#188a3e", "#1a5fb4", "#00b8c4", "#ffffff")
|
||||
PANEL_BG, PANEL_EDGE = "#fafafa", "#ddd"
|
||||
REF_LOW = 99.80 # low-ul candelei de 15 min de semnal (vezi diagrama „directie")
|
||||
SEMNAL = 100.60 # close-ul ei = open-ul primei bare de 3 min
|
||||
|
||||
# ---------------------------------------------------------------- geometrie
|
||||
# Fiecare polilinie: listă de (x, y). y mic = sus.
|
||||
# Index: 0 = start, 1 = vârf/trough anterior, 2 = M, 3 = A, 4 = continuare.
|
||||
LONG_TOP = [(40, 162), (150, 148), (250, 138), (430, 128), (660, 118)]
|
||||
LONG_BOT = [(40, 255), (180, 225), (250, 282), (430, 210), (660, 198)]
|
||||
SHORT_TOP = [(40, 430), (150, 444), (250, 454), (430, 464), (660, 474)]
|
||||
SHORT_BOT = [(40, 527), (180, 562), (250, 500), (430, 574), (660, 588)]
|
||||
# --- DA: primele 13 bare din seria de 3 min a diagramei de ansamblu --------
|
||||
DA = [(100.60, 100.70, 100.40, 100.45), (100.45, 100.50, 100.25, 100.30),
|
||||
(100.30, 100.35, 100.15, 100.20), (100.20, 100.25, 100.05, 100.10),
|
||||
(100.10, 100.15, 100.00, 100.05), (100.05, 100.10, 99.95, 100.00),
|
||||
(100.00, 100.05, 99.92, 99.95), (99.95, 100.00, 99.90, 99.98),
|
||||
(99.98, 100.08, 99.94, 100.02), # 8: capătul pullback-ului
|
||||
(100.02, 100.45, 100.00, 100.40), # 9: primul Buy = trigger
|
||||
(100.40, 100.60, 100.35, 100.55), (100.55, 100.75, 100.50, 100.70),
|
||||
(100.70, 101.00, 100.65, 100.95)]
|
||||
PULL_END = 8
|
||||
|
||||
L_M, L_A, S_M, S_A = 2, 3, 2, 3 # indicii momentelor M și A
|
||||
# --- NU: aceeași plecare, dar urcare continuă, fără pullback --------------
|
||||
NU = [(100.60, 100.80, 100.55, 100.75), (100.75, 100.95, 100.70, 100.90),
|
||||
(100.90, 101.10, 100.85, 101.05), (101.05, 101.20, 101.00, 101.15),
|
||||
(101.15, 101.35, 101.10, 101.30), (101.30, 101.45, 101.25, 101.40),
|
||||
(101.40, 101.60, 101.35, 101.55), (101.55, 101.75, 101.50, 101.70),
|
||||
(101.70, 101.90, 101.65, 101.85), (101.85, 102.00, 101.80, 101.95),
|
||||
(101.95, 102.15, 101.90, 102.10), (102.10, 102.25, 102.05, 102.20),
|
||||
(102.20, 102.40, 102.15, 102.35)]
|
||||
|
||||
PANELS = {
|
||||
"LONG": (14, 92, 672, 250),
|
||||
"SHORT": (14, 362, 672, 270),
|
||||
}
|
||||
|
||||
TEXTS = [] # (x, y, text, size, weight, anchor, color) pentru verificare
|
||||
# ---------------------------------------------------------------- verificări
|
||||
for nume, bars in (("DA", DA), ("NU", NU)):
|
||||
for i, (o, h, l, c) in enumerate(bars):
|
||||
assert h >= max(o, c) and l <= min(o, c), f"{nume}[{i}]: high/low incoerent"
|
||||
if i:
|
||||
assert abs(o - bars[i - 1][3]) < 1e-9, f"{nume}[{i}]: open != close precedent"
|
||||
assert abs(bars[0][0] - SEMNAL) < 1e-9, f"{nume}: nu pornește din close-ul semnalului"
|
||||
|
||||
|
||||
def txt(x, y, s, size=13, weight="400", fill=BLACK, anchor="middle"):
|
||||
TEXTS.append((x, y, s, size, weight, anchor, fill))
|
||||
return (f'<text x="{x:.1f}" y="{y:.1f}" font-size="{size}" '
|
||||
f'font-weight="{weight}" fill="{fill}" text-anchor="{anchor}">'
|
||||
f'{escape(s)}</text>')
|
||||
def run_in_jos(bars):
|
||||
"""Cel mai lung șir de close-uri strict descrescătoare."""
|
||||
best = cur = 1
|
||||
for a, b in zip(bars, bars[1:]):
|
||||
cur = cur + 1 if b[3] < a[3] else 1
|
||||
best = max(best, cur)
|
||||
return best
|
||||
|
||||
|
||||
def line(x1, y1, x2, y2, stroke=GRAY, width=1.0, dash=None):
|
||||
d = f' stroke-dasharray="{dash}"' if dash else ""
|
||||
return (f'<line x1="{x1:.1f}" y1="{y1:.1f}" x2="{x2:.1f}" y2="{y2:.1f}" '
|
||||
f'stroke="{stroke}" stroke-width="{width}"{d}/>')
|
||||
assert run_in_jos(DA) >= 3, "DA nu are pullback (niciun șir de 3 close-uri în jos)"
|
||||
assert run_in_jos(NU) < 3, "NU are totuși un pullback"
|
||||
|
||||
PULL_LOW = min(b[2] for b in DA[:PULL_END + 1])
|
||||
assert abs(PULL_LOW - 99.90) < 1e-9, PULL_LOW
|
||||
assert PULL_LOW > REF_LOW, "pullback-ul rupe minimul din care a pornit mișcarea"
|
||||
assert DA[0][3] > DA[PULL_END - 1][3], "pullback-ul nu coboară"
|
||||
assert DA[9][3] > max(b[1] for b in DA[6:9]), "bara 9 nu rupe în sus capătul pullback-ului"
|
||||
assert min(b[3] for b in NU) > SEMNAL, "NU: o bară se închide sub prețul de plecare"
|
||||
|
||||
|
||||
def poly(pts, stroke, width=2.0):
|
||||
p = " ".join(f"{x:.1f},{y:.1f}" for x, y in pts)
|
||||
return f'<polyline points="{p}" fill="none" stroke="{stroke}" stroke-width="{width}"/>'
|
||||
def chart(bars, arrows):
|
||||
return Chart(candles=[Candle(*b) for b in bars], arrows=arrows,
|
||||
scale=SCALE, gap=GAP, body_w=11, left=LEFT, width=W, top=64)
|
||||
|
||||
|
||||
def dot(x, y, fill, r=5.0):
|
||||
return f'<circle cx="{x:.1f}" cy="{y:.1f}" r="{r:.1f}" fill="{fill}"/>'
|
||||
ch_da = chart(DA, [
|
||||
Arrow(PULL_END - 1, "M: pullback-ul obligatoriu — prețul merge\n"
|
||||
"contra direcției mari, dar se oprește la 99.90",
|
||||
where="below", color=RED, dx=-24, dy=46),
|
||||
Arrow(9, "prima bară care urcă peste capătul pullback-ului:\n"
|
||||
"aici începe pasul 3 (trigger-ul)",
|
||||
where="above", color=GREEN, dx=-40, dy=6)])
|
||||
ch_nu = chart(NU, [
|
||||
Arrow(6, "urcare continuă, fără nicio pauză în jos:\n"
|
||||
"asta e breakout, nu M2D — nu ai unde pune stopul",
|
||||
where="below", color=RED, dx=-70, dy=40)])
|
||||
|
||||
body_da, h_da = duo.panel(ch_da, W)
|
||||
body_nu, h_nu = duo.panel(ch_nu, W)
|
||||
|
||||
def build():
|
||||
p = [
|
||||
f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {W} {H}" '
|
||||
f'width="{W}" height="{H}" role="img" aria-label="Secventa M apoi A a '
|
||||
f'strategiei M2D, pe doua time frame-uri, pentru long si short: time '
|
||||
f'frame-ul mare ramane in directie cat timp time frame-ul mic face '
|
||||
f'pullback (M) si apoi da trigger-ul in directia mare (A)">',
|
||||
'<g font-family="system-ui, sans-serif">',
|
||||
f'<rect x="0" y="0" width="{W}" height="{H}" fill="{WHITE}"/>',
|
||||
txt(W / 2, 30, "Secvența M → A: nu e o stare, e o secvență",
|
||||
19, "700", BLACK),
|
||||
txt(W / 2, 52, "M2D — același moment, două time frame-uri: "
|
||||
"TF mare dă direcția, TF mic dă trigger-ul",
|
||||
13, "400", GRAY),
|
||||
txt(W / 2, 72, "sus = LONG; jos = SHORT — aceleași momente, în oglindă",
|
||||
13, "400", GRAY),
|
||||
]
|
||||
extra_da = (duo.titlu("DA — pullback pe 3 min, care nu rupe minimul de referință", color=GREEN)
|
||||
+ duo.zone(ch_da, 0, PULL_END, "M: pullback", RED, pad=12, lift=26)
|
||||
+ duo.level(ch_da, REF_LOW,
|
||||
["minimul din care a pornit mișcarea 99.80 — sub el nu mai e pullback"],
|
||||
GREY, W, below=True, dash="2 3")
|
||||
+ duo.level(ch_da, PULL_LOW, ["cel mai jos punct al pullback-ului 99.90"],
|
||||
RED, W, below=False, at_left=False))
|
||||
extra_nu = (duo.titlu("NU — niciun pullback: nu ai setup, oricât de frumoasă e urcarea",
|
||||
color=RED)
|
||||
+ duo.level(ch_nu, SEMNAL,
|
||||
["close-ul candelei de 15 min de semnal 100.60"], CYAN, W,
|
||||
below=True, at_left=False))
|
||||
|
||||
# ------------------------------------------------------ panouri
|
||||
for name, (px, py, pw, ph) in PANELS.items():
|
||||
p.append(f'<rect x="{px}" y="{py}" width="{pw}" height="{ph}" rx="8" '
|
||||
f'fill="{PANEL_BG}" stroke="{PANEL_EDGE}" stroke-width="1.2"/>')
|
||||
|
||||
# ------------------------------------------------------ panoul LONG
|
||||
p.append(txt(30, 116, "LONG", 15, "700", GREEN, "start"))
|
||||
p.append(txt(30, 140, "TF mare (ex. 15 min)", 13, "400", GRAY, "start"))
|
||||
p.append(txt(660, 114, "rămâne în Buy pe tot parcursul", 13, "400",
|
||||
GREEN, "end"))
|
||||
for x, y_top, y_bot in ((LONG_TOP[L_M][0], LONG_TOP[L_M][1], LONG_BOT[L_M][1]),
|
||||
(LONG_TOP[L_A][0], LONG_TOP[L_A][1], LONG_BOT[L_A][1])):
|
||||
p.append(line(x, y_top, x, y_bot, "#999999", 1.2, "4 4"))
|
||||
p.append(poly(LONG_TOP, GREEN))
|
||||
p.append(dot(*LONG_TOP[1], CYAN))
|
||||
p.append(txt(185, 126, "Buy Momentum", 13, "400", CYAN, "start"))
|
||||
|
||||
p.append(txt(30, 202, "TF mic (ex. 3 min)", 13, "400", GRAY, "start"))
|
||||
p.append(poly(LONG_BOT, "#333333"))
|
||||
p.append(dot(*LONG_BOT[L_M], RED))
|
||||
p.append(txt(262, 296, "M: Sell Momentum (pullback)", 13, "400",
|
||||
RED, "start"))
|
||||
p.append(dot(*LONG_BOT[L_A], GREEN, r=6))
|
||||
p.append(txt(660, 240, "A: Buy Momentum — TRIGGER, intri long",
|
||||
13, "400", GREEN, "end"))
|
||||
|
||||
# ------------------------------------------------------ panoul SHORT
|
||||
p.append(txt(30, 386, "SHORT", 15, "700", RED, "start"))
|
||||
p.append(txt(30, 410, "TF mare (ex. 15 min)", 13, "400", GRAY, "start"))
|
||||
p.append(txt(660, 494, "rămâne în Sell pe tot parcursul", 13, "400",
|
||||
RED, "end"))
|
||||
for x, y_top, y_bot in ((SHORT_TOP[S_M][0], SHORT_TOP[S_M][1], SHORT_BOT[S_M][1]),
|
||||
(SHORT_TOP[S_A][0], SHORT_TOP[S_A][1], SHORT_BOT[S_A][1])):
|
||||
p.append(line(x, y_top, x, y_bot, "#999999", 1.2, "4 4"))
|
||||
p.append(poly(SHORT_TOP, RED))
|
||||
p.append(dot(*SHORT_TOP[1], RED))
|
||||
p.append(txt(168, 432, "Sell Momentum", 13, "400", RED, "start"))
|
||||
|
||||
p.append(txt(30, 470, "TF mic (ex. 3 min)", 13, "400", GRAY, "start"))
|
||||
p.append(poly(SHORT_BOT, "#333333"))
|
||||
p.append(dot(*SHORT_BOT[S_M], CYAN))
|
||||
p.append(txt(238, 494, "M: Buy Momentum (pullback)", 13, "400",
|
||||
CYAN, "end"))
|
||||
p.append(dot(*SHORT_BOT[S_A], RED, r=6))
|
||||
p.append(txt(660, 610, "A: Sell Momentum — TRIGGER, intri short",
|
||||
13, "400", RED, "end"))
|
||||
|
||||
# ------------------------------------------------------ subsol
|
||||
p.append(f'<rect x="40" y="648" width="620" height="116" rx="8" '
|
||||
f'fill="#ffffff" stroke="{GRAY}" stroke-width="1.2"/>')
|
||||
p.append(txt(W / 2, 676,
|
||||
"Secvența contează, nu starea: mare în Buy → mic în Sell → "
|
||||
"mic în Buy", 13, "400", BLACK))
|
||||
p.append(txt(W / 2, 696,
|
||||
"(cu mare încă în Buy). Un Buy direct pe TF mic, fără Sell "
|
||||
"între ele,", 13, "400", BLACK))
|
||||
p.append(txt(W / 2, 716, "NU e trigger (vezi 1.3).", 13, "400", BLACK))
|
||||
p.append(txt(W / 2, 746,
|
||||
"Sursă: 14_strategia_1_m2d.md:30-38, 172-180; "
|
||||
"09_QA/08_2026-01-20.md:65-67", 13, "400", GRAY))
|
||||
|
||||
p.append('</g></svg>')
|
||||
return "\n".join(p) + "\n"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- verificare
|
||||
def est_w(s, size, weight):
|
||||
factor = 0.62 if weight == "700" else 0.56
|
||||
return len(s) * size * factor
|
||||
|
||||
|
||||
def verify(svg):
|
||||
# 1. geometria: panourile nu se suprapun, sunt în panză
|
||||
long_ = PANELS["LONG"]
|
||||
short_ = PANELS["SHORT"]
|
||||
assert long_[1] + long_[3] < short_[1], "panourile LONG/SHORT se suprapun"
|
||||
assert short_[1] + short_[3] < 648, "panoul SHORT intră în subsol"
|
||||
for _, (px, py, pw, ph) in PANELS.items():
|
||||
assert px >= 0 and py >= 0 and px + pw <= W and py + ph <= H
|
||||
|
||||
# 2. secvența LONG: TF mare rămâne în Buy (urcă monoton: y strict descrescător)
|
||||
ys = [y for _, y in LONG_TOP]
|
||||
assert all(ys[i] > ys[i + 1] for i in range(len(ys) - 1)), \
|
||||
"LONG: TF mare nu urcă monoton (nu rămâne în Buy)"
|
||||
# M = pullback (minim local), A = reluare peste vârful anterior
|
||||
assert LONG_BOT[L_M][1] > LONG_BOT[L_M - 1][1] and \
|
||||
LONG_BOT[L_M][1] > LONG_BOT[L_M + 1][1], "LONG: M nu e un minim local"
|
||||
assert LONG_BOT[L_A][1] < LONG_BOT[1][1], \
|
||||
"LONG: A nu urcă peste vârful anterior (pullback-ul)"
|
||||
assert LONG_TOP[L_M][0] < LONG_TOP[L_A][0], "LONG: M trebuie înainte de A"
|
||||
assert LONG_TOP[L_M][0] == LONG_BOT[L_M][0] and \
|
||||
LONG_TOP[L_A][0] == LONG_BOT[L_A][0], \
|
||||
"LONG: liniile verticale nu leagă exact M și A de rândul de sus"
|
||||
|
||||
# 3. secvența SHORT: oglindit
|
||||
ys = [y for _, y in SHORT_TOP]
|
||||
assert all(ys[i] < ys[i + 1] for i in range(len(ys) - 1)), \
|
||||
"SHORT: TF mare nu coboară monoton (nu rămâne în Sell)"
|
||||
assert SHORT_BOT[S_M][1] < SHORT_BOT[S_M - 1][1] and \
|
||||
SHORT_BOT[S_M][1] < SHORT_BOT[S_M + 1][1], "SHORT: M nu e un maxim local"
|
||||
assert SHORT_BOT[S_A][1] > SHORT_BOT[1][1], \
|
||||
"SHORT: A nu coboară sub minimul anterior"
|
||||
assert SHORT_TOP[S_M][0] < SHORT_TOP[S_A][0], "SHORT: M trebuie înainte de A"
|
||||
assert SHORT_TOP[S_M][0] == SHORT_BOT[S_M][0] and \
|
||||
SHORT_TOP[S_A][0] == SHORT_BOT[S_A][0], \
|
||||
"SHORT: liniile verticale nu leagă exact M și A de rândul de sus"
|
||||
|
||||
# 4. verticalele chiar traversează de la rândul de sus până la moment
|
||||
assert LONG_TOP[2][1] < LONG_BOT[L_M][1]
|
||||
assert LONG_TOP[3][1] < LONG_BOT[L_A][1]
|
||||
assert SHORT_TOP[2][1] < SHORT_BOT[S_M][1]
|
||||
assert SHORT_TOP[3][1] < SHORT_BOT[S_A][1]
|
||||
|
||||
# 5. toate etichetele în panză
|
||||
for x, y, s, size, weight, anchor, _ in TEXTS:
|
||||
ew = est_w(s, size, weight)
|
||||
left = x - ew if anchor == "end" else (x - ew / 2 if anchor == "middle" else x)
|
||||
right = left + ew
|
||||
assert -2 <= left and right <= W + 2, f"text în afara panzei: {s!r}"
|
||||
assert 0 <= y <= H, f"text în afara înălțimii: {s!r} (y={y})"
|
||||
|
||||
# 6. etichete care nu se suprapun
|
||||
for i in range(len(TEXTS)):
|
||||
xi, yi, si, szi, wi, ai, _ = TEXTS[i]
|
||||
we = est_w(si, szi, wi)
|
||||
li = xi - we if ai == "end" else (xi - we / 2 if ai == "middle" else xi)
|
||||
ri = li + we
|
||||
for j in range(i + 1, len(TEXTS)):
|
||||
xj, yj, sj, szj, wj, aj, _ = TEXTS[j]
|
||||
wej = est_w(sj, szj, wj)
|
||||
lj = xj - wej if aj == "end" else (xj - wej / 2 if aj == "middle" else xj)
|
||||
rj = lj + wej
|
||||
if abs(yi - yj) < 13 and li < rj - 4 and lj < ri - 4:
|
||||
raise AssertionError(f"texte suprapuse: {si!r} / {sj!r}")
|
||||
|
||||
# 7. niciun text nu se tastează peste o polilinie (coliziune text-linie)
|
||||
segments = [(LONG_TOP, PANELS["LONG"]), (LONG_BOT, PANELS["LONG"]),
|
||||
(SHORT_TOP, PANELS["SHORT"]), (SHORT_BOT, PANELS["SHORT"])]
|
||||
for x, y, s, size, weight, anchor, _ in TEXTS:
|
||||
ew = est_w(s, size, weight)
|
||||
left = x - ew if anchor == "end" else (x - ew / 2 if anchor == "middle" else x)
|
||||
right = left + ew
|
||||
top, bot = y - size + 1, y
|
||||
for pts, _ in segments:
|
||||
for (x1, y1), (x2, y2) in zip(pts, pts[1:]):
|
||||
xa, xb = min(x1, x2), max(x1, x2)
|
||||
if xb < left - 2 or xa > right + 2:
|
||||
continue
|
||||
for xc in (max(xa, left), min(xb, right)):
|
||||
t = 0 if x2 == x1 else (xc - x1) / (x2 - x1)
|
||||
yc = y1 + t * (y2 - y1)
|
||||
if top - 1 <= yc <= bot + 1:
|
||||
raise AssertionError(
|
||||
f"text peste polilinie: {s!r} (y={y}, linia y={yc:.0f})")
|
||||
|
||||
# 8. etichetele obligatorii din spec sunt prezente
|
||||
for cheie in ("LONG", "SHORT",
|
||||
"TF mare (ex. 15 min)", "TF mic (ex. 3 min)",
|
||||
"rămâne în Buy pe tot parcursul",
|
||||
"rămâne în Sell pe tot parcursul",
|
||||
"Buy Momentum", "Sell Momentum",
|
||||
"M: Sell Momentum (pullback)",
|
||||
"A: Buy Momentum — TRIGGER, intri long",
|
||||
"M: Buy Momentum (pullback)",
|
||||
"A: Sell Momentum — TRIGGER, intri short",
|
||||
"Secvența contează, nu starea",
|
||||
"NU e trigger (vezi 1.3)"):
|
||||
assert cheie in svg, f"lipsește din desen: {cheie!r}"
|
||||
|
||||
# 9. fără cifre de preț inventate (spec: diagramă fără niveluri)
|
||||
for interzis in ("$", "%", "€", "intrare ", "SL ", "TP"):
|
||||
assert interzis not in svg, f"nu ar trebui să apară preț: {interzis!r}"
|
||||
return True
|
||||
|
||||
|
||||
SVG = build()
|
||||
assert verify(SVG), "verificare eșuată"
|
||||
OUT.write_text(SVG, encoding="utf-8")
|
||||
print(f"scris {OUT} ({W}x{H}), verificare OK: {len(TEXTS)} etichete, "
|
||||
f"{len(LONG_TOP) + len(LONG_BOT) + len(SHORT_TOP) + len(SHORT_BOT)} puncte")
|
||||
svg, H, n = duo.build(
|
||||
[("DA", body_da, h_da, extra_da), ("NU", body_nu, h_nu, extra_nu)],
|
||||
["Ambele panouri: 3 minute, serie construită, aceleași cifre ca în diagrama de ansamblu.",
|
||||
'Pullback nu înseamnă „nu mai face minim nou": înseamnă că nu rupe minimul '
|
||||
'din care a pornit mișcarea.'],
|
||||
W)
|
||||
duo.fara_preturi_straine(svg, [REF_LOW, PULL_LOW, SEMNAL])
|
||||
OUT.write_text(svg, encoding="utf-8")
|
||||
print(f"scris {OUT} ({W}x{H:.0f}), {n} etichete | DA: șir în jos de {run_in_jos(DA)} bare, "
|
||||
f"minim {PULL_LOW:.2f} peste referința {REF_LOW:.2f} | NU: șir în jos de "
|
||||
f"{run_in_jos(NU)} bare")
|
||||
|
||||
@@ -1,42 +1,72 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 780" width="700" height="780" role="img" aria-label="Secventa M apoi A a strategiei M2D, pe doua time frame-uri, pentru long si short: time frame-ul mare ramane in directie cat timp time frame-ul mic face pullback (M) si apoi da trigger-ul in directia mare (A)">
|
||||
<g font-family="system-ui, sans-serif">
|
||||
<rect x="0" y="0" width="700" height="780" fill="#ffffff"/>
|
||||
<text x="350.0" y="30.0" font-size="19" font-weight="700" fill="#000000" text-anchor="middle">Secvența M → A: nu e o stare, e o secvență</text>
|
||||
<text x="350.0" y="52.0" font-size="13" font-weight="400" fill="#777777" text-anchor="middle">M2D — același moment, două time frame-uri: TF mare dă direcția, TF mic dă trigger-ul</text>
|
||||
<text x="350.0" y="72.0" font-size="13" font-weight="400" fill="#777777" text-anchor="middle">sus = LONG; jos = SHORT — aceleași momente, în oglindă</text>
|
||||
<rect x="14" y="92" width="672" height="250" rx="8" fill="#fafafa" stroke="#ddd" stroke-width="1.2"/>
|
||||
<rect x="14" y="362" width="672" height="270" rx="8" fill="#fafafa" stroke="#ddd" stroke-width="1.2"/>
|
||||
<text x="30.0" y="116.0" font-size="15" font-weight="700" fill="#188a3e" text-anchor="start">LONG</text>
|
||||
<text x="30.0" y="140.0" font-size="13" font-weight="400" fill="#777777" text-anchor="start">TF mare (ex. 15 min)</text>
|
||||
<text x="660.0" y="114.0" font-size="13" font-weight="400" fill="#188a3e" text-anchor="end">rămâne în Buy pe tot parcursul</text>
|
||||
<line x1="250.0" y1="138.0" x2="250.0" y2="282.0" stroke="#999999" stroke-width="1.2" stroke-dasharray="4 4"/>
|
||||
<line x1="430.0" y1="128.0" x2="430.0" y2="210.0" stroke="#999999" stroke-width="1.2" stroke-dasharray="4 4"/>
|
||||
<polyline points="40.0,162.0 150.0,148.0 250.0,138.0 430.0,128.0 660.0,118.0" fill="none" stroke="#188a3e" stroke-width="2.0"/>
|
||||
<circle cx="150.0" cy="148.0" r="5.0" fill="#00b8c4"/>
|
||||
<text x="185.0" y="126.0" font-size="13" font-weight="400" fill="#00b8c4" text-anchor="start">Buy Momentum</text>
|
||||
<text x="30.0" y="202.0" font-size="13" font-weight="400" fill="#777777" text-anchor="start">TF mic (ex. 3 min)</text>
|
||||
<polyline points="40.0,255.0 180.0,225.0 250.0,282.0 430.0,210.0 660.0,198.0" fill="none" stroke="#333333" stroke-width="2.0"/>
|
||||
<circle cx="250.0" cy="282.0" r="5.0" fill="#c00"/>
|
||||
<text x="262.0" y="296.0" font-size="13" font-weight="400" fill="#c00" text-anchor="start">M: Sell Momentum (pullback)</text>
|
||||
<circle cx="430.0" cy="210.0" r="6.0" fill="#188a3e"/>
|
||||
<text x="660.0" y="240.0" font-size="13" font-weight="400" fill="#188a3e" text-anchor="end">A: Buy Momentum — TRIGGER, intri long</text>
|
||||
<text x="30.0" y="386.0" font-size="15" font-weight="700" fill="#c00" text-anchor="start">SHORT</text>
|
||||
<text x="30.0" y="410.0" font-size="13" font-weight="400" fill="#777777" text-anchor="start">TF mare (ex. 15 min)</text>
|
||||
<text x="660.0" y="494.0" font-size="13" font-weight="400" fill="#c00" text-anchor="end">rămâne în Sell pe tot parcursul</text>
|
||||
<line x1="250.0" y1="454.0" x2="250.0" y2="500.0" stroke="#999999" stroke-width="1.2" stroke-dasharray="4 4"/>
|
||||
<line x1="430.0" y1="464.0" x2="430.0" y2="574.0" stroke="#999999" stroke-width="1.2" stroke-dasharray="4 4"/>
|
||||
<polyline points="40.0,430.0 150.0,444.0 250.0,454.0 430.0,464.0 660.0,474.0" fill="none" stroke="#c00" stroke-width="2.0"/>
|
||||
<circle cx="150.0" cy="444.0" r="5.0" fill="#c00"/>
|
||||
<text x="168.0" y="432.0" font-size="13" font-weight="400" fill="#c00" text-anchor="start">Sell Momentum</text>
|
||||
<text x="30.0" y="470.0" font-size="13" font-weight="400" fill="#777777" text-anchor="start">TF mic (ex. 3 min)</text>
|
||||
<polyline points="40.0,527.0 180.0,562.0 250.0,500.0 430.0,574.0 660.0,588.0" fill="none" stroke="#333333" stroke-width="2.0"/>
|
||||
<circle cx="250.0" cy="500.0" r="5.0" fill="#00b8c4"/>
|
||||
<text x="238.0" y="494.0" font-size="13" font-weight="400" fill="#00b8c4" text-anchor="end">M: Buy Momentum (pullback)</text>
|
||||
<circle cx="430.0" cy="574.0" r="6.0" fill="#c00"/>
|
||||
<text x="660.0" y="610.0" font-size="13" font-weight="400" fill="#c00" text-anchor="end">A: Sell Momentum — TRIGGER, intri short</text>
|
||||
<rect x="40" y="648" width="620" height="116" rx="8" fill="#ffffff" stroke="#777777" stroke-width="1.2"/>
|
||||
<text x="350.0" y="676.0" font-size="13" font-weight="400" fill="#000000" text-anchor="middle">Secvența contează, nu starea: mare în Buy → mic în Sell → mic în Buy</text>
|
||||
<text x="350.0" y="696.0" font-size="13" font-weight="400" fill="#000000" text-anchor="middle">(cu mare încă în Buy). Un Buy direct pe TF mic, fără Sell între ele,</text>
|
||||
<text x="350.0" y="716.0" font-size="13" font-weight="400" fill="#000000" text-anchor="middle">NU e trigger (vezi 1.3).</text>
|
||||
<text x="350.0" y="746.0" font-size="13" font-weight="400" fill="#777777" text-anchor="middle">Sursă: 14_strategia_1_m2d.md:30-38, 172-180; 09_QA/08_2026-01-20.md:65-67</text>
|
||||
</g></svg>
|
||||
<svg viewBox="0 0 680 743" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<g transform="translate(0,0)"><text x="24" y="22" fill="#188a3e" style="font-weight:bold">DA — pullback pe 3 min, care nu rupe minimul de referință</text><rect x="54.0" y="62.4" width="280.0" height="128.4" fill="#c00" fill-opacity="0.12" stroke="#c00" stroke-width="1"/><text x="60.0" y="55.4" fill="#c00" style="font-weight:bold">M: pullback</text><line x1="24" y1="193.6" x2="666" y2="193.6" stroke="#555" stroke-width="1.5" stroke-dasharray="2 3"/><text x="30" y="214.6" fill="#555" text-anchor="start" style="font-weight:bold">minimul din care a pornit mișcarea 99.80 — sub el nu mai e pullback</text><line x1="24" y1="182.8" x2="666" y2="182.8" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="176.8" fill="#c00" text-anchor="end" style="font-weight:bold">cel mai jos punct al pullback-ului 99.90</text>
|
||||
<line x1="66.0" y1="96.4" x2="66.0" y2="128.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="60.5" y="107.2" width="11" height="16.2" fill="#c00"/>
|
||||
<line x1="98.0" y1="118.0" x2="98.0" y2="145.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="92.5" y="123.4" width="11" height="16.2" fill="#c00"/>
|
||||
<line x1="130.0" y1="134.2" x2="130.0" y2="155.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="124.5" y="139.6" width="11" height="10.8" fill="#c00"/>
|
||||
<line x1="162.0" y1="145.0" x2="162.0" y2="166.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="156.5" y="150.4" width="11" height="10.8" fill="#c00"/>
|
||||
<line x1="194.0" y1="155.8" x2="194.0" y2="172.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="188.5" y="161.2" width="11" height="5.4" fill="#c00"/>
|
||||
<line x1="226.0" y1="161.2" x2="226.0" y2="177.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="220.5" y="166.6" width="11" height="5.4" fill="#c00"/>
|
||||
<line x1="258.0" y1="166.6" x2="258.0" y2="180.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="252.5" y="172.0" width="11" height="5.4" fill="#c00"/>
|
||||
<line x1="290.0" y1="172.0" x2="290.0" y2="182.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="284.5" y="174.2" width="11" height="3.2" fill="#188a3e"/>
|
||||
<line x1="322.0" y1="163.4" x2="322.0" y2="178.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="316.5" y="169.8" width="11" height="4.3" fill="#188a3e"/>
|
||||
<line x1="354.0" y1="123.4" x2="354.0" y2="172.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="348.5" y="128.8" width="11" height="41.0" fill="#188a3e"/>
|
||||
<line x1="386.0" y1="107.2" x2="386.0" y2="134.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="380.5" y="112.6" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="418.0" y1="91.0" x2="418.0" y2="118.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="412.5" y="96.4" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="450.0" y1="64.0" x2="450.0" y2="101.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="444.5" y="69.4" width="11" height="27.0" fill="#188a3e"/>
|
||||
<line x1="266.0" y1="258.8" x2="287.5" y2="194.4" stroke="#c00" stroke-width="1.8"/>
|
||||
<polygon points="290.0,186.8 291.3,195.7 283.7,193.1" fill="#c00"/>
|
||||
<text x="266.0" y="272.8" fill="#c00" text-anchor="middle" style="font-weight:bold">M: pullback-ul obligatoriu — prețul merge</text>
|
||||
<text x="266.0" y="286.8" fill="#c00" text-anchor="middle" style="font-weight:bold">contra direcției mari, dar se oprește la 99.90</text>
|
||||
<line x1="314.0" y1="62.0" x2="349.4" y2="112.8" stroke="#188a3e" stroke-width="1.8"/>
|
||||
<polygon points="354.0,119.4 346.1,115.1 352.7,110.5" fill="#188a3e"/>
|
||||
<text x="314.0" y="43.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">prima bară care urcă peste capătul pullback-ului:</text>
|
||||
<text x="314.0" y="57.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">aici începe pasul 3 (trigger-ul)</text>
|
||||
</g>
|
||||
<g transform="translate(0,322)"><text x="24" y="22" fill="#c00" style="font-weight:bold">NU — niciun pullback: nu ai setup, oricât de frumoasă e urcarea</text><line x1="24" y1="258.4" x2="666" y2="258.4" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="279.4" fill="#0891b2" text-anchor="end" style="font-weight:bold">close-ul candelei de 15 min de semnal 100.60</text>
|
||||
<line x1="66.0" y1="236.8" x2="66.0" y2="263.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="60.5" y="242.2" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="98.0" y1="220.6" x2="98.0" y2="247.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="92.5" y="226.0" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="130.0" y1="204.4" x2="130.0" y2="231.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="124.5" y="209.8" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="162.0" y1="193.6" x2="162.0" y2="215.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="156.5" y="199.0" width="11" height="10.8" fill="#188a3e"/>
|
||||
<line x1="194.0" y1="177.4" x2="194.0" y2="204.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="188.5" y="182.8" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="226.0" y1="166.6" x2="226.0" y2="188.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="220.5" y="172.0" width="11" height="10.8" fill="#188a3e"/>
|
||||
<line x1="258.0" y1="150.4" x2="258.0" y2="177.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="252.5" y="155.8" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="290.0" y1="134.2" x2="290.0" y2="161.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="284.5" y="139.6" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="322.0" y1="118.0" x2="322.0" y2="145.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="316.5" y="123.4" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="354.0" y1="107.2" x2="354.0" y2="128.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="348.5" y="112.6" width="11" height="10.8" fill="#188a3e"/>
|
||||
<line x1="386.0" y1="91.0" x2="386.0" y2="118.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="380.5" y="96.4" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="418.0" y1="80.2" x2="418.0" y2="101.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="412.5" y="85.6" width="11" height="10.8" fill="#188a3e"/>
|
||||
<line x1="450.0" y1="64.0" x2="450.0" y2="91.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="444.5" y="69.4" width="11" height="16.2" fill="#188a3e"/>
|
||||
<line x1="188.0" y1="311.8" x2="254.2" y2="188.4" stroke="#c00" stroke-width="1.8"/>
|
||||
<polygon points="258.0,181.4 257.7,190.3 250.7,186.6" fill="#c00"/>
|
||||
<text x="188.0" y="325.8" fill="#c00" text-anchor="middle" style="font-weight:bold">urcare continuă, fără nicio pauză în jos:</text>
|
||||
<text x="188.0" y="339.8" fill="#c00" text-anchor="middle" style="font-weight:bold">asta e breakout, nu M2D — nu ai unde pune stopul</text>
|
||||
</g>
|
||||
<text x="24" y="703" fill="#555">Ambele panouri: 3 minute, serie construită, aceleași cifre ca în diagrama de ansamblu.</text>
|
||||
<text x="24" y="720" fill="#555">Pullback nu înseamnă „nu mai face minim nou": înseamnă că nu rupe minimul din care a pornit mișcarea.</text>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 6.9 KiB |
136
gen/strategii/m2d_stop.py
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""M2D, pasul 4 — stopul: extrema ultimelor 4 bare, și alternativa 2 × ATR(10).
|
||||
|
||||
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: stop -->`.
|
||||
|
||||
Sus: exemplul construit din tot capitolul (3 min). Numeri 4 bare înapoi de la
|
||||
bara de trigger, iei cel mai jos low și acolo stă stopul — fix pe el, fără
|
||||
marjă; asta e regula folosită în TOATE diagramele capitolului.
|
||||
|
||||
Jos: exemplul SPY din curs, singurul loc din material unde apar cifre
|
||||
absolute pentru stop. Reale din curs: close-ul de trigger 517.78, ATR(10)
|
||||
2.88, stopul 2×ATR 512.02 și low-ul metodei pe 4 candele 512.87. Restul
|
||||
seriei e construit ca să scoată exact acel low.
|
||||
|
||||
Rulare: python3 gen/strategii/m2d_stop.py
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, "/workspace/atm-curs-dl")
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from svg_candles import Arrow, Candle, Chart # noqa: E402
|
||||
import m2d_duo as duo # noqa: E402
|
||||
|
||||
OUT = Path(__file__).with_suffix(".svg")
|
||||
W = 680
|
||||
GREEN, RED, BLUE, ORANGE, GREY = "#188a3e", "#c00", "#1a5fb4", "#b06000", "#555"
|
||||
STOP_BARS = 4
|
||||
|
||||
# --- panoul 1: exemplul construit, 3 min (aceleași bare ca în ansamblu) ----
|
||||
MIC = [(100.60, 100.70, 100.40, 100.45), (100.45, 100.50, 100.25, 100.30),
|
||||
(100.30, 100.35, 100.15, 100.20), (100.20, 100.25, 100.05, 100.10),
|
||||
(100.10, 100.15, 100.00, 100.05), (100.05, 100.10, 99.95, 100.00),
|
||||
(100.00, 100.05, 99.92, 99.95), (99.95, 100.00, 99.90, 99.98),
|
||||
(99.98, 100.08, 99.94, 100.02),
|
||||
(100.02, 100.45, 100.00, 100.40), # 9: trigger
|
||||
(100.40, 100.60, 100.35, 100.55), (100.55, 100.75, 100.50, 100.70)]
|
||||
TRIG_M = 9
|
||||
|
||||
# --- panoul 2: SPY, 15 min. Reale: 517.78, 2.88, 512.02, 512.87 -----------
|
||||
SPY_CLOSE_TRIG = 517.78
|
||||
SPY_ATR = 2.88
|
||||
SPY_ATR_STOP = 512.02
|
||||
SPY_LOW4 = 512.87
|
||||
SPY = [(521.40, 521.80, 520.10, 520.50), (520.50, 520.90, 519.20, 519.60),
|
||||
(519.60, 519.80, 518.10, 518.40), (518.40, 518.70, 516.90, 517.20),
|
||||
(517.20, 517.40, 515.70, 516.10), (516.10, 516.40, 514.90, 515.30),
|
||||
(515.30, 515.60, 513.40, 514.60),
|
||||
(514.60, 514.90, 513.40, 514.00), # 7
|
||||
(514.00, 514.30, SPY_LOW4, 513.50), # 8: cel mai jos low din 4
|
||||
(513.50, 514.20, 513.20, 513.90), # 9
|
||||
(513.90, 518.10, 513.80, SPY_CLOSE_TRIG)] # 10: trigger
|
||||
TRIG_S = 10
|
||||
|
||||
# ---------------------------------------------------------------- verificări
|
||||
for nume, bars in (("mic", MIC), ("SPY", SPY)):
|
||||
for i, (o, h, l, c) in enumerate(bars):
|
||||
assert h >= max(o, c) and l <= min(o, c), f"{nume}[{i}]: high/low incoerent"
|
||||
if i:
|
||||
assert abs(o - bars[i - 1][3]) < 1e-9, f"{nume}[{i}]: open != close precedent"
|
||||
|
||||
ENTRY_M = MIC[TRIG_M][3]
|
||||
SL_M = min(b[2] for b in MIC[TRIG_M - STOP_BARS + 1:TRIG_M + 1])
|
||||
RISK_M = round(ENTRY_M - SL_M, 2)
|
||||
assert (ENTRY_M, SL_M, RISK_M) == (100.40, 99.90, 0.50), (ENTRY_M, SL_M, RISK_M)
|
||||
# stopul nu e „undeva pe-aproape": e minimul celor 4 bare, și e minimul întregii serii
|
||||
assert abs(SL_M - min(b[2] for b in MIC)) < 1e-9, "stopul nu e minimul seriei mici"
|
||||
# a cincea bară înapoi are un low mai mare — deci numărul 4 chiar contează
|
||||
assert MIC[TRIG_M - STOP_BARS][2] > SL_M, "a 5-a bară strică demonstrația celor 4"
|
||||
PCT_M = RISK_M / ENTRY_M * 100
|
||||
|
||||
SL_S = min(b[2] for b in SPY[TRIG_S - STOP_BARS + 1:TRIG_S + 1])
|
||||
assert abs(SL_S - SPY_LOW4) < 1e-9, f"low-ul pe 4 bare iese {SL_S}, nu {SPY_LOW4}"
|
||||
assert abs(SPY[TRIG_S][3] - SPY_CLOSE_TRIG) < 1e-9
|
||||
assert abs((SPY_CLOSE_TRIG - 2 * SPY_ATR) - SPY_ATR_STOP) < 1e-9, \
|
||||
"2×ATR nu dă stopul din curs"
|
||||
MARJA = round(SPY_LOW4 - SPY_ATR_STOP, 2)
|
||||
assert MARJA == 0.85, MARJA
|
||||
RISK_S4 = round(SPY_CLOSE_TRIG - SPY_LOW4, 2)
|
||||
RISK_SA = round(SPY_CLOSE_TRIG - SPY_ATR_STOP, 2)
|
||||
assert (RISK_S4, RISK_SA) == (4.91, 5.76), (RISK_S4, RISK_SA)
|
||||
assert SPY_ATR_STOP < SPY_LOW4, "ATR ar trebui să dea un stop mai larg"
|
||||
|
||||
|
||||
def chart(bars, scale, gap, left, body_w, arrows, top=64):
|
||||
return Chart(candles=[Candle(*b) for b in bars], arrows=arrows, scale=scale,
|
||||
gap=gap, body_w=body_w, left=left, width=W, top=top)
|
||||
|
||||
|
||||
ch_m = chart(MIC, 150.0, 34, 62, 13, [
|
||||
Arrow(TRIG_M, "bara de trigger: de la ea numeri înapoi",
|
||||
where="above", color=GREEN, dx=-30, dy=-6),
|
||||
Arrow(TRIG_M - STOP_BARS + 2, "cel mai jos low dintre cele 4 bare: 99.90.\n"
|
||||
"Stopul stă FIX acolo, fără marjă",
|
||||
where="below", color=RED, dx=-40, dy=40)])
|
||||
ch_s = chart(SPY, 17.0, 34, 62, 13, [
|
||||
Arrow(TRIG_S, "close-ul barei de trigger 517.78",
|
||||
where="above", color=GREEN, dx=-60, dy=-4),
|
||||
Arrow(8, "2 × ATR(10) = 5.76 sub close:\n"
|
||||
"stop 512.02, cu 0.85 sub low-ul celor 4 bare",
|
||||
where="below", color=ORANGE, dx=-20, dy=52)])
|
||||
|
||||
body_m, h_m = duo.panel(ch_m, W)
|
||||
body_s, h_s = duo.panel(ch_s, W)
|
||||
|
||||
extra_m = (duo.titlu("Metoda de bază — cele 4 bare", color=RED)
|
||||
+ duo.zone(ch_m, TRIG_M - STOP_BARS + 1, TRIG_M,
|
||||
f"{STOP_BARS} bare, numărate de la trigger înapoi", RED,
|
||||
pad=13, lift=30)
|
||||
+ duo.level(ch_m, ENTRY_M, ["intrare 100.40"], GREEN, W, at_left=False)
|
||||
+ duo.level(ch_m, SL_M, ["stop 99.90 — risc 0.50 pe acțiune (0,50 %)"],
|
||||
RED, W, below=True))
|
||||
extra_s = (duo.titlu("Alternativa din curs — 2 × ATR(10), pe SPY", color=ORANGE)
|
||||
+ duo.zone(ch_s, TRIG_S - STOP_BARS + 1, TRIG_S, "", RED, pad=13)
|
||||
+ duo.level(ch_s, SPY_CLOSE_TRIG, ["intrare 517.78"], GREEN, W, at_left=False)
|
||||
+ duo.level(ch_s, SPY_LOW4, ["stop pe 4 bare 512.87 — risc 4.91"],
|
||||
RED, W, below=False)
|
||||
+ duo.level(ch_s, SPY_ATR_STOP, ["stop 2×ATR 512.02 — risc 5.76"],
|
||||
ORANGE, W, below=True, dash="2 3"))
|
||||
|
||||
svg, H, n = duo.build(
|
||||
[("mic", body_m, h_m, extra_m), ("SPY", body_s, h_s, extra_s)],
|
||||
["Sus: serie construită, aceleași cifre ca în restul capitolului.",
|
||||
"Jos: din curs sunt reale doar 517.78, ATR(10) = 2.88, 512.02 și 512.87; "
|
||||
"restul barelor sunt construite.",
|
||||
"ATR-ul dă un stop mai larg, deci un risc mai mare pe acțiune — și, la același",
|
||||
"risc în dolari, mai puține acțiuni."],
|
||||
W)
|
||||
duo.fara_preturi_straine(svg, [ENTRY_M, SL_M, RISK_M, SPY_CLOSE_TRIG, SPY_LOW4,
|
||||
SPY_ATR_STOP, SPY_ATR, RISK_S4, RISK_SA, MARJA,
|
||||
2 * SPY_ATR, PCT_M])
|
||||
OUT.write_text(svg, encoding="utf-8")
|
||||
print(f"scris {OUT} ({W}x{H:.0f}), {n} etichete | mic: intrare {ENTRY_M:.2f} stop {SL_M:.2f} "
|
||||
f"risc {RISK_M:.2f} ({PCT_M:.2f} %) | SPY: intrare {SPY_CLOSE_TRIG:.2f}, 4 bare "
|
||||
f"{SPY_LOW4:.2f} (risc {RISK_S4:.2f}), 2×ATR {SPY_ATR_STOP:.2f} (risc {RISK_SA:.2f}), "
|
||||
f"diferență {MARJA:.2f}")
|
||||
70
gen/strategii/m2d_stop.svg
Normal file
@@ -0,0 +1,70 @@
|
||||
<svg viewBox="0 0 680 765" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<g transform="translate(0,0)"><text x="24" y="22" fill="#c00" style="font-weight:bold">Metoda de bază — cele 4 bare</text><rect x="253.0" y="71.0" width="128.0" height="128.5" fill="#c00" fill-opacity="0.12" stroke="#c00" stroke-width="1"/><text x="259.0" y="64.0" fill="#c00" style="font-weight:bold">4 bare, numărate de la trigger înapoi</text><line x1="24" y1="116.5" x2="666" y2="116.5" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="110.5" fill="#188a3e" text-anchor="end" style="font-weight:bold">intrare 100.40</text><line x1="24" y1="191.5" x2="666" y2="191.5" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/><text x="30" y="212.5" fill="#c00" text-anchor="start" style="font-weight:bold">stop 99.90 — risc 0.50 pe acțiune (0,50 %)</text>
|
||||
<line x1="62.0" y1="71.5" x2="62.0" y2="116.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="55.5" y="86.5" width="13" height="22.5" fill="#c00"/>
|
||||
<line x1="96.0" y1="101.5" x2="96.0" y2="139.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="89.5" y="109.0" width="13" height="22.5" fill="#c00"/>
|
||||
<line x1="130.0" y1="124.0" x2="130.0" y2="154.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="123.5" y="131.5" width="13" height="15.0" fill="#c00"/>
|
||||
<line x1="164.0" y1="139.0" x2="164.0" y2="169.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="157.5" y="146.5" width="13" height="15.0" fill="#c00"/>
|
||||
<line x1="198.0" y1="154.0" x2="198.0" y2="176.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="191.5" y="161.5" width="13" height="7.5" fill="#c00"/>
|
||||
<line x1="232.0" y1="161.5" x2="232.0" y2="184.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="225.5" y="169.0" width="13" height="7.5" fill="#c00"/>
|
||||
<line x1="266.0" y1="169.0" x2="266.0" y2="188.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="259.5" y="176.5" width="13" height="7.5" fill="#c00"/>
|
||||
<line x1="300.0" y1="176.5" x2="300.0" y2="191.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="293.5" y="179.5" width="13" height="4.5" fill="#188a3e"/>
|
||||
<line x1="334.0" y1="164.5" x2="334.0" y2="185.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="327.5" y="173.5" width="13" height="6.0" fill="#188a3e"/>
|
||||
<line x1="368.0" y1="109.0" x2="368.0" y2="176.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="361.5" y="116.5" width="13" height="57.0" fill="#188a3e"/>
|
||||
<line x1="402.0" y1="86.5" x2="402.0" y2="124.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="395.5" y="94.0" width="13" height="22.5" fill="#188a3e"/>
|
||||
<line x1="436.0" y1="64.0" x2="436.0" y2="101.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="429.5" y="71.5" width="13" height="22.5" fill="#188a3e"/>
|
||||
<line x1="338.0" y1="50.0" x2="364.2" y2="98.0" stroke="#188a3e" stroke-width="1.8"/>
|
||||
<polygon points="368.0,105.0 360.7,99.9 367.7,96.1" fill="#188a3e"/>
|
||||
<text x="338.0" y="45.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">bara de trigger: de la ea numeri înapoi</text>
|
||||
<line x1="260.0" y1="261.5" x2="295.9" y2="202.3" stroke="#c00" stroke-width="1.8"/>
|
||||
<polygon points="300.0,195.5 299.3,204.4 292.4,200.3" fill="#c00"/>
|
||||
<text x="260.0" y="275.5" fill="#c00" text-anchor="middle" style="font-weight:bold">cel mai jos low dintre cele 4 bare: 99.90.</text>
|
||||
<text x="260.0" y="289.5" fill="#c00" text-anchor="middle" style="font-weight:bold">Stopul stă FIX acolo, fără marjă</text>
|
||||
</g>
|
||||
<g transform="translate(0,324)"><text x="24" y="22" fill="#b06000" style="font-weight:bold">Alternativa din curs — 2 × ATR(10), pe SPY</text><rect x="287.0" y="118.9" width="128.0" height="104.9" fill="#c00" fill-opacity="0.12" stroke="#c00" stroke-width="1"/><line x1="24" y1="132.3" x2="666" y2="132.3" stroke="#188a3e" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="126.3" fill="#188a3e" text-anchor="end" style="font-weight:bold">intrare 517.78</text><line x1="24" y1="215.8" x2="666" y2="215.8" stroke="#c00" stroke-width="1.5" stroke-dasharray="4 3"/><text x="30" y="209.8" fill="#c00" text-anchor="start" style="font-weight:bold">stop pe 4 bare 512.87 — risc 4.91</text><line x1="24" y1="230.3" x2="666" y2="230.3" stroke="#b06000" stroke-width="1.5" stroke-dasharray="2 3"/><text x="30" y="251.3" fill="#b06000" text-anchor="start" style="font-weight:bold">stop 2×ATR 512.02 — risc 5.76</text>
|
||||
<line x1="62.0" y1="64.0" x2="62.0" y2="92.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="55.5" y="70.8" width="13" height="15.3" fill="#c00"/>
|
||||
<line x1="96.0" y1="79.3" x2="96.0" y2="108.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="89.5" y="86.1" width="13" height="15.3" fill="#c00"/>
|
||||
<line x1="130.0" y1="98.0" x2="130.0" y2="126.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="123.5" y="101.4" width="13" height="20.4" fill="#c00"/>
|
||||
<line x1="164.0" y1="116.7" x2="164.0" y2="147.3" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="157.5" y="121.8" width="13" height="20.4" fill="#c00"/>
|
||||
<line x1="198.0" y1="138.8" x2="198.0" y2="167.7" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="191.5" y="142.2" width="13" height="18.7" fill="#c00"/>
|
||||
<line x1="232.0" y1="155.8" x2="232.0" y2="181.3" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="225.5" y="160.9" width="13" height="13.6" fill="#c00"/>
|
||||
<line x1="266.0" y1="169.4" x2="266.0" y2="206.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="259.5" y="174.5" width="13" height="11.9" fill="#c00"/>
|
||||
<line x1="300.0" y1="181.3" x2="300.0" y2="206.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="293.5" y="186.4" width="13" height="10.2" fill="#c00"/>
|
||||
<line x1="334.0" y1="191.5" x2="334.0" y2="215.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="327.5" y="196.6" width="13" height="8.5" fill="#c00"/>
|
||||
<line x1="368.0" y1="193.2" x2="368.0" y2="210.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="361.5" y="198.3" width="13" height="6.8" fill="#188a3e"/>
|
||||
<line x1="402.0" y1="126.9" x2="402.0" y2="200.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="395.5" y="132.3" width="13" height="66.0" fill="#188a3e"/>
|
||||
<line x1="342.0" y1="92.9" x2="394.8" y2="119.3" stroke="#188a3e" stroke-width="1.8"/>
|
||||
<polygon points="402.0,122.9 393.1,122.9 396.6,115.7" fill="#188a3e"/>
|
||||
<text x="342.0" y="87.9" fill="#188a3e" text-anchor="middle" style="font-weight:bold">close-ul barei de trigger 517.78</text>
|
||||
<line x1="314.0" y1="297.8" x2="332.0" y2="227.6" stroke="#b06000" stroke-width="1.8"/>
|
||||
<polygon points="334.0,219.8 335.9,228.6 328.1,226.6" fill="#b06000"/>
|
||||
<text x="314.0" y="311.8" fill="#b06000" text-anchor="middle" style="font-weight:bold">2 × ATR(10) = 5.76 sub close:</text>
|
||||
<text x="314.0" y="325.8" fill="#b06000" text-anchor="middle" style="font-weight:bold">stop 512.02, cu 0.85 sub low-ul celor 4 bare</text>
|
||||
</g>
|
||||
<text x="24" y="691" fill="#555">Sus: serie construită, aceleași cifre ca în restul capitolului.</text>
|
||||
<text x="24" y="708" fill="#555">Jos: din curs sunt reale doar 517.78, ATR(10) = 2.88, 512.02 și 512.87; restul barelor sunt construite.</text>
|
||||
<text x="24" y="725" fill="#555">ATR-ul dă un stop mai larg, deci un risc mai mare pe acțiune — și, la același</text>
|
||||
<text x="24" y="742" fill="#555">risc în dolari, mai puține acțiuni.</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.2 KiB |
118
gen/strategii/m2d_trigger.py
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
"""M2D, pasul 3 — trigger-ul (A): DA (bară închisă peste) vs. NU (doar atins).
|
||||
|
||||
Pentru `summaries/17_STRATEGII/03_m2d.md`, marcajul `<!-- DIAGRAMA: trigger -->`.
|
||||
|
||||
Aceeași serie de 3 minute ca în diagrama de ansamblu până la bara 8; de acolo
|
||||
încolo, două continuări. Sus: bara 9 se ÎNCHIDE peste capătul pullback-ului,
|
||||
deci e trigger, și intri la close. Jos: bara 9 atinge același nivel cu
|
||||
fitilul, dar se închide sub el — nu e trigger; pe barele următoare pullback-ul
|
||||
rupe minimul de referință și setup-ul moare.
|
||||
|
||||
Indicatorul care dă săgeata de Buy Momentum e proprietar cursului. Pe desen,
|
||||
săgeata e pusă acolo unde prețul se închide peste capătul pullback-ului —
|
||||
construcția mea, ca regula să fie verificabilă cu ochiul pe un grafic.
|
||||
|
||||
Rulare: python3 gen/strategii/m2d_trigger.py
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, "/workspace/atm-curs-dl")
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
from svg_candles import Arrow, Candle, Chart # noqa: E402
|
||||
import m2d_duo as duo # noqa: E402
|
||||
|
||||
OUT = Path(__file__).with_suffix(".svg")
|
||||
W, SCALE, GAP, LEFT = 680, 104.0, 30, 56
|
||||
GREEN, RED, GREY = "#188a3e", "#c00", "#555"
|
||||
|
||||
REF_LOW = 99.80 # minimul din care a pornit mișcarea (vezi pașii 1 și 2)
|
||||
|
||||
COMUN = [(100.60, 100.70, 100.40, 100.45), (100.45, 100.50, 100.25, 100.30),
|
||||
(100.30, 100.35, 100.15, 100.20), (100.20, 100.25, 100.05, 100.10),
|
||||
(100.10, 100.15, 100.00, 100.05), (100.05, 100.10, 99.95, 100.00),
|
||||
(100.00, 100.05, 99.92, 99.95), (99.95, 100.00, 99.90, 99.98),
|
||||
(99.98, 100.08, 99.94, 100.02)]
|
||||
TRIG = 9
|
||||
DA = COMUN + [(100.02, 100.45, 100.00, 100.40), # 9: se ÎNCHIDE peste capăt
|
||||
(100.40, 100.60, 100.35, 100.55), (100.55, 100.75, 100.50, 100.70),
|
||||
(100.70, 101.00, 100.65, 100.95)]
|
||||
NU = COMUN + [(100.02, 100.45, 99.98, 100.00), # 9: atinge, dar se închide sub
|
||||
(100.00, 100.05, 99.82, 99.85),
|
||||
(99.85, 99.90, 99.55, 99.60), # 11: rupe minimul de referință
|
||||
(99.60, 99.70, 99.45, 99.50)]
|
||||
|
||||
# ---------------------------------------------------------------- verificări
|
||||
for nume, bars in (("DA", DA), ("NU", NU)):
|
||||
for i, (o, h, l, c) in enumerate(bars):
|
||||
assert h >= max(o, c) and l <= min(o, c), f"{nume}[{i}]: high/low incoerent"
|
||||
if i:
|
||||
assert abs(o - bars[i - 1][3]) < 1e-9, f"{nume}[{i}]: open != close precedent"
|
||||
assert DA[:TRIG] == NU[:TRIG] == COMUN, "panourile nu pornesc din aceeași serie"
|
||||
|
||||
CAPAT = max(b[1] for b in COMUN[6:]) # capătul pullback-ului = 100.08
|
||||
assert abs(CAPAT - 100.08) < 1e-9, CAPAT
|
||||
# nicio bară dinaintea trigger-ului nu se închidea deja peste capăt
|
||||
assert all(b[3] <= CAPAT for b in COMUN[6:]), "o bară dinainte închidea deja peste capăt"
|
||||
|
||||
# DA: bara 9 se închide peste capăt — e trigger, și e PRIMA care face asta
|
||||
assert DA[TRIG][3] > CAPAT, "DA: bara de trigger nu se închide peste capăt"
|
||||
assert all(b[3] <= CAPAT for b in DA[6:TRIG]), "DA: trigger-ul nu e primul de după minim"
|
||||
ENTRY = DA[TRIG][3]
|
||||
assert abs(ENTRY - 100.40) < 1e-9, ENTRY
|
||||
# al doilea semnal, pe care NU mai intri
|
||||
AL_DOILEA = next(i for i in range(TRIG + 1, len(DA))
|
||||
if DA[i][3] > max(b[1] for b in DA[i - 3:i]))
|
||||
assert AL_DOILEA == 10, AL_DOILEA
|
||||
|
||||
# NU: bara 9 ATINGE capătul cu fitilul, dar se închide sub el
|
||||
assert NU[TRIG][1] > CAPAT, "NU: bara 9 nici nu atinge capătul"
|
||||
assert NU[TRIG][3] < CAPAT, "NU: bara 9 se închide totuși peste capăt"
|
||||
assert all(b[3] <= CAPAT for b in NU[6:]), "NU: o bară se închide peste capăt"
|
||||
RUPT = next(i for i, b in enumerate(NU) if b[3] < REF_LOW)
|
||||
assert RUPT == 11, RUPT
|
||||
|
||||
|
||||
def chart(bars, arrows):
|
||||
return Chart(candles=[Candle(*b) for b in bars], arrows=arrows,
|
||||
scale=SCALE, gap=GAP, body_w=12, left=LEFT, width=W, top=64)
|
||||
|
||||
|
||||
ch_da = chart(DA, [
|
||||
Arrow(TRIG, "s-a ÎNCHIS peste 100.08: ăsta e trigger-ul.\n"
|
||||
"Intri la close, adică la 100.40",
|
||||
where="below", color=GREEN, dx=-40, dy=54),
|
||||
Arrow(AL_DOILEA, "al doilea semnal — aici NU mai intri:\n"
|
||||
"statistica cursului e măsurată pe primul",
|
||||
where="above", color=RED, dx=40, dy=-4)])
|
||||
ch_nu = chart(NU, [
|
||||
Arrow(TRIG, "fitilul a trecut peste 100.08, close-ul nu:\n"
|
||||
"un puseu de câteva secunde nu e trigger",
|
||||
where="above", color=RED, dx=-90, dy=4),
|
||||
Arrow(RUPT, "pullback-ul rupe 99.80:\nsetup mort, cauți altul",
|
||||
where="below", color=RED, dx=-30, dy=24)])
|
||||
|
||||
body_da, h_da = duo.panel(ch_da, W)
|
||||
body_nu, h_nu = duo.panel(ch_nu, W)
|
||||
|
||||
nivel_capat = ["capătul pullback-ului 100.08", "peste el trebuie ÎNCHIS, nu doar atins"]
|
||||
extra_da = (duo.titlu("DA — bara se închide peste capăt", color=GREEN)
|
||||
+ duo.zone(ch_da, TRIG - 2, TRIG, "aici se decide intrarea", GREEN, pad=13, lift=30)
|
||||
+ duo.level(ch_da, CAPAT, nivel_capat, GREY, W, below=True, at_left=False))
|
||||
extra_nu = (duo.titlu("NU — atins cu fitilul, închis dedesubt: nu e trigger", color=RED)
|
||||
+ duo.level(ch_nu, CAPAT, nivel_capat, GREY, W, below=False, at_left=False)
|
||||
+ duo.level(ch_nu, REF_LOW, ["minimul din care a pornit mișcarea 99.80"],
|
||||
RED, W, below=True, dash="2 3"))
|
||||
|
||||
svg, H, n = duo.build(
|
||||
[("DA", body_da, h_da, extra_da), ("NU", body_nu, h_nu, extra_nu)],
|
||||
["Primele 9 bare sunt identice pe ambele panouri; se schimbă doar ce urmează.",
|
||||
"Trigger-ul se citește pe bară ÎNCHISĂ, nu pe fitil — la fel se citește și "
|
||||
"ieșirea pe trail (pasul 5)."],
|
||||
W)
|
||||
duo.fara_preturi_straine(svg, [CAPAT, ENTRY, REF_LOW])
|
||||
OUT.write_text(svg, encoding="utf-8")
|
||||
print(f"scris {OUT} ({W}x{H:.0f}), {n} etichete | capăt {CAPAT:.2f} | "
|
||||
f"DA: trigger la bara {TRIG}, intrare {ENTRY:.2f}, al doilea semnal la {AL_DOILEA} | "
|
||||
f"NU: bara {TRIG} high {NU[TRIG][1]:.2f} close {NU[TRIG][3]:.2f}, rupe la bara {RUPT}")
|
||||
76
gen/strategii/m2d_trigger.svg
Normal file
@@ -0,0 +1,76 @@
|
||||
<svg viewBox="0 0 680 662" xmlns="http://www.w3.org/2000/svg" style="width:100%;height:auto;font:12px sans-serif">
|
||||
<g transform="translate(0,0)"><text x="24" y="22" fill="#188a3e" style="font-weight:bold">DA — bara se închide peste capăt</text><rect x="253.0" y="83.2" width="86.0" height="103.2" fill="#188a3e" fill-opacity="0.12" stroke="#188a3e" stroke-width="1"/><text x="259.0" y="76.2" fill="#188a3e" style="font-weight:bold">aici se decide intrarea</text><line x1="24" y1="159.7" x2="666" y2="159.7" stroke="#555" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="180.7" fill="#555" text-anchor="end" style="font-weight:bold">capătul pullback-ului 100.08</text><text x="656" y="194.7" fill="#555" text-anchor="end" style="font-weight:bold">peste el trebuie ÎNCHIS, nu doar atins</text>
|
||||
<line x1="56.0" y1="95.2" x2="56.0" y2="126.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="50.0" y="105.6" width="12" height="15.6" fill="#c00"/>
|
||||
<line x1="86.0" y1="116.0" x2="86.0" y2="142.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="80.0" y="121.2" width="12" height="15.6" fill="#c00"/>
|
||||
<line x1="116.0" y1="131.6" x2="116.0" y2="152.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="110.0" y="136.8" width="12" height="10.4" fill="#c00"/>
|
||||
<line x1="146.0" y1="142.0" x2="146.0" y2="162.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="140.0" y="147.2" width="12" height="10.4" fill="#c00"/>
|
||||
<line x1="176.0" y1="152.4" x2="176.0" y2="168.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="170.0" y="157.6" width="12" height="5.2" fill="#c00"/>
|
||||
<line x1="206.0" y1="157.6" x2="206.0" y2="173.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="200.0" y="162.8" width="12" height="5.2" fill="#c00"/>
|
||||
<line x1="236.0" y1="162.8" x2="236.0" y2="176.3" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="230.0" y="168.0" width="12" height="5.2" fill="#c00"/>
|
||||
<line x1="266.0" y1="168.0" x2="266.0" y2="178.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="260.0" y="170.1" width="12" height="3.1" fill="#188a3e"/>
|
||||
<line x1="296.0" y1="159.7" x2="296.0" y2="174.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="290.0" y="165.9" width="12" height="4.2" fill="#188a3e"/>
|
||||
<line x1="326.0" y1="121.2" x2="326.0" y2="168.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="320.0" y="126.4" width="12" height="39.5" fill="#188a3e"/>
|
||||
<line x1="356.0" y1="105.6" x2="356.0" y2="131.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="350.0" y="110.8" width="12" height="15.6" fill="#188a3e"/>
|
||||
<line x1="386.0" y1="90.0" x2="386.0" y2="116.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="380.0" y="95.2" width="12" height="15.6" fill="#188a3e"/>
|
||||
<line x1="416.0" y1="64.0" x2="416.0" y2="100.4" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="410.0" y="69.2" width="12" height="26.0" fill="#188a3e"/>
|
||||
<line x1="286.0" y1="252.0" x2="322.4" y2="179.2" stroke="#188a3e" stroke-width="1.8"/>
|
||||
<polygon points="326.0,172.0 326.0,180.9 318.8,177.4" fill="#188a3e"/>
|
||||
<text x="286.0" y="266.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">s-a ÎNCHIS peste 100.08: ăsta e trigger-ul.</text>
|
||||
<text x="286.0" y="280.0" fill="#188a3e" text-anchor="middle" style="font-weight:bold">Intri la close, adică la 100.40</text>
|
||||
<line x1="396.0" y1="52.0" x2="361.0" y2="95.4" stroke="#c00" stroke-width="1.8"/>
|
||||
<polygon points="356.0,101.6 357.9,92.9 364.1,97.9" fill="#c00"/>
|
||||
<text x="396.0" y="33.0" fill="#c00" text-anchor="middle" style="font-weight:bold">al doilea semnal — aici NU mai intri:</text>
|
||||
<text x="396.0" y="47.0" fill="#c00" text-anchor="middle" style="font-weight:bold">statistica cursului e măsurată pe primul</text>
|
||||
</g>
|
||||
<g transform="translate(0,315)"><text x="24" y="22" fill="#c00" style="font-weight:bold">NU — atins cu fitilul, închis dedesubt: nu e trigger</text><line x1="24" y1="128.5" x2="666" y2="128.5" stroke="#555" stroke-width="1.5" stroke-dasharray="4 3"/><text x="656" y="108.5" fill="#555" text-anchor="end" style="font-weight:bold">capătul pullback-ului 100.08</text><text x="656" y="122.5" fill="#555" text-anchor="end" style="font-weight:bold">peste el trebuie ÎNCHIS, nu doar atins</text><line x1="24" y1="157.6" x2="666" y2="157.6" stroke="#c00" stroke-width="1.5" stroke-dasharray="2 3"/><text x="30" y="178.6" fill="#c00" text-anchor="start" style="font-weight:bold">minimul din care a pornit mișcarea 99.80</text>
|
||||
<line x1="56.0" y1="64.0" x2="56.0" y2="95.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="50.0" y="74.4" width="12" height="15.6" fill="#c00"/>
|
||||
<line x1="86.0" y1="84.8" x2="86.0" y2="110.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="80.0" y="90.0" width="12" height="15.6" fill="#c00"/>
|
||||
<line x1="116.0" y1="100.4" x2="116.0" y2="121.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="110.0" y="105.6" width="12" height="10.4" fill="#c00"/>
|
||||
<line x1="146.0" y1="110.8" x2="146.0" y2="131.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="140.0" y="116.0" width="12" height="10.4" fill="#c00"/>
|
||||
<line x1="176.0" y1="121.2" x2="176.0" y2="136.8" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="170.0" y="126.4" width="12" height="5.2" fill="#c00"/>
|
||||
<line x1="206.0" y1="126.4" x2="206.0" y2="142.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="200.0" y="131.6" width="12" height="5.2" fill="#c00"/>
|
||||
<line x1="236.0" y1="131.6" x2="236.0" y2="145.1" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="230.0" y="136.8" width="12" height="5.2" fill="#c00"/>
|
||||
<line x1="266.0" y1="136.8" x2="266.0" y2="147.2" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="260.0" y="138.9" width="12" height="3.1" fill="#188a3e"/>
|
||||
<line x1="296.0" y1="128.5" x2="296.0" y2="143.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="290.0" y="134.7" width="12" height="4.2" fill="#188a3e"/>
|
||||
<line x1="326.0" y1="90.0" x2="326.0" y2="138.9" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="320.0" y="134.7" width="12" height="2.1" fill="#c00"/>
|
||||
<line x1="356.0" y1="131.6" x2="356.0" y2="155.5" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="350.0" y="136.8" width="12" height="15.6" fill="#c00"/>
|
||||
<line x1="386.0" y1="147.2" x2="386.0" y2="183.6" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="380.0" y="152.4" width="12" height="26.0" fill="#c00"/>
|
||||
<line x1="416.0" y1="168.0" x2="416.0" y2="194.0" stroke="#1a1a1a" stroke-width="1.2"/>
|
||||
<rect x="410.0" y="178.4" width="12" height="10.4" fill="#c00"/>
|
||||
<line x1="236.0" y1="64.0" x2="318.2" y2="84.1" stroke="#c00" stroke-width="1.8"/>
|
||||
<polygon points="326.0,86.0 317.3,88.0 319.2,80.2" fill="#c00"/>
|
||||
<text x="236.0" y="45.0" fill="#c00" text-anchor="middle" style="font-weight:bold">fitilul a trecut peste 100.08, close-ul nu:</text>
|
||||
<text x="236.0" y="59.0" fill="#c00" text-anchor="middle" style="font-weight:bold">un puseu de câteva secunde nu e trigger</text>
|
||||
<line x1="356.0" y1="237.6" x2="381.9" y2="194.5" stroke="#c00" stroke-width="1.8"/>
|
||||
<polygon points="386.0,187.6 385.3,196.5 378.5,192.4" fill="#c00"/>
|
||||
<text x="356.0" y="251.6" fill="#c00" text-anchor="middle" style="font-weight:bold">pullback-ul rupe 99.80:</text>
|
||||
<text x="356.0" y="265.6" fill="#c00" text-anchor="middle" style="font-weight:bold">setup mort, cauți altul</text>
|
||||
</g>
|
||||
<text x="24" y="622" fill="#555">Primele 9 bare sunt identice pe ambele panouri; se schimbă doar ce urmează.</text>
|
||||
<text x="24" y="639" fill="#555">Trigger-ul se citește pe bară ÎNCHISĂ, nu pe fitil — la fel se citește și ieșirea pe trail (pasul 5).</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.4 KiB |