[Returnanalytics-commits] r3426 - pkg/PerformanceAnalytics/R
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Thu Jun 19 01:59:02 CEST 2014
Author: rossbennett34
Date: 2014-06-19 01:59:01 +0200 (Thu, 19 Jun 2014)
New Revision: 3426
Modified:
pkg/PerformanceAnalytics/R/Return.portfolio.R
Log:
Modifying Return.rebalancing to support wealth index and contribution args as well as adding separate functions for arithmetic and geometric returns
Modified: pkg/PerformanceAnalytics/R/Return.portfolio.R
===================================================================
--- pkg/PerformanceAnalytics/R/Return.portfolio.R 2014-06-18 17:26:42 UTC (rev 3425)
+++ pkg/PerformanceAnalytics/R/Return.portfolio.R 2014-06-18 23:59:01 UTC (rev 3426)
@@ -78,8 +78,7 @@
#'
#' To calculate BOP and EOP position value, we create an index for each position. The
#' sum of that value across assets represents an indexed value of the total portfolio.
-#' The change in value contained in slot seven is the asset's period return times its
-#' BOP value.
+#' Note that BOP and EOP position values are only computed when \code{geometric = TRUE}.
#'
#' From the value calculations, we can calculate different aggregations through time
#' for the asset contributions. Those are calculated as the EOP asset value less the
@@ -91,7 +90,13 @@
#' @param R An xts, vector, matrix, data frame, timeSeries or zoo object of
#' asset returns
#' @param weights A time series or single-row matrix/vector containing asset
-#' weights, as decimal percentages, treated as beginning of period weights. See Details below.
+#' weights, as decimal percentages, treated as beginning of period weights.
+#' See Details below.
+#' @param wealth.index TRUE/FALSE whether to return a wealth index. Default FALSE
+#' @param contribution if contribution is TRUE, add the weighted return
+#' contributed by the asset in a given period. Default FALSE
+#' @param geometric utilize geometric chaining (TRUE) or simple/arithmetic (FALSE)
+#' to aggregate returns. Default TRUE.
#' @param rebalance_on Default "none"; alternatively "daily" "weekly" "monthly" "annual" to specify calendar-period rebalancing supported by \code{endpoints}.
#' @param value The beginning of period total portfolio value. This is used for calculating position value.
#' @param verbose If verbose is TRUE, return a list of intermediary calculations.
@@ -121,11 +126,14 @@
#' @export Return.portfolio
#' @export Return.rebalancing
Return.portfolio <- Return.rebalancing <- function(R,
- weights=NULL,
- rebalance_on=c(NA, 'years', 'quarters', 'months', 'weeks', 'days'),
- value=1,
- verbose=FALSE,
- ...){
+ weights=NULL,
+ wealth.index=FALSE,
+ contribution=FALSE,
+ geometric=TRUE,
+ rebalance_on=c(NA, 'years', 'quarters', 'months', 'weeks', 'days'),
+ value=1,
+ verbose=FALSE,
+ ...){
R = checkData(R, method="xts")
rebalance_on = rebalance_on[1]
@@ -186,16 +194,124 @@
R <- R[paste0(as.Date(index(weights[1,]))+1, "/")]
}
+
+ if(geometric){
+ out = Return.portfolio.geometric(R=R,
+ weights=weights,
+ wealth.index=wealth.index,
+ contribution=contribution,
+ rebalance_on=rebalance_on,
+ value=value,
+ verbose=verbose,
+ ...=...)
+ } else {
+ out = Return.portfolio.arithmetic(R=R,
+ weights=weights,
+ wealth.index=wealth.index,
+ contribution=contribution,
+ rebalance_on=rebalance_on,
+ verbose=verbose,
+ ...=...)
+ }
+ return(out)
+}
+
+Return.portfolio.arithmetic <- function(R,
+ weights=NULL,
+ wealth.index=FALSE,
+ contribution=FALSE,
+ rebalance_on=c(NA, 'years', 'quarters', 'months', 'weeks', 'days'),
+ verbose=FALSE,
+ ...)
+{
# bop = beginning of period
# eop = end of period
# Initialize objects
+ bop_weights = matrix(0, NROW(R), NCOL(R))
+ colnames(bop_weights) = colnames(R)
+ eop_weights = period_contrib = bop_weights
+ ret = vector("numeric", NROW(R))
+
+ # initialize counter
+ k = 1
+ for(i in 1:NROW(weights)) {
+ # identify rebalance from and to dates (weights[i,], weights[i+1]) and
+ # subset the R(eturns) object
+ from = as.Date(index(weights[i,]))+1
+ if (i == nrow(weights)){
+ to = as.Date(index(last(R))) # this is correct
+ } else {
+ to = as.Date(index(weights[(i+1),]))
+ }
+ returns = R[paste0(from, "::", to)]
+
+ # Only enter the loop if we have a valid returns object
+ if(nrow(returns) >= 1){
+ # inner loop counter
+ jj = 1
+ for(j in 1:nrow(returns)){
+ # For arithmetic returns, the beginning of period weights are always
+ # equal to the rebalance weights
+ bop_weights[k,] = weights[i,]
+ period_contrib[k,] = coredata(returns[j,]) * bop_weights[k,]
+ eop_weights[k,] = (period_contrib[k,] + bop_weights[k,]) / sum(c(period_contrib[k,], bop_weights[k,]))
+ ret[k] = sum(period_contrib[k,])
+
+ # increment the counters
+ k = k + 1
+ }
+ }
+ }
+ R.idx = index(R)
+ ret = xts(ret, R.idx)
+ colnames(ret) = "portfolio.returns"
+
+ if(wealth.index){
+ result = cumsum(ret) + 1
+ colnames(result) = "portfolio.wealthindex"
+ } else {
+ result = ret
+ }
+
+ if(verbose){
+ out = list()
+ out$returns = ret
+ out$contribution = xts(period_contrib, R.idx)
+ out$BOP.Weight = xts(bop_weights, R.idx)
+ out$EOP.Weight = xts(eop_weights, R.idx)
+ if(wealth.index){
+ out$wealthindex = result
+ }
+ } else if(contribution){
+ out = cbind(result, xts(period_contrib, R.idx))
+ } else {
+ out = result
+ }
+ return(out)
+}
+
+Return.portfolio.geometric <- function(R,
+ weights=NULL,
+ wealth.index=FALSE,
+ contribution=FALSE,
+ rebalance_on=c(NA, 'years', 'quarters', 'months', 'weeks', 'days'),
+ value=1,
+ verbose=FALSE,
+ ...)
+{
+ # bop = beginning of period
+ # eop = end of period
+ # Initialize objects
bop_value = matrix(0, NROW(R), NCOL(R))
colnames(bop_value) = colnames(R)
eop_value = bop_value
- if(verbose){
- bop_weights = bop_value
- eop_weights = bop_value
+
+ if(verbose | contribution){
period_contrib = bop_value
+ if(verbose){
+ bop_weights = bop_value
+ eop_weights = bop_value
+ }
}
ret = eop_value_total = bop_value_total = vector("numeric", NROW(R))
@@ -235,12 +351,14 @@
eop_value[k,] = (1 + coredata(returns[j,])) * bop_value[k,]
eop_value_total[k] = sum(eop_value[k,])
- if(verbose){
- # Compute bop and eop weights
- bop_weights[k,] = bop_value[k,] / bop_value_total[k]
- eop_weights[k,] = eop_value[k,] / eop_value_total[k]
+ if(contribution | verbose){
# Compute period contribution
period_contrib[k,] = returns[j,] * bop_value[k,] / sum(bop_value[k,])
+ if(verbose){
+ # Compute bop and eop weights
+ bop_weights[k,] = bop_value[k,] / bop_value_total[k]
+ eop_weights[k,] = eop_value[k,] / eop_value_total[k]
+ }
}
# Compute portfolio returns
@@ -261,6 +379,13 @@
ret = xts(ret, R.idx)
colnames(ret) = "portfolio.returns"
+ if(wealth.index){
+ result = cumprod(1 + ret)
+ colnames(result) = "portfolio.wealthindex"
+ } else {
+ result = ret
+ }
+
if(verbose){
out = list()
out$returns = ret
@@ -269,8 +394,13 @@
out$EOP.Weight = xts(eop_weights, R.idx)
out$BOP.Value = xts(bop_value, R.idx)
out$EOP.Value = xts(eop_value, R.idx)
+ if(wealth.index){
+ out$wealthindex = result
+ }
+ } else if(contribution){
+ out = cbind(result, xts(period_contrib, R.idx))
} else {
- out = ret
+ out = result
}
return(out)
}
More information about the Returnanalytics-commits
mailing list