"""Buy Doji — diagrama de ansamblu (daily, exemplu construit, fără ticker). Citește specificația `gen/strategii/buy_doji_ansamblu.spec.txt`. Seria de 32 de candele e construită din lista de close-uri dată, cu open-ul fiecărei bare = close-ul precedentului; wick-urile sunt fixate ca nivelurile (doji 50.10/49.20, intrare 50.40, SL 49.20, TP1 51.60, trail 52.60, ieșire sub trail la bara 28) să iasă exact din serie, nu doar din etichetă. """ import sys; sys.path.insert(0, "/workspace/atm-curs-dl") from svg_candles import Chart, Level, Mark, MA, from_closes # --- seria: 32 de close-uri, exact ca în specificație ----------------------- closes = [ 60.20, 59.20, 59.60, 58.40, 57.30, 57.70, 56.50, 55.40, 55.80, 54.70, # 0-9 53.50, 52.30, 51.00, 49.65, # 10-13 downtrend 49.60, # 14 doji 49.90, # 15 +1 (nu confirmă) 50.40, # 16 +2 confirmare => intrare 50.90, 51.20, 51.50, 51.80, 52.10, 52.40, 52.20, 52.70, 52.95, 53.20, # 17-26 52.80, 52.30, 52.00, 51.80, 51.90, # 27-31 ] assert len(closes) == 32 # wick-uri: (up, down) implicite (0.25, 0.30) + excepțiile din specificație wicks = [(0.25, 0.30)] * 32 wicks[14] = (0.45, 0.40) # doji: high 50.10, low 49.20 wicks[15] = (0.15, 0.15) # high 50.05, low 49.45 wicks[16] = (0.15, 0.15) # high 50.55, low 49.75 for k in range(24, 28): # barele 24-27 wicks[k] = (0.25, 0.20) # volum relativ ales de generator (materialul nu dă volum pe exemplu); # peste medie pe doji (14) și pe confirmare (16), apoi normal vols = [42, 44, 40, 46, 43, 41, 45, 42, 44, 47, 43, 45, 48, 52, 78, 46, 88, 55, 50, 48, 52, 47, 45, 49, 46, 44, 48, 51, 54, 47, 45, 46] assert len(vols) == 32 media_vol = sum(vols) / len(vols) assert vols[14] > media_vol and vols[16] > media_vol, "volum peste medie pe doji/confirmare" cds = from_closes(closes, wicks=wicks, vols=vols, start=60.20) # adnotările pe bara +1 și pe confirmare, ca linii sub grafic (fără suprapunere) cds[15].color = "#777" # bara de așteptare: neutră, nu confirmă cds[15].note = "bara 15: close 49.90 sub high-ul dojiului 50.10 — NU confirmă" cds[16].note = "bara 16: close 50.40 peste 50.10 — confirmare (intrare)" doji, wait, conf = cds[14], cds[15], cds[16] entry, sl, tp1, trail = 50.40, 49.20, 51.60, 52.60 # --- cele 9 assert-uri cerute de specificație ------------------------------ # 1. SL-ul e exact low-ul dojiului, cel mai jos din fereastra de 4 candele assert abs(min(cd.l for cd in cds[13:17]) - 49.20) < 1e-9, "min low[13:17] != 49.20" # 2. intrarea e close-ul barei 16 assert abs(conf.c - entry) < 1e-9, f"close[16]={conf.c} != 50.40" # 3. confirmarea închide peste high-ul dojiului assert abs(doji.h - 50.10) < 1e-9 and conf.c > doji.h, "close[16] nu e peste high[14]" # 4. bara +1 NU confirmă assert wait.c <= doji.h, "bara 15 ar confirma, fereastra n-ar avea sens" # 5. 1:1 exact assert abs(abs(entry - sl) - abs(tp1 - entry)) < 1e-9 and abs((entry - sl) - 1.20) < 1e-9, \ "risc != recompensă (nu e 1:1 exact)" # 6. primul high >= TP1 după intrare e bara 19 primul_tp = next(i for i in range(17, len(cds)) if cds[i].h >= tp1) assert primul_tp == 19, f"TP1 51.60 atins întâi la bara {primul_tp}, nu 19" # 7. trailing 52.60 = low[27]; ieșire la bara 28 sub el; ieșirea e pe profit assert abs(cds[27].l - trail) < 1e-9, f"low[27]={cds[27].l} != 52.60" assert abs(cds[28].c - 52.30) < 1e-9 and cds[28].c < trail, "close[28] nu e sub trail" assert trail > entry, "trail sub intrare, ieșirea n-ar fi pe profit" # 8. doji: corp <= 10% din amplitudine assert abs(doji.o - doji.c) <= 0.10 * (doji.h - doji.l), "bara 14 nu e doji" # 9. downtrend vizibil assert cds[13].c < cds[0].c - 10, "downtrend prea mic" print(f"doji {doji.h:.2f}/{doji.l:.2f} intrare {conf.c:.2f} " f"SL {sl:.2f} TP1 {tp1:.2f} trail {trail:.2f} ieșire bara 28 @ {cds[28].c:.2f}") # --- desenul ---------------------------------------------------------------- ch = Chart( candles=cds, levels=[ Level(sl, "SL 49.20 (low 4 candele)", "#c00", label_at="left"), Level(entry, "intrare 50.40", "#188a3e", label_at="left"), Level(tp1, "TP1 51.60 = 1R", "#1a5fb4", label_at="left"), Level(trail, "trail 52.60", "#b06000"), ], marks=[ Mark(14, "doji 50.10 / 49.20", "#b06000", "below"), Mark(28, "ieșire pe trail ~52.60", "#c00", "above", dy=-6), ], mas=[MA(20, "#777", dash="4 3", text="MA(20)")], scale=24.0, gap=15, body_w=9, left=44, width=640, vol_h=70, vol_label="volum", title="Buy Doji — daily (exemplu construit, fără ticker)", caption="Intrare la close-ul confirmării, SL la low-ul ultimelor 4 candele, " "TP1 1:1, apoi trailing stop.", ) svg = ch.render() assert "