"""Sell Doji — oglinda short a ansamblului Buy Doji (daily, exemplu construit). Citește specificația `gen/strategii/buy_doji_sell.spec.txt`. Seria de 31 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 99.20 / 100.10, intrare short 99.00, SL 100.10, TP 97.90, trail 96.45, ieșire la 96.60) 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, from_closes # --- seria: 31 de close-uri, exact ca în specificație ----------------------- closes = [ 93.00, 94.10, 93.70, 95.00, 96.10, 95.80, 97.00, 98.10, 97.80, 98.90, # 0-9 99.80, 100.20, 99.90, 99.65, # 10-13 uptrend 99.60, # 14 doji 99.40, # 15 +1 (nu confirmă) 99.00, # 16 +2 confirmare => intrare short 98.50, 98.30, 97.80, 97.40, 97.00, 96.70, 96.40, 96.10, 95.80, # 17-25 96.20, 96.60, 96.40, 96.10, 96.30, # 26-30 ] assert len(closes) == 31 # wick-uri: (up, down) implicite (0.30, 0.25) + excepțiile din specificație wicks = [(0.30, 0.25)] * 31 # ajustat: cu wu=0.30, high[13] = 99.90+0.30 = 100.20 > SL; îl coborâm la # 100.10 ca max(high[13:17]) == 100.10 (high-ul ultimelor 4 candele = SL) wicks[13] = (0.20, 0.25) wicks[14] = (0.45, 0.40) # doji: high 100.10, low 99.20 wicks[15] = (0.20, 0.15) # high 99.80, low 99.25 (peste 99.20 => nu confirmă) wicks[16] = (0.20, 0.15) # high 99.60, low 98.85 wicks[25] = (0.35, 0.20) # high 96.45 (= trail), low 95.60 (minimul corecției) # ajustat: cu wd=0.25, low[26] = 95.80-0.25 = 95.55 < 95.60, adică bara 26 ar # fi minimul, nu bara 25; wd=0.10 păstrează bara 25 ca minim (low 95.60) wicks[26] = (0.30, 0.10) # volum relativ ales de generator (materialul nu dă volum pe exemplu); # peste medie pe doji (14) și pe confirmare (16) — distribuție — apoi normal vols = [44, 42, 46, 40, 45, 48, 43, 47, 50, 45, 52, 58, 49, 55, 90, 62, 84, 56, 52, 50, 48, 46, 44, 42, 40, 45, 50, 46, 44, 43, 45] assert len(vols) == 31 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=closes[0]) # 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 99.40 peste low-ul dojiului 99.20 — NU confirmă" cds[16].note = "bara 16: close 99.00 sub 99.20 — confirmare (intrare short)" doji, wait, conf = cds[14], cds[15], cds[16] entry, sl, tp = 99.00, 100.10, 97.90 # --- cele 9 assert-uri cerute de specificație ------------------------------ # 1. SL-ul e exact high-ul ultimelor 4 candele assert abs(max(cd.h for cd in cds[13:17]) - 100.10) < 1e-9, "max high[13:17] != 100.10" # 2. intrarea e close-ul barei 16 assert abs(conf.c - entry) < 1e-9, f"close[16]={conf.c} != 99.00" # 3. confirmarea închide sub low-ul dojiului assert abs(doji.l - 99.20) < 1e-9 and conf.c < doji.l, "close[16] nu e sub low[14]" # 4. bara +1 NU confirmă assert wait.c >= doji.l, "bara 15 ar confirma, fereastra n-ar avea sens" # 5. 1:1 exact assert abs(abs(sl - entry) - abs(entry - tp)) < 1e-9 and abs((entry - tp) - 1.10) < 1e-9, \ "risc != recompensă (nu e 1:1 exact)" # 6. primul low <= TP după intrare e bara 19 primul_tp = next(i for i in range(17, len(cds)) if cds[i].l <= tp) assert primul_tp == 19, f"TP 97.90 atins întâi la bara {primul_tp}, nu 19" assert abs(cds[18].l - 98.05) < 1e-9 and abs(cds[19].l - 97.55) < 1e-9, "low-urile 18/19 nu ies" # 7. trailing = high[25] = 96.45; primul close peste el e bara 27; ieșirea e pe profit trail = cds[25].h assert abs(trail - 96.45) < 1e-9, f"high[25]={trail} != 96.45" primul_exit = next(i for i in range(26, len(cds)) if cds[i].c > trail) assert primul_exit == 27 and abs(cds[27].c - 96.60) < 1e-9, "ieșirea nu e bara 27 @ 96.60" assert cds[27].c < entry, "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. uptrend vizibil assert cds[13].c > cds[0].c + 5, "uptrend prea mic" print(f"doji {doji.l:.2f}/{doji.h:.2f} intrare short {conf.c:.2f} " f"SL {sl:.2f} TP {tp:.2f} trail {trail:.2f} ieșire bara 27 @ {cds[27].c:.2f}") # --- desenul ---------------------------------------------------------------- ch = Chart( candles=cds, levels=[ # toate etichetele în dreapta: în stânga sus se suprapuneau cu mark-ul # dojiului (SL la y=62, text până în ~x196; doji la y=58, din ~x193) Level(sl, "SL 100.10 (high 4 candele)", "#c00"), Level(entry, "intrare short 99.00", "#188a3e"), Level(tp, "TP 97.90 = 1R", "#1a5fb4"), Level(trail, "trail 96.45", "#b06000"), ], marks=[ Mark(14, "doji 99.20 / 100.10", "#b06000", "above"), Mark(27, "ieșire pe trail 96.60", "#c00", "above", dy=-6), ], scale=30.0, gap=15, body_w=9, left=44, width=640, vol_h=70, vol_label="volum", title="Sell Doji — daily (exemplu construit, fără ticker)", # scurt: o linie de caption mai lungă de ~90 de caractere iese din viewBox # (640px) și se taie la randare caption="Intrare short la close sub low-ul dojiului, SL la high 4 candele, " "TP 1:1, apoi trail.", ) svg = ch.render() assert "