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:
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!
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