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
106 lines
4.4 KiB
Python
106 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Ce e doji și ce nu — patru candele cu același high 50.10 și low 49.20.
|
|
|
|
Citește `gen/strategii/buy_doji_doji_forma.spec.txt` și scrie
|
|
`gen/strategii/buy_doji_doji_forma.svg`. Definiție de o candelă (stilul
|
|
vechi, candele izolate): diferă doar corpul, deci testul „corp ≤ 10 % din
|
|
range, fitil în ambele părți" se vede direct pe formă.
|
|
|
|
Desenat direct, nu cu `Chart`: `tag`/`note` din svg_candles pun etichetele
|
|
pe un singur rând sau în blocul de jos, iar aici fiecare etichetă trebuie să
|
|
stea lipită sub candela ei, pe 2-3 rânduri.
|
|
|
|
Rulare: python3 gen/strategii/buy_doji_doji_forma.py
|
|
"""
|
|
from pathlib import Path
|
|
|
|
OUT = Path(__file__).with_suffix(".svg")
|
|
GREEN, RED, GREY = "#188a3e", "#c00", "#555"
|
|
|
|
H, L = 50.10, 49.20
|
|
RNG = H - L
|
|
# (nume, o, h, l, c, verdict, rânduri de etichetă sub candelă)
|
|
CANDLES = [
|
|
("A", 49.60, 50.10, 49.20, 49.55, "DA", ["DA: corp 0.05", "= 5.6 % din range"]),
|
|
("B", 49.62, 50.10, 49.20, 49.53, "DA", ["DA, la limită:", "corp 0.09 = 10 %", "(parametrul 10)"]),
|
|
("C", 49.80, 50.10, 49.20, 49.50, "NU", ["NU: corp 0.30", "= 33 %"]),
|
|
("D", 50.05, 50.10, 49.20, 50.10, "NU", ["NU: corp mic (5.6 %),", "dar fără fitil sus"]),
|
|
]
|
|
|
|
# --- assert-urile din spec --------------------------------------------------
|
|
ratio = {n: round(abs(c - o) / (h - l), 4) for n, o, h, l, c, *_ in CANDLES}
|
|
for n, o, h, l, c, *_ in CANDLES:
|
|
assert h == H and l == L, (n, h, l) # 1
|
|
assert ratio == {"A": 0.0556, "B": 0.1000, "C": 0.3333, "D": 0.0556}, ratio # 2
|
|
for n, o, h, l, c, *_ in CANDLES[:2]: # 3
|
|
assert ratio[n] <= 0.10 and min(o, c) > l and max(o, c) < h, n
|
|
assert ratio["C"] > 0.10 # 4
|
|
_, oD, hD, _, cD, *_ = CANDLES[3]
|
|
assert max(oD, cD) == hD
|
|
|
|
# --- geometrie ---------------------------------------------------------------
|
|
SCALE, TOP, W = 260, 72, 740
|
|
XS = [150, 300, 450, 600] # centrele candelelor
|
|
BODY_W = 26
|
|
|
|
|
|
def y(p):
|
|
return TOP + (H - p) * SCALE
|
|
|
|
|
|
oA, cA = CANDLES[0][1], CANDLES[0][4]
|
|
assert y(oA) < y(cA), "open A trebuie să fie mai sus pe ecran decât close A" # 5
|
|
|
|
out = []
|
|
t = out.append
|
|
|
|
|
|
def text(x, yy, s, color=GREY, anchor="start", bold=False, size=12):
|
|
style = f' style="font-weight:bold;font-size:{size}px"' if bold else (
|
|
f' style="font-size:{size}px"' if size != 12 else "")
|
|
t(f'<text x="{x:.1f}" y="{yy:.1f}" fill="{color}" text-anchor="{anchor}"{style}>{s}</text>')
|
|
|
|
|
|
text(24, 22, "Ce e doji și ce nu — aceeași bară 50.10 / 49.20", "#333", bold=True)
|
|
|
|
# high și low comune: linii subțiri pe toată lățimea
|
|
for p in (H, L):
|
|
t(f'<line x1="{XS[0] - 30}" y1="{y(p):.1f}" x2="{W - 24}" y2="{y(p):.1f}" '
|
|
f'stroke="#bbb" stroke-dasharray="4 3"/>')
|
|
text(XS[0] - 36, y(H) + 4, "high 50.10", anchor="end")
|
|
text(XS[0] - 36, y(L) + 4, "low 49.20", anchor="end")
|
|
|
|
label_y0 = y(L) + 24
|
|
for (n, o, h, l, c, verdict, lines), x in zip(CANDLES, XS):
|
|
color = GREEN if c >= o else RED
|
|
vcol = GREEN if verdict == "DA" else RED
|
|
t(f'<line x1="{x}" y1="{y(h):.1f}" x2="{x}" y2="{y(l):.1f}" stroke="#1a1a1a" stroke-width="1.4"/>')
|
|
top, bot = y(max(o, c)), y(min(o, c))
|
|
t(f'<rect x="{x - BODY_W / 2:.1f}" y="{top:.1f}" width="{BODY_W}" '
|
|
f'height="{max(bot - top, 1.6):.1f}" fill="{color}"/>')
|
|
text(x, y(H) - 14, verdict, vcol, "middle", bold=True, size=18)
|
|
for k, s in enumerate(lines):
|
|
text(x, label_y0 + 16 * k, s, vcol, "middle", bold=(k == 0))
|
|
|
|
# prețurile pe A: open la stânga (mai sus), close la dreapta (mai jos)
|
|
x = XS[0]
|
|
text(x - 36, y(oA) + 2, "open 49.60", anchor="end")
|
|
t(f'<line x1="{x - 32}" y1="{y(oA):.1f}" x2="{x - 14}" y2="{y(oA):.1f}" stroke="{GREY}"/>')
|
|
text(x + 36, y(cA) + 8, "close 49.55")
|
|
t(f'<line x1="{x + 14}" y1="{y(cA):.1f}" x2="{x + 32}" y2="{y(cA):.1f}" stroke="{GREY}"/>')
|
|
|
|
# D: close = high, deci fitilul de sus lipsește
|
|
x = XS[3]
|
|
text(x + 20, y(H) + 12, "← fără fitil sus", RED)
|
|
|
|
cap_y = label_y0 + 16 * 3 + 14
|
|
text(24, cap_y, f"Test doji: corp ≤ 10 % din range ({RNG:.2f}) și fitil în ambele părți. "
|
|
"Scară: 0.10 = 26 px.")
|
|
height = cap_y + 12
|
|
|
|
svg = (f'<svg viewBox="0 0 {W} {height:.0f}" xmlns="http://www.w3.org/2000/svg" '
|
|
f'style="width:100%;height:auto;font:12px sans-serif">\n '
|
|
+ "\n ".join(out) + "\n</svg>\n")
|
|
OUT.write_text(svg, encoding="utf-8")
|
|
print(f"scris {OUT} ({W}x{height:.0f})")
|