#!/usr/bin/env python3 """Buy Doji — locația: doji la nivel vs. doji în aer (exemplu construit). Citește `gen/strategii/buy_doji_locatie.spec.txt`. Două panouri alăturate cu ACEEAȘI serie de 10 bare, pe aceeași scară și aceeași axă de preț (candelele stau la aceleași y). Stânga: pivot monthly S1 49.00, la 0,41 % sub low-ul dojiului. Dreapta: S1 46.00 și PP 53.50 — cel mai apropiat nivel sub doji e la 6,96 %. Nivelurile se desenează de mână, cu coordonate absolute (liniile din Chart pornesc mereu de la x=24, ar trece peste panoul vecin). Rulare: python3 gen/strategii/buy_doji_locatie.py """ import re import sys sys.path.insert(0, "/workspace/atm-curs-dl") from svg_candles import Chart, Mark, from_closes # noqa: E402 OUT = "/workspace/atm-curs-dl/gen/strategii/buy_doji_locatie.svg" CLOSES = [52.20, 51.40, 50.60, 49.65, 49.60, 49.90, 50.40, 50.80, 51.10, 51.50] wicks = [(0.15, 0.15)] * len(CLOSES) wicks[4] = (0.45, 0.40) # doji: h 50.10 / l 49.20 cds = from_closes(CLOSES, wicks=wicks, start=53.00) doji = cds[4] S1_DA, S1_NU, PP_NU = 49.00, 46.00, 53.50 NIVELURI_NU = [S1_NU, PP_NU] # --- assert-urile din spec --------------------------------------------------- for i in range(1, len(cds)): # 1 assert cds[i].o == cds[i - 1].c, f"open[{i}] != close[{i-1}]" assert abs(doji.h - 50.10) < 1e-9 and abs(doji.l - 49.20) < 1e-9 assert abs(doji.o - doji.c) <= 0.10 * (doji.h - doji.l), "bara 4 nu e doji" assert cds[6].c > doji.h, "bara 6 nu confirmă" d_da = round((doji.l - S1_DA) / S1_DA * 100, 2) # 2 assert d_da == 0.41 and d_da <= 2 d_nu = round((doji.l - S1_NU) / S1_NU * 100, 2) # 3 assert d_nu == 6.96 and d_nu > 2 and (PP_NU - doji.h) > 0 assert not any(S1_NU < p < PP_NU for p in NIVELURI_NU) d_pp = round((PP_NU - doji.l) / doji.l * 100, 2) # PP e deasupra, mai departe assert d_pp == 8.74 and d_pp > d_nu # --- layout: două panouri, aceeași axă -------------------------------------- BLUE, GREEN, RED, ORANGE, GREY = "#1a5fb4", "#188a3e", "#c00", "#b06000", "#555" W, PW = 760, 350 # lățime totală, lățime panou PX = [24, 24 + PW + 28] # x-ul stâng al fiecărui panou SCALE, TOP = 36.0, 96 # px/unitate și y-ul celui mai mare preț charts = [] for px in PX: ch = Chart(candles=cds, marks=[Mark(4, "doji", ORANGE, "above", dy=-16), Mark(6, "confirmare", GREEN, "above", dy=-26)], scale=SCALE, gap=17, body_w=10, left=px + 34, width=px + PW, top=TOP) body = ch.render() charts.append((ch, body.split(">", 1)[1].rsplit("", 1)[0].strip())) (ch_da, body_da), (ch_nu, body_nu) = charts assert ch_da.scale == ch_nu.scale and ch_da._pmax == ch_nu._pmax, "scări diferite" # 4 y = ch_da._y # axa e comună: același y pe ambele panouri def level(px, price, text, color): yy = y(price) return [f'', f'{text}'] def arrow(x, y1, y2, color): # săgeată dublă verticală între y1 și y2 return [f'', f'', f''] xd_da, xd_nu = ch_da._cx(4), ch_nu._cx(4) y_low, y_bot = y(doji.l), y(S1_NU) ly = y(S1_DA) + 24 # textul de distanță, sub linia 49.00 parts = [ f'', f'' f'Doji la nivel vs. doji în aer — daily, pivoți monthly (exemplu construit)', f'DA — doji la nivel', f'NU — doji în aer', f'', *level(PX[0], S1_DA, "pivot monthly S1 49.00", BLUE), *level(PX[1], PP_NU, "PP 53.50", BLUE), *level(PX[1], S1_NU, "S1 46.00", BLUE), body_da, body_nu, # DA: low-ul dojiului atinge practic linia f'', f'low 49.20 = +0,41 % față de 49.00', f'' f'→ la nivel (daily: ≤ 1-2 %)', # NU: distanța până la cel mai apropiat nivel *arrow(xd_nu, y_low + 3, y_bot - 2, RED), f'' f'cel mai apropiat nivel: 46.00, la 6,96 %', f'→ doji în aer', f'' f'(PP 53.50 e deasupra, la 8,74 % de low)', f'60 min: prag ≤ 0,5 %, pivoți weekly · ' f'daily: 1-2 %, pivoți monthly · weekly: pivoți quarterly', f'Aceeași serie, aceeași scară; ' f'nivelurile 49.00 / 46.00 / 53.50 sunt construite.', "", ] svg = "\n ".join(parts).replace("\n ", "\n") assert "\n\n" not in svg, "linie goală în SVG" # nimic din panoul stâng nu trece de separator (etichete ancorate pe candele) for m in re.finditer(r']*>(.*?)', body_da): assert float(m.group(1)) < PX[1] - 14, f"text din DA trece în NU: {m.group(2)}" with open(OUT, "w") as f: f.write(svg) print(f"scris {OUT} ({W}x{y_bot + 62:.0f}); DA +{d_da}% NU {d_nu}% (PP {d_pp}%)")