tranzactii

This commit is contained in:
Marius
2026-05-29 03:35:36 +03:00
parent f269eda6df
commit e3d21bddf1
3 changed files with 235 additions and 60 deletions

View File

@@ -189,22 +189,31 @@ def build_config(wb: Workbook) -> None:
ws["B5"].number_format = '0.0"%"'
ws["B6"].number_format = "$#,##0.00"
# ---- Bloc Cont Prop Firm (separat de modelul abstract de mai sus) ----
ws["A8"] = "Cont Prop Firm"
# ---- Bloc Cont real TradeLocker / Prop Firm ----
# Lanț de calcul transparent: Lot size -> $/punct -> $ risc la 1% mișcare preț.
# Toate coloanele $ din Trades folosesc B10*B11 (= $ risc la 1% preț pe poziția ta).
# Scalare la 100k: schimbi B9 (Account) și B10 (Lot size) — restul se recalculează.
ws["A8"] = "Cont real TradeLocker (prop firm)"
ws["A8"].font = SUBTITLE_FONT
ws.merge_cells("A8:C8")
ws["A9"] = "Account Prop Start ($)"
ws["A9"] = "Account Start ($)"
ws["B9"] = 50000
ws["C9"] = "Balanța contului de prop"
ws["C9"] = "Balanța contului. Schimbă în 100000 pentru un cont de 100k."
ws["A10"] = "Contracte per trade"
ws["B10"] = 1
ws["C10"] = "Număr de contracte tranzacționate per semnal (TradeLocker)"
ws["A10"] = "Lot size per semnal (US30)"
ws["B10"] = 0.08
ws["C10"] = (
"Câte loturi US30 intri pe fiecare semnal (TradeLocker). "
"Pe 100k cu același risc %: 0.16."
)
ws["A11"] = "$ per 1% per contract"
ws["B11"] = 10000
ws["C11"] = "Pe DIA: 0.10% = $1000 ⇒ 1% = $10,000 (1 contract notional ≈ $1M)"
ws["A11"] = "$ per 1% preț, la 1.0 lot"
ws["B11"] = "=B24*B25/100"
ws["C11"] = (
"Auto = ($/punct la 1 lot, B24) × (Preț reper, B25 / 100). "
"Înmulțit cu Lot size (B10) dă riscul real per 1% — vezi B27."
)
ws["A12"] = "Daily Loss Limit (%)"
ws["B12"] = 4.0
@@ -212,7 +221,7 @@ def build_config(wb: Workbook) -> None:
ws["A13"] = "Daily Loss Limit ($)"
ws["B13"] = "=B9*B12/100"
ws["C13"] = "Auto — derivat din B9 și B12"
ws["C13"] = "Auto — derivat din Account Start (B9) și %"
ws["A14"] = "Max Loss Limit (%)"
ws["B14"] = 7.0
@@ -220,22 +229,7 @@ def build_config(wb: Workbook) -> None:
ws["A15"] = "Max Loss Limit ($)"
ws["B15"] = "=B9*B14/100"
ws["C15"] = "Auto — derivat din B9 și B14"
for r in (9, 10, 11, 12, 14): # inputuri galbene
ws.cell(row=r, column=2).fill = INPUT_FILL
ws.cell(row=r, column=2).border = BORDER
for r in (13, 15): # derived blue
ws.cell(row=r, column=2).fill = DERIVED_FILL
ws.cell(row=r, column=2).border = BORDER
ws["B9"].number_format = "$#,##0"
ws["B10"].number_format = "0"
ws["B11"].number_format = "$#,##0"
ws["B12"].number_format = '0.0"%"'
ws["B13"].number_format = "$#,##0"
ws["B14"].number_format = '0.0"%"'
ws["B15"].number_format = "$#,##0"
ws["C15"] = "Auto — derivat din Account Start (B9) și %"
# Escape hatch performanță: activează/dezactivează filtrul Prima per Indicator
ws["A17"] = "Activează filtru Prima"
@@ -253,6 +247,179 @@ def build_config(wb: Workbook) -> None:
dv_prima.add("B17")
ws.add_data_validation(dv_prima)
# ---- Calibrare $/punct dintr-un ordin reper + derivate informative ----
# Helper universal: dintr-un singur ordin TradeLocker (orice indicator) derivi
# $/punct, apoi $/1% preț. Pentru alt indicator schimbi cele 4 inputuri reper
# (B19-B22) + Preț reper curent (B25). Restul se recalculează singur.
ws["A18"] = "— Calibrare $/punct (dintr-un ordin reper TradeLocker) —"
ws["A18"].font = Font(name="Calibri", size=10, italic=True, bold=True, color="1F3864")
ws.merge_cells("A18:C18")
ws["A19"] = "Preț entry (ordin reper)"
ws["B19"] = 50680.15
ws["C19"] = "Prețul de intrare afișat în ticketul TradeLocker (orice ordin reper)."
ws["A20"] = "Preț SL (ordin reper)"
ws["B20"] = 50618.24
ws["C20"] = "Prețul SL din același ticket."
ws["A21"] = "$ risc afișat (ordin reper)"
ws["B21"] = 495.24
ws["C21"] = "Cifra $ pe care TradeLocker o arată la SL pentru ordinul reper."
ws["A22"] = "Lot size (ordin reper)"
ws["B22"] = 0.08
ws["C22"] = "Câte loturi avea ordinul reper (poate diferi de lotul tău curent, B10)."
ws["A23"] = "↳ Distanță reper (puncte)"
ws["B23"] = "=ABS(B19-B20)"
ws["C23"] = "Auto = |entry SL|. Aici ⇒ 61.91 puncte."
ws["A24"] = "↳ $ per punct la 1.0 lot"
ws["B24"] = "=IF(OR(B23=0,B22=0),0,B21/B23/B22)"
ws["C24"] = (
"Auto = $risc ÷ distanță ÷ lot reper. Pe US30 ⇒ $100/punct la 1 lot. "
"Asta intră în B11. Pe alt indicator se recalibrează singur."
)
ws["A25"] = "Preț reper (curent)"
ws["B25"] = 50700
ws["C25"] = (
"Nivelul curent al indicatorului; convertește % mișcare preț în puncte/$. "
"Pentru alt indicator pui prețul lui."
)
ws["A26"] = "↳ $ per punct (la lotul tău)"
ws["B26"] = "=B10*B24"
ws["C26"] = "Auto = Lot size (B10) × $/punct la 1 lot (B24). La 0.08 loturi ⇒ $8/punct."
ws["A27"] = "↳ $ risc la 1% mișcare preț"
ws["B27"] = "=B10*B11"
ws["C27"] = (
"Auto — INIMA calculului. $ pe trade = R × SL% × această valoare. "
"La 0.08 loturi US30 ⇒ ~$4,056."
)
for r in (9, 10, 12, 14, 19, 20, 21, 22, 25): # inputuri galbene
ws.cell(row=r, column=2).fill = INPUT_FILL
ws.cell(row=r, column=2).border = BORDER
for r in (11, 13, 15, 23, 24, 26, 27): # derived blue
ws.cell(row=r, column=2).fill = DERIVED_FILL
ws.cell(row=r, column=2).border = BORDER
ws["B9"].number_format = "$#,##0"
ws["B10"].number_format = "0.00"
ws["B11"].number_format = "$#,##0"
ws["B12"].number_format = '0.0"%"'
ws["B13"].number_format = "$#,##0"
ws["B14"].number_format = '0.0"%"'
ws["B15"].number_format = "$#,##0"
ws["B19"].number_format = "#,##0.00"
ws["B20"].number_format = "#,##0.00"
ws["B21"].number_format = '"$"#,##0.00'
ws["B22"].number_format = "0.00"
ws["B23"].number_format = "#,##0.00"
ws["B24"].number_format = '"$"#,##0.00'
ws["B25"].number_format = "#,##0"
ws["B26"].number_format = '"$"#,##0.00'
ws["B27"].number_format = '"$"#,##0.00'
# ---- Utilitar: calcul preț SL pentru TradeLocker (pas cu pas) ----
# Forward helper: din SL% (TradeStation) + preț intrare (TradeLocker) + direcție
# → prețul exact la care pui SL în TradeLocker. Celule intermediare vizibile.
ws["A29"] = "— Utilitar: ce prețuri SL/TP pun în TradeLocker —"
ws["A29"].font = Font(name="Calibri", size=10, italic=True, bold=True, color="1F3864")
ws.merge_cells("A29:C29")
ws["A30"] = "SL % (din TradeStation)"
ws["B30"] = 0.08
ws["C30"] = "Procentul SL al semnalului (% mișcare de preț), ex: 0.08."
ws["A31"] = "Preț intrare (TradeLocker)"
ws["B31"] = 50649.50
ws["C31"] = "Prețul tău de intrare US30 (nu prețul reper de la B25)."
ws["A32"] = "Direcție"
ws["B32"] = "Sell"
ws["C32"] = "Sell ⇒ SL DEASUPRA intrării. Buy ⇒ SL DEDESUBT."
ws["A33"] = "↳ Distanță SL (puncte)"
ws["B33"] = "=B31*B30/100"
ws["C33"] = "Auto = Preț intrare × SL% / 100. Ex: 50649.50 × 0.08/100 ⇒ ~40.5 puncte."
ws["A34"] = "↳ PREȚ SL de setat în TradeLocker"
ws["B34"] = '=IF(B32="Sell",B31+B33,B31-B33)'
ws["C34"] = "Sell: intrare + distanță. Buy: intrare distanță. ASTA pui în TradeLocker."
ws["A35"] = "↳ $ risc la acest SL"
ws["B35"] = "=B33*B26"
ws["C35"] = (
"Auto = Distanță (puncte) × $/punct la lotul tău (B26). "
"Verificare: ar trebui să se potrivească cu cifra $ din ticketul TradeLocker."
)
for r in (30, 31, 32): # inputuri galbene
ws.cell(row=r, column=2).fill = INPUT_FILL
ws.cell(row=r, column=2).border = BORDER
for r in (33, 34, 35): # derived blue
ws.cell(row=r, column=2).fill = DERIVED_FILL
ws.cell(row=r, column=2).border = BORDER
# Output principal evidențiat
ws["A34"].font = Font(name="Calibri", size=11, bold=True, color="1F3864")
ws["B34"].font = Font(name="Calibri", size=11, bold=True)
ws["B32"].alignment = CENTER
ws["B30"].number_format = '0.000"%"'
ws["B31"].number_format = "#,##0.00"
ws["B33"].number_format = "#,##0.00"
ws["B34"].number_format = "#,##0.00"
ws["B35"].number_format = '"$"#,##0.00'
# --- TP0/TP1/TP2: aceeași logică, dar în direcția profitului (opus SL) ---
ws["A36"] = "TP0 % (din TradeStation)"
ws["B36"] = 0.03
ws["C36"] = "Procentul TP0 al semnalului (% mișcare de preț)."
ws["A37"] = "TP1 % (din TradeStation)"
ws["B37"] = 0.06
ws["C37"] = "Procentul TP1 al semnalului."
ws["A38"] = "TP2 % (din TradeStation)"
ws["B38"] = 0.08
ws["C38"] = "Procentul TP2 al semnalului."
ws["A39"] = "↳ PREȚ TP0 de setat"
ws["B39"] = '=IF(B32="Sell",B31-B31*B36/100,B31+B31*B36/100)'
ws["C39"] = (
"Distanță = intrare × TP0% / 100. Sell: intrare distanță. "
"Buy: intrare + distanță (TP-ul e opus SL-ului)."
)
ws["A40"] = "↳ PREȚ TP1 de setat"
ws["B40"] = '=IF(B32="Sell",B31-B31*B37/100,B31+B31*B37/100)'
ws["C40"] = "La fel, cu TP1%."
ws["A41"] = "↳ PREȚ TP2 de setat"
ws["B41"] = '=IF(B32="Sell",B31-B31*B38/100,B31+B31*B38/100)'
ws["C41"] = "La fel, cu TP2%."
for r in (36, 37, 38): # inputuri galbene
ws.cell(row=r, column=2).fill = INPUT_FILL
ws.cell(row=r, column=2).border = BORDER
ws.cell(row=r, column=2).number_format = '0.000"%"'
for r in (39, 40, 41): # output evidențiat (albastru, bold)
ws.cell(row=r, column=2).fill = DERIVED_FILL
ws.cell(row=r, column=2).border = BORDER
ws.cell(row=r, column=2).number_format = "#,##0.00"
ws.cell(row=r, column=2).font = Font(name="Calibri", size=11, bold=True)
ws.cell(row=r, column=1).font = Font(
name="Calibri", size=11, bold=True, color="1F3864"
)
dv_dir = DataValidation(type="list", formula1='"Buy,Sell"', allow_blank=False)
dv_dir.add("B32")
ws.add_data_validation(dv_dir)
# Liste dropdown — coloanele EJ (6 coloane)
list_columns = [
("Strategii", STRATEGIES),
@@ -272,7 +439,7 @@ def build_config(wb: Workbook) -> None:
c.alignment = CENTER
widths = {
"A": 24, "B": 14, "C": 38, "D": 2,
"A": 30, "B": 14, "C": 40, "D": 2,
"E": 14, "F": 14, "G": 13, "H": 10, "I": 10, "J": 12,
}
for col, w in widths.items():
@@ -699,7 +866,7 @@ METRIC_HINTS: dict[str, str] = {
),
"Average Loss ($)": (
"Pierderea medie pe trade-urile negative (cifra apare cu minus).\n"
"În dolari reali, 1R depinde de SL%: pierdere ≈ SL% × Contracte × $/1% per contract.\n"
"În dolari reali, 1R depinde de SL%: pierdere ≈ SL% × $ risc la 1% preț (Config B27).\n"
"Dacă e mult mai mare decât riscul calculat din SL, ai SL-uri sărite (slippage, gap-uri)."
),
"Best Trade ($)": (
@@ -709,8 +876,8 @@ METRIC_HINTS: dict[str, str] = {
),
"Worst Trade ($)": (
"Cea mai mare pierdere individuală.\n"
"Ar trebui să fie aproximativ egală cu 1R calculat din SL% × Contracte × $/1% per contract.\n"
"Pe TradeLocker DIA: SL=0.30%, 1 contract → ≈ $3000. Dacă e mai mare, ai slippage/gap."
"Ar trebui să fie aproximativ egală cu 1R calculat din SL% × $ risc la 1% preț (Config B27).\n"
"La 0.08 loturi US30: SL=0.30% × ~$4,056 ≈ $1,217. Dacă e mult mai mare, ai slippage/gap."
),
"Profit Factor": (
"Total bani câștigați împărțit la total bani pierduți (în valoare absolută).\n"
@@ -729,7 +896,7 @@ METRIC_HINTS: dict[str, str] = {
"Pragul de GO LIVE: +0.20R sau mai mult."
),
"Expectancy ($)": (
"Aceeași expectancy convertită în dolari, folosind SL% × Contracte × $/1% per contract.\n"
"Aceeași expectancy convertită în dolari, folosind SL% × $ risc la 1% preț (Config B27).\n"
"Util ca să vezi cât câștigi în medie pe trade în bani reali (TradeLocker), nu doar în R."
),
"Cumulative P&L ($)": (
@@ -750,11 +917,11 @@ METRIC_HINTS: dict[str, str] = {
"Capitalul de start al contului de prop firm (default $50,000).\n"
"Editabil în Config B9."
),
"Position Size ($)": (
"Configurare contract real TradeLocker:\n"
" • Contracte per trade (Config B10) — câte contracte tranzacționezi pe semnal.\n"
" • $ per 1% per contract (Config B11) — pe DIA: 0.10% = $1000 → 1% = $10,000.\n"
"Pierderea pe SL = SL% × Contracte × $/1% per contract. Pentru SL=0.30%, 1 contract → $3000."
"$ risc la 1% preț ($)": (
"Câți $ riști pe poziția ta reală la 1% mișcare de preț (Config B27).\n"
"Lanț: Lot size (B10) × $/punct la 1 lot (B24) = $/punct; × Preț reper (B25)/100 = $ per 1%.\n"
"$/punct la 1 lot (B24) e calibrat dintr-un ordin reper TradeLocker — merge pe orice indicator.\n"
"La 0.08 loturi US30 ⇒ ~$4,056. Pe 100k cu lot 0.16 se dublează (~$8,112)."
),
"Cumulative P&L Prop ($)": (
"Profitul total al contului de prop pe traseul logat.\n"
@@ -762,24 +929,24 @@ METRIC_HINTS: dict[str, str] = {
"Adunat peste $50,000 dă balanța finală reală."
),
"Final Balance Prop ($)": (
"Balanța finală a contului de prop = $50,000 + Cumulative P&L Prop.\n"
"Compar-o cu pragul de stop-out al firmei de prop: $50,000 $3,500 = $46,500."
"Balanța finală a contului de prop = Account Start (Config B9) + Cumulative P&L Prop.\n"
"Compar-o cu pragul de stop-out: Account Start Max Loss Limit $ (Config B15)."
),
"Worst Daily Loss ($)": (
"Cea mai proastă pierdere cumulativă într-o zi calendaristică.\n"
"Dacă e mai mică decât $2,000, ai depășit Daily Loss Limit într-o zi — cont mort.\n"
"Dacă e mai mică decât Daily Loss Limit $ (Config B13), ai depășit limita zilnică — cont mort.\n"
"Atenție: un singur breach = pierdere cont, indiferent dacă ai recuperat ulterior."
),
"Daily Limit Status": (
"PASS dacă nicio zi nu a depășit Daily Loss Limit ($2,000 default).\n"
"PASS dacă nicio zi nu a depășit Daily Loss Limit $ (Config B13, auto din Account × %).\n"
"FAIL = strategia ar fi pierdut contul prin daily breach pe traseul logat."
),
"Max Account Drawdown ($)": (
"Cea mai mare cădere de la peak pe contul de prop.\n"
"Dacă > $3,500 (7% din $50k), ai depășit Max Loss Limit — cont mort."
"Dacă > Max Loss Limit $ (Config B15, auto din Account × %), ai depășit limita — cont mort."
),
"Max Loss Status": (
"PASS dacă Max Account Drawdown ≤ $3,500.\n"
"PASS dacă Max Account Drawdown ≤ Max Loss Limit $ (Config B15).\n"
"FAIL = strategia ar fi pierdut contul prin drawdown cumulativ."
),
"Overall Prop Status": (
@@ -1090,12 +1257,16 @@ def build_dashboard(wb: Workbook) -> None:
f'"CANDIDAT","PRE-CANDIDAT")))'
)
ws[f"{T_LET}{row}"] = (
f'=IF(OR({F_}{row}<1,{D_}{row}<>"Toate"),-1E+12,'
f'{I_}{row}*100000+{K_}{row}*1000+{L_}{row}-{M_}{row}-{O_}{row}/10)'
f'=IF(OR({F_}{row}<1,{D_}{row}<>"Toate",'
f'{P_}{row}="DA",{Q_}{row}="DA"),-1E+12,'
f'{I_}{row}*20000+MIN({F_}{row},150)*100+'
f'{K_}{row}*1500+{L_}{row}-{M_}{row}-{O_}{row}/10)'
)
ws[f"{U_LET}{row}"] = (
f'=IF(OR({F_}{row}<1,{D_}{row}<>"Prima"),-1E+12,'
f'{I_}{row}*100000+{K_}{row}*1000+{L_}{row}-{M_}{row}-{O_}{row}/10)'
f'=IF(OR({F_}{row}<1,{D_}{row}<>"Prima",'
f'{P_}{row}="DA",{Q_}{row}="DA"),-1E+12,'
f'{I_}{row}*20000+MIN({F_}{row},150)*100+'
f'{K_}{row}*1500+{L_}{row}-{M_}{row}-{O_}{row}/10)'
)
combo_rows.append(row)
combo_idx += 1
@@ -1165,7 +1336,7 @@ def build_dashboard(wb: Workbook) -> None:
top_target_letters = ["B", "C", "D", "E", "F", "G", "H", "I", "J", "K"]
def _emit_top_subsection(start_row: int, title: str, note: str,
score_col: str, count: int = 5) -> int:
score_col: str, count: int = 20) -> int:
ws[f"A{start_row}"] = title
ws[f"A{start_row}"].font = SUBTITLE_FONT
ws.merge_cells(f"A{start_row}:K{start_row}")
@@ -1235,21 +1406,25 @@ def build_dashboard(wb: Workbook) -> None:
top_title_row = row + 2
after_top_toate = _emit_top_subsection(
top_title_row,
"TOP 5 FERESTRE — Toate trade-urile",
"TOP 20 FERESTRE — Toate trade-urile",
(
"Top 5 după scor compus, calculat pe rândurile cu Filtru=Toate. "
"CANDIDAT = îndeplinește pragurile (N≥40, WR≥55%, ExpR≥0.2, no breach). "
"PRE-CANDIDAT = N≥1 fără breach dar sub praguri. BREACH = ar fi pierdut prop."
"Top 20 după scor compus, calculat pe rândurile cu Filtru=Toate. "
"EXCLUDE ferestrele cu Daily Breach=DA sau Max Loss Breach=DA (ar fi pierdut contul prop). "
"Scor = ExpR×20000 + MIN(N,150)×100 + PF×1500 + CumP&L MaxDD MaxDDProp/10. "
"Bonusul N (capat la 150) favorizează ferestrele cu sample mai mare, statistic mai fiabile. "
"CANDIDAT = îndeplinește pragurile (N≥40, WR≥55%, ExpR≥0.2). "
"PRE-CANDIDAT = N≥1 fără breach dar sub praguri."
),
score_col=T_LET,
)
after_top_prima = _emit_top_subsection(
after_top_toate + 2,
"TOP 5 FERESTRE — Prima per Indicator",
"TOP 20 FERESTRE — Prima per Indicator",
(
"Top 5 după scor compus, calculat pe rândurile cu Filtru=Prima (doar primul "
"trade pe (Data, Indicator) în fiecare fereastră). Util pentru a vedea dacă "
"filtrul Prima identifică ferestre mai eficiente decât Toate."
"Top 20 după scor compus, calculat pe rândurile cu Filtru=Prima (doar primul "
"trade pe (Data, Indicator) în fiecare fereastră). EXCLUDE ferestrele cu Daily "
"Breach=DA sau Max Loss Breach=DA. Util pentru a vedea dacă filtrul Prima "
"identifică ferestre mai eficiente decât Toate."
),
score_col=U_LET,
)
@@ -1359,9 +1534,9 @@ def build_dashboard(wb: Workbook) -> None:
'"$"#,##0',
),
(
"Position Size ($)",
lambda s: "=Config!$B$11",
'"$"#,##0',
"$ risc la 1% preț ($)",
lambda s: "=Config!$B$27",
'"$"#,##0.00',
),
(
"Cumulative P&L Prop ($)",
@@ -1597,7 +1772,7 @@ def build_dashboard(wb: Workbook) -> None:
# Equity curve prop — al doilea chart, separat de modelul abstract
chart_prop = LineChart()
chart_prop.title = "Equity Curve — Prop ($50k start)"
chart_prop.title = "Equity Curve — Prop (cont real)"
chart_prop.style = 12
chart_prop.y_axis.title = "Balance Prop ($)"
chart_prop.x_axis.title = "Trade #"