Trataremos de explicar un principio básico de las finanzas, la llamada frontera eficiente y sirve como una pequeña introducción en un área de las finanzas: “teoría de portafolio” usando R. Una segunda parte será entonces concentrarse en el capital-Asset-Pricing- método (CAPM) y sus supuestos, implicaciones e inconvenientes.
Uno de los conceptos básicos de las finanzas es la relación riesgo-retorno. A modo de ejemplo ilustrativo: Si tuviera que ofrecer dos inversiones con el mismo riesgo pero con diferentes rendimientos esperados, tomaría la inversión con el rendimiento más alto (una mirada más atenta en lo que se entiende por los términos riesgo y rendimiento esperado sigue más adelante). Si las dos inversiones tuvieran el mismo rendimiento esperado pero con diferentes niveles de riesgo, la mayoría de la gente elige la inversión con menor riesgo. Este comportamiento se denomina la aversión al riesgo.
¿Pero qué sucede si tenemos que tomar la decisión entre una estrategia de cómo distribuir un valor de inversión de $ 100,000 entre las 30 empresas que figuran en el índice alemán DAX, las 100 empresas de FTSE de Gran Bretaña, las 500 empresas del S&P500, o la opción (más realista) para invertir en todas las acciones listadas en el mundo? ¿Cómo se distribuirá el dinero en efectivo para crear una cartera prometedora?
Esta es la pregunta Markowitz trató de responder en 1952 en su artículo “Portfolio Selection”. Ahora, muchos años después, muchos académicos y profesionales han añadido sus respuestas a la discusión, ampliando la discusión, pero la solución de Markowitz todavía se considera como una pieza fundamental en las finanzas. Su selección de la cartera permitió lo que ahora se llama “Capital Asset Pricing Model” o CAPM. Entonces nos preguntamos ¿qué hace el CAPM?, ¿cuáles son sus implicaciones, suposiciones?, ¿cuáles son sus inconvenientes?, y para nosotros lo más importante, ¿cómo podemos calcularlo en R?
Vamos a crear un ejemplo práctico para ilustrar la teoría: Comenzamos por la observación de tres diferentes acciones bien conocidas de Dow-Jones Industrial Average: IBM (IBM), Google/Alphabet (GOOG), y JP Morgan (JPM). He obtenido los datos mensuales desde el año 2000 a partir de Yahoo usando el libray quantmod. Podemos cargar los datos y trazar un índice de precios con el siguiente comando (Nota: usaremos data.table para el almacenamiento y manipulación de datos, pero también se puede utilizar dplyr, o base-r)
library(data.table)
library(scales)
library(ggplot2)
finanza<-fread("/Users/Victor/Documents/datos/datos_finanza.csv")
head(finanza)
## date ticker price
## 1: 2000-01-03 IBM 90.66385
## 2: 2000-02-01 IBM 87.95363
## 3: 2000-03-01 IBM 86.64813
## 4: 2000-04-03 IBM 88.68945
## 5: 2000-05-01 IBM 83.74264
## 6: 2000-06-01 IBM 89.13915
finanza[, date := as.Date(date)]
## date ticker price
## 1: 2000-01-03 IBM 90.66385
## 2: 2000-02-01 IBM 87.95363
## 3: 2000-03-01 IBM 86.64813
## 4: 2000-04-03 IBM 88.68945
## 5: 2000-05-01 IBM 83.74264
## ---
## 532: 2016-01-04 JPM 58.04395
## 533: 2016-02-01 JPM 56.71510
## 534: 2016-03-01 JPM 59.04963
## 535: 2016-04-01 JPM 61.44905
## 536: 2016-05-02 JPM 61.84250
finanza[, id_price := price/price[1], by = ticker]
## date ticker price id_price
## 1: 2000-01-03 IBM 90.66385 1.0000000
## 2: 2000-02-01 IBM 87.95363 0.9701069
## 3: 2000-03-01 IBM 86.64813 0.9557076
## 4: 2000-04-03 IBM 88.68945 0.9782228
## 5: 2000-05-01 IBM 83.74264 0.9236607
## ---
## 532: 2016-01-04 JPM 58.04395 1.9229179
## 533: 2016-02-01 JPM 56.71510 1.8788951
## 534: 2016-03-01 JPM 59.04963 1.9562350
## 535: 2016-04-01 JPM 61.44905 2.0357244
## 536: 2016-05-02 JPM 61.84250 2.0487589
ggplot(finanza, aes(x = date, y = id_price, color = ticker)) +
geom_line() +
theme_bw() + ggtitle("Evolución de los Precios") +
xlab("Fecha") + ylab("Precio\n(Indexed 2000 = 1)") +
scale_color_discrete(name = "Compañía")
finanza[, ret := price / shift(price, 1) - 1, by = ticker]
## date ticker price id_price ret
## 1: 2000-01-03 IBM 90.66385 1.0000000 NA
## 2: 2000-02-01 IBM 87.95363 0.9701069 -0.029893096
## 3: 2000-03-01 IBM 86.64813 0.9557076 -0.014842993
## 4: 2000-04-03 IBM 88.68945 0.9782228 0.023558664
## 5: 2000-05-01 IBM 83.74264 0.9236607 -0.055776756
## ---
## 532: 2016-01-04 JPM 58.04395 1.9229179 -0.110089722
## 533: 2016-02-01 JPM 56.71510 1.8788951 -0.022893787
## 534: 2016-03-01 JPM 59.04963 1.9562350 0.041162469
## 535: 2016-04-01 JPM 61.44905 2.0357244 0.040633842
## 536: 2016-05-02 JPM 61.84250 2.0487589 0.006402911
tab <- finanza[!is.na(ret), .(ticker, ret)]
head(tab)
## ticker ret
## 1: IBM -0.02989310
## 2: IBM -0.01484299
## 3: IBM 0.02355866
## 4: IBM -0.05577676
## 5: IBM 0.06444169
## 6: IBM -0.05886086
tab <- tab[, .(er = round(mean(ret), 4),sd = round(sd(ret), 4)), by = "ticker"]
tab
## ticker er sd
## 1: IBM 0.0040 0.0554
## 2: GOOG 0.0217 0.0801
## 3: JPM 0.0064 0.0741
ggplot(tab, aes(x = sd, y = er, color = ticker)) +
geom_point(size = 5) +
theme_bw() + ggtitle("Riesgo Retorno") +
xlab("Volatilidad") + ylab("Retornos Esperados") +
scale_y_continuous(label = percent, limits = c(0, 0.03)) +
scale_x_continuous(label = percent, limits = c(0, 0.1))
frontera<-data.table(read.csv("/Users/Victor/Documents/datos/mult_activos.csv"))
frontera
## x y z
## 1: 0.099276441 0.0332716757 0.054567527
## 2: 0.105473301 0.0406845529 0.053968795
## 3: 0.064534834 0.0040880569 0.049125643
## 4: 0.047325141 0.0549576911 0.051012931
## 5: 0.100294373 0.0102123152 0.042193865
## ---
## 9996: 0.139479551 0.0333821185 0.052897783
## 9997: 0.147881983 0.0411860741 0.057735664
## 9998: 0.111437836 -0.0009874475 0.004354541
## 9999: -0.009397453 -0.0054304977 0.047642833
## 10000: 0.070907275 0.0498671900 0.090684806
RE_x <- mean(frontera$x)
RE_y <- mean(frontera$y)
SD_x <- sd(frontera$x)
SD_y <- sd(frontera$y)
Cov_xy <- cov(frontera$x,frontera$y)
x_ponderacion <- seq(from = 0, to = 1, length.out = 1000)
dos_activos<- data.table(wx = x_ponderacion, wy = 1 - x_ponderacion)
dos_activos
## wx wy
## 1: 0.000000000 1.000000000
## 2: 0.001001001 0.998998999
## 3: 0.002002002 0.997997998
## 4: 0.003003003 0.996996997
## 5: 0.004004004 0.995995996
## ---
## 996: 0.995995996 0.004004004
## 997: 0.996996997 0.003003003
## 998: 0.997997998 0.002002002
## 999: 0.998998999 0.001001001
## 1000: 1.000000000 0.000000000
dos_activos[, ':=' (RE_p = wx*RE_x + wy*RE_y, SD_p = sqrt(wx^2*SD_x^2 + wy^2*SD_y^2 + 2*wx*(1 - wx)*Cov_xy))]
## wx wy RE_p SD_p
## 1: 0.000000000 1.000000000 0.03000000 0.01973497
## 2: 0.001001001 0.998998999 0.03004001 0.01971606
## 3: 0.002002002 0.997997998 0.03008001 0.01969728
## 4: 0.003003003 0.996996997 0.03012002 0.01967863
## 5: 0.004004004 0.995995996 0.03016002 0.01966010
## ---
## 996: 0.995995996 0.004004004 0.06980549 0.04979363
## 997: 0.996996997 0.003003003 0.06984550 0.04984333
## 998: 0.997997998 0.002002002 0.06988550 0.04989305
## 999: 0.998998999 0.001001001 0.06992551 0.04994277
## 1000: 1.000000000 0.000000000 0.06996551 0.04999250
head(dos_activos)
## wx wy RE_p SD_p
## 1: 0.000000000 1.000000 0.03000000 0.01973497
## 2: 0.001001001 0.998999 0.03004001 0.01971606
## 3: 0.002002002 0.997998 0.03008001 0.01969728
## 4: 0.003003003 0.996997 0.03012002 0.01967863
## 5: 0.004004004 0.995996 0.03016002 0.01966010
## 6: 0.005005005 0.994995 0.03020003 0.01964171
ggplot() +
geom_point(data = dos_activos, aes(x = SD_p, y = RE_p, color = wx)) +
geom_point(data = data.table(sd = c(SD_x, SD_y), mean = c(RE_x, RE_y)),
aes(x = sd, y = mean), color = "red", size = 3, shape = 18) +
theme_bw() + ggtitle("Posibles Portfolios con dos activos de riesgo") +
xlab("Volatilidad") + ylab("Retornos Esperados") +
scale_y_continuous(label = percent, limits = c(0, max(dos_activos$RE_p) * 1.2)) +
scale_x_continuous(label = percent, limits = c(0, max(dos_activos$SD_p) * 1.2)) +
scale_color_continuous(name = expression(omega[x]), labels = percent)