|
6 | 6 | from src.yfinance_manager import YFinanceManager |
7 | 7 | from src.drive_manager import DriveManager |
8 | 8 | from src.risk_manager import RiskManager |
| 9 | +from src.settings_manager import SettingsManager |
9 | 10 | from src.logger import get_logger |
10 | | -from src.strategies import StrategyRSI, StrategyEMA |
| 11 | + |
| 12 | +# Importiamo SOLO il Factory Method, non le classi specifiche |
| 13 | +from src.strategies import get_strategy |
11 | 14 |
|
12 | 15 | logger = get_logger("WeeklyRun") |
13 | 16 |
|
14 | 17 | def main(): |
15 | 18 | logger.info("📅 Inizio Weekly Run (Strategy & Risk Analysis)...") |
16 | 19 |
|
17 | | - # 1. INIT |
18 | | - db = DatabaseManager() |
19 | | - pm = PortfolioManager() |
20 | | - yf = YFinanceManager() |
21 | | - dm = DriveManager() |
| 20 | + # 1. INIT MANAGERS |
| 21 | + try: |
| 22 | + db = DatabaseManager() |
| 23 | + pm = PortfolioManager() |
| 24 | + yf = YFinanceManager() |
| 25 | + dm = DriveManager() |
| 26 | + settings = SettingsManager() # Carica config/strategies.json |
| 27 | + except Exception as e: |
| 28 | + logger.critical(f"Errore inizializzazione manager: {e}") |
| 29 | + return |
22 | 30 |
|
23 | | - # Config Strategia |
24 | | - strategy = StrategyRSI(rsi_period=14, rsi_lower=30, rsi_upper=70) |
| 31 | + # 2. CONFIGURAZIONE DINAMICA STRATEGIA |
| 32 | + try: |
| 33 | + # Leggiamo dal JSON quale strategia usare |
| 34 | + active_strat_name = settings.get_active_strategy_name() |
| 35 | + strat_params = settings.get_strategy_params(active_strat_name) |
| 36 | + |
| 37 | + logger.info(f"⚙️ Strategia Attiva: {active_strat_name}") |
| 38 | + logger.info(f"🔧 Parametri: {strat_params}") |
| 39 | + |
| 40 | + # FACTORY PATTERN: Istanziamo la classe corretta al volo |
| 41 | + strategy = get_strategy(active_strat_name, **strat_params) |
| 42 | + |
| 43 | + except Exception as e: |
| 44 | + logger.critical(f"Errore caricamento strategia da config: {e}") |
| 45 | + return |
| 46 | + |
| 47 | + # Inizializziamo Risk Manager (NB: potremmo parametrizzare anche questo in futuro) |
25 | 48 | risk_manager = RiskManager(risk_per_trade=0.02, stop_atr_multiplier=2.0) |
26 | 49 |
|
27 | | - # 2. LOAD STATE |
28 | | - pm.load_from_db(db.load_portfolio()) |
29 | | - current_equity = pm.get_total_equity() |
30 | | - logger.info(f"Equity Iniziale: {current_equity:.2f}") |
| 50 | + # 3. LOAD STATE |
| 51 | + try: |
| 52 | + pm.load_from_db(db.load_portfolio()) |
| 53 | + current_equity = pm.get_total_equity() |
| 54 | + logger.info(f"💰 Equity Iniziale: {current_equity:.2f} €") |
| 55 | + except Exception as e: |
| 56 | + logger.error(f"Errore caricamento portfolio: {e}") |
| 57 | + return |
31 | 58 |
|
32 | | - # 3. DATA FETCH (Universe + Portfolio) |
| 59 | + # 4. DATA FETCH (Universe + Portfolio) |
33 | 60 | universe_tkr = dm.get_universe_tickers() |
34 | 61 | portfolio_tkr = pm.df_portfolio["ticker"].tolist() |
35 | 62 | all_tickers = list(set(universe_tkr + portfolio_tkr)) |
36 | 63 |
|
| 64 | + if not all_tickers: |
| 65 | + logger.warning("Nessun ticker da analizzare.") |
| 66 | + return |
| 67 | + |
37 | 68 | logger.info(f"Aggiornamento dati per {len(all_tickers)} ticker...") |
| 69 | + # Scarichiamo dati recenti per aggiornare il DB |
38 | 70 | new_data = yf.fetch_ohlc(all_tickers, days=5) |
39 | 71 | db.upsert_ohlc(new_data) |
40 | 72 |
|
41 | | - # 4. STRATEGY ENGINE |
42 | | - logger.info("Recupero storico e calcolo strategia...") |
| 73 | + # 5. STRATEGY ENGINE |
| 74 | + # Per la strategia servono dati storici profondi (es. EMA 200 richiede >200 giorni) |
| 75 | + logger.info("Recupero storico e calcolo segnali...") |
43 | 76 | historical_data = db.get_ohlc_all_tickers(days=365) |
44 | 77 |
|
45 | 78 | if not historical_data: |
46 | | - logger.error("Nessun dato storico trovato.") |
| 79 | + logger.error("Nessun dato storico trovato nel DB.") |
47 | 80 | return |
48 | 81 |
|
| 82 | + # Calcolo della strategia dinamica |
49 | 83 | df_signals = strategy.compute(historical_data) |
50 | 84 |
|
51 | | - # Filtro ultimo segnale (Venerdì) |
| 85 | + # Filtro ultimo segnale (Venerdì/Oggi) |
52 | 86 | if df_signals.empty: |
| 87 | + logger.info("Nessun segnale generato dalla strategia.") |
53 | 88 | latest_signals = pd.DataFrame() |
54 | 89 | else: |
55 | 90 | last_date = df_signals['date'].max() |
56 | 91 | latest_signals = df_signals[df_signals['date'] == last_date] |
57 | | - logger.info(f"Analisi segnali per data: {last_date}") |
| 92 | + logger.info(f"Analisi segnali per data: {last_date.date()}") |
58 | 93 |
|
59 | | - # 5. RISK MANAGER |
| 94 | + # 6. RISK MANAGER & ORDER GENERATION |
60 | 95 | pos_dict = dict(zip(pm.df_portfolio['ticker'], pm.df_portfolio['size'])) |
61 | 96 | available_cash = float(pm.df_cash.iloc[0]['cash']) if not pm.df_cash.empty else 0.0 |
62 | 97 |
|
63 | | - logger.info("Valutazione Rischio e Generazione Ordini...") |
| 98 | + logger.info("Valutazione Rischio...") |
64 | 99 | orders = risk_manager.evaluate( |
65 | 100 | signals_df=latest_signals, |
66 | 101 | total_equity=current_equity, |
67 | 102 | available_cash=available_cash, |
68 | 103 | current_positions=pos_dict |
69 | 104 | ) |
70 | 105 |
|
71 | | - # 6. OUTPUT -> GOOGLE SHEETS |
| 106 | + # 7. OUTPUT -> GOOGLE SHEETS |
72 | 107 | if orders: |
73 | 108 | logger.info(f"✅ Generati {len(orders)} ordini operativi.") |
74 | 109 | for o in orders: |
75 | | - logger.info(f" -> {o['action']} {o['ticker']} Qty:{o['quantity']} @ {o['price']}") |
| 110 | + logger.info(f" -> {o['action']} {o['ticker']} Qty:{o['quantity']} @ {o['price']:.2f}") |
76 | 111 | else: |
77 | | - logger.info("😴 Nessun ordine generato.") |
| 112 | + logger.info("😴 Nessun ordine generato (Risk Manager o Nessun Segnale).") |
78 | 113 |
|
79 | | - # SALVATAGGIO SUL CLOUD |
80 | 114 | # Questo sovrascrive il tab "Orders" nel tuo Report Sheet |
81 | 115 | dm.save_pending_orders(orders) |
82 | 116 |
|
|
0 commit comments