Make strategy whitelist configurable
This commit is contained in:
@@ -31,5 +31,11 @@
|
||||
"base_capital_per_strategy": 100.0,
|
||||
"min_trade_notional": 0.01,
|
||||
"risk_parity_lookback": 60
|
||||
},
|
||||
"equity_log": {
|
||||
"strategy_whitelist": [
|
||||
"Equal_Weight",
|
||||
"Risk_Parity"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,13 @@ import pandas as pd
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
from shared_utils import (
|
||||
detect_column,
|
||||
load_config,
|
||||
read_connection_txt,
|
||||
require_section,
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
# PATH & OUTPUT
|
||||
# =============================================================================
|
||||
@@ -38,53 +45,35 @@ SP_NAME_DEFAULT = "opt_RendimentoGiornaliero1_ALL"
|
||||
SP_N_DEFAULT = 1305
|
||||
PTF_CURR_DEFAULT = "EUR"
|
||||
|
||||
# prova a leggere il file di configurazione condiviso; se manca si usano i default
|
||||
CONFIG = None
|
||||
try:
|
||||
CONFIG = load_config()
|
||||
DB_CONFIG = require_section(CONFIG, "db")
|
||||
except Exception as exc: # pragma: no cover - best effort
|
||||
print(f"[WARN] Config non disponibile ({exc}); uso i default interni.")
|
||||
DB_CONFIG = {}
|
||||
else:
|
||||
SP_NAME_DEFAULT = str(DB_CONFIG.get("stored_proc", SP_NAME_DEFAULT))
|
||||
SP_N_DEFAULT = int(DB_CONFIG.get("n_bars", SP_N_DEFAULT))
|
||||
PTF_CURR_DEFAULT = str(DB_CONFIG.get("ptf_curr", PTF_CURR_DEFAULT))
|
||||
|
||||
# Strategie valide (tutto il resto viene ignorato)
|
||||
VALID_STRATEGIES = ["Equal_Weight", "Risk_Parity"]
|
||||
# "Aggressiva_Crypto" è stata rimossa perché non deve più essere processata
|
||||
DEFAULT_STRATEGIES = ["Equal_Weight", "Risk_Parity"]
|
||||
VALID_STRATEGIES = DEFAULT_STRATEGIES
|
||||
|
||||
# =============================================================================
|
||||
# CONNESSIONE DB
|
||||
# =============================================================================
|
||||
def read_connection_txt(path: Path) -> str:
|
||||
import pyodbc
|
||||
params = {}
|
||||
for line in path.read_text(encoding="utf-8").splitlines():
|
||||
line = line.strip()
|
||||
if not line or "=" not in line or line.startswith("#"):
|
||||
continue
|
||||
k, v = line.split("=", 1)
|
||||
params[k.strip().lower()] = v.strip()
|
||||
try: # opzionale: sezione dedicata nel config per personalizzare la whitelist
|
||||
EQUITY_CFG = CONFIG.get("equity_log", {}) if CONFIG else {}
|
||||
except NameError: # pragma: no cover - CONFIG non definito se load_config fallisce
|
||||
EQUITY_CFG = {}
|
||||
|
||||
username = params.get("username")
|
||||
password = params.get("password")
|
||||
host = params.get("host")
|
||||
port = params.get("port", "1433")
|
||||
database = params.get("database")
|
||||
|
||||
if not all([username, password, host, database]):
|
||||
raise ValueError("connection.txt incompleto: servono username/password/host/database.")
|
||||
|
||||
installed = [d for d in pyodbc.drivers()]
|
||||
driver_q = (
|
||||
"ODBC+Driver+18+for+SQL+Server"
|
||||
if "ODBC Driver 18 for SQL Server" in installed
|
||||
else "ODBC+Driver+17+for+SQL+Server"
|
||||
)
|
||||
|
||||
return f"mssql+pyodbc://{username}:{password}@{host}:{port}/{database}?driver={driver_q}"
|
||||
|
||||
# =============================================================================
|
||||
# UTILS
|
||||
# =============================================================================
|
||||
def _pick(df: pd.DataFrame, candidates):
|
||||
low = {c.lower(): c for c in df.columns}
|
||||
for c in candidates:
|
||||
if c.lower() in low:
|
||||
return low[c.lower()]
|
||||
for col in df.columns:
|
||||
lc = col.lower()
|
||||
if any(tok.lower() in lc for tok in candidates):
|
||||
return col
|
||||
return None
|
||||
if EQUITY_CFG:
|
||||
raw_whitelist = EQUITY_CFG.get("strategy_whitelist")
|
||||
if raw_whitelist:
|
||||
whitelist = [str(x).strip() for x in raw_whitelist if str(x).strip()]
|
||||
if whitelist:
|
||||
VALID_STRATEGIES = whitelist
|
||||
|
||||
# =============================================================================
|
||||
# FETCH RENDIMENTI DAL DB
|
||||
@@ -113,9 +102,9 @@ def fetch_returns_from_db(isins, start_date, end_date) -> pd.DataFrame:
|
||||
if df.empty:
|
||||
continue
|
||||
|
||||
col_date = _pick(df, ["Date", "Data", "Datetime", "Timestamp", "Time"])
|
||||
col_ret = _pick(df, ["Ret", "Return", "Rendimento", "Rend", "Ret_%", "RET"])
|
||||
col_px = _pick(df, ["Close", "AdjClose", "Price", "Px", "Last", "Prezzo", "Chiusura"])
|
||||
col_date = detect_column(df, ["Date", "Data", "Datetime", "Timestamp", "Time"])
|
||||
col_ret = detect_column(df, ["Ret", "Return", "Rendimento", "Rend", "Ret_%", "RET"])
|
||||
col_px = detect_column(df, ["Close", "AdjClose", "Price", "Px", "Last", "Prezzo", "Chiusura"])
|
||||
|
||||
if not col_date:
|
||||
continue
|
||||
@@ -270,7 +259,13 @@ def main():
|
||||
|
||||
# === filtro whitelist: solo strategie volute ===
|
||||
audit["Strategy"] = audit["Strategy"].astype(str)
|
||||
before = len(audit)
|
||||
audit = audit[audit["Strategy"].isin(VALID_STRATEGIES)]
|
||||
removed = before - len(audit)
|
||||
if removed > 0:
|
||||
print(
|
||||
f"[INFO] Filtrate {removed} righe con strategie non incluse in {VALID_STRATEGIES}."
|
||||
)
|
||||
if audit.empty:
|
||||
raise SystemExit(f"Nessuna riga con strategie in {VALID_STRATEGIES} nell'audit log.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user