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:
Claude Agent
2026-09-19 21:09:31 +00:00
parent aff03870e8
commit 8b7b5f6b44
50 changed files with 7011 additions and 6921 deletions

View File

@@ -8,10 +8,10 @@ trendului sunt numerotate sub bară, ca numărătoarea să se vadă.
"""
import re
import sys; sys.path.insert(0, "/workspace/atm-curs-dl")
from svg_candles import Candle, Chart, Mark
from svg_candles import Arrow, Candle, Chart, Mark, Zone
OUT = "/workspace/atm-curs-dl/gen/strategii/buy_doji_trend.svg"
DOJI = (49.65, 50.10, 49.20, 49.60)
DOJI = (49.65, 50.10, 49.25, 49.60)
CONF = (49.60, 50.55, 49.45, 50.40)
@@ -54,12 +54,20 @@ def numbers(ch, idx, color):
for n, i in enumerate(idx, 1)]
def bracket(ch, a, b, y, text, color):
xa, xb = ch._cx(a) - 6, ch._cx(b) + 6
return [f'<polyline points="{xa:.1f},{y + 6:.1f} {xa:.1f},{y:.1f} {xb:.1f},{y:.1f} '
f'{xb:.1f},{y + 6:.1f}" fill="none" stroke="{color}" stroke-width="1.3"/>',
f'<text x="{xb + 8:.1f}" y="{y + 4:.1f}" fill="{color}" '
f'style="font-weight:bold">{text}</text>']
def render_keep_offsets(ch):
"""`Chart.render()` restaurează top/left după desen, deci `_y`/`_cx` de
după el dau coordonate deplasate față de body-ul randat (titlul și
etichetele zonelor mută graficul în jos). `_render()` lasă offset-urile
puse, exact ce ne trebuie ca extra-urile desenate de mână să pice la locul
lor. Se cheamă o singură dată per Chart."""
return ch._render()
def fits(ch, svg):
"""Chart mută graficul dacă un text ar ieși din pânză — aici mutarea ar
dezalinia cele două panouri, deci verificăm că nu s-a întâmplat."""
assert f'viewBox="0 0 {ch.width} ' in svg, \
f"Chart a lărgit pânza ({svg[:60]}): textul unei săgeți iese din {ch.width}px"
def body(svg):
@@ -68,32 +76,35 @@ def body(svg):
# --- panoul de sus: 9 candele ------------------------------------------------
top = Chart(candles=[Candle(*b) for b in L], left=44 + GAP, # dojiul pe aceeași verticală
marks=[Mark(10, "doji", ORANGE, "below", dy=8),
Mark(11, "confirmare 50.40", GREEN, "above")],
title="Trendul dinaintea dojiului: 9 candele vs. 3 candele — exemplu construit",
marks=[Mark(11, "confirmare 50.40", GREEN, "above")],
zones=[Zone(1, 9, "9 candele de scădere — ideal", GREEN)],
arrows=[Arrow(10, "doji la capătul scăderii\nvânzătorii s-au terminat",
where="below", color=ORANGE, dx=70)],
top=54, # titlul se desenează de mână: cel din Chart ar cădea peste eticheta zonei
**common)
svg_top = top.render()
y_br = top._y(max(b[1] for b in L[1:10])) - 10
ext_top = numbers(top, range(1, 10), RED) + bracket(top, 1, 9, y_br, "downtrend 9 candele", RED)
y_cap1 = top._y(DOJI[2]) + 50
svg_top = render_keep_offsets(top)
fits(top, svg_top)
ext_top = numbers(top, range(1, 10), RED) + [
'<text x="24" y="22" fill="#333" style="font-weight:bold">Trendul dinaintea dojiului: '
'9 candele vs. 3 candele — exemplu construit</text>']
y_cap1 = max(top._y(DOJI[2]) + 50, top._arrow_geom(top.arrows[0])["box"][3] + 24)
ext_top.append(f'<text x="24" y="{y_cap1:.1f}" fill="{GREEN}" style="font-weight:bold">'
f'DA — ideal (8-10 candele)</text>')
# --- panoul de jos: range + 3 candele ----------------------------------------
y_sep = y_cap1 + 16
bot = Chart(candles=[Candle(*b) for b in R], left=44,
marks=[Mark(11, "doji", ORANGE, "below", dy=8),
marks=[Mark(11, "doji", ORANGE, "below", dy=22),
Mark(12, "confirmare 50.40", GREEN, "above")],
top=int(y_sep + 62), **common) # titlul și paranteza range-ului, desenate mai jos
svg_bot = bot.render()
y_rg = bot._y(max(b[1] for b in R[0:8])) - 10
zones=[Zone(8, 10, "doar 3 candele — merge, dar mai slab", ORANGE)],
arrows=[Arrow(3, "înainte: preț pe loc,\nnu scădere — de aceea\nsemnalul e mai slab",
where="above", color=GREY)],
top=int(y_sep + 118), **common) # loc pentru titlul panoului și textul săgeții
svg_bot = render_keep_offsets(bot)
fits(bot, svg_bot)
ext_bot = (numbers(bot, range(8, 11), RED)
+ bracket(bot, 8, 10, bot._y(R[8][1]) - 10, "doar 3 candele", RED)
+ bracket(bot, 0, 7, y_rg, "", GREY)
+ [f'<text x="24" y="{y_sep + 24:.1f}" fill="#333" style="font-weight:bold">'
f'Același doji, după un range</text>',
f'<text x="{bot._cx(0) - 6:.1f}" y="{y_rg - 5:.1f}" fill="{GREY}">'
f'range: nu se numără</text>'])
f'Același doji, după un range</text>'])
y_cap2 = bot._y(DOJI[2]) + 50
ext_bot += [f'<text x="24" y="{y_cap2:.1f}" fill="{ORANGE}" style="font-weight:bold">'
f'ACCEPTAT, semnal mai slab</text>',