buy_doji: refacut ca tutorial pe 3 niveluri, cu diagrame adnotate
Userul a respins mostra de format tutorial: prea lunga, prea multe trimiteri in text, termeni tehnici nedefiniti, prea multe cifre fara desen. Cerintele lui sunt acum contract in STYLE.md (FORMAT TUTORIAL v2). Textul: 8430 -> 4190 de cuvinte. Nivel 1 (din avion, cu mini-glosar) -> nivel 2 (6 pasi mecanici, o diagrama fiecare) -> oglinda short -> nivel 3 (rafinari). Trimiterile fisier:linie ies din corp si se aduna la final, cu legenda de prescurtari. Doua tabele in tot documentul. Toate cele 14 diagrame refacute: zone dreptunghiulare de evidentiere si sageti care spun si de ce, nu doar ce. svg_candles primeste Zone si Arrow; render() nu mai muta obiectul la iesire. Trei corecturi de continut: - un singur trade prin toata procedura (doji 50.10/49.25, intrare 50.40, stop 49.20, 1R 1.20, TP1 51.60); seria e acum o functie comuna, importata de stop/transe/iesire - short: stopul urca la 100.15, ca sa fie deasupra maximului cum cere regula oglindita; cifra cursului ramane in text ca observatie - LABU: trei minime dar doua atingeri ale pivotului 86.00, ceea ce impaca "triple bottom" cu "al doilea test", ambele din transcriere Reparat si bug-ul vechi din buy_doji_sell.svg: titlul peste eticheta dojiului. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
This commit is contained in:
@@ -6,10 +6,14 @@ Citește `gen/strategii/buy_doji_fereastra.spec.txt` și scrie
|
||||
cu aceeași serie până la doji: sus confirmarea vine la bara +2 (în fereastră),
|
||||
jos niciuna din +1..+3 nu confirmă, iar a 4-a închide sub low-ul dojiului.
|
||||
|
||||
Toate cifrele din desen vin din specificație: doji h 50.10 / l 49.20,
|
||||
closes-urile DA/NU, pragul 50.10, low-ul 49.20. Seriile sunt construite
|
||||
(open = close-ul barei anterioare, mai puțin open-ul primei bare, start-ul),
|
||||
ca nivelurile afirmate să iasă exact din serie.
|
||||
Adnotat „ca la proști": zonă dreptunghiulară peste cele 3 candele ale
|
||||
ferestrei pe ambele panouri, plus săgeți cu text care spun CE și DE CE
|
||||
(„aici NU intri — s-a închis sub high-ul dojiului", „AICI INTRI, la close").
|
||||
|
||||
Toate cifrele din desen vin din specificație: doji h 50.10 / l 49.25,
|
||||
closes-urile DA/NU, pragul 50.10. Seriile sunt construite (open = close-ul
|
||||
barei anterioare, mai puțin open-ul primei bare, start-ul), ca nivelurile
|
||||
afirmate să iasă exact din serie.
|
||||
|
||||
Rulare: python3 gen/strategii/buy_doji_fereastra.py
|
||||
"""
|
||||
@@ -18,21 +22,23 @@ import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, "/workspace/atm-curs-dl")
|
||||
from svg_candles import Chart, Level, Mark, from_closes # noqa: E402
|
||||
from svg_candles import Arrow, Chart, Mark, from_closes # noqa: E402
|
||||
|
||||
OUT = Path(__file__).with_suffix(".svg")
|
||||
W = 460
|
||||
VGAP = 34
|
||||
SCALE = 45.0 # px / unitate, aceeași pe ambele panouri (comparație)
|
||||
W = 640
|
||||
VGAP = 0
|
||||
SCALE = 60.0 # px / unitate, aceeași pe ambele panouri (comparație)
|
||||
LEFT, GAP = 64, 40
|
||||
ORANGE, RED, GREEN, BLUE, GREY = "#b06000", "#c00", "#188a3e", "#1a5fb4", "#555"
|
||||
|
||||
# --- seriile din specificație ----------------------------------------------
|
||||
CLOSES_DA = [52.20, 51.40, 50.60, 49.65,
|
||||
49.60, # doji, h 50.10 / l 49.20
|
||||
49.60, # doji, h 50.10 / l 49.25
|
||||
49.90, # +1 — sub 50.10
|
||||
50.40, # +2 — peste 50.10 => confirmă
|
||||
50.80]
|
||||
CLOSES_NU = [52.20, 51.40, 50.60, 49.65,
|
||||
49.60, # doji, h 50.10 / l 49.20
|
||||
49.60, # doji, h 50.10 / l 49.25
|
||||
49.95, # +1
|
||||
50.05, # +2
|
||||
49.85, # +3
|
||||
@@ -40,13 +46,13 @@ CLOSES_NU = [52.20, 51.40, 50.60, 49.65,
|
||||
assert len(CLOSES_DA) == 8 and len(CLOSES_NU) == 9
|
||||
assert CLOSES_DA[:5] == CLOSES_NU[:5]
|
||||
|
||||
HIGH_DOJI, LOW_DOJI = 50.10, 49.20
|
||||
HIGH_DOJI, LOW_DOJI = 50.10, 49.25
|
||||
|
||||
# wick-uri: (up, down). Doji-ul (index 4) primește mecioni ca să iasă exact
|
||||
# h=50.10 / l=49.20; restul au mecioni mici, egali.
|
||||
# wick-uri: (up, down). Doji-ul (index 4) primește fitile ca să iasă exact
|
||||
# h=50.10 / l=49.25; restul au fitile mici, egale.
|
||||
wicks_da = [(0.15, 0.15)] * len(CLOSES_DA)
|
||||
wicks_nu = [(0.15, 0.15)] * len(CLOSES_NU)
|
||||
wicks_da[4] = wicks_nu[4] = (0.45, 0.40)
|
||||
wicks_da[4] = wicks_nu[4] = (0.45, 0.35)
|
||||
|
||||
START = CLOSES_DA[0] + 0.15 # prima bară roșie, open > close
|
||||
cds_da = from_closes(CLOSES_DA, wicks=wicks_da, start=START)
|
||||
@@ -72,7 +78,7 @@ assert abs(cds_da[5].c - 49.90) < 1e-9 and cds_da[5].c <= HIGH_DOJI, \
|
||||
assert abs(cds_da[6].c - entry) < 1e-9 and abs(entry - 50.40) < 1e-9, \
|
||||
"intrarea nu e close-ul de 50.40 al barei +2"
|
||||
|
||||
# 2. NU: niciun close din +1..+3 nu depășește 50.10; a 4-a închide sub 49.20
|
||||
# 2. NU: niciun close din +1..+3 nu depășește 50.10; a 4-a închide sub 49.25
|
||||
assert all(cds_nu[i].c <= HIGH_DOJI for i in (5, 6, 7)), \
|
||||
"un close din +1..+3 ar confirma, fereastra n-ar fi expirat"
|
||||
assert cds_nu[8].c < LOW_DOJI, f"close[+4]={cds_nu[8].c} nu e sub {LOW_DOJI}"
|
||||
@@ -87,54 +93,102 @@ ser_nu = [(round(c.o, 9), round(c.h, 9), round(c.l, 9), round(c.c, 9)) for c in
|
||||
assert ser_da == ser_nu, "panourile nu au aceeași serie până la doji"
|
||||
|
||||
# --- desen: două Chart-uri, lipite vertical într-un singur SVG -------------
|
||||
cds_nu[7].note = "+1: 49.95 · +2: 50.05 · +3: 49.85 — toate sub 50.10"
|
||||
|
||||
ch_da = Chart(
|
||||
candles=cds_da,
|
||||
marks=[Mark(4, "doji", ORANGE, "above")],
|
||||
arrows=[
|
||||
Arrow(5, "aici NU intri: s-a închis sub 50.10\nsemnalul cere o ÎNCHIDERE peste",
|
||||
where="below", color=RED),
|
||||
Arrow(6, "AICI INTRI, la close 50.40\nprima închidere peste\nhigh-ul dojiului",
|
||||
price=entry, where="right", color=GREEN, dx=20, dy=46),
|
||||
],
|
||||
scale=SCALE, gap=GAP, body_w=13, left=LEFT, width=W,
|
||||
title="DA — confirmare la +2, în fereastră",
|
||||
)
|
||||
|
||||
ch_nu = Chart(
|
||||
candles=cds_nu,
|
||||
marks=[Mark(4, "doji", ORANGE, "above"), Mark(8, "a 4-a", RED, "above")],
|
||||
arrows=[
|
||||
Arrow(7, "a treia s-a închis tot sub 50.10\nfereastra s-a terminat: ștergi setup-ul",
|
||||
where="above", color=RED, dx=135),
|
||||
Arrow(8, "a închis sub low-ul dojiului\nsetup mort — nu mai intri",
|
||||
where="below", color=RED),
|
||||
],
|
||||
scale=SCALE, gap=GAP, body_w=13, left=LEFT, width=W,
|
||||
title="NU — nicio confirmare în 3 candele",
|
||||
)
|
||||
|
||||
|
||||
def _panel(ch: Chart):
|
||||
svg = ch.render()
|
||||
m = re.search(r'viewBox="0 0 (\d+) ([\d.]+)"', svg)
|
||||
"""`_render()`, nu `render()`: al doilea restaurează top/left după desen,
|
||||
iar liniile și zonele desenate de mână ar pica deplasate față de body."""
|
||||
svg = ch._render()
|
||||
m = re.search(r'viewBox="0 0 ([\d.]+) ([\d.]+)"', svg)
|
||||
assert m, "viewBox lipsă"
|
||||
assert float(m.group(1)) == W, f"textul unei săgeți iese din {W}px"
|
||||
body = svg[svg.index(">") + 1:svg.rindex("</svg>")]
|
||||
return body, float(m.group(2))
|
||||
|
||||
|
||||
# DA — confirmarea vine la +2
|
||||
cds_da[5].note = "+1: close 49.90 — sub 50.10, nu confirmă"
|
||||
cds_da[6].note = "+2: close 50.40 — peste 50.10, confirmă (intrare la close)"
|
||||
ch_da = Chart(
|
||||
candles=cds_da,
|
||||
levels=[Level(HIGH_DOJI, "high doji 50.10", "#b06000", label_at="left"),
|
||||
Level(LOW_DOJI, "low doji 49.20", "#c00", label_at="left")],
|
||||
marks=[Mark(4, "doji", "#b06000", "above"),
|
||||
Mark(6, f"confirmare +2 — intrare {entry:.2f}", "#188a3e", "above")],
|
||||
scale=SCALE, gap=40, body_w=13, left=44, width=W,
|
||||
title="DA — confirmare la +2, în fereastră",
|
||||
)
|
||||
def level(ch, price, text, color, below=False, at_left=True):
|
||||
"""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ă."""
|
||||
y = ch._y(price)
|
||||
out = [f'<line x1="24" y1="{y:.1f}" x2="{W - 14}" y2="{y:.1f}" stroke="{color}" '
|
||||
f'stroke-width="1.5" stroke-dasharray="4 3"/>']
|
||||
for k, s in enumerate(text):
|
||||
ty = (y + 15 + 14 * k) if below else (y - 6 - 14 * (len(text) - 1 - k))
|
||||
tx, anchor = (30, "start") if at_left else (W - 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):
|
||||
"""Dreptunghi de evidențiere peste candelele i0..i1, cu eticheta deasupra.
|
||||
|
||||
`lift` ridică marginea de sus (și deci eticheta), ca să nu cadă peste
|
||||
săgețile care intră în zonă de sus."""
|
||||
cds = ch.candles[i0:i1 + 1]
|
||||
x0, x1 = ch._cx(i0) - 16, ch._cx(i1) + 16
|
||||
y0 = ch._y(max(c.h for c in cds)) - 8 - lift
|
||||
y1 = ch._y(min(c.l for c in cds)) + 8
|
||||
return [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"/>',
|
||||
f'<text x="{x0 + 6:.1f}" y="{y0 - 7:.1f}" fill="{color}" '
|
||||
f'style="font-weight:bold">{label}</text>']
|
||||
|
||||
# NU — nicio confirmare în 3 candele, apoi setup mort
|
||||
cds_nu[5].note = "+1: 49.95; +2: 50.05; +3: 49.85 — toate sub 50.10"
|
||||
cds_nu[8].note = "a 4-a: close 49.15 — sub low-ul dojiului 49.20, setup mort"
|
||||
ch_nu = Chart(
|
||||
candles=cds_nu,
|
||||
levels=[Level(HIGH_DOJI, "high doji 50.10", "#b06000", label_at="left"),
|
||||
Level(LOW_DOJI, "low doji 49.20", "#c00", label_at="left")],
|
||||
marks=[Mark(4, "doji", "#b06000", "above"),
|
||||
Mark(8, "a 4-a", "#c00", "above")],
|
||||
scale=SCALE, gap=40, body_w=13, left=44, width=W,
|
||||
title="NU — nicio confirmare în 3 candele",
|
||||
)
|
||||
|
||||
body_da, h_da = _panel(ch_da)
|
||||
body_nu, h_nu = _panel(ch_nu)
|
||||
|
||||
extra_da = (zone(ch_da, 5, 7, "fereastra: 3 candele", BLUE)
|
||||
+ level(ch_da, HIGH_DOJI,
|
||||
["high-ul dojiului 50.10", "trebuie ÎNCHIS peste,", "nu doar atins"],
|
||||
ORANGE, below=True)
|
||||
+ level(ch_da, LOW_DOJI, ["low-ul dojiului 49.25"], RED, below=True))
|
||||
extra_nu = (zone(ch_nu, 5, 7, "fereastra: 3 candele", BLUE)
|
||||
+ level(ch_nu, HIGH_DOJI,
|
||||
["high-ul dojiului 50.10", "trebuie ÎNCHIS peste,", "nu doar atins"],
|
||||
ORANGE, below=True)
|
||||
+ level(ch_nu, LOW_DOJI, ["low-ul dojiului 49.25"], RED, below=True))
|
||||
|
||||
cap1 = "Serii construite: open = close-ul barei anterioare."
|
||||
cap2 = "Doji: h 50.10 / l 49.20. Fereastra = maximum 3 candele după doji."
|
||||
cap2 = "Doji: h 50.10 / l 49.25. Fereastra = maximum 3 candele după doji."
|
||||
cap_top = h_da + VGAP + h_nu + 20
|
||||
H = cap_top + 22
|
||||
|
||||
parts = [
|
||||
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">',
|
||||
f'<g transform="translate(0,0)">{body_da}</g>',
|
||||
f'<g transform="translate(0,{h_da + VGAP:.0f})">{body_nu}</g>',
|
||||
f'<text x="24" y="{cap_top:.0f}" fill="#555">{cap1}</text>',
|
||||
f'<text x="24" y="{cap_top + 17:.0f}" fill="#555">{cap2}</text>',
|
||||
# zonele și liniile întâi, ca să stea în spatele candelelor
|
||||
f'<g transform="translate(0,0)">{"".join(extra_da)}{body_da}</g>',
|
||||
f'<g transform="translate(0,{h_da + VGAP:.0f})">{"".join(extra_nu)}{body_nu}</g>',
|
||||
f'<text x="24" y="{cap_top:.0f}" fill="{GREY}">{cap1}</text>',
|
||||
f'<text x="24" y="{cap_top + 17:.0f}" fill="{GREY}">{cap2}</text>',
|
||||
"</svg>",
|
||||
]
|
||||
svg = "\n ".join(parts)
|
||||
@@ -162,7 +216,8 @@ def _texts(body: str, y_off: float, tag: str):
|
||||
return out
|
||||
|
||||
|
||||
labels = _texts(body_da, 0.0, "DA") + _texts(body_nu, h_da + VGAP, "NU")
|
||||
labels = (_texts(body_da + "".join(extra_da), 0.0, "DA")
|
||||
+ _texts(body_nu + "".join(extra_nu), h_da + VGAP, "NU"))
|
||||
for left, right, y, s, tag in labels:
|
||||
assert left >= -2 and right <= W + 2, f"[{tag}] text iese din panză: {s!r}"
|
||||
assert 0 <= y <= H, f"[{tag}] text în afara înălțimii: {s!r} (y={y:.0f})"
|
||||
|
||||
Reference in New Issue
Block a user