Smart Data Pipeline & Cache Architecture

1. Filosofia: Sovranità del Dato

In un software finanziario professionale, fidarsi ciecamente dei dati forniti dai provider è un rischio. Molti provider (es. Yahoo Finance) forniscono dati storici già rettificati (Adjusted) per default, nascondendo la storia reale dei prezzi (es. i “gap” dovuti agli split).

La Smart Data Pipeline di FIRE inverte questo paradigma:

  1. Storage RAW: Salviamo su disco sempre e solo i dati Grezzi (RAW). Se il provider non ce li dà, li calcoliamo inversamente.
  2. Metadati Separati: Salviamo gli eventi corporativi (Split, Dividendi) in un file separato.
  3. Rettifica On-Demand: L’applicazione applica la rettifica matematica in memoria solo quando l’utente lo richiede (Toggle ADJ/RAW).

Questo approccio garantisce che il database locale di FIRE sia “puro” e agnostico rispetto alle preferenze di visualizzazione momentanee.


2. Ontologia dei Dati

FIRE classifica ogni dataset storico secondo una tassonomia rigorosa definita nel campo data_nature dei metadati.

Tipo (Enum)DescrizioneComportamento DataManager
RAWDati grezzi storici. I prezzi riflettono il valore di mercato reale al momento dello scambio.Ideale. FIRE può applicare rettifiche matematiche se sono presenti eventi (Split).
ADJUSTEDDati già rettificati dal provider. Non è possibile risalire al prezzo originale con certezza assoluta.🔒 Locked. Il sistema forza la modalità “Adjusted”. Il toggle RAW è disabilitato o ininfluente.
UNKNOWNDati di origine ignota (es. CSV importato manualmente senza metadati).⚠️ As-Is. I dati vengono mostrati come sono. Non vengono applicate rettifiche automatiche.

3. Architettura di Storage: Il Pattern “Sidecar”

Per ogni richiesta dati (es. Ticker NVDA, Timeframe 1d), FIRE crea nella directory market_data_cache due file gemelli:

3.1. Il File Dati (.csv)

Contiene le serie temporali numeriche.

  • Formato: CSV (ottimizzato per leggibilità/debug) o Parquet (futuro, per performance).
  • Contenuto: Colonne Standard Open, High, Low, Close, Volume.
  • Invariante: I valori qui dentro sono sempre normalizzati a RAW.

3.2. Il File Metadati (.meta.json)

Il “passaporto” del dato. Contiene le informazioni necessarie per interpretare e trasformare il CSV.

Esempio Reale (NVDA_1d.meta.json):

{
    "ticker": "NVDA",
    "interval": "1d",
    "last_updated": "2025-12-10T10:00:00",
    "data_nature": "RAW",
    "events_source": "provider_api",
    "splits": {
        "1718026200": { // Timestamp Unix
            "date": 1718026200,
            "numerator": 10.0,
            "denominator": 1.0,
            "splitRatio": "10:1"
        }
    },
    "dividends": { ... }
}

4. Algoritmi di Rettifica

Il cuore matematico della pipeline gestisce due flussi opposti.

4.1. Reverse Adjustment (Normalizzazione in Scrittura)

  • Quando: Al momento del download dal Provider (es. Yahoo).
  • Problema: Yahoo invia prezzi Adjusted anche se chiediamo Raw, ma ci invia anche i metadati dello Split.
  • Soluzione: Calcoliamo il Raw originale per salvarlo pulito.

Dove (es. 10/1 = 10).

4.2. Forward Adjustment (Rettifica in Lettura)

  • Quando: Quando il DataManager serve i dati alla UI/Worker e il flag use_adjusted=True.
  • Logica: Si applica la rettifica a tutte le candele antecedenti la data dello split.


5. Flusso Dati (Data Flow)

5.1. Scrittura (Download & Cache)

graph LR
    A[Yahoo API] -->|JSON Mixed| B[YahooConnector]
    B -->|Extract Splits| C{Has Splits?}
    C -- Yes --> D[Reverse Adj Logic]
    C -- No --> E[Pass Through]
    D --> F[Tuple: DF_RAW + Meta]
    E --> F
    F --> G[DataManager]
    G -->|Write| H[(Disk: .csv + .json)]

5.2. Lettura (Fetch & Serve)

graph LR
    A[Worker Request] -->|Args: use_adj=True| B[DataManager]
    B -->|Check| C[(Disk Cache)]
    C -->|Load| D[DF_RAW + Meta]
    D --> E{User wants Adj?}
    E -- Yes --> F{Nature == RAW?}
    F -- Yes --> G[Apply Math / Ratio]
    G --> H[Return DF_ADJ]
    E -- No --> I[Return DF_RAW]

6. Thread Safety & Determinismo

Per garantire la stabilità in ambiente multithreaded (Qt), la pipeline adotta rigorosamente il Snapshot Pattern.

  1. Configurazione: La preferenza globale (SettingsManager.use_adjusted_prices) è gestita come Singleton.
  2. Snapshot: Quando un Worker viene creato, copia il valore booleano della preferenza nel suo costruttore.
  3. Esecuzione: Durante il run(), il Worker passa questo valore “congelato” al DataManager tramite il parametro use_adjusted_override.

Regola d’Oro: Un Worker non deve mai leggere SettingsManager direttamente durante l’esecuzione. Deve usare solo i valori passati al suo __init__.