ferestre
This commit is contained in:
@@ -195,13 +195,13 @@ def build_config(wb: Workbook) -> None:
|
||||
ws["B9"] = 50000
|
||||
ws["C9"] = "Balanța contului de prop"
|
||||
|
||||
ws["A10"] = "Position Usage (%)"
|
||||
ws["B10"] = 80
|
||||
ws["C10"] = "% din cont folosit ca notional (max contracte)"
|
||||
ws["A10"] = "Contracte per trade"
|
||||
ws["B10"] = 1
|
||||
ws["C10"] = "Număr de contracte tranzacționate per semnal (TradeLocker)"
|
||||
|
||||
ws["A11"] = "Position Size ($)"
|
||||
ws["B11"] = "=B9*B10/100"
|
||||
ws["C11"] = "Auto — notional efectiv pe trade"
|
||||
ws["A11"] = "$ per 1% per contract"
|
||||
ws["B11"] = 10000
|
||||
ws["C11"] = "Pe DIA: 0.10% = $1000 ⇒ 1% = $10,000 (1 contract notional ≈ $1M)"
|
||||
|
||||
ws["A12"] = "Daily Loss Limit (%)"
|
||||
ws["B12"] = 4.0
|
||||
@@ -219,15 +219,15 @@ def build_config(wb: Workbook) -> None:
|
||||
ws["B15"] = "=B9*B14/100"
|
||||
ws["C15"] = "Auto — derivat din B9 și B14"
|
||||
|
||||
for r in (9, 10, 12, 14): # inputuri galbene
|
||||
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 (11, 13, 15): # derived blue
|
||||
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["B10"].number_format = "0"
|
||||
ws["B11"].number_format = "$#,##0"
|
||||
ws["B12"].number_format = '0.0"%"'
|
||||
ws["B13"].number_format = "$#,##0"
|
||||
@@ -351,20 +351,22 @@ R_FN: dict[str, callable] = {
|
||||
|
||||
|
||||
def _f_dollar(r: int, r_col: str) -> str:
|
||||
"""$ P&L pe contul abstract. Variabil per trade = R × SL%/100 × Account Size."""
|
||||
"""$ P&L per trade = R × SL% × Contracte × $/1% per contract (TradeLocker real)."""
|
||||
rc = f"{COL[r_col]}{r}"
|
||||
sl = f"{COL['SL %']}{r}"
|
||||
return f'=IF({rc}="","",{rc}*{sl}/100*Config!$B$4)'
|
||||
return f'=IF({rc}="","",{rc}*{sl}*Config!$B$10*Config!$B$11)'
|
||||
|
||||
|
||||
def _f_sl_dollar(r: int) -> str:
|
||||
"""SL $ = SL% × Contracte × $/1% per contract."""
|
||||
sl = f"{COL['SL %']}{r}"
|
||||
return f'=IF({sl}="","",{sl}/100*Config!$B$4)'
|
||||
return f'=IF({sl}="","",{sl}*Config!$B$10*Config!$B$11)'
|
||||
|
||||
|
||||
def _f_sl_dollar_prop(r: int) -> str:
|
||||
"""SL $ pe contul de prop — același cont real, formula identică cu SL $."""
|
||||
sl = f"{COL['SL %']}{r}"
|
||||
return f'=IF({sl}="","",{sl}/100*Config!$B$11)'
|
||||
return f'=IF({sl}="","",{sl}*Config!$B$10*Config!$B$11)'
|
||||
|
||||
|
||||
def _f_balance(r: int, dollar_col: str) -> str:
|
||||
@@ -395,10 +397,14 @@ def _f_drawdown(r: int, peak_col: str, balance_col: str) -> str:
|
||||
|
||||
|
||||
def _f_dollar_prop(r: int, r_col: str) -> str:
|
||||
"""$ P&L pe contul de prop. Variabil per trade = R × SL%/100 × Position Size."""
|
||||
"""$ P&L pe contul de prop — același calcul ca _f_dollar (cont real TradeLocker).
|
||||
|
||||
Diferența între cont abstract și prop e doar balanța de start; $-ul per trade
|
||||
e identic pentru că reflectă realitatea contractelor tranzacționate.
|
||||
"""
|
||||
rc = f"{COL[r_col]}{r}"
|
||||
sl = f"{COL['SL %']}{r}"
|
||||
return f'=IF({rc}="","",{rc}*{sl}/100*Config!$B$11)'
|
||||
return f'=IF({rc}="","",{rc}*{sl}*Config!$B$10*Config!$B$11)'
|
||||
|
||||
|
||||
def _f_balance_prop(r: int, dollar_col: str) -> str:
|
||||
@@ -620,7 +626,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% × Account Size Start.\n"
|
||||
"În dolari reali, −1R depinde de SL%: pierdere ≈ SL% × Contracte × $/1% per contract.\n"
|
||||
"Dacă e mult mai mare decât riscul calculat din SL, ai SL-uri sărite (slippage, gap-uri)."
|
||||
),
|
||||
"Best Trade ($)": (
|
||||
@@ -630,8 +636,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% × Account Size Start.\n"
|
||||
"Dacă e semnificativ mai mare, ai depășit risk-ul plănuit — SL ratat, slippage, gap overnight."
|
||||
"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."
|
||||
),
|
||||
"Profit Factor": (
|
||||
"Total bani câștigați împărțit la total bani pierduți (în valoare absolută).\n"
|
||||
@@ -650,8 +656,8 @@ METRIC_HINTS: dict[str, str] = {
|
||||
"Pragul de GO LIVE: +0.20R sau mai mult."
|
||||
),
|
||||
"Expectancy ($)": (
|
||||
"Aceeași expectancy convertită în dolari, folosind SL% × Account Size Start per trade.\n"
|
||||
"Util ca să vezi cât câștigi în medie pe trade în bani reali, nu doar în R."
|
||||
"Aceeași expectancy convertită în dolari, folosind SL% × Contracte × $/1% per contract.\n"
|
||||
"Util ca să vezi cât câștigi în medie pe trade în bani reali (TradeLocker), nu doar în R."
|
||||
),
|
||||
"Cumulative P&L ($)": (
|
||||
"Suma profitului și pierderii pe toate trade-urile logate.\n"
|
||||
@@ -672,13 +678,14 @@ METRIC_HINTS: dict[str, str] = {
|
||||
"Editabil în Config B9."
|
||||
),
|
||||
"Position Size ($)": (
|
||||
"Notional efectiv pe trade = Account Prop × Position Usage %.\n"
|
||||
"Default: 80% × $50,000 = $40,000. Pe DIA, ≈ 0.8 contracte din prețul curent.\n"
|
||||
"Pierderea pe SL = SL% × Position Size (NU procent fix din cont)."
|
||||
"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."
|
||||
),
|
||||
"Cumulative P&L Prop ($)": (
|
||||
"Profitul total al contului de prop pe traseul logat.\n"
|
||||
"Reflectă $ real (SL% × Position Size per trade), NU R-multiple-ul abstract de mai sus.\n"
|
||||
"Reflectă $ real (SL% × Contracte × $/1% per contract), nu un procent abstract din cont.\n"
|
||||
"Adunat peste $50,000 dă balanța finală reală."
|
||||
),
|
||||
"Final Balance Prop ($)": (
|
||||
@@ -949,11 +956,13 @@ def build_dashboard(wb: Workbook) -> None:
|
||||
ws[f"P{row}"] = f'=IF(N{row}>Config!$B$15,"DA","NU")'
|
||||
ws[f"Q{row}"] = f'=IF(OR(O{row}="DA",P{row}="DA"),"CONT PIERDUT","CONFORM")'
|
||||
ws[f"R{row}"] = (
|
||||
f'=IF(AND(E{row}>=40,G{row}>=55%,H{row}>=0.2,'
|
||||
f'O{row}="NU",P{row}="NU"),"CANDIDAT","NU")'
|
||||
f'=IF(E{row}<1,"",'
|
||||
f'IF(OR(O{row}="DA",P{row}="DA"),"BREACH",'
|
||||
f'IF(AND(E{row}>=40,G{row}>=55%,H{row}>=0.2),"CANDIDAT","PRE-CANDIDAT")))'
|
||||
)
|
||||
ws[f"S{row}"] = (
|
||||
f'=IF(R{row}="CANDIDAT",H{row}*100000+J{row}*1000+K{row}-L{row}-N{row}/10,-1)'
|
||||
f'=IF(E{row}<1,-1E+12,'
|
||||
f'H{row}*100000+J{row}*1000+K{row}-L{row}-N{row}/10)'
|
||||
)
|
||||
combo_rows.append(row)
|
||||
combo_idx += 1
|
||||
@@ -991,14 +1000,26 @@ def build_dashboard(wb: Workbook) -> None:
|
||||
status_rng, CellIsRule(operator="equal", formula=['"CONT PIERDUT"'], fill=fail_fill)
|
||||
)
|
||||
ws.conditional_formatting.add(
|
||||
status_rng, CellIsRule(operator="equal", formula=['"NU"'], fill=warn_fill)
|
||||
status_rng, CellIsRule(operator="equal", formula=['"BREACH"'], fill=fail_fill)
|
||||
)
|
||||
ws.conditional_formatting.add(
|
||||
status_rng, CellIsRule(operator="equal", formula=['"PRE-CANDIDAT"'], fill=warn_fill)
|
||||
)
|
||||
|
||||
top_title_row = row + 2
|
||||
ws[f"A{top_title_row}"] = "TOP CANDIDATE"
|
||||
ws[f"A{top_title_row}"].font = SUBTITLE_FONT
|
||||
ws.merge_cells(f"A{top_title_row}:J{top_title_row}")
|
||||
top_header_row = top_title_row + 1
|
||||
top_note_row = top_title_row + 1
|
||||
ws[f"A{top_note_row}"] = (
|
||||
"Top 10 ferestre după scor compus. CANDIDAT = îndeplinește toate pragurile "
|
||||
"(N≥40, WR≥55%, ExpR≥0.2, no breach). PRE-CANDIDAT = N≥1 fără breach dar sub praguri. "
|
||||
"BREACH = ar fi pierdut contul prop."
|
||||
)
|
||||
ws[f"A{top_note_row}"].font = Font(name="Calibri", size=10, italic=True, color="595959")
|
||||
ws[f"A{top_note_row}"].alignment = Alignment(horizontal="left", vertical="center", wrap_text=True)
|
||||
ws.merge_cells(f"A{top_note_row}:J{top_note_row}")
|
||||
top_header_row = top_note_row + 1
|
||||
top_headers = [
|
||||
"#", "Fereastra", "Strategie", "N", "WR", "Expectancy R",
|
||||
"Profit Factor", "Cum P&L $", "Max DD Prop $", "Status Edge",
|
||||
@@ -1021,7 +1042,7 @@ def build_dashboard(wb: Workbook) -> None:
|
||||
["A", "D", "E", "G", "H", "J", "K", "N", "R"],
|
||||
):
|
||||
ws[f"{target}{r}"] = (
|
||||
f'=IFERROR(IF({rank_formula}<0,"",'
|
||||
f'=IFERROR(IF({rank_formula}<=-1E+11,"",'
|
||||
f'INDEX(${source}${first_combo}:${source}${last_combo},{match_formula})),"")'
|
||||
)
|
||||
for c in range(1, len(top_headers) + 1):
|
||||
@@ -1034,56 +1055,86 @@ def build_dashboard(wb: Workbook) -> None:
|
||||
ws[f"H{r}"].number_format = '"$"#,##0.00'
|
||||
ws[f"I{r}"].number_format = '"$"#,##0.00'
|
||||
|
||||
# Helper pentru a emite un block breakdown (per Sesiune / Strategie / etc.)
|
||||
def _emit_breakdown(
|
||||
# CF pe coloana Status Edge din TOP CANDIDATE
|
||||
top_status_rng = f"J{top_header_row + 1}:J{top_header_row + 10}"
|
||||
ws.conditional_formatting.add(
|
||||
top_status_rng, CellIsRule(operator="equal", formula=['"CANDIDAT"'], fill=pass_fill)
|
||||
)
|
||||
ws.conditional_formatting.add(
|
||||
top_status_rng, CellIsRule(operator="equal", formula=['"PRE-CANDIDAT"'], fill=warn_fill)
|
||||
)
|
||||
ws.conditional_formatting.add(
|
||||
top_status_rng, CellIsRule(operator="equal", formula=['"BREACH"'], fill=fail_fill)
|
||||
)
|
||||
|
||||
# Conditional formatting reutilizabil pentru celulele Cum $
|
||||
bd_green = PatternFill("solid", fgColor="C6EFCE")
|
||||
bd_red = PatternFill("solid", fgColor="FFC7CE")
|
||||
|
||||
# Helper pentru breakdown wide: rânduri = items, coloane = 5 strategii Cum $ + N total
|
||||
def _emit_breakdown_strats(
|
||||
start_row: int, title: str, first_col_label: str,
|
||||
items: list[str], item_range: str, overlay_strat: str,
|
||||
items: list[str], item_range: str,
|
||||
) -> int:
|
||||
# Layout: A=item, B..F=5 strategii (Cum $), G=N total
|
||||
last_col_idx = 1 + len(STRAT_KEYS) + 1 # A + 5 strategii + N
|
||||
last_letter = get_column_letter(last_col_idx)
|
||||
ws[f"A{start_row}"] = title
|
||||
ws[f"A{start_row}"].font = SUBTITLE_FONT
|
||||
ws.merge_cells(f"A{start_row}:F{start_row}")
|
||||
headers = [first_col_label, "N", "Wins", "WR", "Expectancy R", "Cum $"]
|
||||
ws.merge_cells(f"A{start_row}:{last_letter}{start_row}")
|
||||
headers = [first_col_label] + [STRAT_LABELS[s] for s in STRAT_KEYS] + ["N total"]
|
||||
for col_idx, h in enumerate(headers, start=1):
|
||||
c = ws.cell(row=start_row + 1, column=col_idx, value=h)
|
||||
c.font = HEADER_FONT
|
||||
c.fill = HEADER_FILL
|
||||
c.alignment = CENTER
|
||||
c.border = BORDER
|
||||
strat_letters = [get_column_letter(2 + i) for i in range(len(STRAT_KEYS))]
|
||||
n_letter = get_column_letter(last_col_idx)
|
||||
for i, item in enumerate(items):
|
||||
r = start_row + 2 + i
|
||||
ws[f"A{r}"] = item
|
||||
ws[f"B{r}"] = f'=COUNTIF({item_range},"{item}")'
|
||||
ws[f"C{r}"] = f'=COUNTIFS({item_range},"{item}",{W[overlay_strat]},1)'
|
||||
ws[f"D{r}"] = f"=IFERROR(C{r}/B{r},0)"
|
||||
ws[f"E{r}"] = (
|
||||
f'=IFERROR(AVERAGEIFS({R[overlay_strat]},{item_range},"{item}"),0)'
|
||||
for idx, strat in enumerate(STRAT_KEYS):
|
||||
cl = strat_letters[idx]
|
||||
ws[f"{cl}{r}"] = f'=SUMIFS({D[strat]},{item_range},"{item}")'
|
||||
ws[f"{cl}{r}"].number_format = '"$"#,##0.00'
|
||||
ws[f"{n_letter}{r}"] = f'=COUNTIF({item_range},"{item}")'
|
||||
ws[f"{n_letter}{r}"].number_format = "0"
|
||||
for col_idx in range(1, last_col_idx + 1):
|
||||
cell = ws.cell(row=r, column=col_idx)
|
||||
cell.border = BORDER
|
||||
cell.alignment = LEFT if col_idx == 1 else RIGHT
|
||||
if 2 <= col_idx <= 1 + len(STRAT_KEYS):
|
||||
cell.fill = DERIVED_FILL
|
||||
# CF pe coloanele 5 strategii: verde >0, roșu <0
|
||||
if items:
|
||||
first_data_row = start_row + 2
|
||||
last_data_row = start_row + 1 + len(items)
|
||||
cf_rng = (
|
||||
f"{strat_letters[0]}{first_data_row}:"
|
||||
f"{strat_letters[-1]}{last_data_row}"
|
||||
)
|
||||
ws[f"F{r}"] = f'=SUMIFS({D[overlay_strat]},{item_range},"{item}")'
|
||||
ws[f"B{r}"].number_format = "0"
|
||||
ws[f"C{r}"].number_format = "0"
|
||||
ws[f"D{r}"].number_format = "0.0%"
|
||||
ws[f"E{r}"].number_format = "+0.000;-0.000;0.000"
|
||||
ws[f"F{r}"].number_format = '"$"#,##0.00'
|
||||
for c in ("A", "B", "C", "D", "E", "F"):
|
||||
ws[f"{c}{r}"].border = BORDER
|
||||
ws[f"{c}{r}"].alignment = RIGHT if c != "A" else LEFT
|
||||
return start_row + 2 + len(items)
|
||||
ws.conditional_formatting.add(
|
||||
cf_rng, CellIsRule(operator="greaterThan", formula=["0"], fill=bd_green)
|
||||
)
|
||||
ws.conditional_formatting.add(
|
||||
cf_rng, CellIsRule(operator="lessThan", formula=["0"], fill=bd_red)
|
||||
)
|
||||
return start_row + 1 + len(items)
|
||||
|
||||
# Breakdowns — toate folosesc overlay-ul Hybrid+BE (recomandat de trader)
|
||||
overlay = "hybrid_be"
|
||||
# Breakdowns — toate cele 5 strategii vizibile, Cum P&L $ per strategie
|
||||
start = top_header_row + 13
|
||||
after_sess = start
|
||||
after_strat = _emit_breakdown(
|
||||
after_sess + 2, "PER STRATEGIE (overlay: Hybrid + BE)", "Strategie",
|
||||
STRATEGIES, _range("Strategie"), overlay,
|
||||
after_strat = _emit_breakdown_strats(
|
||||
start + 2, "PER STRATEGIE — Cum P&L $ per strategie", "Strategie",
|
||||
STRATEGIES, _range("Strategie"),
|
||||
)
|
||||
after_ind = _emit_breakdown(
|
||||
after_strat + 2, "PER INDICATOR (overlay: Hybrid + BE)", "Indicator",
|
||||
INDICATORS, _range("Indicator"), overlay,
|
||||
after_ind = _emit_breakdown_strats(
|
||||
after_strat + 2, "PER INDICATOR — Cum P&L $ per strategie", "Indicator",
|
||||
INDICATORS, _range("Indicator"),
|
||||
)
|
||||
after_dir = _emit_breakdown(
|
||||
after_ind + 2, "PER DIRECȚIE (overlay: Hybrid + BE)", "Direcție",
|
||||
DIRECTIONS, _range("Direcție"), overlay,
|
||||
after_dir = _emit_breakdown_strats(
|
||||
after_ind + 2, "PER DIRECȚIE — Cum P&L $ per strategie", "Direcție",
|
||||
DIRECTIONS, _range("Direcție"),
|
||||
)
|
||||
|
||||
# ---- PROP FIRM COMPLIANCE ----
|
||||
@@ -1235,9 +1286,72 @@ def build_dashboard(wb: Workbook) -> None:
|
||||
for r in range(prop_header_row + 1, prop_header_row + 1 + len(prop_metrics)):
|
||||
ws.row_dimensions[r].height = 60
|
||||
|
||||
# ---- PROP FIRM COMPLIANCE per FEREASTRĂ × STRATEGIE ----
|
||||
# Reshape compliance: rânduri = combo (fereastră × strategie), coloane = metrici compliance.
|
||||
# Datele sunt referențiate direct din FERESTRE CANDIDATE (cols A, D, M, N, O, P, Q).
|
||||
if combo_rows:
|
||||
win_prop_title_row = prop_header_row + 1 + len(prop_metrics) + 2
|
||||
ws[f"A{win_prop_title_row}"] = "PROP FIRM COMPLIANCE — per FEREASTRĂ × STRATEGIE"
|
||||
ws[f"A{win_prop_title_row}"].font = SUBTITLE_FONT
|
||||
ws.merge_cells(f"A{win_prop_title_row}:G{win_prop_title_row}")
|
||||
|
||||
win_prop_note_row = win_prop_title_row + 1
|
||||
ws[f"A{win_prop_note_row}"] = (
|
||||
"Defalcat pe fiecare combinație de fereastră tradabilă × strategie management. "
|
||||
"CONFORM = ar fi supraviețuit pe contul de prop pe acel slot."
|
||||
)
|
||||
ws[f"A{win_prop_note_row}"].font = Font(name="Calibri", size=10, italic=True, color="595959")
|
||||
ws[f"A{win_prop_note_row}"].alignment = Alignment(horizontal="left", vertical="center", wrap_text=True)
|
||||
ws.merge_cells(f"A{win_prop_note_row}:G{win_prop_note_row}")
|
||||
|
||||
win_prop_header_row = win_prop_note_row + 1
|
||||
win_prop_headers = [
|
||||
"Fereastra", "Strategie", "Worst Daily Prop $", "Max DD Prop $",
|
||||
"Daily Breach", "Max Breach", "Overall Prop",
|
||||
]
|
||||
for col_idx, h in enumerate(win_prop_headers, start=1):
|
||||
c = ws.cell(row=win_prop_header_row, column=col_idx, value=h)
|
||||
c.font = HEADER_FONT
|
||||
c.fill = HEADER_FILL
|
||||
c.alignment = CENTER
|
||||
c.border = BORDER
|
||||
|
||||
# source cols din FERESTRE CANDIDATE: A=Fereastra, D=Strategie, M=Worst Daily,
|
||||
# N=Max DD, O=Daily Breach, P=Max Breach, Q=Overall Prop
|
||||
source_cols = ["A", "D", "M", "N", "O", "P", "Q"]
|
||||
for offset, combo_row in enumerate(combo_rows, start=1):
|
||||
r = win_prop_header_row + offset
|
||||
for col_idx, source in enumerate(source_cols, start=1):
|
||||
target = get_column_letter(col_idx)
|
||||
ws[f"{target}{r}"] = f"={source}{combo_row}"
|
||||
cell = ws[f"{target}{r}"]
|
||||
cell.border = BORDER
|
||||
cell.fill = DERIVED_FILL
|
||||
cell.alignment = CENTER if col_idx in (1, 2, 5, 6, 7) else RIGHT
|
||||
ws[f"C{r}"].number_format = '"$"#,##0.00'
|
||||
ws[f"D{r}"].number_format = '"$"#,##0.00'
|
||||
|
||||
# CF pe Overall Prop (col G) și pe Daily/Max Breach (cols E, F)
|
||||
win_prop_first = win_prop_header_row + 1
|
||||
win_prop_last = win_prop_header_row + len(combo_rows)
|
||||
overall_rng_win = f"G{win_prop_first}:G{win_prop_last}"
|
||||
ws.conditional_formatting.add(
|
||||
overall_rng_win, CellIsRule(operator="equal", formula=['"CONFORM"'], fill=pass_fill)
|
||||
)
|
||||
ws.conditional_formatting.add(
|
||||
overall_rng_win, CellIsRule(operator="equal", formula=['"CONT PIERDUT"'], fill=fail_fill)
|
||||
)
|
||||
breach_rng_win = f"E{win_prop_first}:F{win_prop_last}"
|
||||
ws.conditional_formatting.add(
|
||||
breach_rng_win, CellIsRule(operator="equal", formula=['"DA"'], fill=fail_fill)
|
||||
)
|
||||
ws.conditional_formatting.add(
|
||||
breach_rng_win, CellIsRule(operator="equal", formula=['"NU"'], fill=pass_fill)
|
||||
)
|
||||
|
||||
# Column widths
|
||||
widths = {
|
||||
"A": 18, "B": 10, "C": 10, "D": 16, "E": 8, "F": 8, "G": 10,
|
||||
"A": 18, "B": 10, "C": 18, "D": 16, "E": 13, "F": 13, "G": 16,
|
||||
"H": 13, "I": 13, "J": 12, "K": 13, "L": 15, "M": 20,
|
||||
"N": 18, "O": 13, "P": 14, "Q": 15, "R": 13, "S": 8,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user