Puede pagar para obtener los componentes históricos del S&P 500 o usar varias fuentes gratuitas. Debido al sesgo de supervivencia, obtener una lista precisa de los componentes del S&P500 a lo largo del tiempo es fundamental al desarrollar un trading estrategia.
Obtención de los componentes históricos del S&P500
Múltiples proveedores de datos pagos y gratuitos brindan la lista de constituyentes del S&P500. Encontrar los componentes de otros índices puede ser más complejo y generalmente requiere una fuente paga. A continuación muestro los mejores recursos gratuitos y de pago que he encontrado para los componentes del S&P500. Agregué los archivos de Analyzing Alpha creados a partir de Wikipedia para mayor comodidad:
Descargue los componentes históricos del S&P 500
Si solo está aquí por los datos CSV, utilice lo siguiente, que se ofrece gratuitamente mediante el siguiente Licencia Creative Commons:
Crear su propia lista de componentes S&P500
Le mostraré cómo crear su propio conjunto de datos de componentes del S&P500 utilizando Python mediante el web scraping de Wikipedia, ya que proporciona más datos del historial del S&P 500. Si me sigue, el cuaderno Jupyter es la mejor herramienta para este tipo de manipulación y limpieza de datos.
Notará que Wikipedia se mantiene actualizada e incluye las adiciones y eliminaciones del S&P 500 para 2022.
Raspado de los constituyentes con pandas
pandas.read_html nos permite raspar una página web para tablas Html y agregarlas a un marco de datos. Importo las bibliotecas requeridas y tomo los datos.
import datetime as dt
import pandas as pd
url = 'https://en.wikipedia.org/wiki/List_of_S%26P_500_companies'
data = pd.read_html(url)
Si echas un vistazo a la Wikipedia Lista de empresas S&P500notará que hay una tabla que contiene los componentes actuales del S&P500 y una tabla que enumera los cambios históricos.
Tomemos la primera tabla y usemos Pandas para manipularla en el formato que queremos. Las tareas iterativas de datos como estas suelen realizarse mejor en Jupyter Notebook. Agregué el primer día de S&P500 trading y verificó las fechas usando RegEx si faltaban datos.
# Get current S&P table and set header column
sp500 = data[0].iloc[:, [0,1,6,7]]
sp500.columns = ['ticker', 'name', 'date' , 'cik']
# Get rows where date is missing or not formatted correctly.
mask = sp500['date'].str.strip().str.fullmatch('\d{4}-\d{2}-\d{2}')
mask.loc[mask.isnull()] = False
mask = mask == False
sp500[mask].head()
ticker name date cik
7 AMD Advanced Micro Devices NaN 2488
51 T AT&T 1983-11-30 (1957-03-04) 732717
126 ED Consolidated Edison NaN 1047862
130 GLW Corning NaN 24741
138 DHR Danaher Corporation NaN 313616
139 DRI Darden Restaurants NaN
Rellene los datos que faltan
A continuación, usaremos zfill para completar con cero el código cik, ya que es una cadena de diez dígitos y no un número entero, y estableceremos todas las fechas faltantes en 1900-01-01. ¡Con suerte, la comunidad y otros pueden ayudar a llenar estos vacíos!
current = sp500.copy()
current.loc[mask, 'date'] = '1900-01-01'
current.loc[:, 'date'] = pd.to_datetime(current['date'])
current.loc[:, 'cik'] = current['cik'].apply(str).str.zfill(10)
Con la tabla actual organizada de la manera que queremos, es hora de trabajar en los ajustes históricos usando pandas para cambiar los datos al formato que queremos. Crearemos un marco de datos para adiciones y eliminaciones, luego las concatenaremos.
# Get the adjustments dataframe and rename columns
adjustments = data[1]
columns = ['date', 'ticker_added','name_added', 'ticker_removed', 'name_removed', 'reason']
adjustments.columns = columns
# Create additions dataframe.
additions = adjustments[~adjustments['ticker_added'].isnull()][['date','ticker_added', 'name_added']]
additions.columns = ['date','ticker','name']
additions['action'] = 'added'
# Create removals dataframe.
removals = adjustments[~adjustments['ticker_removed'].isnull()][['date','ticker_removed','name_removed']]
removals.columns = ['date','ticker','name']
removals['action'] = 'removed'
# Merge the additions and removals into one dataframe.
historical = pd.concat([additions, removals])
historical.head()
date ticker name action
0 September 20, 2021 MTCH Match Group added
1 September 20, 2021 CDAY Ceridian added
2 September 20, 2021 BRO Brown & Brown added
3 August 30, 2021 TECH Bio-Techne added
4 July 21, 2021 MRNA Moderna added
Ahora que tenemos los datos actuales e históricos, agreguemos cualquier ticker en el índice S&P 500 pero no en el historial de Wikipedia.
missing = current[~current['ticker'].isin(historical['ticker'])].copy()
missing['action'] = 'added'
missing = missing[['date','ticker','name','action', 'cik']]
missing.loc[:, 'cik'] = current['cik'].apply(str).str.zfill(10)
missing.head()
date ticker name action cik
0 1976-08-09 MMM 3M added 0000066740
1 1964-03-31 ABT Abbott Laboratories added 0000001800
6 1997-05-05 ADBE Adobe added 0000796343
9 1998-10-02 AES AES Corp added 0000874761
10 1999-05-28 AFL Aflac added 0000004977
Combinar y deduplicar los datos
Ahora fusionaremos las empresas históricas y las del S&P 500 y luego las deduplicaremos.
sp500_history = pd.concat([historical, missing])
sp500_history = sp500_history.sort_values(by=['date','ticker'], ascending=[False, True])
sp500_history = sp500_history.drop_duplicates(subset=['date','ticker'])
sp500_history
date ticker name action cik
112 September 8, 2016 CHTR Charter Communications added NaN
112 September 8, 2016 EMC EMC Corporation removed NaN
113 September 6, 2016 MTD Mettler Toledo added NaN
113 September 6, 2016 TYC Tyco International removed NaN
208 September 5, 2012 LYB LyondellBasell added NaN
... ... ... ... ... ...
484 1900-01-01 00:00:00 WAT Waters Corporation added 0001000697
493 1900-01-01 00:00:00 WHR Whirlpool Corporation added 0000106640
483 1900-01-01 00:00:00 WM Waste Management added 0000823768
491 1900-01-01 00:00:00 WRK WestRock added 0001732845
492 1900-01-01 00:00:00 WY Weyerhaeuser added 0000106535
Exportar datos a CSV
Y finalmente, exportaremos ambos archivos a un CSV para su descarga, que puede encontrar en este cuaderno y los archivos asociados en el Analizando Alfa Github.