rnaportfolioperformanceanalyticsweighting

How do I calculate equal weighted portfolio returns with NA using PerformanceAnalytics?


I am struggling to calculate equal weighted portfolio returns. I am currently using Return.portfolio from the PerformanceAnalytics package and I encounter problems when dealing with NAs.

To give a reproduceable example:

structure(c(5.49295774647889, 4.80640854472629, -0.127388535031836, 
4.71938775510203, 5.75517661388552, NA, NA, NA, 1.46627565982405, 
4.09441233140655, 1.31031876023686, 10.3718442979729, -5.16056338028169, 
0.237614351906856, 1.35119118169966, 2.26775883557192, 5.05941761423306, 
-1.76265063843784, 2.14109258894431, 3.73359337566391, 3.40163825335787, 
7.58912642134959, -2.64397595765676, 2.14109258894431, 3.733593376, 
NA, 7.58912642134959, -2.64397595765676, 2.47850105350444, 3.73359337566391
), .Dim = 5:6, .Dimnames = list(NULL, c("ALVGY", "BAYNGY", "BMWGY", 
"PF.return.wrong", "PF.return.expected", "PF.return.weighted"
)), index = structure(c(1480464000, 1483142400, 1485820800, 1488240000, 
1490918400), tzone = "UTC", tclass = "Date"), class = c("xts", 
"zoo"), ret_type = "discrete", coredata_content = "discreteReturn")

                ALVGY   BAYNGY      BMWGY PF.return.wrong PF.return.expected PF.return.weighted
2016-11-30  5.4929577       NA  1.3103188        2.267759           3.401638                 NA
2016-12-31  4.8064085       NA 10.3718443        5.059418           7.589126           7.589126
2017-01-31 -0.1273885       NA -5.1605634       -1.762651          -2.643976          -2.643976
2017-02-28  4.7193878 1.466276  0.2376144        2.141093           2.141093           2.478501
2017-03-31  5.7551766 4.094412  1.3511912        3.733593           3.733593           3.733593

When I run Example$PF.return <- Return.portfolio(Example[,1:3], geometric = F), I get a warning reading In Return.portfolio(Example, geometric = F) : NA's detected: filling NA's with zeros and indeed the resulting PF.return.wrong includes the NAs as zeros in the calculation.

I am indeed looking to get the results in PF.return.expected.

What I want to do is to exclude the NAs from the portfolio return calculation. However I am not able to this.

As a potential work-around I thought about maybe using return.portfolio in combination with the weighting matrix Example.wt below:

structure(c(0.5, 0.5, 0.5, 0.333333333333333, 0.333333333333333, 
0, 0, 0, 0.333333333333333, 0.333333333333333, 0.5, 0.5, 0.5, 
0.333333333333333, 0.333333333333333), .Dim = c(5L, 3L), .Dimnames = list(
    NULL, c("ALVGY", "BAYNGY", "BMWGY")), index = structure(c(1480464000, 
1483142400, 1485820800, 1488240000, 1490918400), tzone = "UTC", tclass = "Date"), class = c("xts", 
"zoo"))

               ALVGY    BAYNGY     BMWGY
2016-11-30 0.5000000 0.0000000 0.5000000
2016-12-31 0.5000000 0.0000000 0.5000000
2017-01-31 0.5000000 0.0000000 0.5000000
2017-02-28 0.3333333 0.3333333 0.3333333
2017-03-31 0.3333333 0.3333333 0.3333333

Running Example$PF.return.weighted <- Return.portfolio(Example[,1:3], geometric = F, weights = Example.wt) I encounter three problems:

  1. For some reason the first row of PF.return.weighted returns an NA
  2. The value for the fourth row is not equal to PF.return.expected and I don't understand why
  3. The Example.wt was constructed manually because I didn't manage to calculate it.

Do you have any idea why there is an NA for PF.return.weighted and why the fourth row value differs from the expected value?

As for the calculation of the weighting matrix, do you know how I could automatically calculate it from Example? I thought about using some combination of rowSums and !is.na() but did not manage to construct it.

Sorry for this long post but I am really stuck here and would appreciate any help/hints! Many thanks in advance!


Solution

  • I think you encounter this problem, because the weights need be known before the rebalancing, i.e. you can get meaningful values, if you subtract one day from the index of your weights:

    library(xts)
    library(PerformanceAnalytics)
    
    Example.wt2 <- Example.wt
    index(Example.wt2) <- index(Example.wt) - 1 # subtract one day from the index
    
    test <- PerformanceAnalytics::Return.portfolio(Example,
                                                   weights = Example.wt,
                                                   rebalance_on = "months")
    
    test2 <- PerformanceAnalytics::Return.portfolio(Example,
                                                    weights = Example.wt2,
                                                    rebalance_on = "months")
    
    res <- merge.xts(test, test2)
    names(res) <- paste0("portfolio.returns", c(".old", ".new"))
    > print(res)
               portfolio.returns.old portfolio.returns.new
    2016-11-30                    NA              3.401638
    2016-12-31              7.589126              7.589126
    2017-01-31             -2.643976             -2.643976
    2017-02-28              2.478501              2.141093
    2017-03-31              3.733593              3.733593
    

    EDIT: You can get the weights with a functional approach like this:

    ####
    fCalcWeights <- function(x){
      y <- 1/sum(!is.na(x))
      x[!is.na(x)] <- y
      x[is.na(x)] <- 0
      x
    }
    
    Example.wt3 <- t(apply(Example[, c(1:3)], 1, fCalcWeights))
    Example.wt3 <- xts(Example.wt3, order.by = index(Example)-1)
    
    > Example.wt3
                   ALVGY    BAYNGY     BMWGY
    2016-11-29 0.5000000 0.0000000 0.5000000
    2016-12-30 0.5000000 0.0000000 0.5000000
    2017-01-30 0.5000000 0.0000000 0.5000000
    2017-02-27 0.3333333 0.3333333 0.3333333
    2017-03-30 0.3333333 0.3333333 0.3333333
    > 
    > all.equal(Example.wt2, Example.wt3)
    [1] TRUE