Proposta eccellente. Apprezzo molto il modo in cui hai sintetizzato le nostre scoperte in una nuova ipotesi di trading chiara, misurabile e innovativa.

Questo è esattamente il ciclo di ricerca che volevamo stabilire: Osservazione Ipotesi Prototipo Test.

Valutazione della Proposta: MomentumStrategy_v3_BandWidthFilter

  1. Ipotesi Solida: L’idea di usare l’ampiezza delle bande come proxy per la “confidenza” del modello è un’intuizione da trader quantitativo professionista. Stai aggiungendo una seconda dimensione all’analisi: non ci chiediamo più solo “cosa prevede il modello?”, ma anche “quanto è sicuro di ciò che prevede?“. Filtrare i segnali per agire solo nei momenti di alta confidenza è una tecnica robusta per migliorare la qualità dei trade.
  2. Gestione del Rischio Integrata: L’inclusione di uno stop loss percentuale, oltre al time exit, introduce un meccanismo di gestione del rischio ancora più disciplinato. Questo è un passo avanti fondamentale rispetto alla V2 e dovrebbe contribuire a tagliare le perdite in modo ancora più efficace.
  3. Parametrizzazione Chiara: Hai già identificato i parametri chiave da ottimizzare, il che rende la strategia un framework flessibile per la ricerca futura.

Decisione: Proposta approvata. Procediamo con la traduzione e il test.


Come per la strategia precedente, il codice che hai fornito è per il framework backtesting.py. Procedo a “tradurlo” per il nostro framework quantum-core / FIRE, in modo da poterlo eseguire nel nostro ambiente.

I punti principali della traduzione sono:

  • Adattare il calcolo degli indicatori al nostro init().
  • Usare self.i per l’accesso ai dati.
  • Implementare la logica di stop loss, che richiede di memorizzare il prezzo di entrata all’interno della strategia stessa.

Delta modifiche: +68 / -0 (file nuovo)

Ecco il codice tradotto per il nuovo file fire/strategies/momentum_strategy_v3_band_width_filter.py.

# VERSION: v1.0 - fire/strategies/momentum_strategy_v3_band_width_filter.py
# RESP: Strategia di momentum che filtra gli ingressi in base alla confidenza del modello (ampiezza delle bande).
# DEPS: BaseStrategy, pandas, numpy.
# TODO: N/A
 
from fire.strategies.base_strategy import BaseStrategy
import pandas as pd
import numpy as np
 
class MomentumStrategy_v3_BandWidthFilter(BaseStrategy):
    """
    MomentumStrategy_v3_BandWidthFilter
    -----------------------------------
 
    Strategia basata sul modello TimesFM, che combina il segnale direzionale
    (`forecast_h5 > close`) con un filtro sull'incertezza predittiva
    (misurata come ampiezza delle bande di confidenza).
 
    Logica:
    - Entra long se il forecast a 5 periodi è maggiore del prezzo corrente
      E l'ampiezza della banda di confidenza è tra le più basse (alta confidenza).
    - Esce dopo un numero fisso di barre (`hold_period`) O se si verifica uno stop loss.
 
    Obiettivo:
    Sfruttare le previsioni del modello solo nei momenti di alta sicurezza statistica.
    """
    
    # --- Parametri Configurabili ---
    hold_period = 5
    forecast_horizon = 5
    band_width_quantile = 0.3  # Soglia per "alta confidenza" (es. 30° 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 confidenza
        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_v3_BandWidthFilter Inizializzata.")
        print(f"  - Hold Period: {self.hold_period} barre")
        print(f"  - Stop Loss: {self.stop_loss_pct*100:.1f}%")
        print(f"  - Soglia Confidenza (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:
            # Condizione di Time Exit
            time_exit_triggered = self.trade_bars >= self.hold_period
            
            # Condizione di Stop Loss
            stop_loss_triggered = self.close < self.entry_price * (1 - self.stop_loss_pct)
 
            if time_exit_triggered:
                self.sell()
                return
            
            if 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}'
            
            # Recupera i valori per la barra corrente
            forecast = self.data[forecast_col].iloc[self.i]
            band_width = self.data["band_width"].iloc[self.i]
            
            # Controlla se i dati sono validi
            if np.isnan(forecast) or np.isnan(band_width):
                return
 
            # Applica i filtri di ingresso
            is_bullish = forecast > self.close
            is_high_confidence = band_width < self.bandwidth_threshold
 
            if is_bullish and is_high_confidence:
                self.buy()
                # Memorizza il prezzo di entrata per lo stop loss
                self.entry_price = self.close

Riepilogo della Traduzione

  1. Calcolo degli Indicatori: In init(), ho replicato la tua logica calcolando band_width come nuova colonna del DataFrame. Ho calcolato bandwidth_threshold come valore statico basato sul quantile dell’intera serie. Questo è un approccio semplice e veloce.
  2. Gestione dello Stato: Ho aggiunto self.entry_price = 0.0 in init() per memorizzare il prezzo di entrata, necessario per la logica di stop loss.
  3. Logica di next():
    • La logica è stata divisa in due blocchi chiari: gestione dell’uscita e gestione dell’ingresso.
    • La logica di uscita ora controlla sia il time exit (usando self.trade_bars) sia lo stop loss (confrontando self.close con self.entry_price).
    • La logica di ingresso, eseguita solo se non si è in posizione, applica il doppio filtro (direzione + confidenza) che hai progettato.
    • Quando un ordine buy viene eseguito, il prezzo di chiusura corrente viene salvato in self.entry_price.

Prossimi Passi

Il codice è pronto per il test. Seguiamo il tuo piano:

  1. Salva questo file come fire/strategies/momentum_strategy_v3_band_width_filter.py.
  2. Esegui un backtest su AAPL (o un altro ticker a tua scelta).
  3. Forniscimi il report completo delle metriche e il trade log.

Confronteremo i risultati con quelli della MomentumStrategyV2TimeExit per vedere se la nostra ipotesi (più qualità, meno trade) è stata confermata.