diff --git a/gen/strategii/mp2_aplus.py b/gen/strategii/mp2_aplus.py index e1fa0c1..9222ec9 100644 --- a/gen/strategii/mp2_aplus.py +++ b/gen/strategii/mp2_aplus.py @@ -132,7 +132,7 @@ PW = 560 ch_a = Chart( candles=cds_a, levels=[Level(SUP_A, f"suport quarterly {SUP_A:.2f}", GRAY, label_at="left"), - Level(SL_A, f"SL {SL_A:.2f}", RED, label_at="right"), + Level(SL_A, f"SL {SL_A:.2f} (peste suport)", RED, label_at="right"), Level(entry_a, f"intrare {entry_a:.2f}", GREEN, label_at="left"), Level(NECK_A, f"neckline {NECK_A:.2f}", ORANGE, label_at="right"), Level(TP1_A, f"TP1 {TP1_A:.2f} = 1:1", BLUE, label_at="right")], @@ -143,7 +143,7 @@ ch_a = Chart( scale=7.5, gap=15, body_w=9, left=44, width=PW, vol_h=64, vol_label="volum", title="A+ — crossing la confluență (SPY, aprilie)", trend="down", - caption="Confluență: suport 554.00 + double bottom 554.45 + neckline 578.00", + caption="Confluență: 554.00 + double bottom + neckline 578.00 · 1R 22.60", ) ch_m = Chart( candles=cds_m, @@ -258,7 +258,8 @@ for i in range(len(all_txt)): raise AssertionError(f"texte suprapuse: {si!r} / {sj!r}") # etichetele cerute de spec există în desen -for cheie in ("suport quarterly 554.00", f"SL {SL_A:.2f}", "intrare 577.00", +for cheie in ("suport quarterly 554.00", f"SL {SL_A:.2f} (peste suport)", "intrare 577.00", + "crossing", "1R 22.60", "neckline 578.00", "TP1 599.60 = 1:1", f"umăr stâng {ls_a:.0f}", f"head {head_a:.0f}", f"umăr drept {rs_a:.0f}", "A+ — crossing la confluență (SPY, aprilie)", diff --git a/gen/strategii/mp2_aplus.svg b/gen/strategii/mp2_aplus.svg index 96fb625..6693d32 100644 --- a/gen/strategii/mp2_aplus.svg +++ b/gen/strategii/mp2_aplus.svg @@ -3,7 +3,7 @@ suport quarterly 554.00 - SL 554.40 + SL 554.40 (peste suport) intrare 577.00 @@ -117,7 +117,7 @@ head 555 / double bottom umăr drept 568 crossing - Confluență: suport 554.00 + double bottom 554.45 + neckline 578.00 + Confluență: 554.00 + double bottom + neckline 578.00 · 1R 22.60 Mediocru — crossing în mijlocul range-ului (construit) diff --git a/gen/strategii/mp2_crossing.py b/gen/strategii/mp2_crossing.py index 2de8413..9b83c06 100644 --- a/gen/strategii/mp2_crossing.py +++ b/gen/strategii/mp2_crossing.py @@ -117,7 +117,7 @@ def render_pivot_panel(cds, pivots, title) -> tuple[str, float, Chart]: """Randază un panou cu pivot weekly (Level) + pivot daily (polilinie injectată).""" ch = Chart(candles=cds, levels=[Level(WEEKLY, f"pivot weekly (cel MARE) {WEEKLY:.2f}", - BLUE, dash="", label_at="left")], + BLUE, dash="", label_at="right")], marks=[], scale=SCALE, gap=15, body_w=9, left=44, width=W, title=title) @@ -145,26 +145,30 @@ circle = (f'') cross_txt = (f'crossing: 61.70 → 62.20') -mark_txt = (f'' - f'intrare: trigger (prima candelă verde)') +mark_txt = (f'' + f'intrare: trigger') i = body_da.rindex("") + len("") # după candele/marks, ca să fie vizibile body_da = body_da[:i] + "\n " + circle + "\n " + cross_txt + "\n " + mark_txt + body_da[i:] # panoul NU: eticheta din spec pe semnalele ulterioare body_nu, h_nu, ch_nu = render_pivot_panel( cds_nu, PNU, "NU — continuare/buy the dip (+1)") -body_nu = body_nu.rstrip() + (f'\n ' - f'semnale ulterioare = BUY THE DIP, nu crossing') +body_nu = body_nu.rstrip() + ( + f'\n ' + f'fără crossing nou; nu a mai căzut sub pivotul mare' + f'\n ' + f'semnale ulterioare = BUY THE DIP, nu crossing') # ------------------------------------------------- lipirea celor două panouri CAPS = [ "Pivot weekly 62.00 = linia orizontală (pivotul MARE).", "Pivot daily (cel MIC) se recalculează zilnic și sare pe nivel nou.", - "Crossing = pivotul mic traversează 62.00 în sus.", - "Fără re-încrucișare, semnalele ulterioare sunt buy the dip,", - "nu crossing.", + "Trigger = prima candelă verde după crossing,", + "care închide peste pivotul daily.", + "Crossing = pivotul mic traversează 62.00 în sus; fără re-încrucișare,", + "semnalele ulterioare sunt buy the dip, nu crossing.", ] cap_top = h_da + VGAP + h_nu + 16 H = cap_top + 17 * len(CAPS) + 10 diff --git a/gen/strategii/mp2_crossing.svg b/gen/strategii/mp2_crossing.svg index ac2ed98..8ccd8cd 100644 --- a/gen/strategii/mp2_crossing.svg +++ b/gen/strategii/mp2_crossing.svg @@ -1,13 +1,13 @@ - + pivot daily (cel MIC) DA — crossing (+2) - pivot weekly (cel MARE) 62.00 + pivot weekly (cel MARE) 62.00 crossing: 61.70 → 62.20 - intrare: trigger (prima candelă verde) + intrare: trigger @@ -58,7 +58,7 @@ pivot daily (cel MIC) NU — continuare/buy the dip (+1) - pivot weekly (cel MARE) 62.00 + pivot weekly (cel MARE) 62.00 @@ -103,10 +103,12 @@ + fără crossing nou; nu a mai căzut sub pivotul mare semnale ulterioare = BUY THE DIP, nu crossing Pivot weekly 62.00 = linia orizontală (pivotul MARE). Pivot daily (cel MIC) se recalculează zilnic și sare pe nivel nou. - Crossing = pivotul mic traversează 62.00 în sus. - Fără re-încrucișare, semnalele ulterioare sunt buy the dip, - nu crossing. + Trigger = prima candelă verde după crossing, + care închide peste pivotul daily. + Crossing = pivotul mic traversează 62.00 în sus; fără re-încrucișare, + semnalele ulterioare sunt buy the dip, nu crossing. \ No newline at end of file diff --git a/gen/strategii/mp2_pivoti_excel.py b/gen/strategii/mp2_pivoti_excel.py new file mode 100644 index 0000000..d93c5c9 --- /dev/null +++ b/gen/strategii/mp2_pivoti_excel.py @@ -0,0 +1,315 @@ +#!/usr/bin/env python3 +"""Foaie de Excel stilizată: pivoții clasici calculați din OHLC, pas cu pas, +și comparația PP zilnic vs. PP săptămânal (crossing). + +Pentru `strategii/02_mp2.md`, Transfer — Pe BVB, subsecțiunea „Pivoții în +Excel". Spec: `gen/strategii/mp2_pivoti_excel.spec.txt`. + +Nu e grafic de preț (TIP: CONCEPT) — SVG scris de mână, doar stdlib; nu se +folosește svg_candles / pchart. Nu sunt candele, e un tabel. + +Ce arată: +- titlul „Pivoții clasici în Excel — formula, pas cu pas"; +- un tabel cu coloanele Perioada | High | Low | Close | PP | R1 | S1 | R2 | S2, + cu literele de coloană (A..I) și numerele de rând Excel (1..3), ca formulele + =(B2+C2+D2)/3 etc. să aibă sens; +- două rânduri de date: „Săptămâna încheiată (PPW)" și „Ziua încheiată (PPD)", + fiecare celulă de calcul arătând formula ȘI rezultatul; +- sub tabel, rândul de comparație evidențiat: + „PPD 21.57 > PPW 21.37 → CROSSING BULL (long)"; +- legenda că cifrele sunt un exemplu construit, pe TLV, nu date reale. + +Valorile și formulele vin din spec (CIFRE ȘI FORMULE); toate assert-urile +cerute de spec sunt scrise ca assert reale mai jos. + +Rulare: python3 gen/strategii/mp2_pivoti_excel.py -> mp2_pivoti_excel.svg +""" +from pathlib import Path +from xml.sax.saxutils import escape, unescape + +OUT = Path(__file__).with_suffix(".svg") + +W, H = 700, 444 +BLACK, GRAY, BLUE, GREEN, RED, ORANGE, WHITE = ( + "#000000", "#777777", "#1a5fb4", "#188a3e", "#c00", "#b06000", "#ffffff") +BORDER = "#333333" +GRID = "#c9d2dc" +HDR_BG = "#eef1f5" +ALT_BG = "#fafbfc" + +# ---------------------------------------------------------------- date (spec) +# Săptămâna încheiată: H=22.00, L=20.50, C=21.60 (row 2) +# Ziua încheiată: H=21.90, L=21.00, C=21.80 (row 3) +WH = (22.00, 20.50, 21.60) +DH = (21.90, 21.00, 21.80) + +PPW = (WH[0] + WH[1] + WH[2]) / 3 +PPD = (DH[0] + DH[1] + DH[2]) / 3 +# derivate standard: R1=2*PP-Low, S1=2*PP-High, R2=PP+(High-Low), S2=PP-(High-Low) +W_R1, W_S1 = 2 * PPW - WH[1], 2 * PPW - WH[0] +W_R2, W_S2 = PPW + (WH[0] - WH[1]), PPW - (WH[0] - WH[1]) +D_R1, D_S1 = 2 * PPD - DH[1], 2 * PPD - DH[0] +D_R2, D_S2 = PPD + (DH[0] - DH[1]), PPD - (DH[0] - DH[1]) + +# ---------------------------------------------------------------- asserturi spec +assert abs((22.00 + 20.50 + 21.60) / 3 - 21.3667) < 0.001, "PPW din formulă" +assert abs((21.90 + 21.00 + 21.80) / 3 - 21.5667) < 0.001, "PPD din formulă" +assert abs(PPW - 21.3667) < 0.001 and abs(PPD - 21.5667) < 0.001 +assert PPD > PPW, "PPD trebuie deasupra PPW pentru crossing bull" +# R1/S1/R2/S2 ies din formulă, nu din cap (daily: 2*21.5667-21.00=22.1333 etc.) +assert abs(D_R1 - (2 * 21.5667 - 21.00)) < 0.001, "daily R1" +assert abs(D_S1 - (2 * 21.5667 - 21.90)) < 0.001, "daily S1" +assert abs(D_R2 - (21.5667 + (21.90 - 21.00))) < 0.001, "daily R2" +assert abs(D_S2 - (21.5667 - (21.90 - 21.00))) < 0.001, "daily S2" +# ATENȚIE: spec, linia 29, listează daily R2 = 22.5667. Formula dată chiar de +# spec (R2 = PP + (High-Low), linia 21) și datele ei (H=21.90, L=21.00) +# dau 22.4667: 21.5667 + 0.90. S2 din spec (20.6667) confirmă H-L = 0.90. +# Assert-ul din spec („R2 iese din formulă, nu din cap") decide: desenăm 22.47. +assert abs(D_R2 - 22.4667) < 0.001, "daily R2 trebuie derivat din formulă" +assert abs(W_R1 - (2 * 21.3667 - 20.50)) < 0.001, "weekly R1" +assert abs(W_S1 - (2 * 21.3667 - 22.00)) < 0.001, "weekly S1" +assert abs(W_R2 - (21.3667 + (22.00 - 20.50))) < 0.001, "weekly R2" +assert abs(W_S2 - (21.3667 - (22.00 - 20.50))) < 0.001, "weekly S2" + +# ---------------------------------------------------------------- geometrie +LEFT, RIGHT = 8.0, 692.0 +GUT_X, GUT_W = LEFT, 20.0 +COLS = [(28.0, 116.0), (116.0, 164.0), (164.0, 212.0), (212.0, 260.0), + (260.0, 372.0), (372.0, 440.0), (440.0, 508.0), + (508.0, 600.0), (600.0, 692.0)] +HEADERS = ["Perioada", "High", "Low", "Close", "PP", "R1", "S1", "R2", "S2"] +LETTERS = ["A", "B", "C", "D", "E", "F", "G", "H", "I"] + +TBL_Y0, HDR_Y1 = 72.0, 116.0 +ROW1_Y0, ROW1_Y1 = 116.0, 184.0 # săptămâna (rândul 2) +ROW2_Y0, ROW2_Y1 = 184.0, 252.0 # ziua (rândul 3) +CMP_Y0, CMP_Y1 = 268.0, 312.0 + +TEXTS = [] # (x, y, s, size, weight, anchor, cell) cell=(x0,x1) sau None + + +def txt(x, y, s, size=13, weight="400", fill=BLACK, anchor="middle", cell=None): + TEXTS.append((x, y, s, size, weight, anchor, cell)) + return (f'' + f'{escape(s)}') + + +def line(x1, y1, x2, y2, stroke=GRID, width=1.0, dash=None): + d = f' stroke-dasharray="{dash}"' if dash else "" + return (f'') + + +def rect(x, y, w, h, fill=WHITE, stroke=BORDER, width=1.2, rx=0): + r = f' rx="{rx}"' if rx else "" + return (f'') + + +def fmt(v): + return f"{v:.2f}" + + +def build(): + p = [ + f'', + '', + f'', + txt(W / 2, 38, "Pivoții clasici în Excel — formula, pas cu pas", + 20, "700", BLACK), + ] + + # ------- fundaluri: bandă de antet, rânduri alternate, gutter + p.append(rect(GUT_X, TBL_Y0, GUT_W, + ROW2_Y1 - TBL_Y0, fill=HDR_BG, stroke=BORDER, width=1.0)) + p.append(rect(COLS[0][0], TBL_Y0, RIGHT - COLS[0][0], HDR_Y1 - TBL_Y0, + fill=HDR_BG, stroke=BORDER, width=1.0)) + p.append(rect(COLS[0][0], ROW1_Y0, RIGHT - COLS[0][0], ROW1_Y1 - ROW1_Y0, + fill=WHITE, stroke=BORDER, width=1.0)) + p.append(rect(COLS[0][0], ROW2_Y0, RIGHT - COLS[0][0], ROW2_Y1 - ROW2_Y0, + fill=ALT_BG, stroke=BORDER, width=1.0)) + + # ------- grilă verticală + orizontală + for x0, _ in COLS[1:]: + p.append(line(x0, TBL_Y0, x0, ROW2_Y1)) + p.append(line(GUT_X + GUT_W, TBL_Y0, GUT_X + GUT_W, ROW2_Y1, BORDER, 1.0)) + for y in (HDR_Y1, ROW1_Y1): + p.append(line(GUT_X, y, RIGHT, y, BORDER, 1.0)) + p.append(rect(GUT_X, TBL_Y0, RIGHT - GUT_X, ROW2_Y1 - TBL_Y0, + fill="none", stroke=BORDER, width=1.4)) + + # ------- numere de rând Excel și litere de coloană + for num, (y0, y1) in zip("123", ((TBL_Y0, HDR_Y1), (ROW1_Y0, ROW1_Y1), + (ROW2_Y0, ROW2_Y1))): + p.append(txt(GUT_X + GUT_W / 2, (y0 + y1) / 2 + 5, num, 13, "400", + GRAY)) + for (x0, x1), let in zip(COLS, LETTERS): + p.append(txt((x0 + x1) / 2, 90, let, 13, "400", GRAY)) + for (x0, x1), h in zip(COLS, HEADERS): + p.append(txt((x0 + x1) / 2, 110, h, 13, "700", BLACK, + cell=(x0, x1))) + + # ------- rândul 2: săptămâna (PPW) — celulele de calcul = formulă + rezultat + cA = COLS[0] + for k, s in enumerate(("Săptămâna", "încheiată", "(PPW)")): + p.append(txt((cA[0] + cA[1]) / 2, 138 + k * 18, s, 13, "400", + BLACK if k < 2 else GRAY, cell=cA)) + for col, val in zip(COLS[1:4], WH): + p.append(txt((col[0] + col[1]) / 2, 158, fmt(val), 14, "400", BLACK, + cell=col)) + week_calc = [("=(B2+C2+D2)/3", PPW), ("=2*E2-C2", W_R1), ("=2*E2-B2", W_S1), + ("=E2+(B2-C2)", W_R2), ("=E2-(B2-C2)", W_S2)] + for col, (formula, res) in zip(COLS[4:], week_calc): + cx = (col[0] + col[1]) / 2 + p.append(txt(cx, ROW1_Y0 + 26, formula, 13, "400", GRAY, cell=col)) + p.append(txt(cx, ROW1_Y0 + 53, fmt(res), 15, "700", BLUE, cell=col)) + + # ------- rândul 3: ziua (PPD) + for k, s in enumerate(("Ziua", "încheiată", "(PPD)")): + p.append(txt((cA[0] + cA[1]) / 2, 200 + k * 18, s, 13, "400", + BLACK if k < 2 else GRAY, cell=cA)) + for col, val in zip(COLS[1:4], DH): + p.append(txt((col[0] + col[1]) / 2, 226, fmt(val), 14, "400", BLACK, + cell=col)) + day_calc = [("=(B3+C3+D3)/3", PPD), ("=2*E3-C3", D_R1), ("=2*E3-B3", D_S1), + ("=E3+(B3-C3)", D_R2), ("=E3-(B3-C3)", D_S2)] + for col, (formula, res) in zip(COLS[4:], day_calc): + cx = (col[0] + col[1]) / 2 + p.append(txt(cx, ROW2_Y0 + 26, formula, 13, "400", GRAY, cell=col)) + p.append(txt(cx, ROW2_Y0 + 53, fmt(res), 15, "700", BLUE, cell=col)) + + # ------- rândul de comparație, evidențiat + p.append(rect(LEFT, CMP_Y0, RIGHT - LEFT, CMP_Y1 - CMP_Y0, + fill="#eaf7ee", stroke=GREEN, width=1.6, rx=6)) + p.append(txt(W / 2, CMP_Y0 + 28, + f"PPD {fmt(PPD)} > PPW {fmt(PPW)} → CROSSING BULL (long)", + 16, "700", BLACK)) + + # ------- legenda (exemplu construit) + note + p.append(txt(W / 2, 340, + "Cifrele sunt un exemplu construit, cu valori rotunde, pe TLV —", + 13, "400", GRAY)) + p.append(txt(W / 2, 358, "nu sunt date reale de piață.", 13, "400", GRAY)) + p.append(txt(W / 2, 386, + "crossing = PPD trece deasupra PPW; dacă rămâne deasupra — " + "continuare (09_QA/16:35-43).", 13, "400", BLACK)) + p.append(txt(W / 2, 408, + "Surse formule: 03_MODUL_2/02_zone_cerere_oferta_support_" + "resistance.md:42-50", 13, "400", GRAY)) + p.append(txt(W / 2, 426, + "Calcul Excel 1-la-1, MP² = comparația a doi pivoți: " + "09_QA/09_2025-12-09.md:1176-1180.", 13, "400", GRAY)) + + p.append('') + return "\n".join(p) + "\n" + + +# ---------------------------------------------------------------- verificare +# Măsurăm textul cu fontul real folosit la rasterizare (DejaVu Sans), care e +# mai lat decât majoritatea fonturilor „system-ui": dacă încape aici, încape. +try: + from PIL import ImageFont + _REG = "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf" + _BOLD = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" + _FCACHE = {} + + def _pil_w(s, size, weight): + path = _BOLD if weight == "700" else _REG + f = _FCACHE.get((path, size)) + if f is None: + f = ImageFont.truetype(path, size) + _FCACHE[(path, size)] = f + return f.getlength(s) + + _HAVE_PIL = True +except Exception: # pragma: no cover + _HAVE_PIL = False + + +def est_w(s, size, weight): + if _HAVE_PIL: + return _pil_w(s, size, weight) + # fallback conservator: supraestimează cu ~12% + narrow = " .,:;'|()[]{}" + total = 0.0 + for ch in s: + if ch in narrow: + total += 0.30 + elif ch.isdigit(): + total += 0.60 + elif ch.isupper(): + total += 0.70 + elif ch.islower(): + total += 0.56 + else: + total += 0.56 + return total * size * (1.06 if weight == "700" else 1.0) * 1.12 + + +def spans(x, y, s, size, weight, anchor): + ew = est_w(s, size, weight) + left = x - ew if anchor == "end" else (x - ew / 2 if anchor == "middle" + else x) + return left, left + ew + + +def verify(svg): + # 1. toate textele în panză + for x, y, s, size, weight, anchor, cell in TEXTS: + lo, hi = spans(x, y, s, size, weight, anchor) + assert -2 <= lo and hi <= W + 2, f"text în afara panzei: {s!r} ({lo:.0f},{hi:.0f})" + assert 0 <= y <= H, f"text în afara înălțimii: {s!r} (y={y})" + + # 2. textele din tabel încap în celula lor + for x, y, s, size, weight, anchor, cell in TEXTS: + if cell is not None: + lo, hi = spans(x, y, s, size, weight, anchor) + assert cell[0] + 1 <= lo and hi <= cell[1] - 1, \ + f"text iese din celulă: {s!r} ({lo:.0f},{hi:.0f}) vs {cell}" + + # 3. texte care nu se suprapun + for i in range(len(TEXTS)): + xi, yi, si, szi, wi, ai, _ = TEXTS[i] + li, ri = spans(xi, yi, si, szi, wi, ai) + for j in range(i + 1, len(TEXTS)): + xj, yj, sj, szj, wj, aj, _ = TEXTS[j] + lj, rj = spans(xj, yj, sj, szj, wj, aj) + if abs(yi - yj) < 13 and li < rj - 3 and lj < ri - 3: + raise AssertionError(f"texte suprapuse: {si!r} / {sj!r}") + + # 4. condiția de crossing din desen + assert CMP_Y0 > ROW2_Y1, "rândul de comparație nu e sub tabel" + assert CMP_Y1 < 340, "comparația intră în legendă" + assert PPD > PPW + + # 5. conținutul obligatoriu din spec (textul vizibil, cu > decodat) + plain = unescape(svg) + for cheie in ( + "Pivoții clasici în Excel — formula, pas cu pas", + "Perioada", "High", "Low", "Close", "PP", "R1", "S1", "R2", "S2", + "Săptămâna", "încheiată", "(PPW)", + "Ziua", "(PPD)", + "=(B2+C2+D2)/3", "=2*E2-C2", "=2*E2-B2", "=E2+(B2-C2)", "=E2-(B2-C2)", + "=(B3+C3+D3)/3", "=2*E3-C3", "=2*E3-B3", "=E3+(B3-C3)", "=E3-(B3-C3)", + "21.37", "21.57", "22.23", "20.73", "22.87", "19.87", + "22.13", "21.23", "22.47", "20.67", + "PPD 21.57 > PPW 21.37", "CROSSING BULL (long)", + "exemplu construit", "nu sunt date reale de piață", + "09_QA/16:35-43", "09_QA/09_2025-12-09.md:1176-1180", + ): + assert cheie in plain, f"lipsește din desen: {cheie!r}" + + # 6. fără candele / axe de preț / prețuri inventate + for interzis in ("candela", "SL ", "TP1", "TP2", "intrare ", "$", "USD"): + assert interzis not in svg, f"nu ar trebui să apară: {interzis!r}" + return True + + +SVG = build() +assert verify(SVG), "verificare eșuată" +OUT.write_text(SVG, encoding="utf-8") +print(f"scris {OUT} ({W}x{H}), verificare OK: {len(TEXTS)} etichete") diff --git a/gen/strategii/mp2_pivoti_excel.svg b/gen/strategii/mp2_pivoti_excel.svg new file mode 100644 index 0000000..7cf2e72 --- /dev/null +++ b/gen/strategii/mp2_pivoti_excel.svg @@ -0,0 +1,81 @@ + + + +Pivoții clasici în Excel — formula, pas cu pas + + + + + + + + + + + + + + + + +1 +2 +3 +A +B +C +D +E +F +G +H +I +Perioada +High +Low +Close +PP +R1 +S1 +R2 +S2 +Săptămâna +încheiată +(PPW) +22.00 +20.50 +21.60 +=(B2+C2+D2)/3 +21.37 +=2*E2-C2 +22.23 +=2*E2-B2 +20.73 +=E2+(B2-C2) +22.87 +=E2-(B2-C2) +19.87 +Ziua +încheiată +(PPD) +21.90 +21.00 +21.80 +=(B3+C3+D3)/3 +21.57 +=2*E3-C3 +22.13 +=2*E3-B3 +21.23 +=E3+(B3-C3) +22.47 +=E3-(B3-C3) +20.67 + +PPD 21.57 > PPW 21.37 → CROSSING BULL (long) +Cifrele sunt un exemplu construit, cu valori rotunde, pe TLV — +nu sunt date reale de piață. +crossing = PPD trece deasupra PPW; dacă rămâne deasupra — continuare (09_QA/16:35-43). +Surse formule: 03_MODUL_2/02_zone_cerere_oferta_support_resistance.md:42-50 +Calcul Excel 1-la-1, MP² = comparația a doi pivoți: 09_QA/09_2025-12-09.md:1176-1180. + diff --git a/gen/strategii/selectia_ansamblu.py b/gen/strategii/selectia_ansamblu.py new file mode 100644 index 0000000..3feb9ce --- /dev/null +++ b/gen/strategii/selectia_ansamblu.py @@ -0,0 +1,162 @@ +"""ULTA — daily (pivoți monthly): diagrama de ansamblu a selecției (TIP: PRET). + +Citește `gen/strategii/selectia_ansamblu.spec.txt`. Un simbol care vine dintr-un +downtrend weekly, atinge suportul monthly 355.48 și face un buy doji la 373.30 +cu RVOL 0.61; apoi confirmarea (intrare 374.80) și drumul spre pivot/TP1 383.74, +respectiv TP2 402.00. Grafic daily, 32 de candele, serie continuă, cu panou de +volum și SMA-20 — construit prin `svg_candles` (from_closes), la scară. + +Rulează: + python3 gen/strategii/selectia_ansamblu.py +Scrie lângă el `selectia_ansamblu.svg`. +""" +import re +import sys +from pathlib import Path + +sys.path.insert(0, "/workspace/atm-curs-dl") +from svg_candles import Chart, Level, Mark, MA, from_closes # noqa: E402 + +OUT = Path(__file__).resolve().parent / "selectia_ansamblu.svg" + +GRAY, RED, GREEN, BLUE, ORANGE, TEAL = "#777", "#c00", "#188a3e", "#1a5fb4", "#b06000", "#00a0aa" + +# ---------------------------------------------------------------- seria (32 bare) +# bare 0-11 : downtrend vizibil de la ~395 la ~362 (~0.8%/bara) +# bare 12-19 : baza/churn 356-373, minimul atinge suportul 355.48 pe bara 15 +# bara 20 : buy doji, close 373.30 (open = close[19] = 373.00, corp 0.30) +# bara 21 : confirmare, inchide peste intrarea 374.80 +# bare 22-31 : urcare spre pivot/TP1 383.74 (bara 26) si apoi spre TP2 402.00 +CLOSES = [ + 395.00, 391.80, 388.60, 385.20, 382.00, 378.90, 375.70, 372.80, # 0-7 + 369.90, 367.00, 364.20, 361.80, # 8-11 + 363.20, 361.00, 358.50, 356.20, 360.00, 365.00, 369.50, 373.00, # 12-19 + 373.30, 375.60, # 20-21 + 377.00, 378.50, 380.40, 382.00, 384.50, 386.50, 389.50, 393.00, # 22-29 + 397.50, 401.50, # 30-31 +] +assert len(CLOSES) == 32, len(CLOSES) + +WICKS = [(0.35, 0.40)] * 32 +WICKS[0] = (0.40, 0.50) # prima bara, deschide dintr-un varf al downtrend-ului +WICKS[15] = (0.30, 0.72) # low exact 355.48 = suportul monthly +WICKS[16] = (0.40, 0.30) # rebound, nu sparge suportul +WICKS[20] = (0.80, 0.30) # doji: high 374.10, low 372.70 +WICKS[31] = (0.55, 0.40) # high 402.05, atinge TP2 402.00 +assert len(WICKS) == 32, len(WICKS) + +# barele 25-31 in crestere; bara 20 (doji) sub media seriei (RVOL 0.61) +VOLS = [ + 42, 44, 41, 46, 43, 45, 40, 44, 47, 43, # 0-9 + 40, 42, 38, 41, 52, # 10-14 + 56, 50, 45, 42, 39, # 15-19 + 30, # 20 doji, sub medie + 46, # 21 confirmare + 48, 50, 52, 54, 58, 62, 66, 70, 76, 82, # 22-31 +] +assert len(VOLS) == 32, len(VOLS) +media_vol = sum(VOLS) / len(VOLS) +assert VOLS[20] < media_vol, "bara 20 (doji) trebuie sub media seriei" +assert all(a < b for a, b in zip(VOLS[25:32], VOLS[26:32])), "barele 25-31 nu cresc" +# RVOL afisat (0.61) ~ raportul barei de doji fata de media seriei +assert abs(VOLS[20] / media_vol - 0.61) < 0.02, VOLS[20] / media_vol + +cds = from_closes(CLOSES, wicks=WICKS, vols=VOLS, start=396.50) + +# ---------------------------------------------------------------- assert-urile din spec +assert abs(cds[20].c - 373.30) < 1e-9, "doji-ul trebuie sa inchida la 373.30" +assert abs(max(cds[20].o, cds[20].c) - min(cds[20].o, cds[20].c)) <= 0.40, "bara 20 nu e doji" +assert abs(min(c.l for c in cds[12:21]) - 355.48) < 0.05, "suportul 355.48 nu e atins" +assert 352.00 < 355.48 < 373.30 < 374.80 < 383.74 < 402.00, "ordinea nivelurilor" +risc = 374.80 - 352.00 # 22.80 +assert abs((383.74 - 374.80) / risc - 0.39) < 0.02, "TP1 nu e ~0.39R" +assert abs((402.00 - 374.80) / risc - 1.19) < 0.02, "TP2 nu e ~1.19R" +assert cds[-1].c >= 383.74, "TP1 nu e atins in serie" +assert min(c.l for c in cds) >= 351.5, "SL-ul de 352.00 nu poate fi sub minimul seriei" +for a, b in zip(cds, cds[1:]): + assert abs(a.c - b.o) < 1e-9, "serie cu gol artificial intre bare" + +# structura ceruta explicit: doji mic cu fitilele date, confirmare peste intrare +assert abs(cds[20].h - 374.10) < 0.05 and abs(cds[20].l - 372.70) < 0.05, (cds[20].h, cds[20].l) +assert cds[21].c > 374.80, "bara 21 nu confirma intrarea" +assert max(cds[i].h for i in range(22, 27)) >= 383.74, "TP1 nu e atins in jurul barei 26" +assert cds[31].h >= 402.00, "TP2 nu e atins spre final" + +# ---------------------------------------------------------------- niveluri, etichete +levels = [ + Level(352.00, "SL 352.00", RED, label_at="left"), + Level(355.48, "suport monthly 355.48", BLUE, label_at="left"), + Level(374.80, "intrare 374.80", GREEN), + Level(383.74, "pivot / TP1 383.74", BLUE), + Level(402.00, "TP2 402.00", BLUE), +] + +marks = [ + # „sub bara 0" ar insemna peste candelele care coboara (staircase); dy-ul + # o ridica deasupra varfului de start, unde textul se citeste curat + Mark(0, "downtrend weekly", GRAY, "below", dy=-62), + Mark(20, "buy doji close 373.30 (RVOL 0.61)", TEAL, "below"), + Mark(21, "intrare 374.80", GREEN, "above"), + Mark(26, "TP1 383.74 = pivot", BLUE, "above", dy=-8), + Mark(31, "TP2 402.00", BLUE, "above", dy=-22), +] + +caption = ("Ale cursului: close 373.30, suport 355.48, pivot 383.74, RVOL 0.61. " + "Intrarea 374.80, SL 352.00 si TP2 402.00 sunt estimari din 04_MODUL_3/01; " + "structura barelor dintre niveluri e construita, la scara.") + +ch = Chart( + candles=cds, levels=levels, marks=marks, + mas=[MA(20, ORANGE, dash="4 3", text="SMA-20")], + scale=8.5, gap=15, body_w=9, left=44, width=640, vol_h=70, + vol_label="volum", + title="ULTA — daily (pivoți monthly)", + caption=caption, +) +svg = ch.render() + +# ---------------------------------------------------------------- verificarea de scara +ys = {p: ch._y(p) for p in (352.00, 355.48, 374.80, 383.74, 402.00)} +px_risc = ys[352.00] - ys[374.80] # y creste in jos, deci SL-ul are y mai mare +assert abs((ys[374.80] - ys[383.74]) / px_risc - (383.74 - 374.80) / risc) < 1e-9, "TP1 la scara gresita" +assert abs((ys[374.80] - ys[402.00]) / px_risc - (402.00 - 374.80) / risc) < 1e-9, "TP2 la scara gresita" + +# ---------------------------------------------------------------- finisaj text +# caption-ul pe un singur rand depaseste latimea panzei (se taie la viewBox): +# il rupem in linii si crestem inaltimea desenului. +def _wrap(text: str, max_chars: int) -> list[str]: + lines, cur = [], "" + for w in text.split(): + if cur and len(cur) + 1 + len(w) > max_chars: + lines.append(cur) + cur = w + else: + cur = f"{cur} {w}".strip() + if cur: + lines.append(cur) + return lines + + +cap_lines = _wrap(caption, 92) +m = re.search(r'' + re.escape(caption) + r"\s*", svg) +assert m, "caption-ul nu a fost gasit in SVG" +y0 = int(m.group(1)) +wrapped = "\n ".join(f'{ln}' + for i, ln in enumerate(cap_lines)) +svg = svg[:m.start()] + wrapped + "\n" +vm = re.search(r'viewBox="0 0 (\d+) (\d+)"', svg) +assert vm +svg = svg.replace(vm.group(0), + f'viewBox="0 0 {vm.group(1)} {int(vm.group(2)) + 17 * (len(cap_lines) - 1)}"', 1) + +# „SMA-20" (x=515, y=269) sta la 12.6px de eticheta „intrare 374.80" (y=281.6), +# adica lipite: o ridicam 12px pe linia libera de deasupra. +svg, n = re.subn(r'(SMA-20)', + lambda mm: f'{mm.group(1)}{int(mm.group(2)) - 12}{mm.group(3)}', svg) +assert n == 1, f"eticheta SMA-20: {n} potriviri" + +assert " + ULTA — daily (pivoți monthly) + + SL 352.00 + + suport monthly 355.48 + + intrare 374.80 + + pivot / TP1 383.74 + + TP2 402.00 + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + downtrend weekly + buy doji close 373.30 (RVOL 0.61) + intrare 374.80 + TP1 383.74 = pivot + TP2 402.00 + Ale cursului: close 373.30, suport 355.48, pivot 383.74, RVOL 0.61. Intrarea 374.80, SL + 352.00 si TP2 402.00 sunt estimari din 04_MODUL_3/01; structura barelor dintre niveluri e + construita, la scara. + \ No newline at end of file diff --git a/gen/strategii/selectia_cadrane.py b/gen/strategii/selectia_cadrane.py new file mode 100644 index 0000000..e19bd84 --- /dev/null +++ b/gen/strategii/selectia_cadrane.py @@ -0,0 +1,327 @@ +#!/usr/bin/env python3 +"""Relative strength — cele 4 cadrane (matrice 2x2). + +Diagramă conceptuală (NU grafic de preț): pentru `strategii/04_selectia.md`, +Nivel 1, §1.2 F4 „Relative strength în cadranul 1-2". Citește specificația +`gen/strategii/selectia_cadrane.spec.txt` și scrie +`gen/strategii/selectia_cadrane.svg`. + +Nu folosește `svg_candles` / `pchart`: SVG-ul e construit ca string, doar +stdlib. + +Axele (așa cum le dă spec-ul): + - vertical: histograma RS față de linia de 0 (peste / sub 0); + - orizontal: histograma RS față de MA (peste / sub MA). + +Cadranele (definițiile din spec, preluate din +03_MODUL_2/06_indicatorul_de_performanta.md:31-39): + 1 supraperformanță peste 0 ȘI peste MA -> LONG + 2 îmbunătățire sub 0, dar peste MA -> LONG (zona de cumpărat) + 3 înrăutățire peste 0, dar sub MA -> SHORT + 4 subperformanță sub 0 ȘI sub MA -> SHORT / stai pe margine + +Banda de jos e avertismentul despre cadranul 4 (08_ANALIZA_ZILNICA/ +11_selectia_simbolului.md:493-508), plus nota mică despre eroarea de +transcriere (03_MODUL_2/06 ...:41-48) — marcată explicit ca NOTĂ, nu ca +definiție a cursului. + +Fără cifre de RS inventate: desenul e pur calitativ. + +Rulare: .venv/bin/python gen/strategii/selectia_cadrane.py +""" +import html +from pathlib import Path + +W, H = 700, 720 + +BLACK = "#000000" +GRAY = "#777777" +RED = "#c00" +GREEN = "#188a3e" +BLUE = "#1a5fb4" +ORANGE = "#b06000" + +GREEN_BG = "#eef7f0" +RED_BG = "#fdeeee" + +# ---------------------------------------------------------------- geometrie +PLOT_X0, PLOT_X1 = 130.0, 570.0 +PLOT_Y0, PLOT_Y1 = 134.0, 414.0 +CX = (PLOT_X0 + PLOT_X1) / 2.0 # 350 +CY = (PLOT_Y0 + PLOT_Y1) / 2.0 # 266 + +GUT = 4.0 +CW = (PLOT_X1 - PLOT_X0 - GUT) / 2.0 # 218 +CH = (PLOT_Y1 - PLOT_Y0 - GUT) / 2.0 # 138 + +Q3 = {"x": PLOT_X0, "y": PLOT_Y0} # peste 0, sub MA +Q1 = {"x": CX + GUT / 2, "y": PLOT_Y0} # peste 0, peste MA +Q4 = {"x": PLOT_X0, "y": CY + GUT / 2} # sub 0, sub MA +Q2 = {"x": CX + GUT / 2, "y": CY + GUT / 2} # sub 0, peste MA +for _q in (Q1, Q2, Q3, Q4): + _q["w"], _q["h"] = CW, CH + +BAND = {"x": 40.0, "y": 460.0, "w": 620.0, "h": 196.0} + +# ---------------------------------------------------------------- collect +TEXTS = [] # (x, y, s, size, weight, fill, anchor) +RECTS = [] # (x, y, w, h, tag) + + +def add(x, y, s, size=13, weight="normal", fill=BLACK, anchor="middle"): + TEXTS.append((x, y, s, size, weight, fill, anchor)) + return s + + +def est_w(s, size, weight): + factor = 0.62 if weight == "bold" else 0.56 + return len(s) * size * factor + + +def txt(x, y, s, size=13, weight="normal", fill=BLACK, anchor="middle"): + return (f'' + f'{html.escape(s, quote=False)}') + + +def rect(x, y, w, h, tag, fill="#ffffff", stroke=GRAY, sw=1.5, dash=None): + RECTS.append((x, y, w, h, tag)) + d = f' stroke-dasharray="{dash}"' if dash else "" + return (f'') + + +def line(x1, y1, x2, y2, stroke=GRAY, width=1.0, dash=None): + d = f' stroke-dasharray="{dash}"' if dash else "" + return (f'') + + +def cell_text(q, dy, s, *a, **k): + add(q["x"] + q["w"] / 2.0, q["y"] + dy, s, *a, **k) + + +# =============================================================== CONȚINUT +p = [] + +# ---- titlu + subtitlu + legenda axelor +add(W / 2, 34, "Relative strength — cele 4 cadrane", 20, "bold") +add(W / 2, 58, "RS = cât de bine se mișcă simbolul față de benchmark (ex. SPY)", + 13, "normal", GRAY) +add(W / 2, 80, + "Axa verticală: histograma RS față de 0 (peste / sub 0)", + 13, "normal", GRAY) +add(W / 2, 98, + "Axa orizontală: histograma RS față de MA (peste / sub MA)", + 13, "normal", GRAY) + +# ---- etichetele coloanelor / rândurilor (axe) +add(PLOT_X0 + CW / 2 + GUT / 2, 122, "sub MA", 14, "bold", ORANGE) +add(CX + GUT / 2 + CW / 2, 122, "peste MA", 14, "bold", BLUE) +add(PLOT_X0 - 8, Q3["y"] + CH / 2, "peste 0", 14, "bold", GREEN, "end") +add(PLOT_X0 - 8, Q4["y"] + CH / 2, "sub 0", 14, "bold", RED, "end") + +# ---- liniile de 0 (orizontală) și de MA (verticală), în spatele cadranelor +p.append(rect(PLOT_X0, PLOT_Y0, PLOT_X1 - PLOT_X0, PLOT_Y1 - PLOT_Y0, + "plot", fill="#ffffff", stroke=GRAY, sw=1.0)) +p.append(line(PLOT_X0, CY, PLOT_X1, CY, GRAY, 1.0, "4 4")) +p.append(line(CX, PLOT_Y0, CX, PLOT_Y1, GRAY, 1.0, "4 4")) + +# ---- cadrane +p.append(rect(Q3["x"], Q3["y"], CW, CH, "Q3", fill=RED_BG, stroke=RED, sw=1.6)) +p.append(rect(Q1["x"], Q1["y"], CW, CH, "Q1", fill=GREEN_BG, stroke=GREEN, sw=1.6)) +p.append(rect(Q4["x"], Q4["y"], CW, CH, "Q4", fill=RED_BG, stroke=RED, sw=1.6, + dash="6 4")) +p.append(rect(Q2["x"], Q2["y"], CW, CH, "Q2", fill=GREEN_BG, stroke=GREEN, sw=1.6)) + +# Cadran 3 — top-left: peste 0, sub MA -> SHORT +cell_text(Q3, 30, "Cadran 3", 16, "bold", BLACK) +cell_text(Q3, 52, "înrăutățire", 14, "bold", RED) +cell_text(Q3, 80, "peste 0, dar sub MA", 13, "normal", BLACK) +cell_text(Q3, 112, "SHORT", 16, "bold", RED) + +# Cadran 1 — top-right: peste 0, peste MA -> LONG +cell_text(Q1, 30, "Cadran 1", 16, "bold", BLACK) +cell_text(Q1, 52, "supraperformanță", 14, "bold", GREEN) +cell_text(Q1, 80, "peste 0 și peste MA", 13, "normal", BLACK) +cell_text(Q1, 112, "LONG", 16, "bold", GREEN) + +# Cadran 4 — bottom-left: sub 0, sub MA -> SHORT / stai pe margine +cell_text(Q4, 26, "Cadran 4", 16, "bold", BLACK) +cell_text(Q4, 48, "subperformanță", 14, "bold", RED) +cell_text(Q4, 74, "sub 0 și sub MA", 13, "normal", BLACK) +cell_text(Q4, 100, "SHORT", 15, "bold", RED) +cell_text(Q4, 122, "stai pe margine", 13, "normal", RED) + +# Cadran 2 — bottom-right: sub 0, peste MA -> LONG (zona de cumpărat) +cell_text(Q2, 26, "Cadran 2", 16, "bold", BLACK) +cell_text(Q2, 48, "îmbunătățire", 14, "bold", GREEN) +cell_text(Q2, 74, "sub 0, dar peste MA", 13, "normal", BLACK) +cell_text(Q2, 100, "LONG", 15, "bold", GREEN) +cell_text(Q2, 122, "zona de cumpărat", 13, "normal", GREEN) + +# ---- concluzia de sub matrice +add(W / 2, 442, "Long = cadranele 1-2 · Short = cadranele 3-4", + 14, "bold", BLACK) + +# ---- banda de avertisment (cadranul 4) +p.append(rect(BAND["x"], BAND["y"], BAND["w"], BAND["h"], "band", + fill="#fdf0e0", stroke=ORANGE, sw=1.6)) +add(BAND["x"] + 20, 488, "Avertisment — cadranul 4 nu se tranzacționează pe orb", + 15, "bold", RED, "start") +add(BAND["x"] + 20, 516, + "„Cadranul 4 nu se tranzacționează pe orb: aștepți trecerea în 2 sau 1,", + 13, "normal", BLACK, "start") +add(BAND["x"] + 20, 536, "ori un MP4-1 / MBT-10 long ca semn de schimbare.”", + 13, "normal", BLACK, "start") +add(BAND["x"] + 20, 566, + "„Un setup de bottom cu RS fără îmbunătățire are șanse mai mici.”", + 13, "bold", BLACK, "start") +add(BAND["x"] + 20, 596, + "Notă: transcrierea descrierii cadranului 4 are o eroare (îl descrie ca pe", + 13, "normal", GRAY, "start") +add(BAND["x"] + 20, 616, + "cadranul 3); definiția de mai sus e completarea sumarului —", + 13, "normal", GRAY, "start") +add(BAND["x"] + 20, 636, + "03_MODUL_2/06_indicatorul_de_performanta.md:41-48.", + 13, "normal", GRAY, "start") + +# ---- surse +add(W / 2, 686, + "Surse: 08_ANALIZA_ZILNICA/11_selectia_simbolului.md:486-499, :501-508;", + 13, "normal", GRAY) +add(W / 2, 704, + "03_MODUL_2/06_indicatorul_de_performanta.md:31-39.", + 13, "normal", GRAY) + +# =============================================================== EMITERE +head = (f'') +body = [head, f''] +body += p +for x, y, s, size, weight, fill, anchor in TEXTS: + body.append(txt(x, y, s, size, weight, fill, anchor)) +body.append("") +svg = "\n".join(body) + "\n" + +# =============================================================== VERIFICARE +# 1. geometrie: 4 cadrane egale, fără suprapunere, în interiorul plot-ului +assert len(RECTS) == 6, f"aștept 6 dreptunghiuri, am {len(RECTS)}" +quads = [r for r in RECTS if r[4] in ("Q1", "Q2", "Q3", "Q4")] +assert len(quads) == 4, f"aștept 4 cadrane, am {len(quads)}" +for x, y, w, h, tag in quads: + assert abs(w - CW) < 1e-9 and abs(h - CH) < 1e-9, f"{tag}: dimensiune greșită" + assert PLOT_X0 - 0.5 <= x and x + w <= PLOT_X1 + 0.5, f"{tag}: iese orizontal" + assert PLOT_Y0 - 0.5 <= y and y + h <= PLOT_Y1 + 0.5, f"{tag}: iese vertical" +for i in range(len(quads)): + for j in range(i + 1, len(quads)): + x1, y1, w1, h1, t1 = quads[i] + x2, y2, w2, h2, t2 = quads[j] + assert not (x1 < x2 + w2 and x2 < x1 + w1 and + y1 < y2 + h2 and y2 < y1 + h1), \ + f"cadrane suprapuse: {t1} / {t2}" + +# 2. pozițiile relative: 1 sus-dreapta, 2 jos-dreapta, 3 sus-stânga, 4 jos-stânga +by_tag = {r[4]: r for r in quads} +assert by_tag["Q1"][0] > CX and by_tag["Q1"][1] < CY, "cadranul 1 nu e sus-dreapta" +assert by_tag["Q2"][0] > CX and by_tag["Q2"][1] > CY, "cadranul 2 nu e jos-dreapta" +assert by_tag["Q3"][0] < CX and by_tag["Q3"][1] < CY, "cadranul 3 nu e sus-stânga" +assert by_tag["Q4"][0] < CX and by_tag["Q4"][1] > CY, "cadranul 4 nu e jos-stânga" + +# 3. definițiile din spec sunt exact cele desenate +for req in ("Cadran 1", "Cadran 2", "Cadran 3", "Cadran 4", + "supraperformanță", "îmbunătățire", "înrăutățire", + "subperformanță"): + assert any(t[2] == req for t in TEXTS), f"lipsește din desen: {req!r}" + +# condiția fiecărui cadran +assert any(t[2] == "peste 0 și peste MA" for t in TEXTS) +assert any(t[2] == "sub 0, dar peste MA" for t in TEXTS) +assert any(t[2] == "peste 0, dar sub MA" for t in TEXTS) +assert any(t[2] == "sub 0 și sub MA" for t in TEXTS) +# direcția: LONG pe 1-2, SHORT pe 3-4 +assert svg.count(">LONG") == 2, "LONG trebuie să apară exact de 2 ori" +assert svg.count(">SHORT") == 2, "SHORT trebuie să apară exact de 2 ori" +assert "stai pe margine" in svg, "lipsește «stai pe margine» din cadranul 4" +assert "zona de cumpărat" in svg, "lipsește «zona de cumpărat» din cadranul 2" +assert "Long = cadranele 1-2" in svg and "Short = cadranele 3-4" in svg + +# 4. titlu, subtitlu, legenda axelor, avertismentul, nota +for req in ("Relative strength — cele 4 cadrane", + "RS = cât de bine se mișcă simbolul față de benchmark (ex. SPY)", + "Axa verticală: histograma RS față de 0 (peste / sub 0)", + "Axa orizontală: histograma RS față de MA (peste / sub MA)", + "Cadranul 4 nu se tranzacționează pe orb", + "aștepți trecerea în 2 sau 1", + "MP4-1 / MBT-10 long", + "Un setup de bottom cu RS fără îmbunătățire are șanse mai mici", + "transcrierea descrierii cadranului 4 are o eroare", + "e completarea sumarului", + "03_MODUL_2/06_indicatorul_de_performanta.md:41-48", + "11_selectia_simbolului.md:486-499", + "06_indicatorul_de_performanta.md:31-39"): + assert req in svg, f"lipsește din desen: {req!r}" + +# 5. etichetele cadranului 2 și 3 care se pot încurca: verifică asocierea +t2 = [t for t in TEXTS if t[0] > CX and t[1] > CY] +assert any("îmbunătățire" == t[2] for t in t2), "cadranul 2 nu e marcat corect" +t3 = [t for t in TEXTS if t[0] < CX and t[1] < CY] +assert any("înrăutățire" == t[2] for t in t3), "cadranul 3 nu e marcat corect" + +# 6. textul fiecărui cadran încape în cadranul lui +for tag, q in (("Q1", Q1), ("Q2", Q2), ("Q3", Q3), ("Q4", Q4)): + for x, y, s, size, weight, fill, anchor in TEXTS: + if q["x"] <= x <= q["x"] + q["w"] and q["y"] <= y <= q["y"] + q["h"]: + w = est_w(s, size, weight) + assert w <= q["w"] - 16, f"{tag}: text prea lat: {s!r} ({w:.0f})" + +# 7. toate etichetele în panză + fără suprapuneri +boxes = [] +for x, y, s, size, weight, fill, anchor in TEXTS: + assert size >= 13, f"font sub 13px: {s!r} ({size})" + w = est_w(s, size, weight) + if anchor == "end": + left = x - w + elif anchor == "start": + left = x + else: + left = x - w / 2.0 + right = left + w + top, bottom = y - size * 0.78, y + size * 0.22 + assert -2 <= left and right <= W + 2, f"text în afara panzei orizontal: {s!r}" + assert 0 <= top and bottom <= H, f"text în afara panzei vertical: {s!r}" + boxes.append((left, right, top, bottom, s)) +for i in range(len(boxes)): + for j in range(i + 1, len(boxes)): + l1, r1, t1, b1, s1 = boxes[i] + l2, r2, t2_, b2, s2 = boxes[j] + if r1 > l2 + 2 and r2 > l1 + 2 and b1 > t2_ + 2 and b2 > t1 + 2: + raise AssertionError(f"etichete suprapuse: {s1!r} / {s2!r}") + +# 8. stil: fără umbre / gradienți, fontul cerut +assert "filter=" not in svg and "gradient" not in svg, "fără umbre/gradienti" +assert 'font-family="system-ui, sans-serif"' in svg, "lipsește fontul cerut" + +# 8b. SVG-ul e XML valid, cu o singură rădăcină (bug prins la render: +# un rect scris înaintea rădăcinii => „extra content at the end”) +import xml.etree.ElementTree as _ET +assert svg.lstrip().startswith("" +_root = _ET.fromstring(svg) +assert _root.tag.endswith("svg"), f"rădăcină neașteptată: {_root.tag}" + +# 9. fără cifre de RS inventate: niciun text nu conține numere zecimale sau +# procente (axele folosesc doar „0”, ca prag, nu valori de RS) +import re +for _x, _y, _s, _size, _weight, _fill, _anchor in TEXTS: + assert not re.search(r"\d+[.,]\d+", _s), f"cifră de RS inventată: {_s!r}" + assert "%" not in _s, f"procent inventat: {_s!r}" +assert "score" not in svg and "scor" not in svg + +OUT = Path(__file__).with_suffix(".svg") +OUT.write_text(svg, encoding="utf-8") +print(f"scris {OUT} ({len(svg)} bytes, {len(TEXTS)} etichete, " + f"{len(quads)} cadrane, {W}x{H}), verificare OK") diff --git a/gen/strategii/selectia_cadrane.svg b/gen/strategii/selectia_cadrane.svg new file mode 100644 index 0000000..f6e56ae --- /dev/null +++ b/gen/strategii/selectia_cadrane.svg @@ -0,0 +1,47 @@ + + + + + + + + + + +Relative strength — cele 4 cadrane +RS = cât de bine se mișcă simbolul față de benchmark (ex. SPY) +Axa verticală: histograma RS față de 0 (peste / sub 0) +Axa orizontală: histograma RS față de MA (peste / sub MA) +sub MA +peste MA +peste 0 +sub 0 +Cadran 3 +înrăutățire +peste 0, dar sub MA +SHORT +Cadran 1 +supraperformanță +peste 0 și peste MA +LONG +Cadran 4 +subperformanță +sub 0 și sub MA +SHORT +stai pe margine +Cadran 2 +îmbunătățire +sub 0, dar peste MA +LONG +zona de cumpărat +Long = cadranele 1-2 · Short = cadranele 3-4 +Avertisment — cadranul 4 nu se tranzacționează pe orb +„Cadranul 4 nu se tranzacționează pe orb: aștepți trecerea în 2 sau 1, +ori un MP4-1 / MBT-10 long ca semn de schimbare.” +„Un setup de bottom cu RS fără îmbunătățire are șanse mai mici.” +Notă: transcrierea descrierii cadranului 4 are o eroare (îl descrie ca pe +cadranul 3); definiția de mai sus e completarea sumarului — +03_MODUL_2/06_indicatorul_de_performanta.md:41-48. +Surse: 08_ANALIZA_ZILNICA/11_selectia_simbolului.md:486-499, :501-508; +03_MODUL_2/06_indicatorul_de_performanta.md:31-39. + diff --git a/gen/strategii/selectia_exemplu.py b/gen/strategii/selectia_exemplu.py new file mode 100644 index 0000000..75bb69f --- /dev/null +++ b/gen/strategii/selectia_exemplu.py @@ -0,0 +1,208 @@ +"""HIG — daily (Sell Doji + Bear Reversal, RVOL 200%): exemplul oglinda (short). + +Citește `gen/strategii/selectia_exemplu.spec.txt`. Un simbol scos în față de +filtrul de selecție prin Relative Volume mare (200%, cel mai ridicat din cele +16 rezultate ale scanerului), dus până la planul de intrare. Grafic daily, 30 +de candele, serie continuă, cu panou de volum și SMA-20 — construit prin +`svg_candles` (from_closes), la scară. + +Rulează: + python3 gen/strategii/selectia_exemplu.py +Scrie lângă el `selectia_exemplu.svg`. +""" +import re +import sys +from pathlib import Path + +sys.path.insert(0, "/workspace/atm-curs-dl") +from svg_candles import Candle, Chart, Level, Mark, MA, from_closes # noqa: E402 + +OUT = Path(__file__).resolve().parent / "selectia_exemplu.svg" + +GRAY, RED, GREEN, BLUE, ORANGE = "#777", "#c00", "#188a3e", "#1a5fb4", "#b06000" + +# ---------------------------------------------------------------- seria (30 bare) +# bare 0-9 : uptrend / rezistenta spre varful 84.50 (atins pe bara 9) +# bara 10 : gap down, open 79.20 (< close[9] = 84.20), bara rosie +# bara 11 : continuare in jos +# bara 12 : sell doji, close 78.60 (open = close[11] = 78.75, corp 0.15) +# bara 13 : rupere sub low-ul dojii -> intrare short 78.10 +# bare 14-29 : scadere spre 72.00 (TP atins spre final), mici bare verzi de +# respiratie (15, 18, 21, 24), dar trend descendent +CLOSES = [ + 80.00, 80.60, 81.20, 81.90, 81.50, # 0-4 + 82.30, 82.90, 83.60, 84.00, 84.20, # 5-9 varful seriei + 78.95, # 10 gap down (open 79.20, refacut mai jos) + 78.75, # 11 + 78.60, # 12 sell doji + 78.05, # 13 ruperea + 77.50, 77.80, 77.20, 76.60, 76.90, # 14-18 + 76.20, 75.60, 75.90, 75.30, 74.80, # 19-23 + 75.10, 74.40, 73.80, 73.20, 72.60, # 24-28 + 71.90, # 29 TP 72.00 atins +] +assert len(CLOSES) == 30, len(CLOSES) + +# wick-uri moderate (0.3-0.9); bara 9 urca exact la rezistenta 84.50 +WICKS = [(0.45, 0.40)] * 30 +WICKS[1] = (0.40, 0.45) +WICKS[2] = (0.50, 0.40) +WICKS[3] = (0.55, 0.45) +WICKS[4] = (0.45, 0.55) +WICKS[5] = (0.50, 0.40) +WICKS[6] = (0.45, 0.50) +WICKS[7] = (0.40, 0.45) +WICKS[8] = (0.35, 0.40) +WICKS[9] = (0.30, 0.45) # high 84.20 + 0.30 = 84.50 = rezistenta +WICKS[10] = (0.40, 0.50) # gap: open 79.20, high 79.60, low 78.45 +WICKS[11] = (0.45, 0.40) +WICKS[12] = (0.35, 0.40) # doji: high 79.10, low 78.20 +WICKS[13] = (0.40, 0.40) # low 77.65, sub intrarea 78.10 +WICKS[29] = (0.50, 0.55) +assert len(WICKS) == 30, len(WICKS) + +# panoul de volum: bara 10 (gap-ul) = 200% din media seriei, bara cea mai inalta; +# suma 3000 => media 100, bara 10 = 200. +VOLS = [ + 88, 82, 90, 100, 86, 108, 104, 120, 96, 100, # 0-9 + 200, # 10 RVOL 200% + 130, 100, 150, 102, 88, 108, 96, 84, 100, # 11-19 + 90, 78, 98, 86, 74, 92, 82, 104, 76, 88, # 20-29 +] +assert len(VOLS) == 30, len(VOLS) +media_vol = sum(VOLS) / len(VOLS) +assert VOLS[10] == max(VOLS), "bara 10 (gap-ul) nu e cea mai inalta" +assert abs(VOLS[10] / media_vol - 2.00) < 0.01, VOLS[10] / media_vol + +cds = from_closes(CLOSES, wicks=WICKS, vols=VOLS, start=79.80) + +# bara de gap: singura cu open != close-ul barei precedente (open 79.20 explicit) +cds[10] = Candle(79.20, max(79.20, 78.95) + 0.40, min(79.20, 78.95) - 0.50, + 78.95, vol=VOLS[10]) + +# ---------------------------------------------------------------- assert-urile din spec +assert abs(cds[12].c - 78.60) < 1e-9, "doji-ul trebuie sa inchida la 78.60" +assert abs(max(cds[12].o, cds[12].c) - min(cds[12].o, cds[12].c)) <= 0.30, "bara 12 nu e doji" +assert 72.00 < 78.10 < 78.60 < 82.00 < 84.50, "ordinea nivelurilor short" +assert cds[13].l <= 78.10, "intrarea short nu e sub low-ul dojii" +assert cds[13].l < cds[12].l, "intrarea nu sparge low-ul dojii" +assert cds[10].o < cds[9].c, "bara 10 nu e gap down" +risc = 82.00 - 78.10 # 3.90 +reward = 78.10 - 72.00 # 6.10 +assert abs(reward / risc - 1.56) < 0.02, "raportul nu e ~1.56R" +assert cds[-1].c <= 72.00, "TP-ul nu e atins in serie" +# open = close-ul barei precedente peste tot, mai putin bara de gap (10) +for i, (a, b) in enumerate(zip(cds, cds[1:])): + if i + 1 == 10: + continue + assert abs(a.c - b.o) < 1e-9, "serie cu gol artificial intre bare" +assert cds[9].h == 84.50, "varful nu atinge rezistenta 84.50" +assert min(c.l for c in cds) >= 71.30, "SL-ul de 82.00 nu poate fi sub minimul seriei" + +# ---------------------------------------------------------------- niveluri, etichete +levels = [ + Level(84.50, "rezistenta 84.50", GRAY, label_at="left"), + Level(82.00, "SL 82.00", RED, label_at="right"), + Level(78.10, "intrare short 78.10", BLUE, label_at="left"), + Level(72.00, "TP 72.00", GREEN, label_at="left"), +] + +marks = [ + Mark(10, "gap down, open 79.20", "#333", "above", dy=-16), + Mark(12, "sell doji close 78.60", RED, "above", dy=-4), + Mark(13, "intrare short 78.10", GREEN, "below", dy=26), + Mark(10, "RVOL 200%", RED, "below", dy=12), +] + +title = "HIG — daily (Sell Doji + Bear Reversal, RVOL 200%)" +caption = ("RVOL 200% si simbolul sunt reale (04_MODUL_3/01:196-199). Toate " + "nivelurile de preț (79.20 / 78.60 / 78.10 / 82.00 / 72.00) sunt " + "construite in sumarul 04_MODUL_3/01:293-296, nu date de curs; " + "structura barelor e construita, la scara.") + +ch = Chart( + candles=cds, levels=levels, marks=marks, + mas=[MA(20, ORANGE, dash="4 3", text="SMA-20")], + scale=16.0, gap=15, body_w=9, left=44, width=640, vol_h=70, + vol_label="volum", + title="", # titlul se injecteaza sus, ca sa nu se suprapuna + caption=caption, # cu eticheta nivelului "rezistenta 84.50" (stanga) +) +svg = ch.render() + +# ---------------------------------------------------------------- verificarea de scara +ys = {p: ch._y(p) for p in (82.00, 78.10, 72.00)} +px_risc = ys[78.10] - ys[82.00] # y creste in jos, SL-ul e deasupra intrarii +px_reward = ys[72.00] - ys[78.10] +assert px_risc > 0 and px_reward > 0 +assert abs(px_risc / px_reward - risc / reward) < 1e-9, "SL/TP la scara gresita" + +# ---------------------------------------------------------------- titlu injectat +m_svg = re.search(r"]*>", svg) +assert m_svg, "tag lipsa" +svg = svg.replace( + m_svg.group(0), + m_svg.group(0) + f'\n {title}', + 1, +) + +# ---------------------------------------------------------------- caption pe randuri +def _wrap(text: str, max_chars: int) -> list[str]: + lines, cur = [], "" + for w in text.split(): + if cur and len(cur) + 1 + len(w) > max_chars: + lines.append(cur) + cur = w + else: + cur = f"{cur} {w}".strip() + if cur: + lines.append(cur) + return lines + + +cap_lines = _wrap(caption, 70) +m = re.search(r'' + re.escape(caption) + r"\s*", svg) +assert m, "caption-ul nu a fost gasit in SVG" +y0 = int(m.group(1)) +wrapped = "\n ".join(f'{ln}' + for i, ln in enumerate(cap_lines)) +svg = svg[:m.start()] + wrapped + "\n" +vm = re.search(r'viewBox="0 0 (\d+) (\d+)"', svg) +assert vm +svg = svg.replace(vm.group(0), + f'viewBox="0 0 {vm.group(1)} {int(vm.group(2)) + 17 * (len(cap_lines) - 1)}"', 1) + +# ---------------------------------------------------------------- verificare layout +width, height = int(vm.group(1)), int(vm.group(2)) + 17 * (len(cap_lines) - 1) +texts = re.findall(r']*)>(.*?)', svg) +assert texts, "niciun text in SVG" +for x, y, _attrs, t in texts: + assert 0 <= float(x) <= width, f"text in afara pânzei pe x: {t!r} x={x}" + assert 0 <= float(y) <= height, f"text in afara pânzei pe y: {t!r} y={y}" +# nicio pereche de texte nu se suprapune pe ambele axe (12px inaltime, +# latime estimata 6.5px/caracter; ancorele start/middle/end sunt respectate) +boxes = [] +for x, y, attrs, t in texts: + w = 6.5 * len(t) + if 'text-anchor="middle"' in attrs: + x0 = float(x) - w / 2 + elif 'text-anchor="end"' in attrs: + x0 = float(x) - w + else: + x0 = float(x) + boxes.append((x0, float(y), t, w)) +for i in range(len(boxes)): + for j in range(i + 1, len(boxes)): + xi, yi, ti, wi = boxes[i] + xj, yj, tj, wj = boxes[j] + dx = min(xi + wi, xj + wj) - max(xi, xj) + dy = abs(yi - yj) + if dx > 4 and dy < 11: + raise AssertionError(f"texte suprapuse: {ti!r}@{xi:.0f},{yi:.0f} vs {tj!r}@{xj:.0f},{yj:.0f}") + +assert " + HIG — daily (Sell Doji + Bear Reversal, RVOL 200%) + + rezistenta 84.50 + + SL 82.00 + + intrare short 78.10 + + TP 72.00 + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + gap down, open 79.20 + sell doji close 78.60 + intrare short 78.10 + RVOL 200% + RVOL 200% si simbolul sunt reale (04_MODUL_3/01:196-199). Toate + nivelurile de preț (79.20 / 78.60 / 78.10 / 82.00 / 72.00) sunt + construite in sumarul 04_MODUL_3/01:293-296, nu date de curs; + structura barelor e construita, la scara. + \ No newline at end of file diff --git a/gen/strategii/selectia_funnel.py b/gen/strategii/selectia_funnel.py new file mode 100644 index 0000000..ac413c5 --- /dev/null +++ b/gen/strategii/selectia_funnel.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python3 +"""Fluxul de selecție — palnia de filtrare de la scanner la lista scurtă. + +Diagramă conceptuală (NU grafic de preț): palnie cu 8 trepte care se +îngustează de sus în jos, apoi lista scurtă; cutie separată de note laterale. +Pentru `strategii/04_selectia.md`, Nivel 1, §1.2 „Fluxul de filtrare, pas cu +pas". Citește specificația `gen/strategii/selectia_funnel.spec.txt` și scrie +`gen/strategii/selectia_funnel.svg`. + +Nu folosește `svg_candles` / `pchart`: SVG-ul e construit ca string, doar +stdlib. + +Fiecare treaptă are titlul, subtitlul cu pragul și trimiterea (sursa). +Toate cifrele din desen (pragurile, „max ~300 simboluri”, „top 10”) sunt +preluate textual din specificație; nu se inventează valori de RS sau de +sectoare. + +Rulare: .venv/bin/python gen/strategii/selectia_funnel.py +""" +import html +import re +from pathlib import Path + +W = 700 +H = 1024 + +BLACK = "#000000" +GRAY = "#777777" +RED = "#c00" +GREEN = "#188a3e" +BLUE = "#1a5fb4" +ORANGE = "#b06000" + +STEP_FILL = ("#eef3fb", "#e4edf9") # alternanță foarte fină între trepte +GREEN_BG = "#eef7f0" +NOTE_BG = "#fdf0e0" + +# ---------------------------------------------------------------- geometrie +CX = W / 2.0 # 350: axa palniei +TOPW = 610.0 # lățimea gurii palniei +NARROW = 24.0 # cât se strânge pe fiecare treaptă +Y0 = 100.0 +HSTEP = 76.0 + +LIST_W, LIST_Y, LIST_H = 410.0, 722.0, 62.0 +NOTE = {"x": 40.0, "y": 802.0, "w": 620.0, "h": 200.0} + +# ---------------------------------------------------------------- conținut +# (titlu, subtitlu, [linii de sursă]) +STEPS = [ + ("Scanner — multe semnale", + "zeci sau sute de semnale", + ["08_ANALIZA_ZILNICA/11_selectia_simbolului.md:631-637"]), + ("Filtre de bază", + "close > 30-40 $; volum mediu 3 luni > 1M (min 500k)", + ["09_QA/28_2025-05-27.md:372-380;", + "03_MODUL_2/11_construire_scanere_sf_byd_sld.md:70-73"]), + ("Fundamental", + "ATM score peste 7-8; 12-13 = spuma; F-score 6-9", + ["08_ANALIZA_ZILNICA/11_selectia_simbolului.md:199-221"]), + ("Sectorul care domină", + "cele 11 sectoare S&P, sortate cadran 1 + valoarea RS, săptămânal", + ["08_ANALIZA_ZILNICA/11_selectia_simbolului.md:639-717"]), + ("Doar suport / pivot, după downtrend", + "suport monthly, quarterly, anual sau pivot; proximitate ≤ 3%", + ["08_ANALIZA_ZILNICA/11_selectia_simbolului.md:719-728, 787-803"]), + ("Relative strength: cadran 1-2", + "doar cadranele 1 și 2, RS pozitiv", + ["08_ANALIZA_ZILNICA/11_selectia_simbolului.md:730-739"]), + ("Relative volume peste 100%", + "candela de volum / media ultimelor 10 candele", + ["08_ANALIZA_ZILNICA/11_selectia_simbolului.md:741-747"]), + ("Stele (Trinity)", + "RS + Power + volum, cadran 1", + ["08_ANALIZA_ZILNICA/11_selectia_simbolului.md:776-785"]), +] + +LIST = ("Listă scurtă", + "câteva idei pe care le urmărești", + "08_ANALIZA_ZILNICA/11_selectia_simbolului.md:42-50") + +TITLE = "Fluxul de selecție — de la scanner la lista scurtă" +SUBTITLE = ("selecția se face înainte de semnalul tehnic; " + "ea nu spune CÂND intri") +CAPTION = "Palnia se îngustează de sus în jos: 8 filtre, apoi lista scurtă." + +NOTE_TITLE = "Note laterale" +NOTE1 = ["După corecție masivă: doji / hammer la suporturi mari", + "(monthly, quarterly, anual); scanner de apropiere de suport", + "până la 3% (4% e cam departe)."] +NOTE1_SRC = "08_ANALIZA_ZILNICA/11_selectia_simbolului.md:787-803" +NOTE2 = ["Radarscreen (max ~300 simboluri): repetă fluxul — sectoare top 10,", + "RS, apoi 3 stele."] +NOTE2_SRC = "08_ANALIZA_ZILNICA/11_selectia_simbolului.md:815-825" + +# ---------------------------------------------------------------- colect +TEXTS = [] # (x, y, s, size, weight, fill, anchor) +SHAPES = [] # (x, y, w, h, tag) bbox-uri pentru verificare +WIDTHS = [] # (w_sus, w_jos) pe fiecare treaptă, pentru verificat conectarea + + +def add(x, y, s, size=13, weight="normal", fill=BLACK, anchor="middle"): + TEXTS.append((x, y, s, size, weight, fill, anchor)) + return s + + +def est_w(s, size, weight): + factor = 0.62 if weight == "bold" else 0.56 + return len(s) * size * factor + + +def txt(x, y, s, size=13, weight="normal", fill=BLACK, anchor="middle"): + return (f'' + f'{html.escape(s, quote=False)}') + + +def rect(x, y, w, h, tag, fill="#ffffff", stroke=GRAY, sw=1.5, rx=0): + SHAPES.append((x, y, w, h, tag)) + r = f' rx="{rx}"' if rx else "" + return (f'') + + +def trapezoid(y, wt, wb, h, index): + """Treaptă de palnie: muchia de sus lată wt, cea de jos wb.""" + xtl, xtr = CX - wt / 2.0, CX + wt / 2.0 + xbl, xbr = CX - wb / 2.0, CX + wb / 2.0 + SHAPES.append((xbl, y, wb, h, f"step{index}")) + WIDTHS.append((wt, wb)) + d = (f"M {xtl:.1f} {y:.1f} L {xtr:.1f} {y:.1f} " + f"L {xbr:.1f} {y + h:.1f} L {xbl:.1f} {y + h:.1f} Z") + fill = STEP_FILL[index % 2] + return (f'') + + +# =============================================================== CONȚINUT +p = [] + +# ---- titlu / subtitlu / caption +add(W / 2, 34, TITLE, 20, "bold") +add(W / 2, 57, SUBTITLE, 13, "normal", GRAY) +add(W / 2, 79, CAPTION, 13, "normal", GRAY) + +# ---- palnia: 8 trepte +for i, (titlu, subtitlu, surse) in enumerate(STEPS): + y = Y0 + i * HSTEP + wt = TOPW - i * NARROW + wb = TOPW - (i + 1) * NARROW + p.append(trapezoid(y, wt, wb, HSTEP, i)) + add(CX, y + 25, f"{i + 1}. {titlu}", 14.5, "bold", BLACK) + add(CX, y + 45, subtitlu, 13, "normal", BLACK) + for k, src in enumerate(surse): + add(CX, y + 59 + k * 14, src, 13, "normal", GRAY) + +# ---- lista scurtă (vârful palniei, cutie separată) +p.append(rect(CX - LIST_W / 2, LIST_Y, LIST_W, LIST_H, "list", + fill=GREEN_BG, stroke=GREEN, sw=1.8, rx=8)) +add(CX, LIST_Y + 24, LIST[0], 16, "bold", GREEN) +add(CX, LIST_Y + 43, LIST[1], 13, "normal", BLACK) +add(CX, LIST_Y + 57, LIST[2], 13, "normal", GRAY) + +# ---- cutia de note laterale +p.append(rect(NOTE["x"], NOTE["y"], NOTE["w"], NOTE["h"], "note", + fill=NOTE_BG, stroke=ORANGE, sw=1.6, rx=8)) +nx = NOTE["x"] + 20 +add(nx, NOTE["y"] + 28, NOTE_TITLE, 15, "bold", ORANGE, "start") +add(nx, NOTE["y"] + 56, NOTE1[0], 13, "normal", BLACK, "start") +add(nx, NOTE["y"] + 75, NOTE1[1], 13, "normal", BLACK, "start") +add(nx, NOTE["y"] + 94, NOTE1[2], 13, "normal", BLACK, "start") +add(nx, NOTE["y"] + 115, NOTE1_SRC, 13, "normal", GRAY, "start") +add(nx, NOTE["y"] + 150, NOTE2[0], 13, "normal", BLACK, "start") +add(nx, NOTE["y"] + 169, NOTE2[1], 13, "normal", BLACK, "start") +add(nx, NOTE["y"] + 190, NOTE2_SRC, 13, "normal", GRAY, "start") + +# =============================================================== EMITERE +head = (f'') +body = [head, f''] +body += p +for x, y, s, size, weight, fill, anchor in TEXTS: + body.append(txt(x, y, s, size, weight, fill, anchor)) +body.append("") +svg = "\n".join(body) + "\n" + +# =============================================================== VERIFICARE +# 1. palnia are exact 8 trepte, conectate și tot mai înguste +assert len(STEPS) == 8, f"aștept 8 trepte, am {len(STEPS)}" +traps = [s for s in SHAPES if s[4].startswith("step")] +assert len(traps) == 8, f"aștept 8 trapezoide, am {len(traps)}" +assert len(WIDTHS) == 8 +for i, (wt, wb) in enumerate(WIDTHS): + assert wt > wb, f"treapta {i} nu se îngustează" + if i: + assert abs(WIDTHS[i][0] - WIDTHS[i - 1][1]) < 1e-9, \ + f"treapta {i} nu continuă muchia treptei {i - 1}" +assert WIDTHS[-1][1] < WIDTHS[0][0], "palnia nu se îngustează de sus în jos" +assert LIST_W < traps[-1][2], "lista scurtă nu e mai îngustă decât vârful palniei" + +# 2. toate titlurile și subtitlurile din spec sunt desenate +for i, (titlu, subtitlu, surse) in enumerate(STEPS): + assert any(t[2] == f"{i + 1}. {titlu}" for t in TEXTS), \ + f"lipsește titlul treptei {i + 1}: {titlu!r}" + assert any(t[2] == subtitlu for t in TEXTS), \ + f"lipsește subtitlul treptei {i + 1}: {subtitlu!r}" + for src in surse: + assert src in svg, f"lipsește sursa treptei {i + 1}: {src!r}" +assert any(t[2] == LIST[0] for t in TEXTS), "lipsește «Listă scurtă»" +assert "câteva idei pe care le urmărești" in svg + +# 3. titlul, subtitlul și notele din spec sunt exact cele desenate +assert TITLE in svg, "lipsește titlul din spec" +assert SUBTITLE in svg, "lipsește subtitlul din spec" +for line in NOTE1 + [NOTE1_SRC] + NOTE2 + [NOTE2_SRC]: + assert line in svg, f"lipsește din note: {line!r}" + +# 4. fiecare textul încape în lățimea treptei lui (muchia de jos, cea îngustă) +for i in range(8): + ytop = Y0 + i * HSTEP + ybot = ytop + HSTEP + wb = TOPW - (i + 1) * NARROW + for x, y, s, size, weight, fill, anchor in TEXTS: + if ytop <= y <= ybot: + w = est_w(s, size, weight) + assert w <= wb - 14, f"treapta {i + 1}: text prea lat: {s!r} ({w:.0f})" + +# textul din lista scurtă și din note încape în cutiile lor +for x, y, s, size, weight, fill, anchor in TEXTS: + if LIST_Y <= y <= LIST_Y + LIST_H: + assert est_w(s, size, weight) <= LIST_W - 16, f"listă: text prea lat: {s!r}" + if NOTE["y"] <= y <= NOTE["y"] + NOTE["h"]: + assert est_w(s, size, weight) <= NOTE["w"] - 40, f"notă: text prea lat: {s!r}" + +# 5. toate etichetele în panză + fără suprapuneri +boxes = [] +for x, y, s, size, weight, fill, anchor in TEXTS: + assert size >= 13, f"font sub 13px: {s!r}" + w = est_w(s, size, weight) + if anchor == "end": + left = x - w + elif anchor == "start": + left = x + else: + left = x - w / 2.0 + right = left + w + top, bottom = y - size * 0.78, y + size * 0.22 + assert -2 <= left and right <= W + 2, f"text în afara panzei orizontal: {s!r}" + assert 0 <= top and bottom <= H, f"text în afara panzei vertical: {s!r}" + boxes.append((left, right, top, bottom, s)) +for i in range(len(boxes)): + for j in range(i + 1, len(boxes)): + l1, r1, t1, b1, s1 = boxes[i] + l2, r2, t2, b2, s2 = boxes[j] + if r1 > l2 + 2 and r2 > l1 + 2 and b1 > t2 + 2 and b2 > t1 + 2: + raise AssertionError(f"etichete suprapuse: {s1!r} / {s2!r}") + +# 6. cutiile stau una sub alta, în ordinea palnie -> listă -> note +assert LIST_Y >= Y0 + 8 * HSTEP, "lista scurtă se suprapune cu palnia" +assert NOTE["y"] >= LIST_Y + LIST_H, "notele se suprapun cu lista scurtă" +assert NOTE["y"] + NOTE["h"] <= H, "notele ies din panză" + +# 7. stil: fără umbre / gradienți, fontul cerut; fără prețuri inventate +assert "filter=" not in svg and "gradient" not in svg, "fără umbre/gradienti" +assert 'font-family="system-ui, sans-serif"' in svg, "lipsește fontul cerut" +assert " + + + + + + + + + + + +Fluxul de selecție — de la scanner la lista scurtă +selecția se face înainte de semnalul tehnic; ea nu spune CÂND intri +Palnia se îngustează de sus în jos: 8 filtre, apoi lista scurtă. +1. Scanner — multe semnale +zeci sau sute de semnale +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:631-637 +2. Filtre de bază +close > 30-40 $; volum mediu 3 luni > 1M (min 500k) +09_QA/28_2025-05-27.md:372-380; +03_MODUL_2/11_construire_scanere_sf_byd_sld.md:70-73 +3. Fundamental +ATM score peste 7-8; 12-13 = spuma; F-score 6-9 +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:199-221 +4. Sectorul care domină +cele 11 sectoare S&P, sortate cadran 1 + valoarea RS, săptămânal +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:639-717 +5. Doar suport / pivot, după downtrend +suport monthly, quarterly, anual sau pivot; proximitate ≤ 3% +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:719-728, 787-803 +6. Relative strength: cadran 1-2 +doar cadranele 1 și 2, RS pozitiv +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:730-739 +7. Relative volume peste 100% +candela de volum / media ultimelor 10 candele +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:741-747 +8. Stele (Trinity) +RS + Power + volum, cadran 1 +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:776-785 +Listă scurtă +câteva idei pe care le urmărești +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:42-50 +Note laterale +După corecție masivă: doji / hammer la suporturi mari +(monthly, quarterly, anual); scanner de apropiere de suport +până la 3% (4% e cam departe). +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:787-803 +Radarscreen (max ~300 simboluri): repetă fluxul — sectoare top 10, +RS, apoi 3 stele. +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:815-825 + diff --git a/gen/strategii/selectia_scor.py b/gen/strategii/selectia_scor.py new file mode 100644 index 0000000..3bdc2b9 --- /dev/null +++ b/gen/strategii/selectia_scor.py @@ -0,0 +1,286 @@ +#!/usr/bin/env python3 +"""ATM score — scala 0-14 (bară cu praguri). TIP: CONCEPT. + +Citește specificația `gen/strategii/selectia_scor.spec.txt` și scrie +`gen/strategii/selectia_scor.svg`. Diagramă conceptuală (NU candele): nu +folosește `svg_candles` / `pchart`, SVG-ul e construit ca string, doar stdlib. + +Ce arată (toate cifrele vin din spec): + - bara 0-14: F-score 0-9 (albastru, 9/14) + value-score 0-5 (portocaliu, 5/14); + - praguri: 7 (reperul „galben”), 7-8 („intră în analiză”), 12-13 („spuma”), 14 (max); + - benzile F-score: 0-3 slab fundamental, 4-5 mixt, 6-7 solid, 8-9 foarte puternic; + - nota: scor -1 = date indisponibile în platformă, NU scor 0; + - nota: „peste 7-8" e formularea cursului, sub 7 e deducere, nu prag declarat. + +Rulare: .venv/bin/python gen/strategii/selectia_scor.py +""" +import html +from pathlib import Path + +W, H = 700, 610 + +BLACK = "#000000" +GRAY = "#777777" +RED = "#c00" +GREEN = "#188a3e" +BLUE = "#1a5fb4" +ORANGE = "#b06000" +YELLOW = "#e0a800" # „7/14 = galben" (reperul din curs) +DARK_YELLOW = "#8a6d00" # aceeași nuanță, lizibilă ca text + +BLUE_BG = "#eef2fb" +ORANGE_BG = "#fdf0e0" +GREEN_BG = "#eef7f0" +RED_BG = "#fdeeee" +GRAY_BG = "#f4f4f4" + +# ---------------------------------------------------------------- geometrie bară +BAR_X0, BAR_X1 = 60.0, 640.0 +BAR_Y, BAR_H = 150.0, 48.0 +UNIT = (BAR_X1 - BAR_X0) / 14.0 # 41.4286 px per punct de scor +SPLIT = 9 # F-score 0-9, apoi value-score 9-14 + + +def sx(v): + """Poziția pe bară a scorului v (0..14).""" + return BAR_X0 + v * UNIT + + +X_SPLIT = sx(SPLIT) +X7, X8, X12, X13, X14 = sx(7), sx(8), sx(12), sx(13), sx(14) + +# ---------------------------------------------------------------- colectoare +TEXTS = [] # (x, y, s, size, weight, fill, anchor) +RECTS = [] # (x, y, w, h, tag) + + +def add(x, y, s, size=13, weight="normal", fill=BLACK, anchor="middle"): + TEXTS.append((float(x), float(y), s, size, weight, fill, anchor)) + return s + + +def est_w(s, size, weight): + factor = 0.62 if weight == "bold" else 0.56 + return len(s) * size * factor + + +def txt(x, y, s, size=13, weight="normal", fill=BLACK, anchor="middle"): + return (f'' + f'{html.escape(s, quote=False)}') + + +def rect(x, y, w, h, tag, fill="#ffffff", stroke=GRAY, sw=1.5, dash=None): + RECTS.append((float(x), float(y), float(w), float(h), tag)) + d = f' stroke-dasharray="{dash}"' if dash else "" + return (f'') + + +def line(x1, y1, x2, y2, stroke=GRAY, width=1.0, dash=None): + d = f' stroke-dasharray="{dash}"' if dash else "" + return (f'') + + +# =============================================================== CONȚINUT +p = [] + +# ---- titlu + subtitlu +add(W / 2, 34, "ATM score: scala 0-14", 21, "bold") +add(W / 2, 58, "ATM score = F-score (max 9) + value-score (max 5) = max 14", + 13, "normal", GRAY) + +# ---- etichetele celor două componente, deasupra barei +add((BAR_X0 + X_SPLIT) / 2, 112, "F-score 0-9", 15, "bold", BLUE) +add((BAR_X0 + X_SPLIT) / 2, 131, "9/14 din bară", 13, "normal", GRAY) +add((X_SPLIT + BAR_X1) / 2, 112, "value-score 0-5", 15, "bold", ORANGE) +add((X_SPLIT + BAR_X1) / 2, 131, "5/14 din bară", 13, "normal", GRAY) + +# ---- bara celor 14 puncte: partea albastră (0-9) + partea portocalie (9-14) +p.append(rect(BAR_X0, BAR_Y, X_SPLIT - BAR_X0, BAR_H, "fscore", + fill=BLUE_BG, stroke=BLUE, sw=1.8)) +p.append(rect(X_SPLIT, BAR_Y, BAR_X1 - X_SPLIT, BAR_H, "vscore", + fill=ORANGE_BG, stroke=ORANGE, sw=1.8)) +# diviziunea la 9 +p.append(line(X_SPLIT, BAR_Y, X_SPLIT, BAR_Y + BAR_H, BLACK, 1.2, "3 3")) +# reperele peste bară: banda „spuma" 12-13 și linia galbenă de la 7 +p.append(rect(X12, BAR_Y - 6, X13 - X12, BAR_H + 12, "spuma", + fill="none", stroke=RED, sw=1.4, dash="5 3")) +p.append(line(X7, BAR_Y - 10, X7, BAR_Y + BAR_H + 6, YELLOW, 2.4, "4 3")) +# în interiorul barei, numele componentelor +add((BAR_X0 + X_SPLIT) / 2, BAR_Y + BAR_H / 2 + 5, "F-score", 15, "bold", BLUE) +add((X_SPLIT + BAR_X1) / 2, BAR_Y + BAR_H / 2 + 5, "value-score", 15, "bold", ORANGE) + +# ---- scale: tick-uri + numere 0..14 sub bară +for i in range(15): + x = sx(i) + p.append(line(x, BAR_Y + BAR_H, x, BAR_Y + BAR_H + 7, GRAY, 1.0)) + add(x, BAR_Y + BAR_H + 26, str(i), 13, "normal", BLACK) + +# ---- reperul 7/14 (galben) +add(X7 - 8, 244, "7/14 = galben", 13, "bold", DARK_YELLOW, "end") + +# ---- intervalul „spuma" (12-13) și maximul 14 +add(X14, 244, "12-13: spuma", 13, "bold", RED, "end") +add(X14, 264, "14 = maxim", 13, "bold", BLACK, "end") + +# ---- „peste 7-8: intră în analiză" (acoladă sub scală, peste intervalul 7-8) +p.append(line(X7, 234, X7, 242, GRAY, 1.2)) +p.append(line(X8, 234, X8, 242, GRAY, 1.2)) +p.append(line(X7, 242, X8, 242, GRAY, 1.2)) +add((X7 + X8) / 2, 264, "peste 7-8: intră în analiză", 13, "bold", BLACK) + +# ---- benzile F-score, aliniate sub partea albastră (0-9) +add(BAR_X0, 300, "Benzi F-score (partea albastră, 0-9)", 14, "bold", + BLACK, "start") +BANDS = [ + (0, 3, "0-3", ["slab", "fundamental"], RED, RED_BG), + (3, 5, "4-5", ["mixt"], ORANGE, GRAY_BG), + (5, 7, "6-7", ["solid"], BLUE, BLUE_BG), + (7, 9, "8-9", ["foarte", "puternic"], GREEN, GREEN_BG), +] +BAND_Y, BAND_H = 314.0, 64.0 +for a, b, rng, labs, col, bg in BANDS: + x0, x1 = sx(a), sx(b) + p.append(rect(x0, BAND_Y, x1 - x0, BAND_H, f"band{a}", + fill=bg, stroke=col, sw=1.6)) + cx = (x0 + x1) / 2 + add(cx, 336, rng, 15, "bold", col) + add(cx, 358, labs[0], 13, "normal", BLACK) + if len(labs) > 1: + add(cx, 376, labs[1], 13, "normal", BLACK) + +# ---- note (scor -1 + formularea „peste 7-8") +p.append(rect(40, 402, 620, 122, "note", + fill="#f7f7f7", stroke=GRAY, sw=1.2)) +add(60, 430, "Scor -1 = date indisponibile în platformă, NU scor 0.", + 14, "bold", BLACK, "start") +add(60, 450, "Scorul -1 nu se citește ca 0.", 13, "normal", GRAY, "start") +add(60, 470, + "16_ANALIZA_FUNDAMENTALA/09_implementare_f_score_tradestation.md:45-46, 268-269.", + 13, "normal", GRAY, "start") +add(60, 498, + "„peste 7-8” e formularea exactă a cursului; sub 7 se deduce ca excludere,", + 13, "normal", BLACK, "start") +add(60, 518, + "nu e declarat ca prag separat (11_selectia_simbolului.md:199-204).", + 13, "normal", GRAY, "start") + +# ---- surse +add(W / 2, 556, + "Surse: 08_ANALIZA_ZILNICA/11_selectia_simbolului.md:158-164, :199-204;", + 13, "normal", GRAY) +add(W / 2, 574, + "16_ANALIZA_FUNDAMENTALA/08_piotrowski_f_score.md:70-72;", + 13, "normal", GRAY) +add(W / 2, 592, + "16_ANALIZA_FUNDAMENTALA/09_implementare_f_score_tradestation.md:45-46, 268-269.", + 13, "normal", GRAY) + +# =============================================================== EMITERE +head = (f'') +body = [head, f''] +body += p +for x, y, s, size, weight, fill, anchor in TEXTS: + body.append(txt(x, y, s, size, weight, fill, anchor)) +body.append("") +svg = "\n".join(body) + "\n" + +# =============================================================== VERIFICARE +# 1. bara are proporțiile cerute: 9/14 albastru, 5/14 portocaliu +w_f = X_SPLIT - BAR_X0 +w_v = BAR_X1 - X_SPLIT +assert abs(w_f / (BAR_X1 - BAR_X0) - 9 / 14) < 1e-9, "F-score nu e 9/14 din bară" +assert abs(w_v / (BAR_X1 - BAR_X0) - 5 / 14) < 1e-9, "value-score nu e 5/14 din bară" +assert abs(X_SPLIT - sx(9)) < 1e-9 and abs(sx(0) - BAR_X0) < 1e-9, "scara nu e 0-14" + +# 2. toate cifrele/etichetele din spec sunt în desen +for req in ("ATM score: scala 0-14", + "ATM score = F-score (max 9) + value-score (max 5) = max 14", + "F-score 0-9", "9/14 din bară", + "value-score 0-5", "5/14 din bară", + "7/14 = galben", "peste 7-8: intră în analiză", + "12-13: spuma", "14 = maxim", + "0-3", "slab", "fundamental", + "4-5", "mixt", "6-7", "solid", "8-9", "foarte", "puternic", + "Scor -1 = date indisponibile în platformă, NU scor 0.", + "sub 7 se deduce ca excludere", + "nu e declarat ca prag separat"): + assert any(req in t[2] for t in TEXTS), f"lipsește din desen: {req!r}" + +# 3. numerele de pe scală sunt exact 0..14 +nums = [t[2] for t in TEXTS if t[5] == BLACK and t[3] == 13 and t[6] == "middle" + and t[2].isdigit() and BAR_Y < t[1] < BAR_Y + BAR_H + 40] +assert nums == [str(i) for i in range(15)], nums + +# 4. pozițiile relative ale pragurilor +assert abs(sx(7) - (BAR_X0 + 7 * UNIT)) < 1e-9 +assert sx(12) < sx(13) < sx(14) == BAR_X1, "intervalul spuma / maximul greșit" +# reperul 7 (galben) și intervalul spuma sunt desenate ca linii/dreptunghiuri +assert any(r[4] == "spuma" for r in RECTS), "lipsește banda spuma 12-13" +assert any(r[4] == "fscore" for r in RECTS) and any(r[4] == "vscore" for r in RECTS) + +# 5. benzile F-score: aliniate exact sub partea albastră, fără suprapunere +bands = [r for r in RECTS if r[4].startswith("band")] +assert len(bands) == 4, f"aștept 4 benzi F-score, am {len(bands)}" +assert abs(bands[0][0] - BAR_X0) < 1e-9, "prima bandă nu începe la 0" +assert abs((bands[-1][0] + bands[-1][2]) - X_SPLIT) < 1e-9, "ultima bandă nu se termină la 9" +for i in range(1, len(bands)): + assert abs(bands[i][0] - (bands[i - 1][0] + bands[i - 1][2])) < 1e-9, "benzi nelipite" +for i in range(len(bands)): + for j in range(i + 1, len(bands)): + x1, y1, w1, h1, t1 = bands[i] + x2, y2, w2, h2, t2 = bands[j] + assert not (x1 < x2 + w2 and x2 < x1 + w1 and y1 < y2 + h2 and y2 < y1 + h1), \ + f"benzi suprapuse: {t1}/{t2}" + +# 6. numerele de pe scală sunt exact cele din benzi (0,3,5,7,9) +edges = [sx(0), sx(3), sx(5), sx(7), sx(9)] +for e, b in zip(edges, bands): + assert abs(e - b[0]) < 1e-9, "marginile benzilor nu cad pe scală" + +# 7. fiecare etichetă: mărime >= 13, în panză, fără suprapuneri +boxes = [] +for x, y, s, size, weight, fill, anchor in TEXTS: + assert size >= 13, f"font sub 13px: {s!r} ({size})" + w = est_w(s, size, weight) + if anchor == "end": + left = x - w + elif anchor == "start": + left = x + else: + left = x - w / 2.0 + right = left + w + top, bottom = y - size * 0.78, y + size * 0.22 + assert -2 <= left and right <= W + 2, f"text în afara panzei orizontal: {s!r}" + assert 0 <= top and bottom <= H, f"text în afara panzei vertical: {s!r}" + boxes.append((left, right, top, bottom, s)) +for i in range(len(boxes)): + for j in range(i + 1, len(boxes)): + l1, r1, t1, b1, s1 = boxes[i] + l2, r2, t2_, b2, s2 = boxes[j] + if r1 > l2 + 2 and r2 > l1 + 2 and b1 > t2_ + 2 and b2 > t1 + 2: + raise AssertionError(f"etichete suprapuse: {s1!r} / {s2!r}") + +# 8. textele din interiorul barei și benzile încap +for tag, (rx, ry, rw, rh, _) in [(r[4], r) for r in RECTS]: + if tag in ("fscore", "vscore"): + for x, y, s, size, weight, fill, anchor in TEXTS: + if rx <= x <= rx + rw and ry <= y <= ry + rh: + assert est_w(s, size, weight) <= rw - 12, f"text prea lat în {tag}: {s!r}" + +# 9. stil: fără umbre/gradienți, fontul cerut +assert "filter=" not in svg and "gradient" not in svg, "fără umbre/gradienti" +assert 'font-family="system-ui, sans-serif"' in svg, "lipsește fontul cerut" +assert 'fill="#ffffff"' in svg, "fundal alb lipsă" + +OUT = Path(__file__).with_suffix(".svg") +OUT.write_text(svg, encoding="utf-8") +print(f"scris {OUT} ({len(svg)} bytes, {len(TEXTS)} etichete, " + f"{len(bands)} benzi F-score, F-score {w_f:.1f}px / value-score {w_v:.1f}px, " + f"{W}x{H}), verificare OK") diff --git a/gen/strategii/selectia_scor.svg b/gen/strategii/selectia_scor.svg new file mode 100644 index 0000000..2cff486 --- /dev/null +++ b/gen/strategii/selectia_scor.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ATM score: scala 0-14 +ATM score = F-score (max 9) + value-score (max 5) = max 14 +F-score 0-9 +9/14 din bară +value-score 0-5 +5/14 din bară +F-score +value-score +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +7/14 = galben +12-13: spuma +14 = maxim +peste 7-8: intră în analiză +Benzi F-score (partea albastră, 0-9) +0-3 +slab +fundamental +4-5 +mixt +6-7 +solid +8-9 +foarte +puternic +Scor -1 = date indisponibile în platformă, NU scor 0. +Scorul -1 nu se citește ca 0. +16_ANALIZA_FUNDAMENTALA/09_implementare_f_score_tradestation.md:45-46, 268-269. +„peste 7-8” e formularea exactă a cursului; sub 7 se deduce ca excludere, +nu e declarat ca prag separat (11_selectia_simbolului.md:199-204). +Surse: 08_ANALIZA_ZILNICA/11_selectia_simbolului.md:158-164, :199-204; +16_ANALIZA_FUNDAMENTALA/08_piotrowski_f_score.md:70-72; +16_ANALIZA_FUNDAMENTALA/09_implementare_f_score_tradestation.md:45-46, 268-269. + diff --git a/gen/strategii/substituie.py b/gen/strategii/substituie.py index 3e2d63d..cc5c57b 100644 --- a/gen/strategii/substituie.py +++ b/gen/strategii/substituie.py @@ -15,7 +15,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parent.parent.parent CAPITOLE = sorted((ROOT / "strategii").glob("0[1-8]_*.md")) -MARCAJ = re.compile(r"^$", re.M) +MARCAJ = re.compile(r"^[ \t]*[ \t]*$", re.M) def slug(cale: Path) -> str: @@ -32,7 +32,11 @@ def main() -> int: def inlocuieste(m: re.Match) -> str: nonlocal puse, lipsa - svg = ROOT / "gen" / "strategii" / f"{s}_{m.group(1)}.svg" + # unii agenți au pus slug-ul în cheie (mp2_exemplu), alții nu (exemplu) + gen = ROOT / "gen" / "strategii" + svg = next((c for c in (gen / f"{s}_{m.group(1)}.svg", + gen / f"{m.group(1)}.svg") if c.exists()), + gen / f"{s}_{m.group(1)}.svg") if not svg.exists(): lipsa += 1 print(f"LIPSĂ {cap.name}: {svg.name}") diff --git a/strategii/01_buy_doji.md b/strategii/01_buy_doji.md index 7edbe89..96627d7 100644 --- a/strategii/01_buy_doji.md +++ b/strategii/01_buy_doji.md @@ -60,7 +60,122 @@ uriaș, de aceea stopul e obligatoriu și de aceea strategia se repetă des ### Diagrama de ansamblu - + + Buy Doji — daily (exemplu construit, fără ticker) + + SL 49.20 (low 4 candele) + + intrare 50.40 + + TP1 51.60 = 1R + + trail 52.60 + + MA(20) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + doji 50.10 / 49.20 + ieșire pe trail ~52.60 + bara 15: close 49.90 sub high-ul dojiului 50.10 — NU confirmă + bara 16: close 50.40 peste 50.10 — confirmare (intrare) + Intrare la close-ul confirmării, SL la low-ul ultimelor 4 candele, TP1 1:1, apoi trailing stop. + Graficul întreg al trade-ului: downtrend de 12 candele → doji → confirmare în fereastra de 3 → intrare la close-ul de confirmare, SL la extrema ultimelor @@ -131,7 +246,66 @@ Diagrama de mai jos arată exact diferența dintre un setup care se confirmă ș unul care expiră — diferența e strict numerică (a închis sau nu peste 50.10), nu vizuală. - + + + DA — confirmare la +2, în fereastră + + high doji 50.10 + + low doji 49.20 + + + + + + + + + + + + + + + + + doji + confirmare +2 — intrare 50.40 + +1: close 49.90 — sub 50.10, nu confirmă + +2: close 50.40 — peste 50.10, confirmă (intrare la close) + + + NU — nicio confirmare în 3 candele + + high doji 50.10 + + low doji 49.20 + + + + + + + + + + + + + + + + + + + doji + a 4-a + +1: 49.95; +2: 50.05; +3: 49.85 — toate sub 50.10 + a 4-a: close 49.15 — sub low-ul dojiului 49.20, setup mort + + Serii construite: open = close-ul barei anterioare. + Doji: h 50.10 / l 49.20. Fereastra = maximum 3 candele după doji. + ### 1.3 Trigger @@ -147,7 +321,117 @@ Oglinda short, cu cifrele ei: doji high 49.40 / low 48.00, a doua candelă (`01_buy_doji_si_strategia_mici.md:312-314`). Graficul întreg al variantei short: - + + Sell Doji — daily (exemplu construit, fără ticker) + + SL 100.10 (high 4 candele) + + intrare short 99.00 + + TP 97.90 = 1R + + trail 96.45 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + doji 99.20 / 100.10 + ieșire pe trail 96.60 + bara 15: close 99.40 peste low-ul dojiului 99.20 — NU confirmă + bara 16: close 99.00 sub 99.20 — confirmare (intrare short) + Intrare short la close sub low-ul dojiului, SL la high 4 candele, TP 1:1, apoi trail. + ### 1.4 Stop-loss @@ -245,7 +529,168 @@ varianta de execuție cu 48 de acțiuni pe un risc de 25 $ în Același pattern, două contexte. Diagrama le pune alături. - +Setup A+ vs. setup mediocru (două panouri, exemple construite) + A+ — doji la suport, volum în acumulare + + suport 42.00 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + doji la nivel (low 41.95) + acumulare + acumulare: volum peste media ultimelor 10 bare. + + Mediocru — gap-up în rezistență, volum varză + + rezistență 78.50 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + doji 78.50 / 78.10 + gap-up + doji în rezistență, confirmare pe volum slab. +gap-up, volum slabSurse: 13_strategia_3_byh.md:188-190 (doji la nivel); 01_buy_doji_si_strategia_mici.md:227-235 (context invalid). | | **A+** | **Mediocru / NU** | |---|---|---| @@ -338,7 +783,176 @@ Nu aleg eu între variante. Pentru fiecare: ce spune fiecare sursă și ce > Materialul nu dă niciun exemplu numeric complet, de la intrare la ieșire, > cu prețuri de curs. - + + LABU — daily + + pivot monthly 86.00 (construit) + + SL 81.45 (construit) = −9 % (procent real) + + intrare 89.50 (construit) + + TP 116.35 (construit) = +30 % (procent real) + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + bottom 1 82.40 + bottom 2 81.45 + bottom 3 81.45 + doji + confirmare (intrare) + higher high — TP atins + bara 33 = doji: o 85.00, c 84.90, h 86.30, l 84.20 — corp mic exact pe pivotul monthly 86.00 (indecizie la suport) + Procentele (stop 9 %, +30 %) sunt ale cursului; nivelurile de preț sunt construite de sumarizator (18_2025-09-23.md:713). + 1. **Context:** downtrend → consolidare → triple bottom → doji. 2. **Doji la pivotul monthly 86.00** — al doilea test al nivelului, fără low diff --git a/strategii/02_mp2.md b/strategii/02_mp2.md index 2b51207..fd5762d 100644 --- a/strategii/02_mp2.md +++ b/strategii/02_mp2.md @@ -48,7 +48,138 @@ puternică decât un pattern vizual izolat (`04_MODUL_3/04_strategia_2_mp_patrat ### Diagrama de ansamblu - + + + + pivot weekly (mic) + pivot monthly (mare) + NVDA — weekly (pre-split 1:10) + + entry ~13.80 (după M+A) + + SL swing low absolut 10.63, −23% + + TP ~+25% (17.25), ~9 săpt. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + minim absolut 10.63 + M+A + Bottom oct. 2022: entry ~13.80, −23%, ~+25% în ~9 săpt. Traseu și pivoți construiți (cursul nu dă valorile lor). + *Exemplul din curs: NVDA, bottom octombrie 2022, combinația weekly/monthly (cifre pre-split 1:10) — downtrend masiv → crossing → intrare, SL și țintă pe același grafic.* @@ -93,7 +224,120 @@ pre-split 1:10) — downtrend masiv → crossing → intrare, SL și țintă pe ### 1.2 Setup — ce trebuie să vezi pe grafic - + + + + pivot daily (cel MIC) + DA — crossing (+2) + + pivot weekly (cel MARE) 62.00 + + crossing: 61.70 → 62.20 + intrare: trigger + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + pivot daily (cel MIC) + NU — continuare/buy the dip (+1) + + pivot weekly (cel MARE) 62.00 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fără crossing nou; nu a mai căzut sub pivotul mare + semnale ulterioare = BUY THE DIP, nu crossing + Pivot weekly 62.00 = linia orizontală (pivotul MARE). + Pivot daily (cel MIC) se recalculează zilnic și sare pe nivel nou. + Trigger = prima candelă verde după crossing, + care închide peste pivotul daily. + Crossing = pivotul mic traversează 62.00 în sus; fără re-încrucișare, + semnalele ulterioare sunt buy the dip, nu crossing. + 1. **Alege perechea.** Pentru MP²-1 (swing, 1-3 zile): pivot **daily** = mic, pivot **weekly** = mare, execuție pe 60 min (`04_MODUL_3/04_strategia_2_mp_patrat.md:24-28`; @@ -217,7 +461,227 @@ probabil să apară tranzacția care recuperează, nu momentul să te retragi ### 2.2 Setup A+ vs. setup mediocru - +MP² crossing long — setup A+ vs. setup mediocru (aceeași strategie) + A+ — crossing la confluență (SPY, aprilie) + + suport quarterly 554.00 + + SL 554.40 (peste suport) + + intrare 577.00 + + neckline 578.00 + + TP1 599.60 = 1:1 + + downtrend anterior + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + umăr stâng 566 + head 555 / double bottom + umăr drept 568 + crossing + Confluență: 554.00 + double bottom + neckline 578.00 · 1R 22.60 + + Mediocru — crossing în mijlocul range-ului (construit) + + range 110.00 + + range 100.00 + + SL 103.00 + + intrare 105.00 + + TP1 107.00 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + crossing (mijloc) + exemplu construit, nu date reale — SL nu stă pe niciun pivot +Legendă: ce separă cele două sunt nivelurile independente dedesubte (suport quarterly + double bottom + neckline),nu un filtru pus în scaner. Panoul din dreapta e exemplu construit, nu date reale.Surse A+: 09_QA/01_2026-08-25.md:389-394, 485-490, 501-507. **A+ (SPY, bottom aprilie):** crossing-ul cade fix pe un **suport quarterly 554.00**, cu **double bottom** și **Inverted Head & Shoulders** (umăr stâng 566 / head 555 / umăr @@ -297,7 +761,144 @@ pentru că transcrierea scrie în ambele feluri (`08_ANALIZA_ZILNICA/02_mbt10.md ### 2.5 Exemplul complet, pas cu pas - + + SPY — daily + + ținta 4R era 667.00 (+16%) + + 646.00 — +12% efectiv (~3R) + + TP1 599.60 + + neckline 578.00 + + SL 554.40 + + suport quarterly 554.00 + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + umăr stâng 566 + head 555 + umăr drept 568 + intrare 577.00 + Intrare 577.00 = prima verde după umărul drept (MP² long). 1R = 22.60; 646.00 ~3R, într-o lună. + **SPY — LONG la bottom-ul de aprilie, combinația daily/weekly** (curs + Q&A). - **Context:** suport quarterly la **554.00**; double bottom și **Inverted Head & @@ -391,7 +992,87 @@ Autorul a confirmat că pivoții clasici se calculează în Excel din OHLC, „s MP² e doar comparația a doi pivoți (`09_QA/09_2025-12-09.md:1177-1180`). Formula e cea standard, predată în Modul 2 (`03_MODUL_2/02_zone_cerere_oferta_support_resistance.md:42-54`): - + + + +Pivoții clasici în Excel — formula, pas cu pas + + + + + + + + + + + + + + + + +1 +2 +3 +A +B +C +D +E +F +G +H +I +Perioada +High +Low +Close +PP +R1 +S1 +R2 +S2 +Săptămâna +încheiată +(PPW) +22.00 +20.50 +21.60 +=(B2+C2+D2)/3 +21.37 +=2*E2-C2 +22.23 +=2*E2-B2 +20.73 +=E2+(B2-C2) +22.87 +=E2-(B2-C2) +19.87 +Ziua +încheiată +(PPD) +21.90 +21.00 +21.80 +=(B3+C3+D3)/3 +21.57 +=2*E3-C3 +22.13 +=2*E3-B3 +21.23 +=E3+(B3-C3) +22.47 +=E3-(B3-C3) +20.67 + +PPD 21.57 > PPW 21.37 → CROSSING BULL (long) +Cifrele sunt un exemplu construit, cu valori rotunde, pe TLV — +nu sunt date reale de piață. +crossing = PPD trece deasupra PPW; dacă rămâne deasupra — continuare (09_QA/16:35-43). +Surse formule: 03_MODUL_2/02_zone_cerere_oferta_support_resistance.md:42-50 +Calcul Excel 1-la-1, MP² = comparația a doi pivoți: 09_QA/09_2025-12-09.md:1176-1180. + 1. **Adună OHLC perioadei încheiate.** Pentru MP²-1 ai nevoie de două foi: una pentru ziua încheiată (pivotul daily, PPD) și una pentru săptămâna încheiată (pivotul weekly, diff --git a/strategii/03_m2d.md b/strategii/03_m2d.md index 035039c..b76e744 100644 --- a/strategii/03_m2d.md +++ b/strategii/03_m2d.md @@ -14,7 +14,123 @@ Piața se mișcă simultan pe două scări: trendul de pe time frame-ul mare și ### Diagrama de ansamblu - + + bull trail 102.90 + Simbol construit — 3 min (TF mare 15 min în Buy) + + intrare 99.80 + + SL 98.80 (4 candele) + + TP1 100.80 = 1:1 + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + TF mare (15 min) în Buy + M: Sell Momentum (pullback) + A: primul Buy = trigger + vârf 103.30 + close sub bull trail = ieși + ieșire 102.00 pe bull trail (2.2R) + Serie construită (32 bare, 3 min). R = (102.00 − 99.80) / 1.00 = 2.2R. + *(graficul întreg al trade-ului: TF mare în Buy, pullback-ul Sell pe TF mic, triggerul Buy, intrarea, SL-ul de 4 candele, TP1 la 1:1 și ieșirea pe bull trail — spec `gen/strategii/m2d_ansamblu.spec.txt`)* @@ -53,7 +169,48 @@ Piața se mișcă simultan pe două scări: trendul de pe time frame-ul mare și 5. **Verifici că TF mare a rămas în Buy** în acel moment. Dacă s-a răsucit între timp, setup-ul a expirat (`09_QA/08_2026-01-20.md:52-63`). 6. **Short: totul oglindit** — mare Sell → mic Buy (pullback) → mic Sell (`14_strategia_1_m2d.md:172-180`). - + + + +Secvența M → A: nu e o stare, e o secvență +M2D — același moment, două time frame-uri: TF mare dă direcția, TF mic dă trigger-ul +sus = LONG; jos = SHORT — aceleași momente, în oglindă + + +LONG +TF mare (ex. 15 min) +rămâne în Buy pe tot parcursul + + + + +Buy Momentum +TF mic (ex. 3 min) + + +M: Sell Momentum (pullback) + +A: Buy Momentum — TRIGGER, intri long +SHORT +TF mare (ex. 15 min) +rămâne în Sell pe tot parcursul + + + + +Sell Momentum +TF mic (ex. 3 min) + + +M: Buy Momentum (pullback) + +A: Sell Momentum — TRIGGER, intri short + +Secvența contează, nu starea: mare în Buy → mic în Sell → mic în Buy +(cu mare încă în Buy). Un Buy direct pe TF mic, fără Sell între ele, +NU e trigger (vezi 1.3). +Sursă: 14_strategia_1_m2d.md:30-38, 172-180; 09_QA/08_2026-01-20.md:65-67 + *(secvența M → A pe cele două time frame-uri — spec `gen/strategii/m2d_secventa.spec.txt`)* @@ -165,7 +322,115 @@ Piața se mișcă simultan pe două scări: trendul de pe time frame-ul mare și | Execuție | În loc de ieșire la TP1 s-a continuat cu **bear trail**, actualizat la fiecare candelă cu high mai mic; wick-urile au atins linia, dar nicio candelă nu s-a închis peste ea (`14_strategia_1_m2d.md:232-235`) | | Rezultat | Ieșire pe violarea reală a trail-ului la **+4.55%** → risc/recompensă efectiv **≈ 1:5.3** (`14_strategia_1_m2d.md:235-236,326-328`) | - + + RIOT — 3 min (TF mare 15 min în Sell) + + SL 100.85 = +0.85% + + intrare 100.00 (trigger Sell) + + TP1 99.15 = 1:1 + + ieșire 95.45 = +4.55% ≈ 1:5.3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + TF mare (15 min) în Sell + M: Buy Momentum (pullback) + A: primul Sell = trigger, intri short + deja peste TP1 (1.42% din curs) + close peste bear trail = ieși + Axa de preț e construită (intrarea = 100.00); procentele sunt reale din curs. + *(trade-ul întreg, cu entry/SL/TP1 și ieșirea pe trail — spec `gen/strategii/m2d_exemplu.spec.txt`)* diff --git a/strategii/04_selectia.md b/strategii/04_selectia.md index 6f07a34..eb6a43d 100644 --- a/strategii/04_selectia.md +++ b/strategii/04_selectia.md @@ -68,7 +68,127 @@ timp să le citească. ### Diagrama de ansamblu - + + ULTA — daily (pivoți monthly) + + SL 352.00 + + suport monthly 355.48 + + intrare 374.80 + + pivot / TP1 383.74 + + TP2 402.00 + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + downtrend weekly + buy doji close 373.30 (RVOL 0.61) + intrare 374.80 + TP1 383.74 = pivot + TP2 402.00 + Ale cursului: close 373.30, suport 355.48, pivot 383.74, RVOL 0.61. Intrarea 374.80, SL + 352.00 si TP2 402.00 sunt estimari din 04_MODUL_3/01; structura barelor dintre niveluri e + construita, la scara. + ### Fraza de decizie @@ -120,7 +240,58 @@ filtrul de relative strength cade (vezi Nivel 0). Pe ETF-uri scorul nu există. Diagrama fluxului: - + + + + + + + + + + + + +Fluxul de selecție — de la scanner la lista scurtă +selecția se face înainte de semnalul tehnic; ea nu spune CÂND intri +Palnia se îngustează de sus în jos: 8 filtre, apoi lista scurtă. +1. Scanner — multe semnale +zeci sau sute de semnale +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:631-637 +2. Filtre de bază +close > 30-40 $; volum mediu 3 luni > 1M (min 500k) +09_QA/28_2025-05-27.md:372-380; +03_MODUL_2/11_construire_scanere_sf_byd_sld.md:70-73 +3. Fundamental +ATM score peste 7-8; 12-13 = spuma; F-score 6-9 +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:199-221 +4. Sectorul care domină +cele 11 sectoare S&P, sortate cadran 1 + valoarea RS, săptămânal +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:639-717 +5. Doar suport / pivot, după downtrend +suport monthly, quarterly, anual sau pivot; proximitate ≤ 3% +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:719-728, 787-803 +6. Relative strength: cadran 1-2 +doar cadranele 1 și 2, RS pozitiv +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:730-739 +7. Relative volume peste 100% +candela de volum / media ultimelor 10 candele +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:741-747 +8. Stele (Trinity) +RS + Power + volum, cadran 1 +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:776-785 +Listă scurtă +câteva idei pe care le urmărești +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:42-50 +Note laterale +După corecție masivă: doji / hammer la suporturi mari +(monthly, quarterly, anual); scanner de apropiere de suport +până la 3% (4% e cam departe). +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:787-803 +Radarscreen (max ~300 simboluri): repetă fluxul — sectoare top 10, +RS, apoi 3 stele. +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:815-825 + **F0. Filtrele de bază.** Close > 30-40 $, volum mediu 3 luni > 1M (minim 500k), volum mediu scanner ≥ 500k @@ -136,7 +307,83 @@ downtrend pe weekly (`08_ANALIZA_ZILNICA/11_selectia_simbolului.md:199-221, Scala de scor: - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +ATM score: scala 0-14 +ATM score = F-score (max 9) + value-score (max 5) = max 14 +F-score 0-9 +9/14 din bară +value-score 0-5 +5/14 din bară +F-score +value-score +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +7/14 = galben +12-13: spuma +14 = maxim +peste 7-8: intră în analiză +Benzi F-score (partea albastră, 0-9) +0-3 +slab +fundamental +4-5 +mixt +6-7 +solid +8-9 +foarte +puternic +Scor -1 = date indisponibile în platformă, NU scor 0. +Scorul -1 nu se citește ca 0. +16_ANALIZA_FUNDAMENTALA/09_implementare_f_score_tradestation.md:45-46, 268-269. +„peste 7-8” e formularea exactă a cursului; sub 7 se deduce ca excludere, +nu e declarat ca prag separat (11_selectia_simbolului.md:199-204). +Surse: 08_ANALIZA_ZILNICA/11_selectia_simbolului.md:158-164, :199-204; +16_ANALIZA_FUNDAMENTALA/08_piotrowski_f_score.md:70-72; +16_ANALIZA_FUNDAMENTALA/09_implementare_f_score_tradestation.md:45-46, 268-269. + **F2. Sectorul care domină.** Numără din ce sector vin cele mai multe semnale; acolo intră bani (rotație). La nivel de sectoare, cele 11 sectoare @@ -155,7 +402,53 @@ Strand [sic] și vedeți cine este în cadranul 1 și cadranul 2" Cele patru cadrane: - + + + + + + + + + + +Relative strength — cele 4 cadrane +RS = cât de bine se mișcă simbolul față de benchmark (ex. SPY) +Axa verticală: histograma RS față de 0 (peste / sub 0) +Axa orizontală: histograma RS față de MA (peste / sub MA) +sub MA +peste MA +peste 0 +sub 0 +Cadran 3 +înrăutățire +peste 0, dar sub MA +SHORT +Cadran 1 +supraperformanță +peste 0 și peste MA +LONG +Cadran 4 +subperformanță +sub 0 și sub MA +SHORT +stai pe margine +Cadran 2 +îmbunătățire +sub 0, dar peste MA +LONG +zona de cumpărat +Long = cadranele 1-2 · Short = cadranele 3-4 +Avertisment — cadranul 4 nu se tranzacționează pe orb +„Cadranul 4 nu se tranzacționează pe orb: aștepți trecerea în 2 sau 1, +ori un MP4-1 / MBT-10 long ca semn de schimbare.” +„Un setup de bottom cu RS fără îmbunătățire are șanse mai mici.” +Notă: transcrierea descrierii cadranului 4 are o eroare (îl descrie ca pe +cadranul 3); definiția de mai sus e completarea sumarului — +03_MODUL_2/06_indicatorul_de_performanta.md:41-48. +Surse: 08_ANALIZA_ZILNICA/11_selectia_simbolului.md:486-499, :501-508; +03_MODUL_2/06_indicatorul_de_performanta.md:31-39. + **F5. Relative volume peste 100%.** Candela de volum împărțită la media ultimelor **10** candele de volum @@ -371,7 +664,119 @@ avertisment de participare. **HIG — exemplul oglindă (short):** - + + HIG — daily (Sell Doji + Bear Reversal, RVOL 200%) + + rezistenta 84.50 + + SL 82.00 + + intrare short 78.10 + + TP 72.00 + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + gap down, open 79.20 + sell doji close 78.60 + intrare short 78.10 + RVOL 200% + RVOL 200% si simbolul sunt reale (04_MODUL_3/01:196-199). Toate + nivelurile de preț (79.20 / 78.60 / 78.10 / 82.00 / 72.00) sunt + construite in sumarul 04_MODUL_3/01:293-296, nu date de curs; + structura barelor e construita, la scara. + | Pas | Valoarea | Sursă | |---|---|---| diff --git a/strategii/05_atmi.md b/strategii/05_atmi.md index 5fc8c51..387b9ce 100644 --- a/strategii/05_atmi.md +++ b/strategii/05_atmi.md @@ -56,7 +56,125 @@ nicăieri în material** — NEACOPERIT ÎN MATERIAL. ### Diagrama de ansamblu - + + SQ — zonă quarterly + PPQ — zonă quarterly + fără stop-loss standard(03_strategia_2_atmi.md:164-169) + SPY — daily: corecție ≥4 % → SQ/PPQ → BIM + verde → intrare → TP +10 % + + 100.00 — swing high recent + + intrare 96.00 + + TP +10 % = 105.60 + + SMA-20 (ilustrativ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + corecție 4.0 % + BIM + BIM + candelă verde → intrare + Niveluri (100.00 / 96.00 / 105.60) din curs; PPQ/SQ schematice, fără cifre în material. + Graficul întreg al trade-ului, pe structura din exemplul „DA" al cursului: swing high 100.00 → corecție de exact 4.0 % → 96.00, adică în zona quarterly; @@ -247,7 +365,125 @@ formulă de tip „risc % din cont"** în material pentru ATMI. Aceeași corecție, două deznodăminte. Diagrama le pune alături. - + + + SPY — daily: aceeași corecție, 4.0 % (DA) vs. 3.9 % (NU) + + 100.00 — swing high + + 96.00 = 4.0 % — DA, intri + + TP +10 % = 105.60 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + BIM + candelă verde → trigger + Regula e pe procent, nu pe cât de dramatică arată linia: calea NU pare o cădere mare, dar e 3.9 %. + Calea DA (candele): 4.0 % la 96.00. Calea NU (punctat): 3.9 % („3.93 %” în curs) — fără intrare. + + + + 96.10 = 3.9 % — NU, sub prag + zonă quarterly + calea DA (candelele) + calea NU (continuă în jos) + | | **A+** | **Mediocru / NU** | |---|---|---| @@ -311,7 +547,53 @@ Nu aleg eu între variante. Pentru fiecare: ce spune fiecare sursă și ce clarificat cu autorul; nu o rezolv aici. Diagrama de mai jos pune cele două orizonturi alături. - + + + +Cât ții poziția? Două descrieri, același nume +fișierul principal vs. sfatul din Q&A pentru calificarea pe prop +Aceeași axă de timp pentru ambele bare (0 → 1 an); fără axe de preț. + + + + + + + +0 + +3 luni + +6 luni + +9 luni + +~1 an +ATMI clasică — fișierul principal + +„fără stop-loss, poziția ținută luni/ani” + +TP1 atins — aproximativ un an mai târziu +Sursă: 04_MODUL_3/03_strategia_2_atmi.md:26-29; :358-363 +ATMI ca adaptare pentru prop — Q&A 11.06.2025 + + + +2 săptămâni + +„aștepți o corecție și intri pe ATMI la suport quarterly, +swing, 2 săptămâni în poziție” +„Ai nevoie de 3 transacții să califici propul.” +Sursă: 09_QA/26_2025-06-11.md:225-227 + +Anotare separată — mecanismul care face diferența +Pe prop, limita zilnică se calculează și pe pozițiile deschise, +iar la atingere firma închide automat poziția. +Sursă: 09_QA/26_2025-06-11.md:216-222 +Notă: cele două descrieri nu se rezolvă aici — de clarificat cu autorul. +Fără axe de preț și fără să alegem una dintre variante. +Bara de 2 săptămâni e scurtă exact pentru că atât ține, pe aceeași scară. + 2. **Aritmetica contribuției vs. backtest.** Fișierul principal recomandă „1 unitate SPY per trimestru (~600 $) ... ~1.200 $/an", ajustabil 0.2-0.5 @@ -353,7 +635,137 @@ aproximativ un an mai târziu** (`04_MODUL_3/03_strategia_2_atmi.md:358-363`). > PPQ/SQ intermediate nu sunt date de curs. Structura barelor dintre nivele > e construită de mine; cifrele de intrare/țintă sunt ale materialului. - + + SPY — weekly: intrare 117.43 (27.01.2005) → TP +10 % = 129.17 + + intrare 117.43 + + TP1 129.17 (+10 %) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + swing high ~123.00 + BIM + 27.01.2005 + TP1 + după TP: capital + profit → cash până la următorul trigger valid + TP1 atins ~1 an mai târziu (data exactă neclară în transcriere — ASR) + Swing high ~123.00 construit de mine; cifrele de intrare/TP sunt din material. + 1. **Context:** indicele lat (SPY) corectează ≥4 % de la swing-ul recent, în zona quarterly — condiția M (`04_MODUL_3/03_strategia_2_atmi.md:153-154`). diff --git a/strategii/06_hammer_mbt10.md b/strategii/06_hammer_mbt10.md index 294d760..bc8f2d0 100644 --- a/strategii/06_hammer_mbt10.md +++ b/strategii/06_hammer_mbt10.md @@ -59,7 +59,54 @@ materialul nu dă un prag scrie explicit. > Contradicțiile din fișă sunt împărțite în cele două secțiuni 2.4: cele două > care ating hammer-ul în Partea A, restul de patru în Partea B. - + + + +Același trigger de bottom, două naturi +buy hammer (public) vs. MBT-10 (cutie neagră) + +Trigger de bottom: unde + când +Setup-urile de fond — suport, locul crimei, double bottom, buy doji, +divergență de volum — spun UNDE. Trigger-ul de candelă spune CÂND. +02_mbt10.md:9-11, 43-49 + + + + + +BUY HAMMER — pattern standard + +„formă de candelă + downtrend” +05_patternuri_candele.md:77-88 +„trigger: close peste +high-ul hammer-ului” +05_patternuri_candele.md:99-124 +„fără niciun indicator proprietar” + +„pe BVB: se poate rula long-only” + +MBT-10 — cutie neagră + +„formula nu e publică nicăieri” +02_mbt10.md:21-39 +„reconstituibil doar: +close peste pivotul daily” +02_mbt10.md:179-188 +„scanner + indicator proprietar” +02_mbt10.md:853-863 + +„pe BVB: nu, ca sistem” + + + + + + +Ce rămâne pe BVB: hammer la un nivel major ++ close peste PPD +Regulile = materialul cursului (cu trimiteri); verdictul de BVB = judecata mea +din secțiunea Transfer. + --- @@ -91,7 +138,121 @@ pattern-ul nu se ia singur — se ia la un nivel major #### Diagrama de ansamblu - + + Buy hammer — daily (ticker ilustrativ XYZ, din lecția de pattern) + + SL 62.05 — sub low-ul hammer-ului + + intrare 63.35 + + TP 65.95 = 2R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + hammer 63.30 / 62.10 + bara 20: confirmare — close 63.35 peste high-ul hammer-ului 63.30 (intrare) +Exemplu ilustrativ (XYZ) din lecția de pattern (01_MODUL_1/05_patternuri_candele.md:210-215);prețurile sunt cele ale lecției, structura barelor dintre ele e construită. Graficul întreg al trade-ului: downtrend → hammer la un nivel → candela de confirmare închide peste high-ul lui (intrare) → SL sub low-ul hammer-ului → @@ -248,7 +409,145 @@ Lecția de hammer dă exemplul complet: 2 % dintr-un cont de **10.000 $** = Amândouă au aceeași formă de candelă; le separă contextul. Diagrama le pune alături. - +Buy hammer A+ vs. mediocru (două panouri, exemple construite) + A+ — hammer la suport monthly, volum în acumulare + + suport monthly 42.00 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + hammer la nivel (low 41.90) + acumulare + bara 13: 42.95 > high 42.90, pe volum peste medie. + + Mediocru — hammer în mijloc de range, fără nivel + + fără nivel apropiat (suport 42.50 la −3,6 %) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + hammer în mijloc de range + volum slab + bara 13: 45.15 > 45.10, dar pe volum slab. +Reguli din curs: 26_2025-06-11.md:701-703 (locația la nivel), 05_patternuri_candele.md:77-80, 05_volum.md:2169.Nivelurile 42.00 / 42.50 și cifrele de preț sunt construite (materialul nu dă prețuri pentru acest contrast). | | **A+** | **Mediocru / NU** | |---|---|---| @@ -314,7 +613,139 @@ prețuri de intrare diferite. > suportul monthly, **+20 % în jumătate de lună** (`18_2025-09-23.md:721-726`). > **Materialul nu dă entry, SL sau TP** pentru acest caz. - + + LABU — daily + + suport monthly 80.00 + + SL sub low-ul hammer-ului 79.60 (construit) + + intrare 81.30 (construit) + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + hammer 80.90 / 79.60 (construit) + +20 % (cifra cursului): 97.56 / 81.30 + bara 23 = hammer: o 80.80, h 80.90, l 79.60, c 80.90 — corp 0.10, fitil jos 1.20 (H=C), pe suportul 80.00 + bara 24 = confirmare: close 81.30 — close peste high-ul hammer-ului 80.90 = intrare 81.30 (construit) + Procentul (+20 % în jumătate de lună) și contextul (suport monthly) sunt ale cursului (18_2025-09-23.md:721-726); + nivelurile de preț sunt construite de sumarizator. + 1. **Context:** downtrend → suport monthly, unde prețul se oprește (`18_2025-09-23.md:721-726`). @@ -360,7 +791,148 @@ asta rămâne: o regulă de close peste pivot, fără indicator. #### Diagrama de ansamblu - + + MBT-10 — pullback în locul crimei + hammer, închidere la 54.60 (exemplu construit) + + locul crimei 52.10 (fost vârf spart) + + SL 52.00 — sub codița hammer-ului + + intrare 54.60 (close în MBT-10) + + TP 58.90 = 1.65R + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + hammer — codița pe 52.10 + MBT-10 închis + Legendă: MBT-10 nu se desenează — formula nu e publică (02_mbt10.md:21-39); se marchează doar bara la care + semnalul s-a închis. Nivelurile sunt exemplul construit al sumarizatorului (02_mbt10.md:165-173, 978-984). + bara 9 = fostul vârf 52.10 (locul crimei); bara 21 = vârful nou 58.90. + bara 29 = hammer: o 52.20, h/c 53.40, l 52.10 (codița exact pe locul crimei); bara 30 = ziua închisă în MBT-10. + Graficul întreg al trade-ului: uptrend, fost vârf spart, pullback în locul crimei cu hammer pe 52.10, ziua următoare se închide în MBT-10 la 54.60 @@ -543,7 +1115,124 @@ aceeași, fiindcă nu se vede), ci contextul din jur. `03_2026-08-11.md:146-152`, `173-178`). Diagrama arată de ce: #1 și #2 au **același risc în bani**, iar #2 singur acoperă pierderea de la #1. - + + După gap down — primul MBT-10 te scoate, al doilea merge (exemplu construit) + + #1 intrare 64.80 + + #1 SL 63.20 + + #2 intrare 62.20 + + #2 SL 60.40 + + TP 70.60 = 4.7R (gap închis) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + gap down + MBT-10 #1 + stop #1 atins + MBT-10 #2 +MBT-10 #1: intrare 64.80 / SL 63.20 — risc 1R în baniMBT-10 #2: intrare 62.20 / SL 60.40 — risc 1R în bani (mărime ajustată)Exemplu construit (02_mbt10.md:728-734): #1 și #2 au același risc în bani; #2 singur dă 4.7R.De aceea mărimea se împarte pe 2-3 încercări. 3. **Scannerul nu e listă de cumpărături.** Fără suport, volum și pattern de bottom, MBT-10 e doar un semnal pe o bară oarecare @@ -620,7 +1309,65 @@ peste pivotul daily", cu edge mult mai slab. Nu inventa o formulă. > **Ce lipsește:** materialul **nu dă SL-ul** acestui exemplu. Axa de preț > din diagramă e construită pe cifrele reale, nu citită din curs. - + + Tesla — daily: trigger MBT-10, intrare 311.21 → 333.00 = +7.0 % în 6 zile + + intrare 311.21 (close) + + rezultat 333.00 = +7.0 % în 6 zile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + trigger MBT-10 + exact 6 bare +Cifrele 311.21 / 333.00 / +7.0 % sunt reale (03_2026-08-11.md:118-120);structura barelor dintre ele e construită.SL: materialul nu îl dă pentru acest exemplu. 1. **Context:** cădere anterioară, apoi trigger MBT-10 pe daily. 2. **Intrare:** la închiderea zilei, **311.21** (`03_2026-08-11.md:118-119`). diff --git a/strategii/07_mdsrt.md b/strategii/07_mdsrt.md index 349b88c..b9999ab 100644 --- a/strategii/07_mdsrt.md +++ b/strategii/07_mdsrt.md @@ -99,7 +99,115 @@ Q&A, risc 2.50 → 5R pe pullback vs. risc 9.50 → 0.6R pe breakout ### Diagrama de ansamblu - + + SPY — 5 min (exemplu construit pe scara lecției; + cifrele planului nu vin din curs) + + suport / pivot 590.00 + + SL 589.40 — risc 0.80 + + TP1 591.00 = 1:1 + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + minim 589.80 — divergență (M) + intrare 590.20 + ieșire trail 592.40 + Legendă: entry/SL/TP/trail sunt exemplul construit al autorului sumarului, + nu citate din curs (transcrierea se întrerupe înainte de planul numeric). + Graficul întreg al trade-ului: downtrend cu candele mixte → al doilea picior mai jos, la 589.80 sub suportul/pivotul 590.00 → divergență bull (M) → Buy @@ -179,7 +287,42 @@ Filtrul fundamental e **NEACOPERIT ÎN MATERIAL** pentru MDSRT. 7. **Abia apoi aștepți trigger-ul** (A). Divergența singură nu e intrare (`05_MODUL_4/02_strategia_5_mdsrt.md:27-32`). - + + + +Divergența: cum o măsori corect +Aceeași structură pe preț și pe indicator: două swing low-uri, două minime + +PREȚ (schematic) — downtrend, lower low + + + +maxim 60 de candele în spate + + + + +L1 +L2 + + + +minim 5 candele între puncte + + +NU +2-3 candele +NU e divergență + +INDICATOR (Power / volum / RS) — higher low + + + +I1 +I2 +Prețul face un lower low (L2 sub L1), indicatorul face un higher low (I2 peste I1): +divergență bull. Dar dacă al doilea punct e la doar 2-3 candele, nu se numără. + ### 1.3 Trigger @@ -282,7 +425,36 @@ confirmat" numără **surse distincte** din fișă, nu loturi de triaj. | 7 | **Nu intri pe breakout, intri pe pullback** | Aceeași țintă cu risc mult mai mic (risc 2.50 → 5R vs. risc 9.50 → 0.6R) | **1 sursă** (Q&A, dar argument explicit) | `09_QA/15_2025-10-14.md:125-127` | | 8 | **Primele semnale sunt cele bune statistic** | Al doilea semnal e permis, dar primul are statistica mai bună | **1 sursă** | `09_QA/01_2026-08-25.md:272-275` | - + + + + + + + + +MDSRT — minimul obligatoriu vs. Trinity +Minim Power + unul din ceilalți e obligatoriu; toți trei în divergență = Trinity. +Minimul obligatoriu (M complet) +Power (obligatoriu) +Volume SAU Relative Strength +— oricare una +Power lipsește → setup-ul NU se califică +Trinity (opțional, semnal mai puternic) +Power (obligatoriu) +divergență +Volume +divergență +Relative Strength +divergență +toți trei în divergență simultan, pe aceeași zonă de preț +comparat în curs cu un «setup de 5 stele» +La MDSRT, „Trinity” se folosește local cu sensul „toți trei în divergență”. +Lecția de selecție dă aceluiași cuvânt alt sens: +aliniere în cadranul 1, nu divergență (contradicția 2.4). +Sursa: 05_MODUL_4/02_strategia_5_mdsrt.md:6-8, 34-42, 59-61, 85-88; +08_ANALIZA_ZILNICA/11_selectia_simbolului.md:612-627. + ### 2.2 Setup A+ vs. setup mediocru @@ -362,7 +534,119 @@ Nu aleg eu între variante. Pentru fiecare: ce spune fiecare sursă și ce (`09_QA/24_2025-07-15.md:12-14, 26-29, 121-128`). Singurul exemplu real, cu niveluri citite din transcriere. - + + SPY — 5 min (Q&A 15.07.2025; intrare/SL/TP construite) + + pivot daily 622.00 + + SL 621.30 (construit) + + intrare 622.60 (construit) + + TP1 623.90 = 1:1 (construit) + + picior 1 = 622.40 + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + volum + picior 1 = 622.40 + picior 2 = 621.40 (mai jos) · Buy Hammer + hammer închide 622.60, înapoi peste pivot + Legendă: nivelurile 622.40 / 622.00 / 621.40 / 622.60 și cele 8 candele dintre + picioare sunt reale, din curs. Intrarea 622.60, SL-ul 621.30 și TP-ul 623.90 + sunt construcția mea — materialul nu le dă. + Ce e **real, din curs**: diff --git a/strategii/08_mbp.md b/strategii/08_mbp.md index e5685fc..f91669a 100644 --- a/strategii/08_mbp.md +++ b/strategii/08_mbp.md @@ -91,7 +91,101 @@ backtesting-urile, nu am găsit nimic pe TICSP. Și atunci folosesc TICUS-ul.", ### Diagrama de ansamblu - + + + 623.90 — bandă inferioară + + 624.70 — bandă superioară + + 624.30 — SMA20 / TP1 + + SL 623.60 (lowest low, 4 candele) + + trigger Buy Momentum → intrare 623.95 + + ieșire ilustrativă ~625.35 (≈ 1:4) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + M: roșie, close 623.87 sub bandă + SPY — 15 min: bandă + TICUS pe aceeași candelă → trigger → intrare → SL → TP1 → trail + trend descendent anterior (14 bare) + + TICUS — presiunea pieței (↑ = peste 0) + + +1000 — supracumpărare + + +500 (doar referință vizuală) + + 0 + + -500 (doar referință vizuală) + + -1000 — oversold + + M: TICUS -1150 (sub -1000) + SPY 15 min. Cifre din curs: M close 623.87 (sub bandă 623.90), TICUS -1150 pe aceeași candelă, + trigger Buy Momentum → entry 623.95, SL 623.60 (lowest low din 4 candele, trigger inclus), + TP1 624.30 (+0.35, 1:1). Ieșirea ~625.35 = entry + 4R (≈1:4) e ilustrativă — preț derivat din R, + nu din curs. Structura candelelor (30 bare continue) e construită de mine. + Graficul întreg al trade-ului din exemplul long al cursului: downtrend, candela „M" roșie care închide la **623.87** sub banda inferioară **623.90**, TICUS @@ -205,7 +299,84 @@ iar trigger-ul fin poate veni din **M2D 15/80 secunde** | **NU — prea devreme** | M e îndeplinit, dar candelele următoare rămân roșii/plate, fără buy momentum/doji/hammer → **nu intri** | close **623.85**, TICUS **-1200** pe candelă (condiție OK), apoi fără trigger (`05_MODUL_4/03_strategia_6_mbp_mbappe.md:351-420`) | | **NU — invalidat** | Banda și TICUS **nu sunt pe aceeași candelă** (TICUS extrem pe o candelă vecină) → M neîndeplinit | diagramele DA/NU din `05_MODUL_4/03_strategia_6_mbp_mbappe.md:179-221` | - + + + bandă 623.90 + + + + + + + + + + + + + + + + + + + + + + TICUS + +1000 (prag) + +500 + 0 + -500 + -1000 (prag) + + M: TICUS -1150 (sub -1000) + M: close 623.87 < bandă 623.90 + + bandă 623.90 + + + + + + + + + + + + + + + + + + + + + + + TICUS + +1000 (prag) + +500 + 0 + -500 + -1000 (prag) + + + TICUS(m-1) = -1200 (extrem) + TICUS(M) = -600 (nu atinge -1000) + M: close 623.87 < bandă 623.90 + DA — aceeași candelă, M îndeplinit + NU — TICUS extrem pe altă candelă, + M neîndeplinit + Regula: banda (close sub 623.90) și TICUS ≤ -1000 trebuie pe ACEEAȘI candelă. + Pragurile TICUS sunt ±1000 (overbought / oversold); ±500 sunt doar referință vizuală. + Verificarea se face prin click pe candelă, nu din ochi — TICUS(M) se citește exact pe candela M. + DA: TICUS(M) = -1150 (exemplul real din curs). + NU: TICUS(M) = -600, TICUS(m-1) = -1200 — cifre construite de mine ca ilustrare. + Structura candelelor (10 bare de 15 min, aceeași în ambele panouri) e construită de mine. + Regulă practică din curs: **nu te uita „din ochi"** dacă închiderea e dincolo de bandă sau dacă TICUS a trecut pragul — click pe candelă și citește valoarea @@ -471,7 +642,107 @@ Singurul exemplu cu toate nivelurile luate din fișierul principal: **Short real, 25.11.2025** (`09_QA/11_2025-11-25.md:557-648`) — singurul trade complet, cu rezultat, din material: - + + + SPY — 15 min: MBAP short 25.11.2025 (risc 0.41 % → ieșire 4.9R) + + SL 662.71 (risc 0.41 %) + + intrare short 660.00 + + bandă superioară (schematic) + + TP1 657.29 (1:1) + + ieșire trail 646.80 = 2 % = ~4.9R + + SMA-20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + M: candelă verde peste bandă + TICUS ≥ +1000 + M: valori exacte NEACOPERIT în material (bandă + TICUS); bara ~+1000 din panou e ilustrativă + trigger Sell Momentum → intrare short 660.00 (risc 0.41 % = 2.71) + TP1 657.29 (1:1) atins în prima candelă după intrare + ieșire pe trail 646.80 = 2 % = ~4.9R, după 7 candele de 15 min de la intrare + + Panou TICUS — linia 0 și pragul +1000 (ilustrativ) + + +1000 (prag) + + 0 + + ilustrativ + candela M + Legendă: procentele (risc 0.41 %, ieșire 2 %) sunt ale instructorului. + Prețurile absolute (660.00 / 662.71 / 657.29 / 646.80) sunt construite de sumarizator — + 09_QA/11_2025-11-25.md:716-719. + Structura de reținut: risc mic → TP1 (1:1) atins imediat → trail lung (7 candele de 15 min). + Valoarea exactă a benzii și a TICUS la candela M nu e dată în sesiune; bara ~+1000 e ilustrativă. + „Taurii urcă pe scări, urșii sar de la etaj" — de ce short-ul se consumă în ore. + (09_QA/11_2025-11-25.md:643-648). + - Intrare short **660.00**, SL **662.71** (risc **0.41 %**), TP1 **657.29** (1:1) atins în prima candelă; trail până la ieșirea la **646.80** = **2 % =