Las finanzas y la economía son cada vez más interesantes para todo tipo de personas, independientemente de su carrera o profesión. Esto se debe a que a todos nos afectan los datos económicos, o al menos nos interesa cada vez más estar al día, y tenemos mucha información a la mano.
Cada día se envían miles de millones de bytes de datos financieros a través de Internet. Ya sea el precio de una acción, una transacción de comercio electrónico o incluso información sobre el PIB de un país. Todos estos datos, cuando se organizan y gestionan adecuadamente, pueden utilizarse para construir algunas aplicaciones de software sorprendentes y perspicaces.
Utilizaremos Python para acceder a datos financieros públicos, organizarlos y combinarlos para obtener nuevos conocimientos sobre cómo el dinero hace girar el mundo. Nos centraremos principalmente en dos módulos de Python:
Utilizaremos estos módulos para importar datos de algunas de las mayores organizaciones financieras del mundo, así como datos almacenados localmente en nuestros ordenadores. Al final del post, deberías sentirte cómodo importando datos financieros, ya sea de una fuente pública o de un archivo local, en Python, organizando esos datos y combinándolos entre sí
Muchas instituciones financieras, mercados de valores y bancos globales proporcionan al público grandes cantidades de datos que almacenan públicamente. La mayoría de estos datos están bien organizados, se actualizan en directo y son accesibles mediante el uso de una interfaz de programación de aplicaciones (API), que ofrece a los lenguajes de programación como Python una forma de descargarlos e importarlos.
El módulo pandas-datareader
está específicamente diseñado para interactuar con algunas de las APIs de datos financieros más populares del mundo, e importar sus datos en un DataFrame de pandas fácilmente digerible. Se accede a cada API financiera mediante una función diferente expuesta por pandas-datareader
. Generalmente, el acceso a cada API requiere un conjunto diferente de argumentos e información que debe proporcionar el programador.
Vamos a importar datos de varias de estas API y a jugar con ellos. Para una lista completa de todos los datos a los que puede acceder el pandas-datareader
, puedes consultar la documentación oficial.
Vamos a hacer un pequeño programa que utilice pandas-datareader
para obtener los datos de la API gdp del Banco Mundial. Primero instalaremos la librería de la siguiente manera (Por favor, ejecuta el comando por tu cuenta en la siguiente celda, ¡ya la tengo instalada!)
!pip3 install pandas_datareader
from pandas_datareader import wb
from datetime import datetime
Aquí hemos importado los datos del Banco Mundial a través de wb
. Y hemos importado la librería python datetime
, para poner las fechas de inicio y fin en las que quiero hacer el análisis. Para más información sobre Python Datetimes ver este otro articulo!
start = datetime(2005, 1, 1)
end = datetime(2008, 1, 1)
indicator_id = 'NY.GDP.PCAP.KD'
gdp_per_capita = wb.download(indicator=indicator_id, start=start, end=end, country=['US', 'CA', 'MX'])
gdp_per_capita
NY.GDP.PCAP.KD | ||
---|---|---|
country | year | |
Canada | 2008 | 48495.204040 |
2007 | 48534.174477 | |
2006 | 45857.996552 | |
2005 | 44471.080060 | |
Mexico | 2008 | 9587.636339 |
2007 | 9622.047957 | |
2006 | 9547.333571 | |
2005 | 9270.656542 | |
United States | 2008 | 49319.478865 |
2007 | 49856.281490 | |
2006 | 49405.767296 | |
2005 | 48499.812374 |
El método download
tiene diferentes parámetros que podemos pasar para obtener los datos del Banco Mundial. Entre ellos está el indicator_id
. Puedes encontrar más información sobre los parámetros aquí.
Como podemos ver, con este comando hemos obtenido los datos del PIB per cápita de 3 países en una fecha determinada
El mercado de valores NASDAQ identifica cada una de sus acciones con un símbolo único:
También proporciona una útil API para acceder a los símbolos que se negocian actualmente en ella. Pandas-datareader proporciona varias funciones para importar datos de la API de NASDAQ a través de su submódulo nasdaq_trader
.
from pandas_datareader.nasdaq_trader import get_nasdaq_symbols
Para importar la lista de símbolos bursátiles, queremos utilizar la función get_nasdaq_symbols
de nasdaq_trader
. Se hace de esta manera
symbols = get_nasdaq_symbols()
Cuando se llame, irá a la API de NASDAQ, e importará la lista de símbolos que se están negociando actualmente. La ventaja de usar pandas-datareader
es que toda la lógica para interactuar con la API de NASDAQ o cualquier otra API está encapsulada en submódulos y funciones fáciles de usar como las anteriores.
symbols
Nasdaq Traded | Security Name | Listing Exchange | Market Category | ETF | Round Lot Size | Test Issue | Financial Status | CQS Symbol | NASDAQ Symbol | NextShares | |
---|---|---|---|---|---|---|---|---|---|---|---|
Symbol | |||||||||||
A | True | Agilent Technologies, Inc. Common Stock | N | False | 100.0 | False | NaN | A | A | False | |
AA | True | Alcoa Corporation Common Stock | N | False | 100.0 | False | NaN | AA | AA | False | |
AAA | True | Listed Funds Trust AAF First Priority CLO Bond... | P | True | 100.0 | False | NaN | AAA | AAA | False | |
AAAU | True | Goldman Sachs Physical Gold ETF Shares | P | True | 100.0 | False | NaN | AAAU | AAAU | False | |
AAC.U | True | Ares Acquisition Corporation Units, each consi... | N | False | 100.0 | False | NaN | AAC.U | AAC= | False | |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
ZXYZ.A | True | Nasdaq Symbology Test Common Stock | Q | Q | False | 100.0 | True | N | NaN | ZXYZ.A | False |
ZXZZT | True | NASDAQ TEST STOCK | Q | G | False | 100.0 | True | N | NaN | ZXZZT | False |
ZYME | True | Zymeworks Inc. Common Shares | N | False | 100.0 | False | NaN | ZYME | ZYME | False | |
ZYNE | True | Zynerba Pharmaceuticals, Inc. - Common Stock | Q | G | False | 100.0 | False | N | NaN | ZYNE | False |
ZYXI | True | Zynex, Inc. - Common Stock | Q | S | False | 100.0 | False | N | NaN | ZYXI | False |
9798 rows × 11 columns
Tenemos un total de 9.338 acciones diferentes que cotizan en el Nasdaq, y en cuyas columnas tenemos diferente información económica y financiera sobre esa acción. Pero, ¿qué ocurre si queremos acceder a un solo símbolo/acción?
symbols.loc['IBM']
Nasdaq Traded True Security Name International Business Machines Corporation Co... Listing Exchange N Market Category ETF False Round Lot Size 100 Test Issue False Financial Status NaN CQS Symbol IBM NASDAQ Symbol IBM NextShares False Name: IBM, dtype: object
El análisis técnico en finanzas es el tipo de análisis que se realiza mediante estadísticas y gráficos sobre acciones (o índices en nuestro caso). Vamos a ver cómo hacer algo muy sencillo con 'Plotly' una librería de Python para hacer gráficos. En este caso accederemos a las cotizaciones diarias de Microsoft. ¡Vamos a hacerlo!
!pip3 install plotly
Requirement already satisfied: plotly in /home/daniel/Desktop/datacademy_project/notebooks/lib/python3.6/site-packages (4.11.0)
Requirement already satisfied: six in /home/daniel/Desktop/datacademy_project/notebooks/lib/python3.6/site-packages (from plotly) (1.15.0)
Requirement already satisfied: retrying>=1.3.3 in /home/daniel/Desktop/datacademy_project/notebooks/lib/python3.6/site-packages (from plotly) (1.3.3)
WARNING: You are using pip version 20.1.1; however, version 21.0.1 is available.
You should consider upgrading via the '/home/daniel/Desktop/datacademy_project/notebooks/bin/python -m pip install --upgrade pip' command.
import plotly.graph_objects as go
import pandas_datareader.data as web
stock = 'MSFT'
start = datetime(2019, 1, 1)
df = web.DataReader(stock, data_source='yahoo', start=start)
df
High | Low | Open | Close | Volume | Adj Close | |
---|---|---|---|---|---|---|
Date | ||||||
2019-01-02 | 101.750000 | 98.940002 | 99.550003 | 101.120003 | 35329300.0 | 98.602066 |
2019-01-03 | 100.190002 | 97.199997 | 100.099998 | 97.400002 | 42579100.0 | 94.974693 |
2019-01-04 | 102.510002 | 98.930000 | 99.720001 | 101.930000 | 44060600.0 | 99.391899 |
2019-01-07 | 103.269997 | 100.980003 | 101.639999 | 102.059998 | 35656100.0 | 99.518669 |
2019-01-08 | 103.970001 | 101.709999 | 103.040001 | 102.800003 | 31514400.0 | 100.240234 |
... | ... | ... | ... | ... | ... | ... |
2021-02-01 | 242.500000 | 232.429993 | 235.059998 | 239.649994 | 33314200.0 | 239.649994 |
2021-02-02 | 242.309998 | 238.690002 | 241.300003 | 239.509995 | 25916300.0 | 239.509995 |
2021-02-03 | 245.089996 | 239.259995 | 239.570007 | 243.000000 | 27158100.0 | 243.000000 |
2021-02-04 | 243.240005 | 240.369995 | 242.660004 | 242.009995 | 25262400.0 | 242.009995 |
2021-02-05 | 243.279999 | 240.419998 | 242.229996 | 240.931702 | 3204875.0 | 240.931702 |
529 rows × 6 columns
Hemos accedido a los datos de MSFT
. Lo hemos hecho importando .data
de datareader y dándole el alias web
. Bajo el capó estamos usando Yahoo Finance para importar los datos desde una API, pero en este caso pandas.datareader
nos ha permitido hacerlo de forma muy sencilla. Ahora vamos a graficar el resultado para hacer un Análisis Técnico.
graph = {
'x': df.index,
'open': df.Open,
'close': df.Close,
'high': df.High,
'low': df.Low,
'type': 'candlestick',
'name': 'MSFT',
'showlegend': True
}
layout = go.Figure(
data = [graph],
layout_title="Microsoft Stock"
)
layout
¡Acabamos de hacer algo muy interesante y es graficar la acicón de MSFT con los datos actualizados! ¡Hoy es 5 de Febrero de 2021, por lo que el último dato de mi gráfico es esa fecha, tú puedes hacer lo mismo, colocar el mouse al final del gráfico y ver la última cotización de la acción! ¡Podrías en este caso acceder a tu cartera de inversiones y ejecutar el código diariamente y hacer un análisis técnico sobre esas entradas!
Muchas de las APIs a las que se conecta el pandas-datareader
nos permiten filtrar los datos que obtenemos por fecha. Las instituciones financieras suelen llevar un registro de datos que se remonta a varias décadas atrás, y cuando importamos esos datos, es útil poder especificar exactamente cuándo queremos que procedan
Una API que hace precisamente eso es la del Banco de la Reserva Federal de San Luis (FRED
), a la que podemos acceder importando primero el submódulo pandas_datareader.data
y llamando después a su función DataReader:
import pandas_datareader.data as web
start = datetime(2019, 1, 1)
end = datetime(2019, 2, 1)
sap_data = web.DataReader('SP500', 'fred', start, end)
sap_data
SP500 | |
---|---|
DATE | |
2019-01-01 | NaN |
2019-01-02 | 2510.03 |
2019-01-03 | 2447.89 |
2019-01-04 | 2531.94 |
2019-01-07 | 2549.69 |
2019-01-08 | 2574.41 |
2019-01-09 | 2584.96 |
2019-01-10 | 2596.64 |
2019-01-11 | 2596.26 |
2019-01-14 | 2582.61 |
2019-01-15 | 2610.30 |
2019-01-16 | 2616.10 |
2019-01-17 | 2635.96 |
2019-01-18 | 2670.71 |
2019-01-21 | NaN |
2019-01-22 | 2632.90 |
2019-01-23 | 2638.70 |
2019-01-24 | 2642.33 |
2019-01-25 | 2664.76 |
2019-01-28 | 2643.85 |
2019-01-29 | 2640.00 |
2019-01-30 | 2681.05 |
2019-01-31 | 2704.10 |
2019-02-01 | 2706.53 |
La función DataReader toma 4 argumentos:
Cambiando las fechas de inicio y fin, podemos filtrar fácilmente los datos que recibimos
Shift()
¶Una vez que hemos importado un DataFrame lleno de datos financieros, hay algunas formas muy interesantes de manipularlo. En este ejercicio veremos la operación shift()
, una función de DataFrame que mueve todas las filas de una columna hacia arriba o hacia abajo
Shift()
puede ser llamado en una sola columna (como en la imagen de arriba), o en todo el DataFrame donde todas las columnas serán desplazadas. También puede desplazarse por más de una fila, y en cualquier dirección.
# desplaza todas las filas hacia abajo en 1
dataframe.shift(1)
# desplaza todas las filas de la columna nombre hacia arriba 5
dataframe[name].shift(-5)
# desplaza todas las filas de la columna del nombre hacia abajo 3
dataframe[name].shift(3)
Shift es especialmente útil cuando se trata de datos financieros. Por ejemplo, se puede utilizar para ayudar a calcular el porcentaje de crecimiento entre una fila y la siguiente, o para encontrar la diferencia en los precios de las acciones durante una serie de días. Veamos un ejemplo
start = datetime(2008, 1, 1)
end = datetime(2018, 1, 1)
gdp = web.DataReader('GDP', 'fred', start, end)
gdp.head()
GDP | |
---|---|
DATE | |
2008-01-01 | 14651.039 |
2008-04-01 | 14805.611 |
2008-07-01 | 14835.187 |
2008-10-01 | 14559.543 |
2009-01-01 | 14394.547 |
Hemos importado el GDP
del FRED
, ahora crearemos una nueva columna llamada Growth
donde podremos hacer el cálculo de la diferencia (en valores absolutos) entre los diferentes días
gdp['Growth'] = gdp['GDP'] - gdp['GDP'].shift(1)
gdp.head()
GDP | Growth | |
---|---|---|
DATE | ||
2008-01-01 | 14651.039 | NaN |
2008-04-01 | 14805.611 | 154.572 |
2008-07-01 | 14835.187 | 29.576 |
2008-10-01 | 14559.543 | -275.644 |
2009-01-01 | 14394.547 | -164.996 |
Ahora podemos ver las diferencias absolutas en esta nueva columna. Una aclaración importante: la primera fila de la columna de crecimiento es ahora NaN
porque no tiene nadie con quien hacer el cálculo, es la primera fila del conjunto de datos
Dos cálculos útiles que se pueden hacer con los datos financieros son la varianza y la covarianza. Para ilustrar estos conceptos, utilicemos el ejemplo de un DataFrame que mide los precios de las acciones y los bonos a lo largo del tiempo
La varianza mide la distancia entre un conjunto de números y su media. En finanzas, se utiliza para determinar la volatilidad de las inversiones.
dataframe['acciones'].var() # 106427
dataframe['bonos'].var() # 2272
En los cálculos de varianza anteriores, el valor de las acciones es mayor que el de los bonos (106427
frente a 2272
). Esto se debe a que los precios de las acciones están más dispersos que los de los bonos, lo que indica que las acciones son una inversión más volátil.
La covarianza, en un contexto financiero, describe la relación entre los rendimientos de dos inversiones diferentes a lo largo de un periodo de tiempo, y puede utilizarse para ayudar a equilibrar una cartera. Llamar a nuestras columnas de acciones y bonos cov()
produce una matriz que define los valores de covarianza entre cada par de columnas en el DataFrame. La covarianza también se conoce como correlación en finanzas. En nuestros datos de ejemplo, cuando los precios de las acciones suben, los bonos bajan. Podemos utilizar la función de covarianza para ver esto numéricamente.
dataframe.cov()
El código anterior produce la siguiente salida de DataFrame:
Cada valor anterior representa la covarianza entre dos columnas. Cuanto más alto sea el número, más tienden las inversiones a subir y bajar al mismo tiempo. Las columnas superior derecha e inferior izquierda representan la covarianza entre acciones y bonos. Aquí tenemos un número negativo, que indica que las acciones y los bonos tienden a moverse en direcciones diferentes. Para ver esto con un ejemplo, vamos a hacer un ejercicio más complejo, ¡vamos!
La rentabilidad logarítmica es uno de los tres métodos para calcular la rentabilidad y supone que los rendimientos se componen de forma continua y no a través de subperíodos. Se calcula tomando el logaritmo natural del valor final dividido por el valor inicial.
Como ejemplo, digamos que el valor final de una inversión fue de 11 dólares y el valor inicial de 10 dólares. La función diría =LN(11/10)
para un resultado de 9,53%
.
En matemáticas y estadística, se suele distinguir entre datos discretos y continuos. El retorno aritmético es la versión continua más teórica. En el mundo real, sin embargo, la mayoría de la gente piensa en rendimientos divididos en períodos discretos.
Así que el retorno logarítmico es la versión no discreta, continua, lo que significa que si todo el período se dividiera en un número infinito de períodos, ¿cuál sería ese retorno? Como ves, es teórico.
Salvo para periodos de tiempo muy cortos (menos de un día), y para aplicaciones teóricas que impliquen el cálculo y la medición precisa de curvas, los rendimientos logarítmicos no se suelen utilizar.
Los datos de los precios son útiles, pero en este caso, ya que queremos comparar cada conjunto de datos, sería aún mejor si en lugar de los precios diarios/anuales, tuviéramos información sobre los rendimientos de los precios diarios/anuales.
Como primer paso, vamos a definir una función llamada log_return
, que debería aceptar un parámetro, los precios.
def log_return(prices):
pass
La ecuación para calcular la rentabilidad logarítmica entre dos precios es la siguiente
log_natural(precio actual/precio anterior)
En nuestro caso queremos ejecutar esta ecuación para cada día/año de datos de precios en nuestra serie de DataFrame importada (la serie A es una sola columna en un DataFrame).
La función pandas shift (sifth()
) se puede utilizar para dividir cada precio actual por su precio anterior en la serie.
precios / precios.shift(1)
Y podemos utilizar la función de logaritmo natural de Numpy para obtener el rendimiento logarítmico de cada entrada de la nueva Serie.
import numpy as np
np.log(Series)
Hagámoslo
import numpy as np
def log_return(prices):
return np.log(prices / prices.shift(1))
Utilicemos nuestra nueva función log_return
para calcular el rendimiento logarítmico del DataFrame del Nasdaq, el PIB y otro indicador que ya hemos cargado
start = datetime(1999, 1, 1)
end = datetime(2019, 1, 1)
nasdaq_data = web.DataReader("NASDAQ100", "fred", start, end)
sap_data = web.DataReader("SP500", "fred", start, end)
gdp_data = wb.download(indicator='NY.GDP.MKTP.CD', country=['US'], start=start, end=end)
export_data = wb.download(indicator='NE.EXP.GNFS.CN', country=['US'], start=start, end=end)
Ahora vamos a pasar cada variable a la función log_return
.
nasdaq_returns = log_return(nasdaq_data['NASDAQ100'])
nasdaq_returns
DATE 1999-01-01 NaN 1999-01-04 NaN 1999-01-05 0.025876 1999-01-06 0.031526 1999-01-07 0.001221 ... 2018-12-26 NaN 2018-12-27 0.004069 2018-12-28 -0.000483 2018-12-31 0.007087 2019-01-01 NaN Name: NASDAQ100, Length: 5218, dtype: float64
sap_returns = log_return(sap_data['SP500'])
sap_returns
DATE 2011-02-07 NaN 2011-02-08 0.004176 2011-02-09 -0.002790 2011-02-10 0.000749 2011-02-11 0.005492 ... 2018-12-26 NaN 2018-12-27 0.008526 2018-12-28 -0.001242 2018-12-31 0.008457 2019-01-01 NaN Name: SP500, Length: 2062, dtype: float64
gdp_returns = log_return(gdp_data['NY.GDP.MKTP.CD'])
gdp_returns
country year United States 2019 NaN 2018 -0.040615 2017 -0.052921 2016 -0.042083 2015 -0.026545 2014 -0.039026 2013 -0.043275 2012 -0.035650 2011 -0.041243 2010 -0.036063 2009 -0.036900 2008 0.018100 2007 -0.017898 2006 -0.045096 2005 -0.057963 2004 -0.065203 2003 -0.063851 2002 -0.046611 2001 -0.032961 2000 -0.031631 1999 -0.062554 Name: NY.GDP.MKTP.CD, dtype: float64
export_returns = log_return(export_data['NE.EXP.GNFS.CN'])
export_returns
country year United States 2019 NaN 2018 0.005533 2017 -0.062895 2016 -0.064079 2015 0.017222 2014 0.045653 2013 -0.042320 2012 -0.036803 2011 -0.041123 2010 -0.130190 2009 -0.154485 2008 0.149476 2007 -0.100832 2006 -0.120293 2005 -0.120663 2004 -0.102871 2003 -0.127967 2002 -0.036798 2001 0.025597 2000 0.067562 1999 -0.099148 Name: NE.EXP.GNFS.CN, dtype: float64
Ahora estamos preparados para comparar la volatilidad de cada tipo de datos. Recordemos que la varianza, en el contexto de los datos financieros, nos indica la volatilidad de una inversión. Utilizaremos la función var()
de Pandas para calcular la varianza de los rendimientos de las acciones y de los datos del Banco Mundial, e imprimiremos los resultados.
Los resultados pueden interpretarse de varias maneras, pero en general, cuanto mayor sea la varianza, más volátiles serán los datos.
¿Qué conclusiones se pueden sacar de estos datos? ¿Qué conjunto de datos fue el más volátil? ¿Algún conjunto de datos tenía varianzas similares?
serie sap: sap: 8,860342194008153e-05
que equivale a 0,00008860342194008153
print('nasdaq_returns:', nasdaq_returns.var())
nasdaq_returns: 0.0003178379833057229
print('sap_returns:', sap_returns.var())
sap_returns: 8.463335599326003e-05
print('gdp_returns:', gdp_returns.var())
gdp_returns: 0.000342043019210802
print('export_returns:', export_returns.var())
export_returns: 0.006201903531105136
El S&P 500, un conjunto de 500 grandes empresas que cotizan en las bolsas de Estados Unidos, es el que tiene la menor variación y, por tanto, el menos volátil. Como el índice S&P 500 es una medida ponderada de muchos valores de diversos sectores, se considera una inversión más segura y diversificada.
Las acciones son interesantes. El NASDAQ 100 es más volátil que el S&P 500, lo cual, si lo pensamos bien, tiene sentido ya que el S&P 500 está mucho más diversificado y sigue más de cerca al mercado.
Por último, tenemos el PIB y las exportaciones.
Las exportaciones son muy volátiles, lo que podría tener que ver con las industrias que se han trasladado al extranjero en los últimos 20 años, y la competencia mundial para la producción de bienes.
En realidad, el PIB es bastante similar al NASDAQ 100 en términos de volatilidad, lo cual es quizás una correlación interesante.
Espero que haya disfrutado y aprendido de esta lectura!