1- import gspread
2- from google .oauth2 .service_account import Credentials
3- from google .cloud import secretmanager
4- import pandas as pd
1+ # scripts/pipeline/update_db.py (REFACTORED)
52from datetime import datetime
6- import json
7- import psycopg2
8- import yfinance as yf
93
10- # --- 1. Leggi il JSON della SA dal Secret Manager ---
11- SECRET_NAME = "projects/trading-469418/secrets/service_account/versions/latest"
12- client_sm = secretmanager .SecretManagerServiceClient ()
13- response = client_sm .access_secret_version (name = SECRET_NAME )
14- service_account_info = json .loads (response .payload .data .decode ("UTF-8" ))
4+ # Import delle utilities
5+ from ..utils .gcp_utils import GoogleSheetsManager
6+ from ..utils .data_utils import download_yfinance_data , prepare_db_batch
7+ from ..utils .db_utils import DatabaseManager
158
16- SCOPES = [
17- "https://www.googleapis.com/auth/spreadsheets" ,
18- "https://www.googleapis.com/auth/drive"
19- ]
20-
21- creds = Credentials .from_service_account_info (service_account_info , scopes = SCOPES )
22- client = gspread .authorize (creds )
23-
24- # --- 2. Apri lo Sheet ---
9+ # Configurazioni
2510SPREADSHEET_ID = '1Uh3S3YCyvupZ5yZh2uDi0XYGaZIkEkupxsYed6xRxgA'
26- sheet = client .open_by_key (SPREADSHEET_ID )
27- worksheet = sheet .sheet1
28-
29- # --- 3. Leggi i ticker dallo Sheet ---
30- data = worksheet .get_all_records ()
31- df_sheet = pd .DataFrame (data )
32- tickers = df_sheet ['Ticker' ].dropna ().unique ().tolist ()
33-
34- print (f"Trovati { len (tickers )} ticker nello Sheet." )
3511
36- # --- 4. Scarica i prezzi odierni con yfinance ---
37- today = datetime .today ().strftime ('%Y-%m-%d' )
38- prices = yf .download (tickers , period = "1d" , interval = "1d" , group_by = "ticker" , auto_adjust = True , progress = False )
39-
40- # Normalizza i dati in lista di dizionari per l'inserimento
41- records = []
42- for ticker in tickers :
12+ def update_daily_prices ():
13+ """
14+ Aggiorna i prezzi giornalieri nel database con i dati più recenti
15+ """
16+ print ("🔄 Inizio aggiornamento prezzi giornalieri..." )
17+
18+ # --- 1. Setup Google Sheets e recupero ticker ---
19+ print ("📊 Recupero ticker da Google Sheets..." )
20+ sheets_manager = GoogleSheetsManager ()
21+ tickers = sheets_manager .get_tickers_from_sheet (SPREADSHEET_ID )
22+ print (f"✅ Trovati { len (tickers )} ticker nello Sheet." )
23+
24+ if not tickers :
25+ print ("❌ Nessun ticker trovato. Operazione interrotta." )
26+ return
27+
28+ # --- 2. Download dati da yfinance ---
29+ print ("📈 Download dati odierni da yfinance..." )
4330 try :
44- df_t = prices [ticker ] if len (tickers ) > 1 else prices
45- df_t = df_t [['Open' , 'High' , 'Low' , 'Close' , 'Volume' ]].reset_index ()
46- df_t ['Ticker' ] = ticker
47- df_t .rename (columns = {
48- 'Date' : 'date' ,
49- 'Open' : 'open' ,
50- 'High' : 'high' ,
51- 'Low' : 'low' ,
52- 'Close' : 'close' ,
53- 'Volume' : 'volume' ,
54- 'Ticker' : 'ticker'
55- }, inplace = True )
56- records .extend (df_t .to_dict (orient = 'records' ))
31+ df_prices = download_yfinance_data (tickers , period = "1d" , interval = "1d" )
32+ print (f"✅ Righe pronte da inserire: { len (df_prices )} " )
33+
34+ if df_prices .empty :
35+ print ("❌ Nessun dato scaricato. Operazione interrotta." )
36+ return
37+
5738 except Exception as e :
58- print (f"Errore con { ticker } : { e } " )
59-
60- df_prices = pd .DataFrame (records )
61- print (f"Righe pronte da inserire: { len (df_prices )} " )
62-
63- # --- 5. Leggi i secret del DB ---
64- SECRET_DB_NAME = "projects/trading-469418/secrets/db_info/versions/latest"
65- response_db = client_sm .access_secret_version (name = SECRET_DB_NAME )
66- db_info = json .loads (response_db .payload .data .decode ("UTF-8" ))
67-
68- conn = psycopg2 .connect (
69- host = db_info ["DB_HOST" ],
70- port = db_info ["DB_PORT" ],
71- database = db_info ["DB_NAME" ],
72- user = db_info ["DB_USER" ],
73- password = db_info ["DB_PASSWORD" ]
74- )
75- cursor = conn .cursor ()
76-
77- # --- 6. Inserisci/aggiorna dati nella tabella universe ---
78- insert_query = """
79- INSERT INTO universe (date, ticker, open, high, low, close, volume)
80- VALUES (%s, %s, %s, %s, %s, %s, %s)
81- ON CONFLICT (date, ticker) DO UPDATE
82- SET open = EXCLUDED.open,
83- high = EXCLUDED.high,
84- low = EXCLUDED.low,
85- close = EXCLUDED.close,
86- volume = EXCLUDED.volume;
87- """
88-
89- batch = [
90- (row ['date' ].date (), row ['ticker' ], row ['open' ], row ['high' ], row ['low' ], row ['close' ], row ['volume' ])
91- for _ , row in df_prices .iterrows ()
92- ]
93-
94- cursor .executemany (insert_query , batch )
95- conn .commit ()
96- cursor .close ()
97- conn .close ()
39+ print (f"❌ Errore nel download dati: { e } " )
40+ return
41+
42+ # --- 3. Preparazione dati per DB ---
43+ print ("🔧 Preparazione dati per inserimento..." )
44+ batch_data = prepare_db_batch (df_prices )
45+
46+ if not batch_data :
47+ print ("❌ Nessun dato valido da inserire." )
48+ return
49+
50+ # --- 4. Inserimento in database ---
51+ print ("💾 Inserimento dati nel database..." )
52+ try :
53+ db_manager = DatabaseManager ()
54+
55+ # Usa DO UPDATE per aggiornare dati esistenti (prezzi possono cambiare durante il giorno)
56+ conflict_resolution = """DO UPDATE
57+ SET open = EXCLUDED.open,
58+ high = EXCLUDED.high,
59+ low = EXCLUDED.low,
60+ close = EXCLUDED.close,
61+ volume = EXCLUDED.volume"""
62+
63+ rows_processed = db_manager .insert_batch_universe (batch_data , conflict_resolution )
64+ print (f"✅ { rows_processed } righe inserite/aggiornate su PostgreSQL" )
65+
66+ except Exception as e :
67+ print (f"❌ Errore nell'inserimento database: { e } " )
68+ return
69+
70+ print ("🎉 Aggiornamento completato con successo!" )
9871
99- print (f"{ len (batch )} righe inserite/aggiornate su PostgreSQL" )
72+ if __name__ == "__main__" :
73+ update_daily_prices ()
0 commit comments