Home > other >  Calculate a rolling percent change in R
Calculate a rolling percent change in R

Time:12-31

I am trying to calculate a 20-day rolling percent change in R based off of a stock's closing price. Below is a sample of the most recent 100 days of closing price data. df$Close[1] is the most recent day, df$Close[2] is the previous day, and so on.

    df$Close
   [1] 342.94 346.22 346.18 335.24 330.45 334.20 325.45 333.79 334.90 341.66 333.74 334.49 329.75 329.82 330.56 322.81 317.87 306.84
  [19] 310.39 310.60 324.46 338.03 333.12 341.06 337.25 341.01 345.30 338.69 340.77 342.96 347.56 340.89 327.74 327.64 335.37 338.62
  [37] 341.13 335.85 331.62 328.08 329.98 323.57 316.92 312.22 315.81 328.69 324.61 341.88 340.78 339.99 335.34 324.76 328.53 324.54
  [55] 323.77 325.45 330.05 329.22 333.64 332.96 326.23 343.01 339.39 339.61 340.65 353.58 352.96 345.96 343.21 357.48 355.70 364.72
  [73] 373.06 373.92 376.53 376.51 378.69 378.00 377.57 382.18 376.26 375.28 382.05 379.38 380.66 372.63 364.38 368.39 365.51 363.35
  [91] 359.37 355.12 355.45 358.45 366.56 363.18 362.65 359.96 361.13 361.61 

Previously, I had used the following code to calculate the percent change:

PercChange(df, Var = 'Close', type = 'percent', NewVar = 'OneMonthChange', slideBy = 20)

which gave me the following output:

df$OneMonthChange


  [1]  5.695617e-02  2.422862e-02  3.920509e-02 -1.706445e-02 -2.016308e-02 -1.997009e-02 -5.748624e-02 -1.446751e-02 -1.722569e-02
  [10] -3.790530e-03 -3.976292e-02 -1.877438e-02  6.132910e-03  6.653644e-03 -1.434237e-02 -4.668950e-02 -6.818515e-02 -8.637785e-02
  [19] -6.401906e-02 -5.327969e-02 -1.672829e-02  4.468894e-02  5.111700e-02  9.237076e-02  6.788892e-02  3.748213e-02  6.373802e-02
  [28] -9.330759e-03 -2.934445e-05  8.735551e-03  3.644063e-02  4.966745e-02 -2.404651e-03  9.551981e-03  3.582790e-02  4.046705e-02
  [37]  3.357067e-02  2.013851e-02 -6.054430e-03 -1.465642e-02  1.149496e-02 -5.667473e-02 -6.620702e-02 -8.065134e-02 -7.291942e-02
  [46] -7.039425e-02 -8.032072e-02 -1.179327e-02 -7.080213e-03 -4.892581e-02 -5.723925e-02 -1.095635e-01 -1.193642e-01 -1.320603e-01
  [55] -1.401216e-01 -1.356139e-01 -1.284428e-01 -1.290476e-01 -1.163493e-01 -1.287875e-01 -1.329666e-01 -8.598913e-02 -1.116608e-01
  [64] -1.048289e-01 -1.051069e-01 -5.112310e-02 -3.134091e-02 -6.088656e-02 -6.101064e-02 -1.615522e-02 -1.021232e-02  2.703312e-02
  [73]  4.954283e-02  4.315804e-02  2.719882e-02  3.670356e-02  4.422997e-02  5.011668e-02  4.552377e-02  5.688449e-02  3.507469e-02
  [82]  3.391465e-02  6.444333e-02  8.011616e-02  8.157409e-02  4.583216e-02  1.691226e-02 -1.310009e-02 -6.253229e-03 -2.445900e-02
  [91] -2.817816e-02  1.119052e-02  2.662970e-02  4.914242e-02  8.787654e-02  6.454450e-02  5.280729e-02  3.546875e-02  2.567525e-02
 [100]  2.392683e-02

The PercChange function has now been deprecated and I need to find a new function to replace it. Essentially, I need a function that calculates the percent change of df$Close[1:20] (This would be Close of day 1 minus close of day 20, divided by close of day 20), then rolls to [2:21] for the next row, then [3:22],[4:23], and so on.

Thanks in advance!

CodePudding user response:

Here is a simple Base R solution:

PercChange<- function(x, slideBy){
  -diff(x, slideBy)/ tail(x, -slideBy)
}

PercChange(df$Close, slideBy = 20)

 [1]  5.695617e-02  2.422862e-02  3.920509e-02 -1.706445e-02
 [5] -2.016308e-02 -1.997009e-02 -5.748624e-02 -1.446751e-02
 [9] -1.722569e-02 -3.790530e-03 -3.976292e-02 -1.877438e-02

If you desire a datframe back, then modify this into:

PercChange<- function(data, Var, NewVar, slideBy){
  x <- data[[Var]]
  data[NewVar] <- c(-diff(x, slideBy)/ tail(x, -slideBy), numeric(slideBy))
  data
}

PercChange(df, Var = 'Close', NewVar = 'OneMonthChange', slideBy = 20)

data:

df <- structure(list(Close = c(342.94, 346.22, 346.18, 335.24, 330.45, 
334.2, 325.45, 333.79, 334.9, 341.66, 333.74, 334.49, 329.75, 
329.82, 330.56, 322.81, 317.87, 306.84, 310.39, 310.6, 324.46, 
338.03, 333.12, 341.06, 337.25, 341.01, 345.3, 338.69, 340.77, 
342.96, 347.56, 340.89, 327.74, 327.64, 335.37, 338.62, 341.13, 
335.85, 331.62, 328.08, 329.98, 323.57, 316.92, 312.22, 315.81, 
328.69, 324.61, 341.88, 340.78, 339.99, 335.34, 324.76, 328.53, 
324.54, 323.77, 325.45, 330.05, 329.22, 333.64, 332.96, 326.23, 
343.01, 339.39, 339.61, 340.65, 353.58, 352.96, 345.96, 343.21, 
357.48, 355.7, 364.72, 373.06, 373.92, 376.53, 376.51, 378.69, 
378, 377.57, 382.18, 376.26, 375.28, 382.05, 379.38, 380.66, 
372.63, 364.38, 368.39, 365.51, 363.35, 359.37, 355.12, 355.45, 
358.45, 366.56, 363.18, 362.65, 359.96, 361.13, 361.61)), class = "data.frame", row.names = c(NA, 
-100L))

CodePudding user response:

A tidyverse approach

library(tidyr)
library(dplyr)

df %>% mutate(OneMonthChange=(Close-lead(Close, 20))/lead(Close, 20), 
  OneMonthChange=replace_na(OneMonthChange,0))
     Close OneMonthChange
1   342.94   5.695617e-02
2   346.22   2.422862e-02
3   346.18   3.920509e-02
4   335.24  -1.706445e-02
5   330.45  -2.016308e-02
6   334.20  -1.997009e-02
etc...
  •  Tags:  
  • r
  • Related