Ecco l’audit comparativo delle tre proposte architetturali emerse durante la discussione.
Ho analizzato le proposte in base a 5 pilastri: Architettura (Come funziona), Robustezza (Sicurezza dei dati), Performance (Velocità), Storage (Spazio su disco) e Complessità (Sforzo di sviluppo).
I Contendenti
- La Nostra (Iniziale): “On-the-Fly Calculation”
- Scarica Raw +
AdjClose. Salva 6 colonne. Calcola i dati rettificati matematicamente ogni volta che vengono richiesti.
- Scarica Raw +
- Davide (Stakeholder Review): “Smart & Metadata”
- Evoluzione della “Fat Data”. Suggerisce pre-calcolo, ma aggiunge un layer di Metadati (versioning della cache), validazione della qualità dei dati e raccomanda formati binari (Parquet) e gestione rigorosa del Volume.
- Claudio (Expert Kimi): “Fat Data (Pragmatic)”
- Scarica tutto, calcola tutto subito, salva tutto (10 colonne) in un CSV “largo”. Approccio brutale ma efficace: spazio su disco vs semplicità.
Tabella di Audit Comparativo
| Caratteristica | 1. La Nostra (On-the-Fly) | 2. Davide (Smart & Metadata) | 3. Claudio (Fat Data - Pragmatic) |
|---|---|---|---|
| Logica Core | Calcolo a runtime (Open * Factor). | Pre-calcolo + Metadati di validazione. | Pre-calcolo e salvataggio di tutto. |
| Integrità Dati | ⚠️ Medio Rischio. Se cambia l’algoritmo, i dati storici cambiano. | ✅ Massima. I dati sono versionati e validati. | ✅ Alta. I dati sono “congelati” su disco al momento del download. |
| Gestione Volume | ❌ Ignorata. (Grave mancanza iniziale). | ✅ Corretta. (Vol / Ratio) con controlli. | ✅ Corretta. (Vol / Ratio) semplice. |
| Storage (Disco) | 🟢 Basso. File piccoli (6 colonne). | 🟡 Medio. File doppi + Metadati JSON. | 🔴 Alto. File doppi (10 colonne). |
| Performance | ⚡ Buona. Calcolo vettoriale veloce, ma ripetuto. | 🚀 Eccellente. Lettura diretta, zero calcoli. | 🚀 Eccellente. Lettura diretta CSV. |
| Debuggabilità | 🔴 Difficile. Devi calcolare a mente per verificare. | 🟢 Ottima. I metadati dicono “chi, cosa, quando”. | 🟢 Buona. Apri il CSV e vedi subito le colonne. |
| Sforzo Dev | 🟢 Basso (2-3 ore). | 🔴 Alto (6-8 ore). Gestione metadata complessa. | 🟡 Medio (3-4 ore). Modifica schema CSV. |
Analisi Critica dei Pro e Contro
1. Proposta “On-the-Fly” (La Nostra)
- Pro: È la più elegante dal punto di vista ingegneristico “teorico” (non duplica informazioni).
- Contro: È fragile. Come ha notato Davide, se Yahoo cambia il modo in cui fornisce
AdjClosedomani, il tuo calcolo si rompe. Inoltre, avevamo dimenticato l’adjusting del Volume, che è critico. - Verdetto: SCARTATA. Troppo rischiosa per un software che punta a standard professionali.
2. Proposta “Smart & Metadata” (Davide)
- Pro: È la soluzione “Enterprise”. I metadati (JSON header o file sidecar) risolvono il problema dell’invalidazione della cache (“Ho scaricato questi dati con la versione 1 o 2 dell’algoritmo?”).
- Contro: Introduce una complessità notevole nella gestione dei file (bisogna leggere header, verificare versioni, gestire formati Parquet). Potrebbe essere Over-Engineering per la fase attuale.
- Verdetto: GOLD STANDARD (Obiettivo Futuro). Da implementare quando il progetto sarà maturo.
3. Proposta “Fat Data” (Claudio)
- Pro: Pragmatismo puro. Lo spazio su disco costa poco. Avere le colonne
Adj Open,Adj Closeesplicite nel CSV rende il debug banale (basta aprire Excel). Risolve il problema del Volume e della coerenza senza la complessità dei metadati. - Contro: I file sono più grossi e “brutti” da vedere.
- Verdetto: VINCITORE OPERATIVO. È il miglior compromesso tra robustezza e velocità di implementazione oggi.
Ho completato l’analisi d’impatto basandomi su tutti i file forniti. La mappa è chiara. La Soluzione 2 (“Smart & Metadata”) richiede un intervento chirurgico su 4 livelli dell’applicazione.
Ecco il rapporto dettagliato e il piano d’azione.
1. Report di Impatto Architetturale
Livello A: Stato e Configurazione (Foundation)
fire/settings_manager.py:- Modifica: Aggiunta del default
"use_adjusted_prices": True. - Modifica: Getter/Setter per questa preferenza.
- Modifica: Aggiunta del default
fire/app_state.py:- Modifica: Aggiunta della property
use_adjusted_pricescon relativo segnaleadjusted_prices_changed. Questo permetterà alla UI (es. un toggle nella Toolbar) di scatenare il ricaricamento dei grafici in tempo reale.
- Modifica: Aggiunta della property
Livello B: Connettori (The Raw Material)
fire/core/data/abstract_data_connector.py:- Refactoring: L’attuale firma
get_historical_data -> DataFrameè limitante. - Nuova Strategia: Introdurremo un metodo esteso (o modificheremo quello esistente) per restituire una struttura più ricca:
(DataFrame, List[Event]).
- Refactoring: L’attuale firma
fire/connectors/yahoo_finance_connector.py:- Modifica Critica: Implementazione del parsing del blocco
events(splits e dividends) dal JSON di Yahoo, attualmente ignorato.
- Modifica Critica: Implementazione del parsing del blocco
Livello C: Gestore Dati (The Brain)
fire/core/data/data_manager.py:- Rivoluzione: Questo file subirà le modifiche più pesanti.
- Logica Metadata: Implementazione lettura/scrittura file JSON “sidecar” (es.
AAPL_1d.json) accanto al Parquet/CSV. - Logica Calcolo: Implementazione dell’algoritmo di rettifica (
Open * Factor,Volume / Factor) da eseguire dopo il download Raw e prima del salvataggio (o al volo, a seconda della strategia di caching scelta).
Livello D: Consumatori (The Workers)
fire/synapses/backtest/chart_data_worker.py:- Wiring: Deve ascoltare
AppState.use_adjusted_pricese passarlo alDataManager.
- Wiring: Deve ascoltare
2. Strategia per i “Dati Sconosciuti”
Hai sollevato un punto fondamentale: “Cosa facciamo se il provider non ci dice se i dati sono raw o adjusted?” (es. AlphaVantage o Binance).
In FIRE, applicheremo la regola della “Metadata Honesty”.
Nel file sidecar JSON, avremo un campo adjustment_status.
-
Caso Yahoo (Supportato):
{ "provider": "Yahoo", "adjustment_status": "calculated_by_fire", "events_source": "provider" }Comportamento: FIRE ha scaricato Raw + Eventi e ha calcolato la rettifica. L’utente può fare toggle.
-
Caso Binance (Crypto):
{ "provider": "Binance", "adjustment_status": "not_applicable", "asset_class": "crypto" }Comportamento: Le crypto non hanno stock split nello stesso senso. Il toggle è disabilitato o ininfluente.
-
Caso Opaco (es. CSV locale o API semplice):
{ "provider": "LocalCSV", "adjustment_status": "unknown/provider_default" }Comportamento: FIRE visualizza i dati “as-is”. Se l’utente attiva “Adjusted”, mostreremo un Warning Toast: “Dati di origine sconosciuta: impossibile garantire la rettifica.”
3. Il Piano d’Azione (Step-by-Step)
Procederemo in questo ordine per mantenere il sistema stabile (ogni step è testabile).
- Step 1: Foundation. Aggiorniamo
SettingsManagereAppStateper supportare il flag booleano globale. - Step 2: Connector Upgrade. Modifichiamo
YahooFinanceConnectorper estrarre splits e dividendi. (Useremo uno script POC per validare il parsing prima di integrarlo). - Step 3: DataManager Evolution. Implementiamo la logica di salvataggio “Sidecar Metadata” e la logica di calcolo.
- Step 4: Wiring. Colleghiamo i Worker e testiamo il flusso completo.
Questa è un’ottima domanda di validazione architetturale. Prima di scrivere codice, dobbiamo definire la nostra “Ontologia dei Dati”.
Nel mondo finanziario non esiste un unico standard ISO globale per lo storage dei dati storici su file (a differenza di FIX per il trading live), ma esistono Best Practices consolidate (usate da QuantConnect, Zipline, Bloomberg).
Ecco la proposta per lo standard FIRE Data Protocol (FDP), che risponde alle tue domande su gestione dell’incertezza e persistenza.
1. La Tassonomia: Come gestiamo i Provider “Opachi”?
Non possiamo indovinare. Dobbiamo classificare il dato in base a ciò che il provider (o l’utente, nel caso di CSV manuali) dichiara.
Nel nostro file di Metadata, introdurremo il campo obbligatorio data_nature (Natura del Dato), che può assumere solo questi valori (Enum):
Valore data_nature | Significato | Comportamento di FIRE |
|---|---|---|
RAW | Dati grezzi confermati. Nessuna rettifica applicata alla fonte. | ✅ Ideale. FIRE applica la rettifica se abbiamo gli eventi. |
ADJUSTED_PROVIDER | Il provider ci ha dato dati già rettificati (es. AlphaVantage standard). | 🔒 Locked. Il toggle “Adjusted” è bloccato su ON. Non possiamo “srettificare” (Un-adjust) in modo affidabile. |
UNKNOWN | Il provider non specifica o è un CSV generico senza metadati. | ⚠️ As-Is. Trattiamo i dati come sono. Il toggle “Adjusted” è disabilitato con un tooltip: “Natura del dato sconosciuta”. |
CRYPTO | Asset class che non subisce split azionari classici. | ℹ️ Neutral. Il concetto di adjusted non si applica allo stesso modo. |
2. Dove scriviamo queste informazioni? (Lo Standard JSON Sidecar)
Per ogni file dati (es. AAPL_1d.parquet o AAPL_1d.csv), creeremo un file gemello AAPL_1d.meta.json. Questo è il passaporto del dato.
Ecco la struttura standard proposta:
{
"schema_version": "1.0",
"ticker": "AAPL",
"asset_class": "equity", // o "crypto", "forex", "index"
"provider": "YahooFinance",
"last_updated": "2023-10-27T14:30:00Z",
// IL CUORE DELLA TUA DOMANDA
"data_nature": "RAW",
// GLI INGREDIENTI PER LA RETTIFICA (Se presenti)
"has_embedded_events": true, // Se il file dati contiene colonne 'Split'/'Dividend'
"events_source": "provider", // Chi ci ha dato gli eventi?
// TRACKING DELLE COLONNE (Mappatura Standard)
"columns_map": {
"open": "Open",
"close": "Close",
"adj_close": "Adj Close", // Opzionale
"split_factor": "Stock Splits",
"dividend_amt": "Dividends"
}
}3. Come gestiamo l’Importazione Manuale (Il Caso Peggiore)?
Se l’utente trascina un CSV dentro FIRE (“Drag & Drop”), non possiamo sapere se quei numeri sono Raw o Adjusted.
Soluzione: “L’Import Wizard” (Obbligo di Dichiarazione)
Quando l’utente importa un file CSV locale che non ha ancora un .meta.json:
- FIRE apre un piccolo dialogo.
- Chiede all’utente: “Questi dati sono Grezzi (Raw) o già Rettificati?”
- In base alla risposta, genera il
.meta.jsonimpostandodata_naturesuRAWoUNKNOWN.
4. Sintesi della Strategia
- Non inventiamo nulla: Usiamo termini standard (
OHLCV,Split,Dividend). - Siamo onesti: Se non sappiamo, scriviamo
UNKNOWNe disabilitiamo le feature avanzate per quel ticker, invece di mostrare dati falsati. - Persistenza separata: Il dato numerico sta nel CSV/Parquet (veloce da leggere), il significato sta nel JSON (facile da ispezionare/debuggare).
Ti convince questo approccio formale?
Se sì, procedo con l’implementazione partendo dallo Step 1 (Settings & AppState), integrando già questa logica di data_nature.
1. stiamo facendo “Reverse Engineering” dei Dati Raw
Yahoo Finance (e molti provider “consumer”) tende a fornire i dati storici già “puliti” e rettificati per facilitare la vita all’utente medio.
- Cosa ci manda Yahoo: Prezzo 2023 = $120 (Post-Split).
- La Realtà Storica: Prezzo 2023 = $1200 (Pre-Split).
- La nostra “Normalizzazione”: Prendiamo i 120 * 10 = $1200.
Perché lo facciamo? (Il vantaggio strategico) Salvando su disco il valore $1200 (RAW) e il metadato “Split 10:1”, otteniamo la massima flessibilità:
- Se l’utente vuole vedere il grafico “storico reale” (es. per capire quanto costava un’azione nel 2023), glielo possiamo mostrare ($1200).
- Se l’utente vuole fare analisi tecnica (es. Medie Mobili), applichiamo la rettifica al volo ($120) per evitare scalini nel grafico.
Se avessimo salvato direttamente $120 come “Raw”, avremmo perso per sempre l’informazione originale.
2. Come fa l’utente a passare da una serie all’altra?
Al momento, la funzionalità è implementata nel “motore” (Backend), ma manca l’interruttore sul “cruscotto” (Frontend).
L’interazione utente sarà immediata e fluida. Ecco come funzionerà una volta completata la UI:
-
Il Controllo UI: Nella Toolbar in alto (o nel menu dei controlli del grafico), ci sarà un pulsante/toggle: “ADJ” (o un’icona simile).
- Acceso (Default): Grafico rettificato (continuo).
- Spento: Grafico Raw (con i “salti” di prezzo storici).
-
Il Flusso “Reattivo” (Dietro le quinte): Quando l’utente clicca il pulsante:
- Il click chiama
AppState.set_use_adjusted_prices(False). AppStateemette il segnaleadjusted_prices_toggled(False).- Tutti i grafici aperti ascoltano questo segnale e lanciano automaticamente un Reload.
- Il
DataManagerrilegge lo stesso file CSV dal disco (senza riscaricare nulla da internet!). - Poiché il flag è
False, ilDataManagersalta il passaggio matematico di divisione. - Il grafico si ridisegna istantaneamente con i dati Raw.
- Il click chiama
Prossimo Step Naturale: Il Toggle UI
Se sei d’accordo, il prossimo passo è rendere visibile questo potere all’utente.
Dobbiamo aggiungere il pulsante “ADJ” alla MainWindow o alla toolbar dei grafici e collegarlo all’AppState.
Procediamo con l’implementazione del pulsante?