Files
atm-curs-dl/gen/strategii/buy_doji_stop.py
Claude Agent 9c1936e73a buy_doji: capitolul rescris ca tutorial in 9 pasi, cu 9 diagrame noi
Mostra de format ceruta de user pe 19.09.2026 — de aprobat inainte sa
aplicam formatul la celelalte 8 capitole. Specificatia e in STYLE.md,
sectiunea FORMAT TUTORIAL.

Structura: pasii 1-9 in ordinea in care faci lucrurile la ecran, fiecare
terminat cu "Treci mai departe doar daca...". Cele trei perechi de TF
(weekly-daily, monthly-weekly, daily-60min) una langa alta in pasul 2;
perechea monthly-weekly e acoperita doar partial de material si scrie asta.
Nivelurile 0/1/2 desfiintate ca structura. Niciun tabel de 2 coloane.
Sursele mutate la final.

14 diagrame, de la 5: cele 5 vechi raman neatinse, 9 noi. Un agent per
diagrama, fiecare cu audit + PNG privit. Toate 9 ies curate.

10 reguli din material care lipseau din versiunea veche, fiecare cu citat
si fisier:linie — printre ele stopul se numara pe TF-ul deciziei
(20_2025-08-25:9-15) si nu muti ordinul dupa pret (03_locul_crimei:296-311).
Contradictie noua, a 7-a: pe weekly regula de pivoti spune Quarterly, dar
MICI citeste pivotul monthly.

Completarile proprii stau in blocuri "Completare proprie:", conform
deciziei userului de azi.

Cunoscut, nereparat: audit_diagrams da 9 fals-pozitive pe buy_doji_aplus si
buy_doji_fereastra, care folosesc <g transform> (auditul nu-l intelege).
A zecea, in buy_doji_sell (titlu peste eticheta "doji 99.20 / 100.10"), e
reala si preexistenta.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ThN7ixZrowca8aTGrK1MUJ
2026-09-19 18:27:13 +00:00

131 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Buy Doji — unde pui stopul: 4 candele înapoi, sub structură (exemplu construit).
Citește specificația `gen/strategii/buy_doji_stop.spec.txt`. Două panouri
stivuite, aceeași serie 0-14 ca buy_doji_transe (downtrend, doji 12, +1 13,
confirmare 14). Sus: numărătoarea celor 4 candele (1 = confirmarea). Jos:
același trade, stop „la ochi" 52.90 față de stopul din regulă 51.55.
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
from svg_candles import Candle, Chart, Level, Mark
OUT = "/workspace/atm-curs-dl/gen/strategii/buy_doji_stop.svg"
# --- seria: barele 0-14 exact ca în buy_doji_transe.spec.txt -----------------
closes = [60.40, 59.60, 59.90, 58.80, 58.10, 58.40, 57.20, 56.30, 56.60,
55.30, 54.20, 52.40]
bars, o = [], 61.00
for c in closes: # fitile implicite 0.15 peste/sub corp
bars.append((o, max(o, c) + 0.15, min(o, c) - 0.15, c))
o = c
bars += [(52.40, 53.00, 51.60, 52.30), # 12 doji
(52.30, 52.85, 52.10, 52.60), # 13 +1
(52.60, 53.85, 52.45, 53.70)] # 14 confirmare
after = [(53.70, 53.75, 52.70, 52.90), # 15 lovește stopul la ochi
(52.90, 53.05, 52.00, 52.20), # 16 al doilea picior, higher low
(52.20, 53.40, 52.10, 53.30),
(53.30, 54.30, 53.20, 54.20),
(54.20, 55.10, 54.10, 55.00),
(55.00, 56.00, 54.90, 55.95)] # 20 TP1
full = bars + after
o_, h_, l_, c_ = (list(x) for x in zip(*full))
ENTRY, SL, OCHI, TP1, LOW4 = 53.70, 51.55, 52.90, 55.85, 51.60
# --- assert-urile din spec ---------------------------------------------------
for i in range(1, len(full)): # 1
assert abs(o_[i] - c_[i - 1]) < 1e-9, f"open[{i}] != close[{i-1}]"
for i in range(len(full)):
assert l_[i] <= min(o_[i], c_[i]) and h_[i] >= max(o_[i], c_[i]), f"bara {i}"
assert min(l_[11:15]) == min(l_[10:15]) == LOW4 # 2
assert l_.index(LOW4) == 12, "cel mai jos low nu e dojiul"
assert round(LOW4 - 0.05, 2) == SL
assert min(l_[15:21]) == 52.00 and SL < 52.00 < OCHI # 3
assert next(i for i in range(15, 21) if l_[i] <= OCHI) == 15 # 4
assert all(l_[i] > SL for i in range(15, 21))
assert next(i for i in range(15, 21) if h_[i] >= TP1) == 20 # 5
assert 52.00 > LOW4 # 6
assert round(ENTRY - OCHI, 2) == 0.80 and c_[14] == ENTRY
assert round(ENTRY + (ENTRY - SL), 2) == TP1
GREY, RED, ORANGE, GREEN, BLUE = "#555", "#c00", "#b06000", "#188a3e", "#1a5fb4"
W = 640
common: dict = dict(scale=34.0, gap=18, body_w=10, left=44, width=W)
def mk(n):
return [Candle(*b) for b in full[:n]]
# --- panoul de sus: numărătoarea ---------------------------------------------
top = Chart(
candles=mk(15),
levels=[Level(LOW4, "cel mai jos low: 51.60 (doji)", GREY, "2 2", "left"),
Level(SL, "SL 51.55", RED, "4 3")],
# fără Mark pe doji: la gap 18 eticheta calcă pe bara 11; îl numește
# paranteza de dedesubt și cercul de pe low
marks=[Mark(14, "confirmare 53.70", GREEN, "above")],
title="Unde pui stopul: 4 candele înapoi, sub structură — exemplu construit",
**common,
)
svg_top = top.render()
# numerele 4 3 2 1 + (5) sub bare, bandă de evidențiere, paranteză
yb = top._y(SL) + 18 # rândul cu numere, sub linia de SL
x = top._cx
extra_top = [
f'<rect x="{x(11) - 8:.1f}" y="{top._y(max(h_[11:15])) - 4:.1f}" '
f'width="{x(14) - x(11) + 16:.1f}" height="{yb + 6 - top._y(max(h_[11:15])):.1f}" '
f'fill="{BLUE}" opacity="0.08"/>',
f'<circle cx="{x(12):.1f}" cy="{top._y(LOW4):.1f}" r="4" fill="none" '
f'stroke="{RED}" stroke-width="1.5"/>',
]
for i, n in zip(range(11, 15), "4321"):
extra_top.append(f'<text x="{x(i):.1f}" y="{yb:.1f}" fill="{BLUE}" '
f'text-anchor="middle" style="font-weight:bold">{n}</text>')
extra_top.append(f'<text x="{x(10):.1f}" y="{yb:.1f}" fill="#999" '
f'text-anchor="middle">(5)</text>')
yp = yb + 8
extra_top.append(f'<polyline points="{x(11) - 5:.1f},{yp:.1f} {x(11) - 5:.1f},{yp + 5:.1f} '
f'{x(14) + 5:.1f},{yp + 5:.1f} {x(14) + 5:.1f},{yp:.1f}" '
f'fill="none" stroke="{BLUE}" stroke-width="1.2"/>')
extra_top.append(f'<text x="{x(14) + 14:.1f}" y="{yp + 9:.1f}" fill="{BLUE}">'
f'ultimele 4 candele (3 = doji, 1 = confirmarea)</text>')
extra_top.append(f'<text x="24" y="{yp + 28:.1f}" fill="#555">'
f'Cu 4 sau cu 5 candele iese la fel: în downtrend low-ul dojiului '
f'e oricum cel mai jos. SL = 51.60 − 0.05.</text>')
h_top = yp + 40
# --- panoul de jos: același trade, două stopuri -------------------------------
bot = Chart(
candles=mk(21),
levels=[Level(TP1, "TP1 55.85", GREEN, "2 2"),
Level(ENTRY, "intrare 53.70", GREY, "4 3"),
Level(OCHI, "stop la ochi 52.90 — lovit", ORANGE, "4 3"),
Level(SL, "SL din regulă 51.55 — ținut", RED, "4 3")],
marks=[Mark(16, "al doilea picior: 52.00, higher low", BLUE, "below", dy=10),
Mark(20, "TP1", GREEN, "above")],
title="Același trade: stop la ochi (0.80 sub intrare) vs stop din regulă",
caption="Barele 15-20 și stopul la ochi sunt construite, pentru contrast.",
top=h_top + 10 + 34, # panoul de jos începe sub cel de sus, fără <g transform>
**common,
)
svg_bot = bot.render()
extra_bot = [
f'<circle cx="{bot._cx(15):.1f}" cy="{bot._y(OCHI):.1f}" r="5" fill="none" '
f'stroke="{ORANGE}" stroke-width="2"/>',
]
# header-ul (viewBox) e al panoului de jos: el conține și offset-ul celui de sus
svg = "\n ".join([
svg_bot.split(">", 1)[0] + ">",
svg_top.split(">", 1)[1].rsplit("</svg>", 1)[0].strip(), *extra_top,
f'<line x1="24" y1="{h_top + 2:.0f}" x2="{W - 14}" y2="{h_top + 2:.0f}" stroke="#ccc"/>',
svg_bot.split(">", 1)[1].rsplit("</svg>", 1)[0].strip(), *extra_bot,
]) + "\n</svg>"
H = float(re.search(r'viewBox="0 0 \d+ ([\d.]+)"', svg).group(1))
assert "<svg" in svg and "\n\n" not in svg, "linie goală în SVG"
with open(OUT, "w") as f:
f.write(svg)
print(f"scris {OUT} ({W}x{H:.0f})")