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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user