From 3a176253ab201eb6cca8b3eb35ebee68ed442744 Mon Sep 17 00:00:00 2001 From: Marius Date: Wed, 13 May 2026 19:23:58 +0300 Subject: [PATCH] =?UTF-8?q?dashboard:=20hint-uri=20mai=20simple=20cu=20cif?= =?UTF-8?q?re=20concrete=20+=20Win=20Ratio=20l=C3=A2ng=C4=83=20R:R?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Glosar separat eliminat — toate explicațiile sunt acum în coloana G de lângă fiecare metrică - Win Ratio mutat lângă R:R (rândul 12-13) ca să se citească împreună - Hint-uri rescrise în limbaj simplu cu exemple în dolari (fără jargon, fără emoji-uri) - Coloana G lățită la 75, înălțime rânduri 75 pentru text multi-line - Titluri Config + Dashboard fără emoji-uri Co-Authored-By: Claude Opus 4.7 --- data/backtest.xlsx | Bin 226759 -> 226915 bytes scripts/generate_template.py | 154 +++++++++++++++++------------------ 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/data/backtest.xlsx b/data/backtest.xlsx index 5240a82037b0bdac73e9b9ca31ff1495268e9f41..a1521bbf986037d6a42e6c03150817531de63aa0 100644 GIT binary patch delta 7526 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 delta 7396 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 J*FONL{{a{iv|j)K diff --git a/scripts/generate_template.py b/scripts/generate_template.py index e513cb6..1d6bd3d 100644 --- a/scripts/generate_template.py +++ b/scripts/generate_template.py @@ -114,7 +114,7 @@ def build_config(wb: Workbook) -> None: ws = wb.create_sheet("Config", 0) ws.sheet_view.showGridLines = False - ws["A1"] = "📋 Config — editează doar celulele galbene" + ws["A1"] = "Config — editează doar celulele galbene" ws["A1"].font = TITLE_FONT ws.merge_cells("A1:C1") @@ -448,20 +448,72 @@ def _range(col_name: str) -> str: METRIC_HINTS: dict[str, str] = { - "Trades Placed": "Numărul total de trade-uri logate", - "Wins": "Trade-uri cu R > 0", - "Win Ratio": "% wins. Singur NU spune mult — vezi împreună cu R:R și Expectancy", - "Average Win ($)": "Câștigul mediu pe trade winning", - "Average Loss ($)": "Pierderea medie pe trade losing", - "Best Trade ($)": "Cel mai mare câștig individual", - "Worst Trade ($)": "Cea mai mare pierdere individuală", - "Profit Factor": ">1.0 profitabil • >1.5 solid • >2.0 foarte bun • <1.0 pierzător", - "Risk:Reward": "Avg Win ÷ |Avg Loss|. >1 = câștig mediu > pierdere medie", - "Expectancy (R)": "★ STEAUA NORDULUI ★ >+0.20R = GO LIVE • negativ = ABANDON", - "Expectancy ($)": "Expectancy R convertit în $ (folosește Risk per Trade)", - "Cumulative P&L ($)": "P&L total în $ pe toate trade-urile", - "HWM Balance ($)": "Highest watermark — balanța de vârf atinsă", - "Max Drawdown ($)": "Cea mai mare cădere ($) din vârf la fund", + "Trades Placed": ( + "Câte trade-uri ai logat în total.\n" + "Cu cât N e mai mare, cu atât celelalte metrici sunt mai de încredere.\n" + "Exemplu: la N=10 Win Ratio e zgomot pur, la N=40 începe să aibă semnal, la N=100 e solid." + ), + "Wins": ( + "Câte trade-uri s-au închis pe plus (R > 0).\n" + "Singur nu spune nimic — privește-l raportat la total (vezi Win Ratio mai jos)." + ), + "Win Ratio": ( + "Procentul de trade-uri câștigătoare. WR = 60% înseamnă 6 wins din 10 trade-uri.\n" + "Singur NU spune dacă strategia e profitabilă — citește-l împreună cu R:R de pe rândul următor." + ), + "Average Win ($)": ( + "Câștigul mediu pe trade-urile pozitive.\n" + "Comparat cu Average Loss îți spune cât de mari sunt câștigurile vs pierderile.\n" + "Exemplu: 4 wins de $50 și 2 wins de $80 — Average Win = $60." + ), + "Average Loss ($)": ( + "Pierderea medie pe trade-urile negative (cifra apare cu minus).\n" + "Cu Risk per Trade fix, ar trebui să fie aproape de −1R în dolari.\n" + "Dacă e mult mai mare decât Risk per Trade, ai SL-uri sărite (slippage, gap-uri)." + ), + "Best Trade ($)": ( + "Cel mai mare câștig individual.\n" + "Dacă majoritatea profitului total vine dintr-un singur trade outlier, edge-ul e fragil — " + "elimini acel trade și strategia devine pierzătoare." + ), + "Worst Trade ($)": ( + "Cea mai mare pierdere individuală.\n" + "Ar trebui să fie aproximativ egală cu −1R (Risk per Trade din Config).\n" + "Dacă e semnificativ mai mare, ai depășit risk-ul plănuit — SL ratat, slippage, gap overnight." + ), + "Profit Factor": ( + "Total bani câștigați împărțit la total bani pierduți (în valoare absolută).\n" + "Sub 1.0 = pierzi pe ansamblu. Peste 1.5 = solid. Peste 2.0 = câștigi de 2× cât pierzi.\n" + "Exemplu: 4 wins de $50 (= $200) + 6 losses de $30 (= $180) — PF = 200÷180 = 1.11, profitabil marginal." + ), + "Risk:Reward": ( + "De câte ori e mai mare câștigul mediu decât pierderea medie.\n" + "R:R = 2 înseamnă: când câștigi, câștigi $2; când pierzi, pierzi $1.\n" + "Cu R:R mare poți avea Win Ratio mic și tot să faci bani." + ), + "Expectancy (R)": ( + "Cât bani câștigi în medie pe UN trade (în R; 1R = Risk per Trade, default $100).\n" + "+0.30R = câștigi $30 pe trade. Pe 100 trade-uri: +$3.000.\n" + "−0.10R = pierzi $10 pe trade. Pe 100 trade-uri: −$1.000.\n" + "Pragul de GO LIVE: +0.20R sau mai mult." + ), + "Expectancy ($)": ( + "Aceeași expectancy convertită în dolari, folosind Risk per Trade din Config.\n" + "Util ca să vezi cât câștigi în medie pe trade în bani reali, nu doar în R." + ), + "Cumulative P&L ($)": ( + "Suma profitului și pierderii pe toate trade-urile logate.\n" + "E ce-ai avea în plus (sau minus) față de balanța de start din Config." + ), + "HWM Balance ($)": ( + "Highest Watermark — cea mai mare balanță atinsă vreodată în jurnal.\n" + "Punct de referință pentru calculul drawdown-ului." + ), + "Max Drawdown ($)": ( + "Cea mai mare cădere ($) din vârf la fundul ulterior al balanței. Măsoară durerea psihologică maximă.\n" + "Exemplu: ai urcat la $11,500, ai coborât la $9,800 — DD = $1,700, adică 17% din peak.\n" + "Un drawdown mare la backtest e foarte greu de tolerat în live cu bani reali — așteaptă-te să renunți." + ), } @@ -469,7 +521,7 @@ def build_dashboard(wb: Workbook) -> None: ws = wb.create_sheet("Dashboard", 2) ws.sheet_view.showGridLines = False - ws["A1"] = "📊 Backtest Dashboard" + ws["A1"] = "Backtest Dashboard" ws["A1"].font = TITLE_FONT ws.merge_cells("A1:G1") @@ -507,13 +559,13 @@ def build_dashboard(wb: Workbook) -> None: # (label, fn(strat_key) -> formula, number_format) ("Trades Placed", lambda s: f'=COUNTA({OUTCOME_RANGE})', "0"), ("Wins", lambda s: f'=COUNTIF({W[s]},1)', "0"), - # Win Ratio: depends on rows above — handled after metrics list (placeholder) - ("Win Ratio", lambda s: None, "0.0%"), ("Average Win ($)", lambda s: f'=IFERROR(AVERAGEIF({D[s]},">0"),0)', '"$"#,##0.00'), ("Average Loss ($)", lambda s: f'=IFERROR(AVERAGEIF({D[s]},"<0"),0)', '"$"#,##0.00'), ("Best Trade ($)", lambda s: f'=IFERROR(MAX({D[s]}),0)', '"$"#,##0.00'), ("Worst Trade ($)", lambda s: f'=IFERROR(MIN({D[s]}),0)', '"$"#,##0.00'), ("Profit Factor", lambda s: f'=IFERROR(SUMIF({D[s]},">0")/ABS(SUMIF({D[s]},"<0")),0)', "0.00"), + # Win Ratio: depends on Wins + Trades Placed — handled after metrics list (placeholder) + ("Win Ratio", lambda s: None, "0.0%"), # Risk:Reward — placeholder; bazat pe rândurile Avg Win/Loss ("Risk:Reward", lambda s: None, "0.00"), ("Expectancy (R)", lambda s: f'=IFERROR(AVERAGE({R[s]}),0)', "+0.000;-0.000;0.000"), @@ -555,65 +607,13 @@ def build_dashboard(wb: Workbook) -> None: cell.fill = DERIVED_FILL cell.border = BORDER cell.alignment = RIGHT - # Coloana G — interpretare scurtă + # Coloana G — interpretare narativă + exemplu numeric hint_cell = ws[f"G{r}"] hint_cell.value = METRIC_HINTS.get(label, "") - hint_cell.font = Font(name="Calibri", size=10, italic=True, color="595959") - hint_cell.alignment = Alignment(horizontal="left", vertical="center", wrap_text=True) + hint_cell.font = Font(name="Calibri", size=10, color="595959") + hint_cell.alignment = Alignment(horizontal="left", vertical="top", wrap_text=True) hint_cell.border = BORDER - # ---- Glosar section: exemple concrete pentru metricile-cheie ---- - glosar_start = 5 + len(metrics) + 2 # 2 rânduri spațiu după metrici - ws[f"A{glosar_start}"] = "📖 Glosar metrici — exemple concrete" - ws[f"A{glosar_start}"].font = SUBTITLE_FONT - ws.merge_cells(f"A{glosar_start}:G{glosar_start}") - - glosar_entries = [ - ( - "Profit Factor", - "Suma câștigurilor ÷ |suma pierderilor|. Total cumulativ, nu mediu.", - "10 trade-uri: 4 wins de $50 (=$200) + 6 losses de −$30 (=−$180). PF = 200÷180 = 1.11 (marginal profitabil). La PF=2.0 câștigi de 2× cât pierzi în total.", - ), - ( - "Risk:Reward", - "Avg Win ÷ |Avg Loss|. Privește per-trade, nu total.", - "Avg win $50, avg loss −$30 → R:R = 1.67. La R:R=2.0 ești profitabil chiar cu Win Ratio doar 40%. La R:R=0.5 ai nevoie de WR >67%.", - ), - ( - "Expectancy (R)", - "Câștigul mediu per trade exprimat în multipli de risc (R). CEA MAI ONESTĂ metrică — combină WR și R:R într-un singur număr.", - "10 trade-uri cu R = [+0.5, +0.5, +0.5, +0.5, −1, −1, −1, −1, −1, −1] → media = −0.30R (pierdere) chiar dacă WR=40%. Pragul GO LIVE din STOPPING_RULE.md: ≥ +0.20R.", - ), - ( - "Win Ratio (WR)", - "% trade-uri cu R > 0. ÎNȘELĂTOR singur — un WR mare cu R:R mic poate fi pierzător.", - "WR=70% pare excelent, dar dacă R:R=0.3 (câștigi $30, pierzi $100) → Expectancy = 0.7·30 − 0.3·100 = −$9 per trade. Pierzător.", - ), - ( - "Max Drawdown", - "Cea mai mare cădere din vârful balanței la fundul ulterior. Măsoară 'durerea psihologică'.", - "Balance peak $11,500 → fund $9,800 → DD = $1,700 (17% din peak). DD mare la backtest = greu de tolerat în live.", - ), - ] - - row = glosar_start + 1 - for term, definition, example in glosar_entries: - ws[f"A{row}"] = term - ws[f"A{row}"].font = Font(name="Calibri", size=11, bold=True, color="1F3864") - ws[f"A{row}"].alignment = Alignment(horizontal="left", vertical="top", wrap_text=True) - ws[f"B{row}"] = definition - ws[f"B{row}"].font = Font(name="Calibri", size=10) - ws[f"B{row}"].alignment = Alignment(horizontal="left", vertical="top", wrap_text=True) - ws.merge_cells(f"B{row}:C{row}") - ws[f"D{row}"] = f"Exemplu: {example}" - ws[f"D{row}"].font = Font(name="Calibri", size=10, italic=True, color="595959") - ws[f"D{row}"].alignment = Alignment(horizontal="left", vertical="top", wrap_text=True) - ws.merge_cells(f"D{row}:G{row}") - ws.row_dimensions[row].height = 48 - row += 1 - - glosar_end = row # primul rând după glosar - # Helper pentru a emite un block breakdown (per Sesiune / Strategie / etc.) def _emit_breakdown( start_row: int, title: str, first_col_label: str, @@ -651,7 +651,7 @@ def build_dashboard(wb: Workbook) -> None: # Breakdowns — toate folosesc overlay-ul Hybrid+BE (recomandat de trader) overlay = "hybrid_be" - start = glosar_end + 2 # 2 rânduri spațiu după glosar + start = 5 + len(metrics) + 2 # 2 rânduri spațiu după tabelul de metrici after_sess = _emit_breakdown( start, "PER SESIUNE (overlay: Hybrid + BE)", "Sesiune", SESSIONS, _range("Sesiune"), overlay, @@ -670,13 +670,13 @@ def build_dashboard(wb: Workbook) -> None: ) # Column widths - widths = {"A": 22, "B": 14, "C": 14, "D": 14, "E": 16, "F": 16, "G": 50} + widths = {"A": 22, "B": 14, "C": 14, "D": 14, "E": 16, "F": 16, "G": 75} for col, w in widths.items(): ws.column_dimensions[col].width = w - # Row height pentru rândurile cu hint (cu wrap) + # Row height pentru rândurile cu hint (cu wrap) — explicații multi-line for r in range(5, 5 + len(metrics)): - ws.row_dimensions[r].height = 22 + ws.row_dimensions[r].height = 75 # Equity curve chart — 5 linii chart = LineChart()