1. Filosofia: “Dichiara le Intenzioni, non Disegnare”

Per replicare la flessibilità di Pine Script, abbiamo esteso BaseStrategy con un’API che permette di “dichiarare” le proprie esigenze di visualizzazione. L’architettura è progettata per disaccoppiare la logica della strategia dal rendering finale.

Il tuo ruolo come sviluppatore di strategie è usare i metodi plot(), plot_shape() e set_bar_color() per descrivere COSA vuoi vedere. Il framework si occuperà di COME disegnarlo.

Questa guida illustra il riferimento completo dell’API e le best practice.

2. Disegnare Linee e Indicatori (self.plot)

Il metodo self.plot è l’equivalente della funzione plot() di Pine Script e serve per disegnare serie di dati continue, come Medie Mobili, RSI, o bande.

Sintassi

self.plot(series, name, color, style, width, overlay)
  • series (pd.Series): Obbligatorio. La serie di dati da disegnare.
  • name (str): Obbligatorio. Il nome da mostrare nella legenda del grafico.
  • color (str): Colore della linea (es. 'orange', '#FFD700'). Default: 'blue'.
  • width (int): Spessore della linea. Default: 1.
  • style (str): Stile della linea ('line', 'dotted', 'dashed'). Supporto futuro per 'histogram'. Default: 'line'.
  • overlay (bool): Se True, la linea viene disegnata sul grafico principale dei prezzi. Se False, verrà disegnata in un pannello separato sotto il grafico (non ancora implementato, ma previsto). Default: True.

Dove usarlo?

Il metodo self.plot va chiamato esclusivamente all’interno del metodo init() della tua strategia, subito dopo aver calcolato la serie dell’indicatore.

Esempio: Disegnare una EMA

# In fire/strategies/my_strategy.py
 
class MyEmaStrategy(BaseStrategy):
    def __init__(self):
        super().__init__()
        self.add_parameter("ema_period", 20, type="int")
 
    def init(self):
        ema_period = self.params["ema_period"]
        
        # 1. Calcola l'indicatore
        self.my_ema = self.data['Close'].ewm(span=ema_period, adjust=False).mean()
        
        # 2. Dichiara l'intenzione di disegnarlo
        self.plot(self.my_ema, name=f"EMA({ema_period})", color="cyan", width=2)

3. Disegnare Marker di Segnale (self.plot_shape)

Il metodo self.plot_shape è l’equivalente di plotshape() e serve a disegnare icone (marker) su specifiche barre per evidenziare un evento (es. un segnale di setup, un incrocio).

Sintassi

self.plot_shape(style, color, location, text)
  • style (str): La forma dell’icona ('circle', 'square', 'arrow_up', 'arrow_down').
  • color (str): Il colore dell’icona.
  • location (str): La posizione rispetto alla barra ('above', 'below').
  • text (str): Un breve testo opzionale da mostrare vicino al marker.

Dove usarlo?

Il metodo self.plot_shape va chiamato all’interno del metodo next(), solo sulla barra in cui la condizione è vera.

Esempio: Marcare un Setup “SlingShot”

# In fire/strategies/slingshot_strategy.py
 
    def next(self):
        # ... (logica di calcolo) ...
        is_slingshot = (c > ema) and (c_1 < ema_1) # ...
 
        if not self.position:
            if is_slingshot:
                self.buy()
                
                # Disegna un marker blu sotto la barra del segnale
                if self.params["show_slingshot"]:
                    self.plot_shape(style="circle", color="blue", location="below", text="Sling")

4. Colorare le Barre (self.set_bar_color)

Il metodo self.set_bar_color è l’equivalente di barcolor() e serve a cambiare il colore di una specifica candela per evidenziarla.

Sintassi

self.set_bar_color(color)
  • color (str): Il colore da applicare alla candela corrente (es. 'yellow', '#FFD700').

Dove usarlo?

Come plot_shape, va chiamato all’interno del metodo next(), condizionalmente.

Esempio: Colorare la Candela del Segnale SlingShot

# In fire/strategies/slingshot_strategy.py
 
    def next(self):
        # ... (logica di calcolo) ...
        is_slingshot = (c > ema) and (c_1 < ema_1) # ...
 
        if not self.position:
            if is_slingshot:
                self.buy()
                
                # Colora la candela corrente di giallo/oro
                if self.params["paint_bar"]:
                    self.set_bar_color(self.params["bar_color"])

5. Il Flusso Dati Dietro le Quinte (Architettura)

  1. Raccolta: La tua strategia, eseguita dal BacktestEngine, popola i dizionari interni (_plot_lines, _plot_shapes, _bar_colors).
  2. Trasporto: Al termine del backtest, il BacktestEngine impacchetta questi dati in un dizionario custom_plots e lo restituisce al BacktestWorker.
  3. Inoltro: Il BacktestWorker aggiunge custom_plots all’oggetto dei risultati che viene inviato alla UI tramite un segnale Qt.
  4. Preparazione: Il BacktestPlottingHandler riceve i risultati e passa custom_plots al LWCOverlayManager.
  5. Rendering: Il LWCOverlayManager itera sulle istruzioni e chiama i metodi JavaScript (add_line_series, set_markers, etc.) per disegnare gli elementi sul grafico.