dashboard: hint-uri mai simple cu cifre concrete + Win Ratio lângă R:R

- 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 <noreply@anthropic.com>
This commit is contained in:
Marius
2026-05-13 19:23:58 +03:00
parent 017921794e
commit 3a176253ab
2 changed files with 77 additions and 77 deletions

Binary file not shown.

View File

@@ -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()