# build_prices_beta.py # Dépendances : pandas, yfinance, openpyxl (pour écrire .xlsx), requests (optionnel) # pip install pandas yfinance openpyxl requests import os import time import pandas as pd import yfinance as yf # ====== PARAMÈTRES À ADAPTER SI BESOIN ====== BASE_DIR = r"C:\Users\jeanl\Documents\01. Finance in London\16. Python" # Mets ici le nom exact de ton fichier tickers (CSV ou XLSX) présent dans BASE_DIR. # Format attendu : une seule colonne contenant les tickers Yahoo (sans header ou avec header "Ticker") TICKERS_FILENAME = "tickers.xlsx" # ex: "tickers.csv" ou "tickers.xlsx" # Nom du fichier Excel de sortie OUTPUT_FILENAME = "prices_beta.xlsx" # Période et fréquence des prix YF_PERIOD = "1y" # 1 an YF_INTERVAL = "1d" # quotidien # =========================================== def load_tickers(file_path: str) -> list[str]: """ Charge une liste de tickers depuis un CSV ou un XLSX. Accepte : - un fichier sans en-tête (1 colonne) - ou un fichier avec une colonne 'Ticker' Nettoie: trim, upper, supprime doublons et valeurs vides. """ ext = os.path.splitext(file_path)[1].lower() if ext == ".csv": try: df = pd.read_csv(file_path, header=None, dtype=str) if df.shape[1] == 1: tickers = df.iloc[:, 0].tolist() else: # Si CSV avec en-têtes et une colonne "Ticker" df2 = pd.read_csv(file_path, dtype=str) if "Ticker" not in df2.columns: raise ValueError("CSV must have a single column or a 'Ticker' column.") tickers = df2["Ticker"].tolist() except pd.errors.ParserError: # Deuxième tentative avec en-tête df = pd.read_csv(file_path, dtype=str) if "Ticker" not in df.columns: raise tickers = df["Ticker"].tolist() elif ext in (".xlsx", ".xls"): try: df = pd.read_excel(file_path, header=None, dtype=str) if df.shape[1] == 1: tickers = df.iloc[:, 0].tolist() else: df2 = pd.read_excel(file_path, dtype=str) if "Ticker" not in df2.columns: raise ValueError("Excel must have a single column or a 'Ticker' column.") tickers = df2["Ticker"].tolist() except ValueError: # Deuxième tentative avec en-tête df = pd.read_excel(file_path, dtype=str) if "Ticker" not in df.columns: raise tickers = df["Ticker"].tolist() else: raise ValueError("Unsupported file type. Use .csv or .xlsx") # Nettoyage tickers = [str(t).strip() for t in tickers if pd.notna(t)] tickers = [t for t in tickers if t] # non vides tickers = list(dict.fromkeys(tickers)) # dédoublonnage en gardant l'ordre return tickers def main(): input_path = os.path.join(BASE_DIR, TICKERS_FILENAME) output_path = os.path.join(BASE_DIR, OUTPUT_FILENAME) tickers = load_tickers(input_path) if not tickers: raise RuntimeError("No tickers found in input file.") print(f"Loaded {len(tickers)} tickers from: {input_path}") # 1) Prix ajustés 1 an — un batch unique pour tous les tickers print("Downloading 1y adjusted close prices from Yahoo...") prices = yf.download( tickers=tickers, period=YF_PERIOD, interval=YF_INTERVAL, auto_adjust=True, # 'Close' sera ajusté (dividendes/splits) threads=True ) # yfinance peut renvoyer un multi-index de colonnes si plusieurs champs sont présents if isinstance(prices.columns, pd.MultiIndex): # Avec auto_adjust=True, 'Close' correspond déjà à l'ajusté if "Close" in prices.columns.get_level_values(0): close = prices["Close"].copy() elif "Adj Close" in prices.columns.get_level_values(0): close = prices["Adj Close"].copy() else: raise RuntimeError("Expected 'Close' or 'Adj Close' in downloaded data.") else: close = prices.copy() # On ne garde que les colonnes présentes (yfinance peut en manquer si ticker invalide) cols = [c for c in tickers if c in close.columns] close = close[cols] if close.empty: raise RuntimeError("No price data retrieved. Check tickers or internet connection.") # 2) Betas Yahoo (info['beta']) — un appel par ticker print("Fetching Yahoo betas (info['beta'])...") betas = [] for sym in tickers: beta = None try: info = yf.Ticker(sym).info beta = info.get("beta", None) except Exception: pass betas.append({"Ticker": sym, "YahooBeta": beta}) time.sleep(0.2) # petite pause pour éviter d'éventuels rate limits beta_df = pd.DataFrame(betas) # 3) Écriture Excel (2 onglets) print(f"Writing Excel to: {output_path}") with pd.ExcelWriter(output_path, engine="openpyxl") as writer: close.to_excel(writer, sheet_name="Prices") # index = dates, colonnes = tickers beta_df.to_excel(writer, sheet_name="Beta", index=False) print("Done.") if __name__ == "__main__": main()