"""Buy Doji — unde pui stopul: 4 candele înapoi, sub structură (exemplu construit). Citește specificația `gen/strategii/buy_doji_stop.spec.txt`. Două panouri stivuite, aceeași serie 0-14 ca buy_doji_transe (downtrend, doji 12, +1 13, confirmare 14). Sus: numărătoarea celor 4 candele (1 = confirmarea). Jos: același trade, stop „la ochi" 52.90 față de stopul din regulă 51.55. """ import re import sys; sys.path.insert(0, "/workspace/atm-curs-dl") from svg_candles import Candle, Chart, Level, Mark OUT = "/workspace/atm-curs-dl/gen/strategii/buy_doji_stop.svg" # --- seria: barele 0-14 exact ca în buy_doji_transe.spec.txt ----------------- closes = [60.40, 59.60, 59.90, 58.80, 58.10, 58.40, 57.20, 56.30, 56.60, 55.30, 54.20, 52.40] bars, o = [], 61.00 for c in closes: # fitile implicite 0.15 peste/sub corp bars.append((o, max(o, c) + 0.15, min(o, c) - 0.15, c)) o = c bars += [(52.40, 53.00, 51.60, 52.30), # 12 doji (52.30, 52.85, 52.10, 52.60), # 13 +1 (52.60, 53.85, 52.45, 53.70)] # 14 confirmare after = [(53.70, 53.75, 52.70, 52.90), # 15 lovește stopul la ochi (52.90, 53.05, 52.00, 52.20), # 16 al doilea picior, higher low (52.20, 53.40, 52.10, 53.30), (53.30, 54.30, 53.20, 54.20), (54.20, 55.10, 54.10, 55.00), (55.00, 56.00, 54.90, 55.95)] # 20 TP1 full = bars + after o_, h_, l_, c_ = (list(x) for x in zip(*full)) ENTRY, SL, OCHI, TP1, LOW4 = 53.70, 51.55, 52.90, 55.85, 51.60 # --- assert-urile din spec --------------------------------------------------- for i in range(1, len(full)): # 1 assert abs(o_[i] - c_[i - 1]) < 1e-9, f"open[{i}] != close[{i-1}]" for i in range(len(full)): assert l_[i] <= min(o_[i], c_[i]) and h_[i] >= max(o_[i], c_[i]), f"bara {i}" assert min(l_[11:15]) == min(l_[10:15]) == LOW4 # 2 assert l_.index(LOW4) == 12, "cel mai jos low nu e dojiul" assert round(LOW4 - 0.05, 2) == SL assert min(l_[15:21]) == 52.00 and SL < 52.00 < OCHI # 3 assert next(i for i in range(15, 21) if l_[i] <= OCHI) == 15 # 4 assert all(l_[i] > SL for i in range(15, 21)) assert next(i for i in range(15, 21) if h_[i] >= TP1) == 20 # 5 assert 52.00 > LOW4 # 6 assert round(ENTRY - OCHI, 2) == 0.80 and c_[14] == ENTRY assert round(ENTRY + (ENTRY - SL), 2) == TP1 GREY, RED, ORANGE, GREEN, BLUE = "#555", "#c00", "#b06000", "#188a3e", "#1a5fb4" W = 640 common: dict = dict(scale=34.0, gap=18, body_w=10, left=44, width=W) def mk(n): return [Candle(*b) for b in full[:n]] # --- panoul de sus: numărătoarea --------------------------------------------- top = Chart( candles=mk(15), levels=[Level(LOW4, "cel mai jos low: 51.60 (doji)", GREY, "2 2", "left"), Level(SL, "SL 51.55", RED, "4 3")], # fără Mark pe doji: la gap 18 eticheta calcă pe bara 11; îl numește # paranteza de dedesubt și cercul de pe low marks=[Mark(14, "confirmare 53.70", GREEN, "above")], title="Unde pui stopul: 4 candele înapoi, sub structură — exemplu construit", **common, ) svg_top = top.render() # numerele 4 3 2 1 + (5) sub bare, bandă de evidențiere, paranteză yb = top._y(SL) + 18 # rândul cu numere, sub linia de SL x = top._cx extra_top = [ f'', f'', ] for i, n in zip(range(11, 15), "4321"): extra_top.append(f'{n}') extra_top.append(f'(5)') yp = yb + 8 extra_top.append(f'') extra_top.append(f'' f'ultimele 4 candele (3 = doji, 1 = confirmarea)') extra_top.append(f'' f'Cu 4 sau cu 5 candele iese la fel: în downtrend low-ul dojiului ' f'e oricum cel mai jos. SL = 51.60 − 0.05.') h_top = yp + 40 # --- panoul de jos: același trade, două stopuri ------------------------------- bot = Chart( candles=mk(21), levels=[Level(TP1, "TP1 55.85", GREEN, "2 2"), Level(ENTRY, "intrare 53.70", GREY, "4 3"), Level(OCHI, "stop la ochi 52.90 — lovit", ORANGE, "4 3"), Level(SL, "SL din regulă 51.55 — ținut", RED, "4 3")], marks=[Mark(16, "al doilea picior: 52.00, higher low", BLUE, "below", dy=10), Mark(20, "TP1", GREEN, "above")], title="Același trade: stop la ochi (0.80 sub intrare) vs stop din regulă", caption="Barele 15-20 și stopul la ochi sunt construite, pentru contrast.", top=h_top + 10 + 34, # panoul de jos începe sub cel de sus, fără **common, ) svg_bot = bot.render() extra_bot = [ f'', ] # header-ul (viewBox) e al panoului de jos: el conține și offset-ul celui de sus svg = "\n ".join([ svg_bot.split(">", 1)[0] + ">", svg_top.split(">", 1)[1].rsplit("", 1)[0].strip(), *extra_top, f'', svg_bot.split(">", 1)[1].rsplit("", 1)[0].strip(), *extra_bot, ]) + "\n" H = float(re.search(r'viewBox="0 0 \d+ ([\d.]+)"', svg).group(1)) assert "