rtidyversequantmodtidyquant

Calculate multiple moving calculations in one statement


I want to calculate all moving averages in one statement rather than repeating myself. Is this possible using quantmod or does it require some clever use of tidyeval and/or purrr?

library(tidyquant)
library(quantmod)
library(zoo)

tibble(date = as.Date('2018-01-01') + days(1:100), 
       value = 100 + cumsum(rnorm(100))) %>% 
  tq_mutate(mutate_fun = rollapply, select = "value", width = 10, FUN = mean, col_rename = "rm10") %>% 
  tq_mutate(mutate_fun = rollapply, select = "value", width = 5, FUN = mean, col_rename = "rm5") %>% 
  gather(series, value, -date) %>% 
  ggplot(aes(date, value, color = series)) + 
     geom_line()

Solution

  • Here is a solution using data.table's new frollmean()-function
    data.table v1.12.0 or higher required.

    sample data

    library( data.table )
    set.seed(123)
    dt <- data.table( date = as.Date('2018-01-01') + days(1:100), 
                value = 100 + cumsum(rnorm(100)))
    

    code

    #set windwos you want to roll on
    windows <- c(5,10)
    #create a rm+window column for each roll
    dt[, ( paste0( "rm", windows ) ) := lapply( windows, function(x) frollmean( value, x)) ]
    

    output

    head( dt, 15 )
    #           date     value      rm5     rm10
    #  1: 2018-01-02  99.43952       NA       NA
    #  2: 2018-01-03  99.20935       NA       NA
    #  3: 2018-01-04 100.76806       NA       NA
    #  4: 2018-01-05 100.83856       NA       NA
    #  5: 2018-01-06 100.96785 100.2447       NA
    #  6: 2018-01-07 102.68292 100.8933       NA
    #  7: 2018-01-08 103.14383 101.6802       NA
    #  8: 2018-01-09 101.87877 101.9024       NA
    #  9: 2018-01-10 101.19192 101.9731       NA
    # 10: 2018-01-11 100.74626 101.9287 101.0867
    # 11: 2018-01-12 101.97034 101.7862 101.3398
    # 12: 2018-01-13 102.33015 101.6235 101.6519
    # 13: 2018-01-14 102.73092 101.7939 101.8482
    # 14: 2018-01-15 102.84161 102.1239 102.0485
    # 15: 2018-01-16 102.28577 102.4318 102.1802
    

    plot

    #plot molten data
    library(ggplot2)
    ggplot( data = melt(dt, id.vars = c("date") ), 
            aes(x = date, y = value, colour = variable)) + 
      geom_line()
    

    enter image description here

    update - grouped data

    library(data.table)
    library(ggplot2)
    set.seed(123)
    #changed the sample data a bit, to get different values for grp=1 and grp=2
    dt <- data.table(grp = rep(1:2, each = 100), date = rep(as.Date('2018-01-01') + days(1:100), 2), value = 100 + cumsum(rnorm(200)))
    dt[, ( paste0( "rm", windows ) ) := lapply( windows, function(x) frollmean( value, x)), by = "grp" ]
    ggplot( data = melt(dt, id.vars = c("date", "grp") ), 
            aes(x = date, y = value, colour = variable)) + 
      geom_line() +
      facet_wrap(~grp, nrow = 1)
    

    enter image description here