Sistemato salvataggio grafici e tolta visualizzazione dall'esecuzione
This commit is contained in:
@@ -20,6 +20,7 @@ import numpy as np
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import text
|
||||
import matplotlib.pyplot as plt
|
||||
from pathlib import Path
|
||||
|
||||
from shared_utils import (
|
||||
build_pattern_library,
|
||||
@@ -70,6 +71,10 @@ def savefig_safe(path, **kwargs):
|
||||
# =========================================
|
||||
# PARAMETRI GLOBALI
|
||||
# =========================================
|
||||
OUTPUT_DIR = Path("output")
|
||||
PLOT_DIR = Path("plot")
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
PLOT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
CONFIG = load_config()
|
||||
DB_CONFIG = require_section(CONFIG, "db")
|
||||
PATTERN_CONFIG = require_section(CONFIG, "pattern")
|
||||
@@ -80,12 +85,18 @@ PATTERN_CONFIG = CONFIG.get("pattern", {})
|
||||
TAGGING_CONFIG = CONFIG.get("tagging", {})
|
||||
RANKING_CONFIG = CONFIG.get("ranking", {})
|
||||
|
||||
UNIVERSO_XLSX = "Universo per Trading System.xlsx"
|
||||
UNIVERSO_XLSX = "Input/Universo per Trading System.xlsx"
|
||||
|
||||
# Export
|
||||
OUTPUT_HURST_XLSX = "hurst_by_isin.xlsx"
|
||||
OUTPUT_PATTERN_XLSX = "pattern_signals.xlsx"
|
||||
ERROR_LOG_CSV = "errori_isin.csv"
|
||||
OUTPUT_HURST_XLSX = OUTPUT_DIR / "hurst_by_isin.xlsx"
|
||||
OUTPUT_PATTERN_XLSX = OUTPUT_DIR / "pattern_signals.xlsx"
|
||||
ERROR_LOG_CSV = OUTPUT_DIR / "errori_isin.csv"
|
||||
FORWARD_BT_SIGNALS_XLSX = OUTPUT_DIR / "forward_bt_signals.xlsx"
|
||||
FORWARD_BT_SUMMARY_XLSX = OUTPUT_DIR / "forward_bt_summary.xlsx"
|
||||
TRADES_REPORT_XLSX = OUTPUT_DIR / "trades_report.xlsx"
|
||||
DAILY_FROM_TRADES_CSV = OUTPUT_DIR / "daily_from_trades.csv"
|
||||
DAILY_FROM_TRADES_XLSX = OUTPUT_DIR / "daily_from_trades.xlsx"
|
||||
FINAL_METRICS_XLSX = OUTPUT_DIR / "final_metrics.xlsx"
|
||||
|
||||
# Stored Procedure & parametri
|
||||
STORED_PROC = str(require_value(DB_CONFIG, "stored_proc", "db"))
|
||||
@@ -883,10 +894,10 @@ bt_summary_df = pd.DataFrame(bt_summary) if bt_summary else pd.DataFrame(
|
||||
columns=["ISIN","Nome","Categoria","Asset Class","CAGR_%","AnnVol_%","Sharpe","MaxDD_%eq","Calmar","HitRate_%","AvgTradeRet_bps","Turnover_%/step","N_Steps"]
|
||||
)
|
||||
|
||||
bt_signals_df.to_excel("forward_bt_signals.xlsx", index=False)
|
||||
bt_summary_df.to_excel("forward_bt_summary.xlsx", index=False)
|
||||
print(f"✅ Salvato: forward_bt_signals.xlsx ({len(bt_signals_df):,} righe)")
|
||||
print(f"✅ Salvato: forward_bt_summary.xlsx ({len(bt_summary_df):,} righe)")
|
||||
bt_signals_df.to_excel(FORWARD_BT_SIGNALS_XLSX, index=False)
|
||||
bt_summary_df.to_excel(FORWARD_BT_SUMMARY_XLSX, index=False)
|
||||
print(f"✅ Salvato: {FORWARD_BT_SIGNALS_XLSX} ({len(bt_signals_df):,} righe)")
|
||||
print(f"✅ Salvato: {FORWARD_BT_SUMMARY_XLSX} ({len(bt_summary_df):,} righe)")
|
||||
|
||||
if errors:
|
||||
pd.DataFrame(errors).to_csv(ERROR_LOG_CSV, index=False)
|
||||
@@ -957,7 +968,7 @@ def plot_heatmap_monthly(r: pd.Series, title: str, save_path: str = None):
|
||||
plt.tight_layout()
|
||||
if save_path:
|
||||
savefig_safe(save_path, dpi=150)
|
||||
plt.show()
|
||||
# Non mostrare il plot durante l'esecuzione
|
||||
|
||||
def inverse_vol_weights(df, window=60, max_weight=None):
|
||||
vol = df.rolling(window).std()
|
||||
@@ -1420,7 +1431,7 @@ def plot_portfolio_composition(weights: pd.DataFrame,
|
||||
full = save_path
|
||||
print(f"💾 Salvato: {full}")
|
||||
|
||||
plt.show()
|
||||
# Plot salvato senza visualizzazione interattiva
|
||||
|
||||
def make_active_weights(w_base: pd.DataFrame,
|
||||
sig: pd.DataFrame,
|
||||
@@ -1469,12 +1480,11 @@ plt.plot(eq_eq, label="Equal Weight")
|
||||
plt.plot(eq_rp, label="Risk Parity")
|
||||
plt.legend(); plt.grid(); plt.title("Equity line - Selezione dinamica (Top N)")
|
||||
plt.tight_layout()
|
||||
savefig_safe("equity_line_portafogli.png", dpi=150)
|
||||
plt.show()
|
||||
savefig_safe(str(PLOT_DIR / "equity_line_portafogli.png"), dpi=150)
|
||||
|
||||
for name, r, path in [
|
||||
("Equal Weight", ret_eq, "heatmap_equal_weight.png"),
|
||||
("Risk Parity", ret_rp, "heatmap_risk_parity.png"),
|
||||
("Equal Weight", ret_eq, PLOT_DIR / "heatmap_equal_weight.png"),
|
||||
("Risk Parity", ret_rp, PLOT_DIR / "heatmap_risk_parity.png"),
|
||||
]:
|
||||
|
||||
m = portfolio_metrics(r)
|
||||
@@ -1491,7 +1501,7 @@ import matplotlib.pyplot as plt
|
||||
def plot_portfolio_composition_fixed(weights: pd.DataFrame,
|
||||
title: str,
|
||||
save_path: str | None = None,
|
||||
max_legend: int = 12):
|
||||
max_legend: int = 20):
|
||||
"""
|
||||
Stacked area dei pesi nel tempo.
|
||||
'weights' deve essere già quello ATTIVO (già mascherato con i Signal)
|
||||
@@ -1527,10 +1537,17 @@ def plot_portfolio_composition_fixed(weights: pd.DataFrame,
|
||||
|
||||
# Raggruppa coda lunga in "Altri"
|
||||
if len(ordered) > max_legend:
|
||||
head, tail = ordered[:max_legend], ordered[max_legend:]
|
||||
head = ordered[:max_legend]
|
||||
# Garantisce che 'Cash' resti in legenda anche oltre il cap
|
||||
if "Cash" not in head and "Cash" in ordered:
|
||||
head = head[:-1] + ["Cash"]
|
||||
tail = [c for c in ordered if c not in head]
|
||||
W_show = W[head].copy()
|
||||
W_show["Altri"] = W[tail].sum(1)
|
||||
ordered = head + ["Altri"]
|
||||
if tail:
|
||||
W_show["Altri"] = W[tail].sum(1)
|
||||
ordered = head + ["Altri"]
|
||||
else:
|
||||
ordered = head
|
||||
else:
|
||||
W_show = W[ordered].copy()
|
||||
|
||||
@@ -1563,7 +1580,7 @@ def plot_portfolio_composition_fixed(weights: pd.DataFrame,
|
||||
fig.savefig(save_path, dpi=150, bbox_inches="tight")
|
||||
print(f"💾 Salvato: {os.path.abspath(save_path)}")
|
||||
|
||||
plt.show()
|
||||
# Plot salvato senza visualizzazione interattiva
|
||||
|
||||
# --- 1) Pesi teorici dei tre portafogli (già costruiti sopra) ---
|
||||
# w_eq : equal weight su 'cols'
|
||||
@@ -1607,9 +1624,8 @@ w_rp_act = make_active_weights(w_rp, wide_sig, renorm_to_1=False, add_cash=Tru
|
||||
w_agg_act = make_active_weights(w_agg, wide_sig, renorm_to_1=False, add_cash=True, cash_label="Cash")
|
||||
|
||||
# --- 3) Plot + salvataggio ---
|
||||
os.makedirs("plots", exist_ok=True)
|
||||
plot_portfolio_composition_fixed(w_eq_act, "Equal Weight (attivi + Cash)", "plots/composition_equal_weight_active.png")
|
||||
plot_portfolio_composition_fixed(w_rp_act, "Risk Parity (attivi + Cash)", "plots/composition_risk_parity_active.png")
|
||||
plot_portfolio_composition_fixed(w_eq_act, "Equal Weight (attivi + Cash)", str(PLOT_DIR / "composition_equal_weight_active.png"))
|
||||
plot_portfolio_composition_fixed(w_rp_act, "Risk Parity (attivi + Cash)", str(PLOT_DIR / "composition_risk_parity_active.png"))
|
||||
|
||||
|
||||
# -----------------------------
|
||||
@@ -1721,11 +1737,11 @@ rep_rp = make_trades_report(wide_sig[[c for c in cols if c in wide_sig.columns]
|
||||
wide_pnl[[c for c in cols if c in wide_pnl.columns]],
|
||||
w_rp, "Risk Parity")
|
||||
|
||||
with pd.ExcelWriter("trades_report.xlsx") as xw:
|
||||
with pd.ExcelWriter(TRADES_REPORT_XLSX) as xw:
|
||||
rep_eq.to_excel(xw, "Equal_Weight", index=False)
|
||||
rep_rp.to_excel(xw, "Risk_Parity", index=False)
|
||||
|
||||
print("✅ Report trades salvato in trades_report.xlsx")
|
||||
print(f"✅ Report trades salvato in {TRADES_REPORT_XLSX}")
|
||||
# ============================================================
|
||||
# 5.6 Rebuild DAILY PnL from trades_report (calendarized)
|
||||
# → per rendere coerente il compounding dei trade con equity/heatmap
|
||||
@@ -1808,17 +1824,15 @@ daily_from_trades = rebuild_daily_from_trades_dict(trades_dict)
|
||||
|
||||
# Salva su disco (CSV + XLSX) per ispezione
|
||||
if not daily_from_trades.empty:
|
||||
daily_from_trades.to_csv("daily_from_trades.csv", index_label="Date")
|
||||
daily_from_trades.to_csv(DAILY_FROM_TRADES_CSV, index_label="Date")
|
||||
try:
|
||||
with pd.ExcelWriter("daily_from_trades.xlsx") as xw:
|
||||
with pd.ExcelWriter(DAILY_FROM_TRADES_XLSX) as xw:
|
||||
daily_from_trades.to_excel(xw, "Daily", index=True)
|
||||
except Exception as e:
|
||||
print(f"[WARN] Impossibile scrivere daily_from_trades.xlsx: {e}")
|
||||
print(f"[WARN] Impossibile scrivere {DAILY_FROM_TRADES_XLSX}: {e}")
|
||||
|
||||
# Plot equity & heatmap basati sui DAILY da trade (coerenti col compounding)
|
||||
import matplotlib.pyplot as plt
|
||||
from pathlib import Path
|
||||
Path("plots_by_topN").mkdir(exist_ok=True)
|
||||
|
||||
fig, ax = plt.subplots(figsize=(10,6))
|
||||
for col, lab in [("Equal_Weight","Equal Weight"),
|
||||
@@ -1829,9 +1843,9 @@ if not daily_from_trades.empty:
|
||||
ax.legend(); ax.grid(True)
|
||||
ax.set_title("Equity line – ricostruita dai trades (calendarizzata)")
|
||||
fig.tight_layout()
|
||||
fig.savefig("plots_by_topN/equity_from_trades.png", dpi=150)
|
||||
fig.savefig(PLOT_DIR / "equity_from_trades.png", dpi=150)
|
||||
plt.close(fig)
|
||||
print("💾 Salvato: plots_by_topN/equity_from_trades.png")
|
||||
print(f"💾 Salvato: {PLOT_DIR / 'equity_from_trades.png'}")
|
||||
|
||||
# Heatmap per ciascuna strategia
|
||||
for col, lab, fname in [
|
||||
@@ -1841,7 +1855,7 @@ if not daily_from_trades.empty:
|
||||
if col in daily_from_trades.columns:
|
||||
try:
|
||||
plot_heatmap_monthly(daily_from_trades[col], f"Heatmap mensile – {lab} (da trades)",
|
||||
save_path=f"plots_by_topN/{fname}")
|
||||
save_path=PLOT_DIR / fname)
|
||||
except Exception as e:
|
||||
print(f"[WARN] Heatmap {lab} da trades: {e}")
|
||||
else:
|
||||
@@ -2093,13 +2107,13 @@ final_byN_df = pd.DataFrame(rows_byN)[[
|
||||
# Salvataggio: aggiunge/riscrive i fogli in final_metrics.xlsx
|
||||
# - mantiene (se vuoi) anche il foglio "Portfolio_Metrics" del caso corrente TOP_N
|
||||
try:
|
||||
with pd.ExcelWriter("final_metrics.xlsx", engine="openpyxl", mode="a", if_sheet_exists="replace") as xw:
|
||||
with pd.ExcelWriter(FINAL_METRICS_XLSX, engine="openpyxl", mode="a", if_sheet_exists="replace") as xw:
|
||||
final_byN_df.to_excel(xw, "Portfolio_Metrics_By_N", index=False)
|
||||
except Exception:
|
||||
with pd.ExcelWriter("final_metrics.xlsx") as xw:
|
||||
with pd.ExcelWriter(FINAL_METRICS_XLSX) as xw:
|
||||
final_byN_df.to_excel(xw, "Portfolio_Metrics_By_N", index=False)
|
||||
|
||||
print("✅ Salvato: final_metrics.xlsx (Portfolio_Metrics_By_N) per TopN = 8..15")
|
||||
print(f"✅ Salvato: {FINAL_METRICS_XLSX} (Portfolio_Metrics_By_N) per TopN = 8..15")
|
||||
|
||||
# ======================================================================
|
||||
# 6bis) Plot per ciascun TopN (8..15): Equity + Heatmap per strategia
|
||||
@@ -2108,8 +2122,8 @@ import os
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
OUT_DIR = "plots_by_topN"
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
OUT_DIR = PLOT_DIR
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
def _safe_series(r: pd.Series) -> pd.Series:
|
||||
"""Forza tipo numerico e se tutto NaN, rimpiazza con 0.0 (linea piatta ma plot salvato)."""
|
||||
@@ -2133,9 +2147,9 @@ def _save_equity_plot_byN(ret_eq, ret_rp, top_n: int):
|
||||
eq_rp.plot(ax=ax, label="Risk Parity")
|
||||
ax.legend()
|
||||
ax.grid(True)
|
||||
ax.set_title(f"Equity line – TopN={top_n}")
|
||||
ax.set_title(f"Equity line - TopN={top_n}")
|
||||
fig.tight_layout()
|
||||
savefig_safe(os.path.join(OUT_DIR, f"equity_topN_{top_n}.png"), dpi=150)
|
||||
savefig_safe(str(OUT_DIR / f"equity_topN_{top_n}.png"), dpi=150)
|
||||
plt.close(fig)
|
||||
|
||||
def _save_heatmaps_byN(ret_eq, ret_rp, top_n: int):
|
||||
@@ -2144,13 +2158,13 @@ def _save_heatmaps_byN(ret_eq, ret_rp, top_n: int):
|
||||
|
||||
plot_heatmap_monthly(
|
||||
ret_eq,
|
||||
f"Heatmap mensile – Equal Weight (TopN={top_n})",
|
||||
save_path=os.path.join(OUT_DIR, f"heatmap_equal_topN_{top_n}.png")
|
||||
f"Heatmap mensile - Equal Weight (TopN={top_n})",
|
||||
save_path=OUT_DIR / f"heatmap_equal_topN_{top_n}.png"
|
||||
)
|
||||
plot_heatmap_monthly(
|
||||
ret_rp,
|
||||
f"Heatmap mensile – Risk Parity (TopN={top_n})",
|
||||
save_path=os.path.join(OUT_DIR, f"heatmap_rp_topN_{top_n}.png")
|
||||
f"Heatmap mensile - Risk Parity (TopN={top_n})",
|
||||
save_path=OUT_DIR / f"heatmap_rp_topN_{top_n}.png"
|
||||
)
|
||||
|
||||
# Loop 8..15 replicando i plot per ciascuna combinazione
|
||||
@@ -2170,8 +2184,8 @@ import os
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
OUT_DIR = "plots_by_topN"
|
||||
os.makedirs(OUT_DIR, exist_ok=True)
|
||||
OUT_DIR = PLOT_DIR
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# -- safety: helper per pesi attivi e plotting, se mancassero già nel file --
|
||||
|
||||
@@ -2203,7 +2217,7 @@ if 'plot_portfolio_composition_fixed' not in globals():
|
||||
def plot_portfolio_composition_fixed(weights: pd.DataFrame,
|
||||
title: str,
|
||||
save_path: str | None = None,
|
||||
max_legend: int = 12):
|
||||
max_legend: int = 20):
|
||||
if weights is None or getattr(weights, "empty", True):
|
||||
print(f"[SKIP] Nessun peso per: {title}")
|
||||
return
|
||||
@@ -2221,10 +2235,16 @@ if 'plot_portfolio_composition_fixed' not in globals():
|
||||
if "Cash" in ordered:
|
||||
ordered = [c for c in ordered if c!="Cash"] + ["Cash"]
|
||||
if len(ordered) > max_legend:
|
||||
head, tail = ordered[:max_legend], ordered[max_legend:]
|
||||
head = ordered[:max_legend]
|
||||
if "Cash" not in head and "Cash" in ordered:
|
||||
head = head[:-1] + ["Cash"]
|
||||
tail = [c for c in ordered if c not in head]
|
||||
W_show = W[head].copy()
|
||||
W_show["Altri"] = W[tail].sum(1)
|
||||
ordered = head + ["Altri"]
|
||||
if tail:
|
||||
W_show["Altri"] = W[tail].sum(1)
|
||||
ordered = head + ["Altri"]
|
||||
else:
|
||||
ordered = head
|
||||
else:
|
||||
W_show = W[ordered].copy()
|
||||
cmap = plt.colormaps.get_cmap("tab20")
|
||||
@@ -2245,7 +2265,7 @@ if 'plot_portfolio_composition_fixed' not in globals():
|
||||
os.makedirs(folder, exist_ok=True)
|
||||
fig.savefig(save_path, dpi=150, bbox_inches="tight")
|
||||
print(f"💾 Salvato: {os.path.abspath(save_path)}")
|
||||
plt.show()
|
||||
# Nessuna visualizzazione interattiva
|
||||
|
||||
def _build_weights_for_isins(base_isins_N, crypto_isin_N, wide_pnl):
|
||||
"""Costruisce i pesi TEORICI per Equal / Risk Parity / Aggressiva su un dato insieme di ISIN."""
|
||||
@@ -2295,8 +2315,8 @@ for top_n in range(8, 16):
|
||||
w_rp_act_N = make_active_weights(w_rp_N, wide_sig, renorm_to_1=False, add_cash=True, cash_label="Cash")
|
||||
|
||||
# path di salvataggio
|
||||
sp_eq = os.path.join(OUT_DIR, f"composition_equal_topN_{top_n}.png")
|
||||
sp_rp = os.path.join(OUT_DIR, f"composition_rp_topN_{top_n}.png")
|
||||
sp_eq = OUT_DIR / f"composition_equal_topN_{top_n}.png"
|
||||
sp_rp = OUT_DIR / f"composition_rp_topN_{top_n}.png"
|
||||
|
||||
# plot + salvataggio (SOLO Equal e Risk Parity)
|
||||
plot_portfolio_composition_fixed(w_eq_act_N, f"Equal Weight (attivi + Cash) – TopN={top_n}", sp_eq)
|
||||
|
||||
@@ -31,14 +31,16 @@ from shared_utils import (
|
||||
# PATH & OUTPUT
|
||||
# =============================================================================
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
AUDIT_LOG_CSV = BASE_DIR / "trades_audit_log.csv"
|
||||
OUTPUT_DIR = BASE_DIR / "output"
|
||||
PLOT_DIR = BASE_DIR / "plot"
|
||||
AUDIT_LOG_CSV = OUTPUT_DIR / "trades_audit_log.csv"
|
||||
CONNECTION_TXT = BASE_DIR / "connection.txt"
|
||||
|
||||
OUT_DAILY_CSV = BASE_DIR / "daily_returns_by_strategy.csv"
|
||||
OUT_EQUITY_CSV = BASE_DIR / "equity_by_strategy.csv"
|
||||
OUT_DEBUG_CSV = BASE_DIR / "debug_daily_by_strategy.csv"
|
||||
PLOT_EQUITY = BASE_DIR / "equity_by_strategy.png"
|
||||
PLOT_DD = BASE_DIR / "drawdown_by_strategy.png"
|
||||
OUT_DAILY_CSV = OUTPUT_DIR / "daily_returns_by_strategy.csv"
|
||||
OUT_EQUITY_CSV = OUTPUT_DIR / "equity_by_strategy.csv"
|
||||
OUT_DEBUG_CSV = OUTPUT_DIR / "debug_daily_by_strategy.csv"
|
||||
PLOT_EQUITY = PLOT_DIR / "equity_by_strategy.png"
|
||||
PLOT_DD = PLOT_DIR / "drawdown_by_strategy.png"
|
||||
|
||||
# Stored procedure
|
||||
SP_NAME_DEFAULT = "opt_RendimentoGiornaliero1_ALL"
|
||||
@@ -243,6 +245,8 @@ def rebuild_daily_from_log(audit: pd.DataFrame, returns_wide: pd.DataFrame) -> p
|
||||
# MAIN
|
||||
# =============================================================================
|
||||
def main():
|
||||
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
PLOT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
if not AUDIT_LOG_CSV.exists():
|
||||
raise FileNotFoundError("Missing trades_audit_log.csv")
|
||||
|
||||
@@ -295,7 +299,6 @@ def main():
|
||||
plt.legend()
|
||||
plt.tight_layout()
|
||||
plt.savefig(str(PLOT_EQUITY), dpi=150)
|
||||
plt.show()
|
||||
plt.close()
|
||||
|
||||
# Drawdown
|
||||
@@ -308,7 +311,6 @@ def main():
|
||||
plt.legend()
|
||||
plt.tight_layout()
|
||||
plt.savefig(str(PLOT_DD), dpi=150)
|
||||
plt.show()
|
||||
plt.close()
|
||||
|
||||
print("Salvati:")
|
||||
|
||||
@@ -69,15 +69,17 @@ RANKING_CONFIG = CONFIG.get("ranking", {})
|
||||
SIGNALS_CONFIG = CONFIG.get("signals", {})
|
||||
|
||||
BASE_DIR = Path(".")
|
||||
UNIVERSO_XLSX = BASE_DIR / "Universo per Trading System.xlsx"
|
||||
OUTPUT_DIR = BASE_DIR / "output"
|
||||
# Universe now expected inside Input folder
|
||||
UNIVERSO_XLSX = BASE_DIR / "Input" / "Universo per Trading System.xlsx"
|
||||
CONNECTION_TXT = BASE_DIR / "connection.txt"
|
||||
AUDIT_LOG_CSV = BASE_DIR / "trades_audit_log.csv"
|
||||
AUDIT_LOG_CSV = OUTPUT_DIR / "trades_audit_log.csv"
|
||||
OPEN_TRADES_DIR = BASE_DIR / "open_trades"
|
||||
DROPBOX_EXPORT_DIR = Path(r"C:\Users\Admin\Dropbox\Condivisa Lavoro\Segnali di trading su ETF")
|
||||
|
||||
def _dated_signals_filename() -> Path:
|
||||
date_prefix = pd.Timestamp.today().strftime("%Y%m%d")
|
||||
return BASE_DIR / f"{date_prefix}_signals.xlsx"
|
||||
return OUTPUT_DIR / f"{date_prefix}_signals.xlsx"
|
||||
|
||||
# Stored procedure / parametri DB
|
||||
SP_NAME_DEFAULT = str(require_value(DB_CONFIG, "stored_proc", "db"))
|
||||
@@ -448,6 +450,7 @@ def save_open_trades(strategy: str, df: pd.DataFrame):
|
||||
def append_audit_rows(rows: List[Dict]):
|
||||
if not rows:
|
||||
return
|
||||
ensure_dir(AUDIT_LOG_CSV.parent)
|
||||
log = pd.DataFrame(rows)
|
||||
if AUDIT_LOG_CSV.exists():
|
||||
old = pd.read_csv(AUDIT_LOG_CSV)
|
||||
@@ -701,6 +704,7 @@ def update_positions_and_build_orders(universe: pd.DataFrame,
|
||||
# =========================
|
||||
def main_run(run_date: Optional[dt.date] = None):
|
||||
today = run_date or dt.date.today()
|
||||
ensure_dir(OUTPUT_DIR)
|
||||
|
||||
# 1) Universo
|
||||
universe = load_universe(UNIVERSO_XLSX)
|
||||
|
||||
Reference in New Issue
Block a user