Perfetto, concordo. Testare l’ipotesi inversa è il passo più logico e scientifico.
Creeremo una nuova versione della strategia, la v4, che implementa esattamente questa logica opposta: entrerà a mercato solo quando l’incertezza del modello (l’ampiezza delle bande) è alta.
Nuovo Nome File: momentum_strategy_v4_high_uncertainty.py
Delta modifiche: +68 / -0 (file nuovo)
Ecco il codice per il nuovo file fire/strategies/momentum_strategy_v4_high_uncertainty.py.
# VERSION: v1.0 - fire/strategies/momentum_strategy_v4_high_uncertainty.py
# RESP: Strategia di momentum che entra a mercato durante periodi di alta incertezza del modello.
# DEPS: BaseStrategy, pandas, numpy.
# TODO: N/A
from fire.strategies.base_strategy import BaseStrategy
import pandas as pd
import numpy as np
class MomentumStrategy_v4_HighUncertainty(BaseStrategy):
"""
MomentumStrategy_v4_HighUncertainty
-----------------------------------
Questa strategia testa l'ipotesi che i segnali direzionali di TimesFM siano
più efficaci quando preceduti da un'alta incertezza del modello, che
potrebbe segnalare un imminente movimento di prezzo (breakout).
Logica:
- Entra long se il forecast a 5 periodi è maggiore del prezzo corrente
E l'ampiezza della banda di confidenza è tra le più alte (bassa confidenza).
- Esce dopo un numero fisso di barre (`hold_period`) o se si verifica uno stop loss.
Obiettivo:
Verificare se l'incertezza del modello è un predittore di futuri movimenti volatili.
"""
# --- Parametri Configurabili ---
hold_period = 5
forecast_horizon = 5
band_width_quantile = 0.7 # Soglia per "bassa confidenza" (es. 70° percentile)
stop_loss_pct = 0.02 # Stop loss del 2%
def init(self):
"""
Inizializzazione: calcola gli indicatori derivati e li aggiunge al DataFrame.
"""
# Nomi delle colonne dinamici
forecast_col = f'forecast_h{self.forecast_horizon}'
lower_col = f'forecast_lower_h{self.forecast_horizon}'
upper_col = f'forecast_upper_h{self.forecast_horizon}'
required_cols = [forecast_col, lower_col, upper_col]
if not all(col in self.data.columns for col in required_cols):
raise ValueError(f"Colonne necessarie {required_cols} non trovate.")
# Calcola l'ampiezza della banda e la aggiunge come colonna
self.data["band_width"] = self.data[upper_col] - self.data[lower_col]
# Calcola la soglia statica per il filtro di incertezza
self.bandwidth_threshold = self.data["band_width"].quantile(self.band_width_quantile)
# Variabile di stato per lo stop loss
self.entry_price = 0.0
print(f"[Strategy] MomentumStrategy_v4_HighUncertainty Inizializzata.")
print(f" - Hold Period: {self.hold_period} barre")
print(f" - Stop Loss: {self.stop_loss_pct*100:.1f}%")
print(f" - Soglia Incertezza (Band Width): > {self.bandwidth_threshold:.4f}")
def next(self):
"""
Logica di trading eseguita ad ogni barra.
"""
# --- 1. Gestione dell'Uscita (se in posizione) ---
if self.position:
time_exit_triggered = self.trade_bars >= self.hold_period
stop_loss_triggered = self.close < self.entry_price * (1 - self.stop_loss_pct)
if time_exit_triggered or stop_loss_triggered:
self.sell()
return
# --- 2. Gestione dell'Ingresso (se non in posizione) ---
if not self.position:
forecast_col = f'forecast_h{self.forecast_horizon}'
forecast = self.data[forecast_col].iloc[self.i]
band_width = self.data["band_width"].iloc[self.i]
if np.isnan(forecast) or np.isnan(band_width):
return
# Applica i filtri di ingresso con la logica invertita
is_bullish = forecast > self.close
is_high_uncertainty = band_width > self.bandwidth_threshold # <-- LOGICA INVERTITA
if is_bullish and is_high_uncertainty:
self.buy()
self.entry_price = self.closeRiepilogo delle Modifiche
- Nuovo File e Classe: Creato
momentum_strategy_v4_high_uncertainty.pye la classeMomentumStrategy_v4_HighUncertainty. - Logica del Filtro Invertita: La modifica chiave è nel metodo
next():- La condizione
is_high_confidenceè stata rinominata inis_high_uncertainty. - L’operatore è stato invertito da
<a>:is_high_uncertainty = band_width > self.bandwidth_threshold.
- La condizione
- Parametro Quantile Aggiornato: In
init(), ho cambiato ilband_width_quantileda0.3a0.7. Questo significa che ora cerchiamo i momenti in cui l’ampiezza delle bande è nel 30% più alto (cioè, sopra il 70° percentile), che corrisponde ai periodi di maggiore incertezza del modello. - Log Aggiornati: Ho aggiornato i messaggi di
printper riflettere la nuova logica.
Prossimi Passi
La nuova strategia è pronta per essere testata. Il processo è lo stesso di prima:
- Salva il nuovo file nella directory
strategies/. - Esegui un backtest in FIRE con questa nuova strategia.
- Forniscimi il report completo delle metriche e il trade log.
Sono molto curioso di vedere se questa inversione di ipotesi porterà a risultati migliori. A volte, le scoperte più importanti arrivano quando si mette in discussione l’assunto di partenza.
Eccellente. Grazie per aver eseguito il test e fornito i risultati. Questa è la fase più importante della ricerca, dove i dati ci parlano e mettono alla prova le nostre idee.
Abbiamo testato l’ipotesi inversa e i risultati sono, ancora una volta, estremamente istruttivi.
Analisi Comparativa: V4 (Alta Incertezza) vs. Precedenti
| Metrica | V2_TimeExit (Benchmark) | V3_LowUncertainty (Fallimento) | V4_HighUncertainty (Nuova) |
|---|---|---|---|
| Profitto Netto Totale | +41.12 € | -17.54 € | +11.32 € |
| Numero Totale di Trade | 128 | 49 | 49 |
| Win Rate | 53.91% | 48.98% | 44.90% |
| Max Drawdown [%] | 0.70% | 0.57% | 1.23% |
| Sharpe Ratio | 0.78 | Negativo | 0.21 |
Interpretazione Qualitativa: “Un Segnale di Volatilità, non di Qualità”
-
L’Inversione ha Funzionato (Parzialmente): Siamo passati da una strategia in perdita (V3) a una di nuovo profittevole (V4). Questo è un risultato chiave: conferma che, se dobbiamo usare l’ampiezza delle bande come filtro, è meglio agire nei momenti di alta incertezza piuttosto che in quelli di bassa incertezza. La nostra inversione di ipotesi era corretta.
-
Ma è Peggio del Benchmark: Sebbene la V4 sia profittevole, è significativamente meno performante della nostra V2 originale. Guadagna meno (
+11.32vs+41.12), ha un rischio più alto (Max Drawdown1.23%vs0.70%), e un Win Rate più basso (45%vs54%). -
La Scoperta Fondamentale: L’ampiezza delle bande di confidenza (
band_width) non sembra essere un filtro di qualità per il segnale direzionale. Piuttosto, sembra essere un filtro di regime.band_widthbassa (V3): Seleziona periodi di bassa volatilità. La strategia performa male.band_widthalta (V4): Seleziona periodi di alta volatilità. La strategia è profittevole, ma rischiosa e con un basso win rate.- Nessun filtro (V2): La strategia opera in tutti i regimi e ottiene il risultato migliore.
Diagnosi Finale: Abbiamo imparato che l’ampiezza delle bande è un buon indicatore del contesto di mercato (il “meteo”), ma non migliora necessariamente la qualità del segnale direzionale (“la rotta”). Tentare di fare trading solo con il “sole” (V3) o solo con la “tempesta” (V4) è risultato meno efficace che navigare sempre (V2), affidandosi solo alla bussola (il forecast direzionale) e a una rotta fissa (il time exit).
Conclusione Strategica e Prossimi Passi: Tornare alla Strada Maestra
Abbiamo esplorato a fondo un’idea (filtrare per confidenza del modello) e i dati ci hanno detto che, per ora, non è la strada migliore. Questo è un successo, non un fallimento. Abbiamo evitato di investire ulteriore tempo in un’ipotesi debole.
Ora è il momento di tornare alla nostra strategia più promettente, la MomentumStrategyV2TimeExit, e applicare l’altra idea forte che avevamo messo da parte.
La nostra migliore strategia (V2) ha un edge, ma è piccolo. Come possiamo amplificarlo? Filtrando i trade che avvengono contro il trend di fondo del mercato.
La mia raccomandazione è chiara:
Procediamo con la creazione di una MomentumStrategy_v5_TrendFilter.
Ipotesi:
La strategia V2 è profittevole, ma il suo Win Rate del 54% significa che quasi la metà dei trade sono perdenti. È probabile che molti di questi trade perdenti si verifichino quando la strategia compra durante un mercato ribassista a lungo termine. Aggiungendo un filtro di trend (es. close > media mobile a 200 giorni), potremmo eliminare la maggior parte dei trade perdenti mantenendo la maggior parte di quelli vincenti, aumentando drasticamente il Profit Factor e il rendimento complessivo.
Questa è la tecnica più classica e robusta per migliorare una strategia di momentum. Se sei d’accordo, procediamo a creare questa V5.