Componentes y cambios históricos del S&P 500

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:

  • Archivo CSV de componentes SP500
  • Archivo CSV de cambios históricos de SP500
  • 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.

    Deja un comentario