Francisco Guijarro

Universidad Politécnica de Valencia

Creative Commons Attribution 4.0 International License (CC BY 4.0)

1 Introducción

En esta tema introduciremos algunos elementos adicionales de programación, como las estructuras condicionales y las estructuras iterativas, que nos permitirán programar scripts de mayor complejidad que los vistos hasta ahora.

Veremos cómo el uso de este tipo de estructuras permiten modelizar situaciones más complejas, así como poder ejecutar de forma repetida una serie de comandos haciendo más eficiente el código.

También se presentarán las funciones, que permiten encapsular un bloque de código bajo una nombre determinado. Las funciones será útiles cuando nuestros scripts necesiten repetir bloques de códigos con pequeñas modificaciones, evitando tener que repetir partes del código a lo largo del script.

2 Lógica de programación

Hasta ahora hemos ejecutado diferentes comandos en forma secuencial. Cada una de las funciones se han ejecutado en un orden determinado. Sin embargo, todos los lenguajes de programación tienen la opción de ejecutar comandos en base a condiciones, o repetir un mismo bloque de código varias veces mediante un proceso iterativo.

2.1 Estructuras condicionales

Una estructura condicional es una pieza de código que permite ejecutar uno o varios comandos siempre que se cumpla una condición.

Por ejemplo, supongamos que tenemos la siguiente pieza de código:

dia <- "martes"
if(dia == "martes") {
  print("Hoy es martes")
}
## [1] "Hoy es martes"

El comando if comprueba si se cumple la condición dia == "martes". En caso afirmativo, imprime en pantalla el texto Hoy es martes.

Supongamos que el valor de la variable dia fuera otro:

dia <- "miércoles"
if(dia == "martes") {
  print("Hoy es martes")
}
if(dia != "martes") {
  print("Hoy no es martes")
}
## [1] "Hoy no es martes"

La anterior secuencia se podría haber escrito a través de la estructura if ... else:

dia <- "miércoles"
if(dia == "martes") {
  print("Hoy es martes")
} else {
  print("Hoy no es martes")
}
## [1] "Hoy no es martes"

2.2 Estructuras iterativas (bucles)

Una estructura iterativa permite ejecutar uno o más comandos de forma repetitiva siempre que se siga cumpliendo una condición.

Supongamos que tenemos una variable semana que recoje los días de la semana ordenados de lunes a domingo, y queremos recorrer su estructura hasta llegar al sábado. Una opción poco recomendable sería:

semana <- c("lunes", "martes", "miércoles", "jueves", "viernes", "sábado", "domingo")
if(semana[1] == "sábado") {
  print("¡Por fin es sábado! El elemento 1 del vector semana")
} else {
  if(semana[2] == "sábado") {
    print("¡Por fin es sábado! El elemento 2 del vector semana")
  } else {
    if(semana[3] == "sábado") {
      print("¡Por fin es sábado! El elemento 3 del vector semana")
    } else {
      if (semana[4] == "sábado") {
        print("¡Por fin es sábado! El elemento 4 del vector semana")
      } else {
        if (semana[5] == "sábado") {
          print("¡Por fin es sábado! El elemento 5 del vector semana")
          } else {
            if (semana[6] == "sábado") {
              print("¡Por fin es sábado! El elemento 6 del vector semana")
            } else {
              print("¡Por fin es sábado! El elemento 7 del vector semana")
            }
          }
        }
      }
    }
  }
## [1] "¡Por fin es sábado! El elemento 6 del vector semana"

En lugar de utilizar un código tan largo como el anterior, podemos hacer uso del comando while que ejecuta un bloque de código mientras se cumpla la condición que pasamos como parámetro al propio while:

contador <- 1
while(semana[contador] != "sábado") {
  contador <- contador + 1
}
paste0("¡Por fin es sábado! El elemento ", contador, " del vector semana")
## [1] "¡Por fin es sábado! El elemento 6 del vector semana"

Otra forma de expresar un bucle es a través del comando for. En este caso, los comandos se repiten de forma iterativa a través de un contador:

for(contador in 1:7) {
  print(paste("Hoy es", semana[contador]))
}
## [1] "Hoy es lunes"
## [1] "Hoy es martes"
## [1] "Hoy es miércoles"
## [1] "Hoy es jueves"
## [1] "Hoy es viernes"
## [1] "Hoy es sábado"
## [1] "Hoy es domingo"

Esto último también se podría haber obtenido de otra forma alternativa:

for(dia in semana) {
  print(paste("Hoy es", dia))
}
## [1] "Hoy es lunes"
## [1] "Hoy es martes"
## [1] "Hoy es miércoles"
## [1] "Hoy es jueves"
## [1] "Hoy es viernes"
## [1] "Hoy es sábado"
## [1] "Hoy es domingo"

Ejercicio 1

Calcula el factorial de 10 utilizando a) un bucle for, y b) un bucle while. Puedes comprobar si el resultado es correcto con la función factorial(10).

factorial <- 1
for (i in 2:10) {
  factorial <- factorial * i
}
paste("El factorial de 10 es", factorial)
## [1] "El factorial de 10 es 3628800"
factorial <- 1
i <- 2
while (i <= 10) {
  factorial <- factorial * i
  i <- i+1
}
paste("El factorial de 10 es", factorial)
## [1] "El factorial de 10 es 3628800"
factorial(10)
## [1] 3628800

Ejercicio 2

Calcula los números primos que existen entre 2 y 100; es decir, cuáles son sólo divisibles por 1 y por sí mismos. Puedes utilizar la función %% para calcular el resto de una división. Por ejemplo, 10 %% 2da como resultado 0; pero 10 %% 3 da como resultado 1. Deberías obtener algo similar a esto:

## [1] "El número 2 es primo"
## [1] "El número 3 es primo"
## [1] "El número 5 es primo"
## [1] "El número 7 es primo"
## [1] "El número 11 es primo"
## [1] "El número 13 es primo"
## [1] "El número 17 es primo"
## [1] "El número 19 es primo"
## [1] "El número 23 es primo"
## [1] "El número 29 es primo"
## [1] "El número 31 es primo"
## [1] "El número 37 es primo"
## [1] "El número 41 es primo"
## [1] "El número 43 es primo"
## [1] "El número 47 es primo"
## [1] "El número 53 es primo"
## [1] "El número 59 es primo"
## [1] "El número 61 es primo"
## [1] "El número 67 es primo"
## [1] "El número 71 es primo"
## [1] "El número 73 es primo"
## [1] "El número 79 es primo"
## [1] "El número 83 es primo"
## [1] "El número 89 es primo"
## [1] "El número 97 es primo"

3 Funciones

Una función permite encapsular un bloque de código, dándole una denominación determinada. Esto permite que podamos ejecutar ese bloque de código cada vez que llamemos a la función.

Por ejemplo, supongamos que queremos crear una función que nos informe sobre la fecha actual:

dime_fecha_actual <- function() {
  fecha <- Sys.Date()
  print(fecha)
}

dime_fecha_actual()
## [1] "2020-10-18"

Observa la diferencia entre dime_fecha_actual() y dime_fecha_actual:

dime_fecha_actual
## function() {
##   fecha <- Sys.Date()
##   print(fecha)
## }

Esto es, para que la función ejecute su bloque de código, al nombre de la función debe seguirle los paréntesis (). Habitualmente entre paréntesis pasaremos los parámetros de la función, aunque en el caso anterior lo hemos dejado en blanco (sin parámetros).

Pongamos ahora el caso de una función a la que pasamos un único parámetro (más adelante veremos que podemos pasar tantos parámetros como queramos, separándolos mediante una coma):

imprime_nombre <- function(nombre) {
  print(nombre)
}

imprime_nombre("Jaime")
## [1] "Jaime"
imprime_nombre("Valentina")
## [1] "Valentina"

Precisamente la opción de pasar uno a más parámetros a las funciones va a facilitar la codificación de muchos scripts.

Ejercicio 3

Escribe una función que calcule el factorial de un número. Posteriormente, llama a la función para que calcule el factorial de 10.

factorial <- function(numero) {
  resultado <- 1
  for (i in 2:numero) {
    resultado <- resultado * i
  }
  return(resultado)
}

factorial(10)
## [1] 3628800

A diferencia de imprime_nombre, la función factorial no imprime nada, sino que devuelve un valor: el resultado del factorial. Esto lo hacemos a través del comando return. Veremos que igual que podemos pasar más de un parámetro a una función, también podemos devolver más de una variable con una función.

Ejercicio 4

Obtener el factorial de 1 con la función anterior. Corrije la función para que devuelva un valor correcto.

factorial(1)
## [1] 2

Vemos como la función anterior calcula incorrectamente el factorial de 1. De ahí que se precise su modificación.

El resultado de la nueva función debería arrojar valores como los siguientes:

factorial(10)
## [1] 3628800
factorial(1)
## [1] 1
factorial(0)
## [1] NA
factorial(-5)
## [1] NA

4 Análisis bursátil

En este apartado descargaremos las cotizaciones bursátiles de diferentes títulos, los representaremos gráficamente, e implementaremos una sencilla (y poco rentable) estrategia de inversión.

Esto nos ayudará a ejercitar los nuevos comandos aprendidos en el tema, así como familiarizarnos con el tratamiento de datos y terminología bursátiles.

Respecto de la terminología, conviene saber el significado de los siguientes términos:

  • Ticker bursátil de un título.

  • Precios OHLC.

  • Precios ajustados.

  • Posiciones largas y posiciones cortas.

  • Tendencia.

  • Indicadores técnicos.

  • Rentabilidad absoluta y rentabilidad relativa.

  • Riesgo, Drawdown, Máximo drawdown.

En primer lugar vamos a descargar las cotizaciones diarias de Apple, cuyo ticker bursátil es AAPL:

library(quantmod)
getSymbols("AAPL", from = '2010-01-01', to = "2020-10-15")
## [1] "AAPL"
head(AAPL)
##            AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume AAPL.Adjusted
## 2010-01-04  7.622500  7.660714 7.585000   7.643214   493729600      6.604801
## 2010-01-05  7.664286  7.699643 7.616071   7.656428   601904800      6.616219
## 2010-01-06  7.656428  7.686786 7.526786   7.534643   552160000      6.510980
## 2010-01-07  7.562500  7.571429 7.466072   7.520714   477131200      6.498945
## 2010-01-08  7.510714  7.571429 7.466429   7.570714   447610800      6.542150
## 2010-01-11  7.600000  7.607143 7.444643   7.503929   462229600      6.484439

La información de los títulos viene en formato OHLC (Open, High, Low, Close).

Podemos representar gráficamente toda la serie o solo un subconjunto de la misma:

chart_Series(AAPL)

chart_Series(AAPL["2020-01/2020-10"])

También podemos realizar diferentes representaciones de las cotizaciones:

chartSeries(AAPL, type = "line", subset = "2020-09/2020-10", 
            theme = chartTheme("white"), TA = NULL)

chartSeries(AAPL, type = "bars", subset = "2020-09/2020-10", 
            theme = chartTheme("white"), TA = NULL)

chartSeries(AAPL, type = "candlesticks", subset = "2020-09/2020-10", 
            theme = chartTheme("white"), TA = NULL)

4.1 Primera estrategia de inversión: Sigue la tendencia. La tendencia es tu amiga

A continuación vamos a plantear una sencilla estrategia de inversión.

  • Tendremos una señal de compra (buy) cuando durante dos sesiones consecutivas el precio de cierre sea superior al precio de cierre del día anterior.

  • Tendremos una señal de venta (sell) cuando durante dos sesiones consecutivas el precio de cierre sea inferior al precio de cierre del día anterior.

  • Una señal de entrada al mercado (compra o venta) sólo se cancelará cuando tengamos una señal en dirección contraria.

  • Sólo podemos tener una posición abierta: o estamos comprados (buy), o estamos vendidos (sell). Pero no podemos tener dos o más posiciones abiertas, en la misma o distinta dirección.

Para poder visualizar en detalle la estrategia vamos a trabajar únicamente con los datos de 2020.

Los siguientes pasos resumen la operativa que vamos a llevar a cabo:

library(dplyr)
datos <- AAPL["2020"]
datos_estrategia <- datos %>%
  as.data.frame() %>%
  select(AAPL.Adjusted) %>%
  mutate(variacion = AAPL.Adjusted - lag(AAPL.Adjusted))
datos_estrategia[1:12, ]
##    AAPL.Adjusted variacion
## 1       74.57304        NA
## 2       73.84803 -0.725006
## 3       74.43647  0.588440
## 4       74.08639 -0.350075
## 5       75.27816  1.191765
## 6       76.87714  1.598976
## 7       77.05093  0.173790
## 8       78.69707  1.646149
## 9       77.63441 -1.062668
## 10      77.30170 -0.332703
## 11      78.27002  0.968316
## 12      79.13655  0.866531
  • Tomamos únicamente los datos de AAPL del año 2020.

  • Creamos el objeto datos_estrategia a partir del objeto datos, y lo convertimos en un dataframe (el formato original es xts, un formato propio para series temporales).

  • Nos quedamos con la columna AAPL.Adjusted, o de cierre ajustado, y creamos la columna variacion que nos indica cuánto subió o bajó la cotización. La columna variacion recoge las diferencias en el precio ajustado de una sesión y la anterior.

  • Por ejemplo, el primer día el precio ajustado de cierre es 74.573036, mientras que el segundo día el precio de cierre ajustado es de 73.84803. Esto implica una variación negativa, por lo que registramos un descenso en la cotización de -0.725006 para el día 2. Esto es, el segundo día la cotización ha bajado 0.725006.

  • De la misma forma se calculan el resto de elementos de la columna variacion. Vemos cómo tenemos varios días con subidas consecutivas, y un periodo de dos días consecutivas con pérdidas en la cotización.

  • Siguiendo la estrategia planteada anteriormente, calculamos la nueva columna signal:

datos_estrategia$signal <- 0
for (t in 3:nrow(datos_estrategia)) {
  if(datos_estrategia$variacion[t] > 0 & datos_estrategia$variacion[t-1] > 0) {
    datos_estrategia$signal[t] <- 1
  }
  if(datos_estrategia$variacion[t] < 0 & datos_estrategia$variacion[t-1] < 0) {
    datos_estrategia$signal[t] <- -1
  }
}
datos_estrategia[1:12, ]
##    AAPL.Adjusted variacion signal
## 1       74.57304        NA      0
## 2       73.84803 -0.725006      0
## 3       74.43647  0.588440      0
## 4       74.08639 -0.350075      0
## 5       75.27816  1.191765      0
## 6       76.87714  1.598976      1
## 7       77.05093  0.173790      1
## 8       78.69707  1.646149      1
## 9       77.63441 -1.062668      0
## 10      77.30170 -0.332703     -1
## 11      78.27002  0.968316      0
## 12      79.13655  0.866531      1
  • Por defecto, la columna signal tendrá valor 0; esto es, neutral, sin señal de compra ni de venta. Veamos qué señal tenemos para cada uno de los primeros días de la estrategia:

  • Los días 1 a 4 se alternan días de subida y bajada en la cotización. No se encuentran dos días consecutivos con el mismo signo en la variación. Por lo tanto, ni compramos ni vendemos. Nos quedamos fuera de la operativa.

  • Los días 5 y 6 registramos subidas consecutivas en la cotización. Esto da la primera señal de compra, que reflejamos con una señal de compra en la columna signal: asignamos un valor 1 al finalizar el sexto día:

datos_estrategia[4:6, ]
##   AAPL.Adjusted variacion signal
## 4      74.08639 -0.350075      0
## 5      75.27816  1.191765      0
## 6      76.87714  1.598976      1
  • La cotización sigue subiendo hasta el día 9 donde se registra la primera caída. Eso implica que, hasta ese día, seguimos encontrando pares de días con subidas, y asignando valores 1 a la columna signal, mientras que en el día 9 dejamos a cero la columna signal por no tener ni dos días consecutivos de subidas ni dos días consecutivos de bajadas:
datos_estrategia[7:9, ]
##   AAPL.Adjusted variacion signal
## 7      77.05093  0.173790      1
## 8      78.69707  1.646149      1
## 9      77.63441 -1.062668      0
  • El día 10 se registra la segunda caída consecutiva en la cotización, con lo que tenemos señal de venta: asignamos un -1 a la colunma signal:
datos_estrategia[7:10, ]
##    AAPL.Adjusted variacion signal
## 7       77.05093  0.173790      1
## 8       78.69707  1.646149      1
## 9       77.63441 -1.062668      0
## 10      77.30170 -0.332703     -1
  • En el día 11 se rompe la racha bajista, por lo que la señal al finalizar ese día será neutral (0):
datos_estrategia[7:11, ]
##    AAPL.Adjusted variacion signal
## 7       77.05093  0.173790      1
## 8       78.69707  1.646149      1
## 9       77.63441 -1.062668      0
## 10      77.30170 -0.332703     -1
## 11      78.27002  0.968316      0
  • Y así continuaríamos con el proceso de cálculo de la columna signal.

  • Una vez contamos con información sobre las señales de compra y venta para cada uno de los días, vamos a crear una columna donde pongamos la posicion que tenemos en el mercaddo a raíz de esas señales.

  • Comenzaremos estando fuera del mercado, y nuestra posición se va actualizando conforme nos llegan las señales.

  • Observa como, en el caso de no tener señal de compra ni de venta, copiamos la posición del día anterior.

datos_estrategia$posicion <- "fuera"
for(t in 3:nrow(datos_estrategia)) {
  if(datos_estrategia$signal[t] == 1) {
    datos_estrategia$posicion[t] <- "buy"
  } else {
    if(datos_estrategia$signal[t] == -1) {
      datos_estrategia$posicion[t] <- "sell"
    } else {
      datos_estrategia$posicion[t] <- datos_estrategia$posicion[t-1]
    }
  }
}
datos_estrategia[1:12, ]
##    AAPL.Adjusted variacion signal posicion
## 1       74.57304        NA      0    fuera
## 2       73.84803 -0.725006      0    fuera
## 3       74.43647  0.588440      0    fuera
## 4       74.08639 -0.350075      0    fuera
## 5       75.27816  1.191765      0    fuera
## 6       76.87714  1.598976      1      buy
## 7       77.05093  0.173790      1      buy
## 8       78.69707  1.646149      1      buy
## 9       77.63441 -1.062668      0      buy
## 10      77.30170 -0.332703     -1     sell
## 11      78.27002  0.968316      0     sell
## 12      79.13655  0.866531      1      buy
  • El primer día para entar largos (buy) es el 6º. Nos mantenemos en posición buy hasta recibir una señal en dirección contraria (sell), cosa que ocurre el día 10.

  • Seguimos cortos (sell) hasta recibir una señal de compra que varíe nuestra posición: el día 12.

  • Una vez que ya sabemos qué días debemos comprar y cuáles vender, podemos calcular el beneficio diario de nuestras posiciones abiertas:

datos_estrategia$beneficio <- 0
for(t in 3:(nrow(datos_estrategia)-1)) {
  if(datos_estrategia$posicion[t] == "buy") {
    datos_estrategia$beneficio[t+1] = datos_estrategia$variacion[t+1] + 
      datos_estrategia$beneficio[t]
  } else {
    if(datos_estrategia$posicion[t] == "sell") {
      datos_estrategia$beneficio[t+1] = -datos_estrategia$variacion[t+1] + 
        datos_estrategia$beneficio[t]
    }
  }
}
datos_estrategia[1:15, ]
##    AAPL.Adjusted variacion signal posicion beneficio
## 1       74.57304        NA      0    fuera  0.000000
## 2       73.84803 -0.725006      0    fuera  0.000000
## 3       74.43647  0.588440      0    fuera  0.000000
## 4       74.08639 -0.350075      0    fuera  0.000000
## 5       75.27816  1.191765      0    fuera  0.000000
## 6       76.87714  1.598976      1      buy  0.000000
## 7       77.05093  0.173790      1      buy  0.173790
## 8       78.69707  1.646149      1      buy  1.819939
## 9       77.63441 -1.062668      0      buy  0.757271
## 10      77.30170 -0.332703     -1     sell  0.424568
## 11      78.27002  0.968316      0     sell -0.543748
## 12      79.13655  0.866531      1      buy -1.410279
## 13      78.60025 -0.536301      0      buy -1.946580
## 14      78.88082  0.280571      0      buy -1.666009
## 15      79.26070  0.379875      1      buy -1.286134
  • Vemos que para cada día llevamos un registro de nuestro beneficio “flotante”. Esto es, el valor actualizado de nuestra posición, incluyendo los beneficios/pérdidas de nuestras operaciones pasadas, así como el estado actual de la posición abierta.

  • Podemos representar la cuenta de resultados diaria:

library(ggplot2)
ggplot(datos_estrategia, aes(y = beneficio, x = index(datos_estrategia))) + 
  geom_line() +
  labs(y = "Beneficio", x = "Tiempo")

  • El beneficio total de la estrategia es $28.17.

Ejercicio 5

Aplicar la estrategia de inversión sobre todos los datos descargados de AAPL. ¿Resulta la estrategia más rentable que la propia inversión en el título?

##    AAPL.Adjusted variacion signal posicion beneficio
## 1       6.604801        NA      0    fuera  0.000000
## 2       6.616219  0.011418      0    fuera  0.000000
## 3       6.510980 -0.105239      0    fuera  0.000000
## 4       6.498945 -0.012035     -1     sell  0.000000
## 5       6.542150  0.043205      0     sell -0.043205
## 6       6.484439 -0.057711      0     sell  0.014506
## 7       6.410679 -0.073760     -1     sell  0.088266
## 8       6.501104  0.090425      0     sell -0.002159
## 9       6.463451 -0.037653      0     sell  0.035494
## 10      6.355436 -0.108015     -1     sell  0.143509
## 11      6.636590  0.281154      0     sell -0.137645
## 12      6.534435 -0.102155      0     sell -0.035490
## 13      6.421480 -0.112955     -1     sell  0.077465
## 14      6.102983 -0.318497     -1     sell  0.395962
## 15      6.267169  0.164186      0     sell  0.231776
## 16      6.355743  0.088574      1      buy  0.143202
## 17      6.415617  0.059874      1      buy  0.203076
## 18      6.150510 -0.265107      0      buy -0.062031
## 19      5.927377 -0.223133     -1     sell -0.285164
## 20      6.009779  0.082402      0     sell -0.367566

Ejercicio 6

¿Cuántos días hemos estado largos, cuántos cortos, y cuántos fuera del mercado? Puede parecer llamativo que para un título tan alcista, la estrategia de continuación de tendencia no arroje muchos más días largos que cortos.

## 
##   buy fuera  sell 
##  1444     3  1268

Ejercicio 7

Una vez conocida la distribución de nuestra posición, calcula el número de operaciones largas frente al número de operaciones cortas. ¿Te sorprende el resultado o es lógico?

## cambio_posicion
##  buy sell 
##  214  214
  • El beneficio total de la estrategia es $51.67, con un total de 428 de operaciones entre largos y cortos.

Ejercicio 8

Repetir la estrategia pero tomando señales cuando se repita la tendencia durante 3 días consecutivos (en lugar de 2).

##    AAPL.Adjusted variacion signal posicion beneficio
## 1       6.604801        NA      0    fuera  0.000000
## 2       6.616219  0.011418      0    fuera  0.000000
## 3       6.510980 -0.105239      0    fuera  0.000000
## 4       6.498945 -0.012035      0    fuera  0.000000
## 5       6.542150  0.043205      0    fuera  0.000000
## 6       6.484439 -0.057711      0    fuera  0.000000
## 7       6.410679 -0.073760      0    fuera  0.000000
## 8       6.501104  0.090425      0    fuera  0.000000
## 9       6.463451 -0.037653      0    fuera  0.000000
## 10      6.355436 -0.108015      0    fuera  0.000000
## 11      6.636590  0.281154      0    fuera  0.000000
## 12      6.534435 -0.102155      0    fuera  0.000000
## 13      6.421480 -0.112955      0    fuera  0.000000
## 14      6.102983 -0.318497     -1     sell  0.000000
## 15      6.267169  0.164186      0     sell -0.164186
## 16      6.355743  0.088574      0     sell -0.252760
## 17      6.415617  0.059874      1      buy -0.312634
## 18      6.150510 -0.265107      0      buy -0.577741
## 19      5.927377 -0.223133      0      buy -0.800874
## 20      6.009779  0.082402      0      buy -0.718472
## 21      6.044655  0.034876      0      buy -0.683596
## 22      6.148659  0.104004      1      buy -0.579592
## 23      5.927071 -0.221588      0      buy -0.801180
## 24      6.032310  0.105239      0      buy -0.695941
## 25      5.990953 -0.041357      0      buy -0.737298

  • El beneficio total de la estrategia es $40.04.

Ejercicio 9

Repetir la estrategia sobre los dos días de tendencia pero únicamente abriendo largos. Esto es, omitimos las señales de venta y sólo lanzamos largos: si recibimos señal de largo, compramos; si recibimos señal de corto, cerramos la posición de largos (pero no abrimos un corto). Calcula el número de operaciones (largos) realizados.

##    AAPL.Adjusted variacion signal posicion beneficio
## 1       6.604801        NA      0    fuera  0.000000
## 2       6.616219  0.011418      0    fuera  0.000000
## 3       6.510980 -0.105239      0    fuera  0.000000
## 4       6.498945 -0.012035     -1    fuera  0.000000
## 5       6.542150  0.043205      0    fuera  0.000000
## 6       6.484439 -0.057711      0    fuera  0.000000
## 7       6.410679 -0.073760     -1    fuera  0.000000
## 8       6.501104  0.090425      0    fuera  0.000000
## 9       6.463451 -0.037653      0    fuera  0.000000
## 10      6.355436 -0.108015     -1    fuera  0.000000
## 11      6.636590  0.281154      0    fuera  0.000000
## 12      6.534435 -0.102155      0    fuera  0.000000
## 13      6.421480 -0.112955     -1    fuera  0.000000
## 14      6.102983 -0.318497     -1    fuera  0.000000
## 15      6.267169  0.164186      0    fuera  0.000000
## 16      6.355743  0.088574      1      buy  0.000000
## 17      6.415617  0.059874      1      buy  0.059874
## 18      6.150510 -0.265107      0      buy -0.205233
## 19      5.927377 -0.223133     -1    fuera -0.428366
## 20      6.009779  0.082402      0    fuera -0.428366

  • El beneficio total de la estrategia es $83.18.

  • El número de operaciones asciende a 214. Todo largos, claro.

4.2 Una función para implementar la estrategia

Volvamos al plantemiento original de la estrategia. Vamos a crear una función que permite calcular el beneficio de la estrategia tomando como parámetros:

  • La serie de precios sobre la que aplicar la estrategia.

  • El número necesario de periodos consecutivos al alza/baja para lanzar una señal.

  • Si se toman largos y cortos, sólo largos, o solo cortos. Si no se toma nada, entonces la estrategia tendrá necesariamente beneficio 0.

Observa 3 novedades en la siguiente implementación:

  1. Algunos parámetros vienen con valores por defecto, viz. n_periodos, largos y cortos.

  2. El nuevo comando all.

  3. La función devuelve una lista de variables (en lugar de un único valor).

estrategia_tendencia <- function(datos, n_periodos = 2, largos = TRUE, cortos = TRUE) {
  require(dplyr)
  datos_estrategia <- 
    data.frame(adjusted = as.numeric(datos[, ncol(datos)])) %>%
    mutate(variacion = adjusted - lag(adjusted))
  # Calculamos la señal
  datos_estrategia$signal <- 0
  for (t in (n_periodos+1):nrow(datos_estrategia)) {
    if(all(datos_estrategia$variacion[(t-n_periodos+1):t] > 0)) {
      datos_estrategia$signal[t] <- 1
    }
    if(all(datos_estrategia$variacion[(t-n_periodos+1):t] < 0)) {
      datos_estrategia$signal[t] <- -1
    }
  }
  # Calculamos las posiciones
  datos_estrategia$posicion <- "fuera"
  for(t in (n_periodos+1):nrow(datos_estrategia)) {
    if(datos_estrategia$signal[t] == 1) {
      datos_estrategia$posicion[t] <- "buy"
    } else {
      if(datos_estrategia$signal[t] == -1) {
        datos_estrategia$posicion[t] <- "sell"
      } else {
        datos_estrategia$posicion[t] <- datos_estrategia$posicion[t-1]
      }
    }
  }
  # Calculamos el beneficio
  datos_estrategia$beneficio <- 0
  for(t in (n_periodos+1):(nrow(datos_estrategia)-1)) {
    if(datos_estrategia$posicion[t] == "buy" & largos == TRUE) {
      datos_estrategia$beneficio[t+1] = datos_estrategia$variacion[t+1] + 
        datos_estrategia$beneficio[t]
    }
    if(datos_estrategia$posicion[t] == "buy" & largos == FALSE) {
      datos_estrategia$beneficio[t+1] = datos_estrategia$beneficio[t]
    }
    if(datos_estrategia$posicion[t] == "sell" & cortos == TRUE) {
      datos_estrategia$beneficio[t+1] = -datos_estrategia$variacion[t+1] + 
        datos_estrategia$beneficio[t]
    }
    if(datos_estrategia$posicion[t] == "sell" & cortos == FALSE) {
      datos_estrategia$beneficio[t+1] = datos_estrategia$beneficio[t]
    }
  }
  # Devolvemos la serie con el beneficio diario, la rentabilidad absoluta y la rentabilidad relativa
  return(list(serie_beneficio = datos_estrategia$beneficio,
              rent_absoluta = datos_estrategia$beneficio[nrow(datos_estrategia)],
              rent_relativa =  datos_estrategia$beneficio[nrow(datos_estrategia)] / 
                datos_estrategia$adjusted[1]))
}
library(scales)
resultado_1 <- estrategia_tendencia(AAPL, n_periodos = 2)
str(resultado_1)
## List of 3
##  $ serie_beneficio: num [1:2715] 0 0 0 0 -0.0432 ...
##  $ rent_absoluta  : num 51.7
##  $ rent_relativa  : num 7.82
dollar(resultado_1$rent_absoluta)
## [1] "$51.67"
resultado_2 <- estrategia_tendencia(AAPL, n_periodos = 3)
dollar(resultado_2$rent_absoluta)
## [1] "$40.04"
resultado_3 <- estrategia_tendencia(AAPL, n_periodos = 2, cortos = FALSE)
dollar(resultado_3$rent_absoluta)
## [1] "$83.18"

La anterior función ha permitido calcular el beneficio de la estrategia para diferentes valores del parámetro n_periodos.

Puede resultar interesante calcular el beneficio para otras posibles combinaciones de n_periodos, largos y cortos.

matriz_beneficio <- expand.grid(n_periodos = 1:5, 
                                largos = c(TRUE, FALSE), 
                                cortos = c(TRUE, FALSE))
matriz_beneficio$rent_absoluta <- matriz_beneficio$rent_relativa <- 0
matriz_beneficio
##    n_periodos largos cortos rent_relativa rent_absoluta
## 1           1   TRUE   TRUE             0             0
## 2           2   TRUE   TRUE             0             0
## 3           3   TRUE   TRUE             0             0
## 4           4   TRUE   TRUE             0             0
## 5           5   TRUE   TRUE             0             0
## 6           1  FALSE   TRUE             0             0
## 7           2  FALSE   TRUE             0             0
## 8           3  FALSE   TRUE             0             0
## 9           4  FALSE   TRUE             0             0
## 10          5  FALSE   TRUE             0             0
## 11          1   TRUE  FALSE             0             0
## 12          2   TRUE  FALSE             0             0
## 13          3   TRUE  FALSE             0             0
## 14          4   TRUE  FALSE             0             0
## 15          5   TRUE  FALSE             0             0
## 16          1  FALSE  FALSE             0             0
## 17          2  FALSE  FALSE             0             0
## 18          3  FALSE  FALSE             0             0
## 19          4  FALSE  FALSE             0             0
## 20          5  FALSE  FALSE             0             0

Ejercicio 10

Completa los campos rent_absoluta y rent_relativa utilizando la función estrategia_tendencia, utilizando un bucle for o while. ¿Por qué las últimas filas de matriz_beneficio aparecen con ceros?

matriz_beneficio
##    n_periodos largos cortos rent_relativa rent_absoluta
## 1           1   TRUE   TRUE     -5.335212     -35.23801
## 2           2   TRUE   TRUE      7.822646      51.66702
## 3           3   TRUE   TRUE      6.061900      40.03764
## 4           4   TRUE   TRUE     11.654840      76.97790
## 5           5   TRUE   TRUE     11.168879      73.76823
## 6           1  FALSE   TRUE    -11.341129     -74.90590
## 7           2  FALSE   TRUE     -4.771078     -31.51202
## 8           3  FALSE   TRUE     -5.681426     -37.52469
## 9           4  FALSE   TRUE     -2.858696     -18.88112
## 10          5  FALSE   TRUE     -3.068897     -20.26946
## 11          1   TRUE  FALSE      6.005917      39.66789
## 12          2   TRUE  FALSE     12.593724      83.17904
## 13          3   TRUE  FALSE     11.743326      77.56233
## 14          4   TRUE  FALSE     14.513535      95.85901
## 15          5   TRUE  FALSE     14.237776      94.03768
## 16          1  FALSE  FALSE      0.000000       0.00000
## 17          2  FALSE  FALSE      0.000000       0.00000
## 18          3  FALSE  FALSE      0.000000       0.00000
## 19          4  FALSE  FALSE      0.000000       0.00000
## 20          5  FALSE  FALSE      0.000000       0.00000

Ejercicio 11

Obtén un modelo de regresión que explique la variable rent_absoluta del anterior ejercicio a partir de las variables n_periodos, largos y cortos. Atendiendo a los resultados, ¿recomiendas hacer sólo largos, sólo cortos, o ambos? ¿Es mejor basar la tendencia en varios días o reducirlo a unos pocos?

## 
## Call:
## lm(formula = rent_absoluta ~ n_periodos + largos + cortos, data = matriz_beneficio)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -52.348  -9.308  -0.249  13.443  24.332 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -36.499     12.362  -2.952 0.009364 ** 
## n_periodos    12.166      3.192   3.811 0.001535 ** 
## largosTRUE    78.061      9.028   8.646    2e-07 ***
## cortosTRUE   -36.619      9.028  -4.056 0.000917 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 20.19 on 16 degrees of freedom
## Multiple R-squared:  0.8686, Adjusted R-squared:  0.8439 
## F-statistic: 35.25 on 3 and 16 DF,  p-value: 2.793e-07

4.3 Medida del riesgo

En el anterior epígrafe hemos comparado la rentabilidad, tanto absoluta como relativa, de diferentes combinaciones de los parámetros.

En la presente sección calcularemos una popular medida de riesgo en el análisis de estrategias de inversión: el máximo drawdown (MD), que mide la profundidad de la mayor caída en el beneficio de una estrategia. Para ello debe calcularse previamente el drawdown (D) para caulquier instante de tiempo t.

El drawdown para un instante de tiempo t se define como la diferencia entre el beneficio (flotante) registrado en el instante t y el máximo beneficio registrado hasta el instante t:

\[D(t) = \max_{s \in \{0,t \}} \left[beneficio(s) - beneficio(t)\right ]\]

El máximo drawdown de la estrategia se obtiene como el mayor drawdown registrado por la estrategia durante todo el periodo de tiempo analizado (T):

\[MD = max_{t \in \{0,T \}} D(t)\] En la siguiente figura se recoge un ejemplo gráfico sobre el cálculo del máximo drawdown:

Ejercicio 12

Modificar la función estrategia_tendencia para que devuelva dos parámetros adicionales: el drawdown en cada instante de tiempo (los datos son diarios) y el max_drawdown de la estrategia. Aquí van algunos ejemplos del resultado que debería obtenerse:

resultado_4 <- estrategia_tendencia(AAPL, n_periodos = 2)
dollar(resultado_4$max_drawdown)
## [1] "$30.41"
resultado_4 %>%
  as.data.frame() %>%
  select(serie_beneficio, drawdown) %>%
  slice(1:20)
##    serie_beneficio drawdown
## 1         0.000000 0.000000
## 2         0.000000 0.000000
## 3         0.000000 0.000000
## 4         0.000000 0.000000
## 5        -0.043205 0.043205
## 6         0.014506 0.000000
## 7         0.088266 0.000000
## 8        -0.002159 0.090425
## 9         0.035494 0.052772
## 10        0.143509 0.000000
## 11       -0.137645 0.281154
## 12       -0.035490 0.178999
## 13        0.077465 0.066044
## 14        0.395962 0.000000
## 15        0.231776 0.164186
## 16        0.143202 0.252760
## 17        0.203076 0.192886
## 18       -0.062031 0.457993
## 19       -0.285164 0.681126
## 20       -0.367566 0.763528

Comparemos la primera parte de la figura del drawdown frente al beneficio:

plot(resultado_4$drawdown[1:100], type = "l", col = "blue", lty = 3,
     ylim = c(min(resultado_4$drawdown[1:100], resultado_4$serie_beneficio[1:100]), 
              max(resultado_4$drawdown[1:100], resultado_4$serie_beneficio[1:100])))
lines(resultado_4$serie_beneficio[1:100], col = "grey50")

Y ahora la serie completa:

plot(resultado_4$drawdown, type = "l", col = "blue", lty = 3,
     ylim = c(min(resultado_4$max_drawdown, resultado_4$serie_beneficio), 
              max(resultado_4$max_drawdown, resultado_4$serie_beneficio)))
lines(resultado_4$serie_beneficio, col = "grey50")

resultado_5 <- estrategia_tendencia(AAPL, n_periodos = 3, cortos = FALSE)
dollar(resultado_5$max_drawdown)
## [1] "$29.28"
resultado_5 %>%
  as.data.frame() %>%
  select(serie_beneficio, drawdown) %>%
  slice(1:20)
##    serie_beneficio drawdown
## 1         0.000000 0.000000
## 2         0.000000 0.000000
## 3         0.000000 0.000000
## 4         0.000000 0.000000
## 5         0.000000 0.000000
## 6         0.000000 0.000000
## 7         0.000000 0.000000
## 8         0.000000 0.000000
## 9         0.000000 0.000000
## 10        0.000000 0.000000
## 11        0.000000 0.000000
## 12        0.000000 0.000000
## 13        0.000000 0.000000
## 14        0.000000 0.000000
## 15        0.000000 0.000000
## 16        0.000000 0.000000
## 17        0.000000 0.000000
## 18       -0.265107 0.265107
## 19       -0.488240 0.488240
## 20       -0.405838 0.405838
plot(resultado_5$drawdown[1:100], type = "l", col = "blue", lty = 3,
     ylim = c(min(resultado_5$drawdown[1:100], resultado_5$serie_beneficio[1:100]), 
              max(resultado_5$drawdown[1:100], resultado_5$serie_beneficio[1:100])))
lines(resultado_5$serie_beneficio[1:100], col = "grey50")

5 Indicadores técnicos (opcional)

En el análisis bursátil existen dos enfoques para enfrentarse a las decisiones de inversión: el análisi fundamental y el análisis técnico.

El análisis fundamental guía sus decisiones utilizando la información económico-financiera de las empresas, de forma que se invierte en aquellas empresas cuyas cuentas se encuentran más saneadas y con mejor proyección de futuro.

En el análisis técnico las decisiones de inversión se llevan a cabo atendiendo únicamente a la cotización de la acción y a su comportamiento en el pasado. Para ello se dispone de gran cantidad de indicadores técnicos, que no son otra cosa que fórmulas aplicadas sobre las cotizaciones de los títulos (y en ocasiones considerando también el volumen).

En esta sección vamos a emplear el enfoque del análisis técnico, implementando alguna estrategia a partir de diferentes indicadores técnicos.

Utilizaremos la librería quantmod para obtener diferentes indicadores técnicos.

5.1 La media móvil (simple moving average)

La media móvil se obtiene promediando los últimos valores de la cotización, por lo que se utiliza como un indicador retrasado de la tendencia de la cotización:

merge(AAPL$AAPL.Adjusted[1:20], SMA(AAPL$AAPL.Adjusted[1:20], n = 10))
##            AAPL.Adjusted      SMA
## 2010-01-04      6.604801       NA
## 2010-01-05      6.616219       NA
## 2010-01-06      6.510980       NA
## 2010-01-07      6.498945       NA
## 2010-01-08      6.542150       NA
## 2010-01-11      6.484439       NA
## 2010-01-12      6.410679       NA
## 2010-01-13      6.501104       NA
## 2010-01-14      6.463451       NA
## 2010-01-15      6.355436 6.498820
## 2010-01-19      6.636590 6.501999
## 2010-01-20      6.534435 6.493821
## 2010-01-21      6.421480 6.484871
## 2010-01-22      6.102983 6.445275
## 2010-01-25      6.267169 6.417777
## 2010-01-26      6.355743 6.404907
## 2010-01-27      6.415617 6.405401
## 2010-01-28      6.150510 6.370341
## 2010-01-29      5.927377 6.316734
## 2010-02-01      6.009779 6.282168
chartSeries(AAPL, type = "line", subset = "2020-04::2020-06", 
            TA = "addSMA(n = 20)", theme = chartTheme("white"))

Como puedes observar en el anterior gráfico, la media móvil puede utilizarse fácilmente para establecer otra estrategia bursátil de continuación de la tendencia:

  • Señal de largos cuando el precio cruza al alza la media móvil.

  • Señal de cortos cuando el precio cruza a la baja la media móvil.

Ejercicio 13

Implementar a través de una función la estrategia de inversión basada en la media móvil sobre los datos completos de AAPL. La función debe tomar los mismos parámetros que la función estrategia_tendencia). En este caso, el parámetro número de periodos n_periodos hara referencia al número de periodos con que se calcula la media móvil.

resultado_6 <- estrategia_SMA(AAPL)
dollar(resultado_6$max_drawdown)
## [1] "$26.75"
resultado_6 %>%
  as.data.frame() %>%
  select(serie_beneficio, drawdown) %>%
  slice(1:20)
##    serie_beneficio drawdown
## 1         0.000000 0.000000
## 2         0.000000 0.000000
## 3         0.000000 0.000000
## 4         0.000000 0.000000
## 5         0.000000 0.000000
## 6         0.000000 0.000000
## 7         0.000000 0.000000
## 8         0.000000 0.000000
## 9         0.000000 0.000000
## 10        0.000000 0.000000
## 11       -0.281154 0.281154
## 12       -0.383309 0.383309
## 13       -0.496264 0.496264
## 14       -0.177767 0.177767
## 15       -0.341953 0.341953
## 16       -0.430527 0.430527
## 17       -0.490401 0.490401
## 18       -0.755508 0.755508
## 19       -0.532375 0.532375
## 20       -0.614777 0.614777

Comparemos la primera parte de la figura del drawdown frente al beneficio:

plot(resultado_6$drawdown[1:100], type = "l", col = "blue", lty = 3,
     ylim = c(min(resultado_6$drawdown[1:100], resultado_6$serie_beneficio[1:100]), 
              max(resultado_6$drawdown[1:100], resultado_6$serie_beneficio[1:100])))
lines(resultado_6$serie_beneficio[1:100], col = "grey50")

Y ahora la serie completa:

plot(resultado_6$drawdown, type = "l", col = "blue", lty = 3,
     ylim = c(min(resultado_6$max_drawdown, resultado_6$serie_beneficio), 
              max(resultado_6$max_drawdown, resultado_6$serie_beneficio)))
lines(resultado_6$serie_beneficio, col = "grey50")

resultado_7 <- estrategia_SMA(AAPL, n_periodos = 20)
resultado_7 %>%
  as.data.frame() %>%
  select(serie_beneficio, drawdown) %>%
  slice(1:30)
##    serie_beneficio drawdown
## 1         0.000000 0.000000
## 2         0.000000 0.000000
## 3         0.000000 0.000000
## 4         0.000000 0.000000
## 5         0.000000 0.000000
## 6         0.000000 0.000000
## 7         0.000000 0.000000
## 8         0.000000 0.000000
## 9         0.000000 0.000000
## 10        0.000000 0.000000
## 11        0.000000 0.000000
## 12        0.000000 0.000000
## 13        0.000000 0.000000
## 14        0.000000 0.000000
## 15        0.000000 0.000000
## 16        0.000000 0.000000
## 17        0.000000 0.000000
## 18        0.000000 0.000000
## 19        0.000000 0.000000
## 20        0.000000 0.000000
## 21       -0.034876 0.034876
## 22       -0.138880 0.138880
## 23        0.082708 0.000000
## 24       -0.022531 0.105239
## 25        0.018826 0.063882
## 26       -0.045060 0.127768
## 27       -0.012035 0.094743
## 28       -0.121598 0.204306
## 29       -0.174370 0.257078
## 30       -0.267574 0.350282
plot(resultado_7$drawdown, type = "l", col = "blue", lty = 3,
     ylim = c(min(resultado_7$max_drawdown, resultado_7$serie_beneficio), 
              max(resultado_7$max_drawdown, resultado_7$serie_beneficio)))
lines(resultado_7$serie_beneficio, col = "grey50")

resultado_8 <- estrategia_SMA(AAPL, n_periodos = 50, cortos = FALSE)
plot(resultado_8$drawdown, type = "l", col = "blue", lty = 3,
     ylim = c(min(resultado_8$max_drawdown, resultado_8$serie_beneficio), 
              max(resultado_8$max_drawdown, resultado_8$serie_beneficio)))
lines(resultado_8$serie_beneficio, col = "grey50")

Ejercicio 14

Obtén en una matriz (matriz_beneficio) los resultados de aplicar la estrategia sobre el siguiente grid de valores. Mediante una regresión, calcula la incidencia de los parámetros en la rentabilidad absoluta de la estrategia. Haz una segunda regresión eliminando del análisis los casos donde largos y cortos son FALSE. ¿Se mantienen unos resultados similares?

matriz_beneficio <- expand.grid(n_periodos = c(10, 20, 30, 40, 50), 
                                largos = c(TRUE, FALSE), 
                                cortos = c(TRUE, FALSE))
matriz_beneficio$rent_absoluta <- matriz_beneficio$rent_relativa <- 0
##    n_periodos largos cortos rent_relativa rent_absoluta
## 1          10   TRUE   TRUE      7.336529     48.456312
## 2          20   TRUE   TRUE     14.589063     96.357857
## 3          30   TRUE   TRUE     14.209305     93.849635
## 4          40   TRUE   TRUE      6.772099     44.728368
## 5          50   TRUE   TRUE      4.962183     32.774229
## 6          10  FALSE   TRUE     -5.025000    -33.189127
## 7          20  FALSE   TRUE     -1.424900     -9.411183
## 8          30  FALSE   TRUE     -1.594523    -10.531507
## 9          40  FALSE   TRUE     -5.300393    -35.008041
## 10         50  FALSE   TRUE     -6.168904    -40.744386
## 11         10   TRUE  FALSE     12.361529     81.645439
## 12         20   TRUE  FALSE     16.013963    105.769040
## 13         30   TRUE  FALSE     15.803828    104.381142
## 14         40   TRUE  FALSE     12.072492     79.736409
## 15         50   TRUE  FALSE     11.131087     73.518615
## 16         10  FALSE  FALSE      0.000000      0.000000
## 17         20  FALSE  FALSE      0.000000      0.000000
## 18         30  FALSE  FALSE      0.000000      0.000000
## 19         40  FALSE  FALSE      0.000000      0.000000
## 20         50  FALSE  FALSE      0.000000      0.000000
## 
## Call:
## lm(formula = rent_absoluta ~ n_periodos + largos + cortos, data = matriz_beneficio)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -23.076  -9.813  -4.616  12.314  30.616 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   12.449     10.379   1.199  0.24781    
## n_periodos    -0.415      0.268  -1.548  0.14106    
## largosTRUE    89.010      7.580  11.743 2.81e-09 ***
## cortosTRUE   -25.777      7.580  -3.401  0.00365 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 16.95 on 16 degrees of freedom
## Multiple R-squared:  0.9047, Adjusted R-squared:  0.8868 
## F-statistic: 50.62 on 3 and 16 DF,  p-value: 2.176e-08
## 
## Call:
## lm(formula = rent_absoluta ~ n_periodos + largos + cortos, data = matriz_beneficio %>% 
##     filter(largos | cortos))
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -25.843 -15.701  -3.741  13.236  30.616 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  16.5987    18.9014   0.878   0.3986    
## n_periodos   -0.5533     0.3638  -1.521   0.1565    
## largosTRUE   89.0101    12.6009   7.064 2.09e-05 ***
## cortosTRUE  -25.7768    12.6009  -2.046   0.0655 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 19.92 on 11 degrees of freedom
## Multiple R-squared:  0.8949, Adjusted R-squared:  0.8663 
## F-statistic: 31.23 on 3 and 11 DF,  p-value: 1.118e-05

Ejercicio 15

Realiza el mismo ejercicio sobre otros valores. Pueden ser americanos o europeos.

Ejercicio 16

La librería quantmod incorpora muchos más indicadores técnicos. Prueba a implementar alguna estrategia que utilice uno o varios de estos indicadores.

6 Resumen de funciones empleadas en el capítulo

  • %%

  • chart_Series

  • chartSeries

  • dollar

  • expand_grid

  • for

  • function

  • getSymbols

  • if .. else

  • merge

  • paste

  • paste0

  • return

  • slice

  • SMA

  • Sys.Date

  • while