[Returnanalytics-commits] r2054 - pkg/PortfolioAnalytics/sandbox/attribution/R
noreply at r-forge.r-project.org
noreply at r-forge.r-project.org
Sun Jun 24 19:08:36 CEST 2012
Author: ababii
Date: 2012-06-24 19:08:36 +0200 (Sun, 24 Jun 2012)
New Revision: 2054
Added:
pkg/PortfolioAnalytics/sandbox/attribution/R/DaviesLaker.R
Modified:
pkg/PortfolioAnalytics/sandbox/attribution/R/attribution.R
Log:
- Davies Laker linking
Added: pkg/PortfolioAnalytics/sandbox/attribution/R/DaviesLaker.R
===================================================================
--- pkg/PortfolioAnalytics/sandbox/attribution/R/DaviesLaker.R (rev 0)
+++ pkg/PortfolioAnalytics/sandbox/attribution/R/DaviesLaker.R 2012-06-24 17:08:36 UTC (rev 2054)
@@ -0,0 +1,104 @@
+#' calculates total attribution effects using Davies and Laker smoothing
+#'
+#' Calculates total attribution effects over multiple periods using
+#' Davies and Laker linking method. Used internally by the
+#' \code{\link{Attribution}} function. Arithmetic attribution effects do not
+#' naturally link over time. This function uses Davies and Laker linking method
+#' to compute total attribution effects.
+#' Arithmetic excess returns are decomposed as follows:
+#' \deqn{r - b = Allocation + Selection + Interaction}
+#' \deqn{Allocation = \overset{T}{\underset{t=1}{\prod}}(1+bs_{t})-\overset{T}{\underset{t=1}{\prod}}(1+rb_{t})}
+#' \deqn{Selection = \overset{T}{\underset{t=1}{\prod}}(1+rs_{t})-\overset{T}{\underset{t=1}{\prod}}(1+rb_{t})}
+#' \deqn{Interaction = \overset{T}{\underset{t=1}{\prod}}(1+rp_{t})-\overset{T}{\underset{t=1}{\prod}}(1+rs_{t})-\overset{T}{\underset{t=1}{\prod}}(1+bs_{t})+\overset{T}{\underset{t=1}{\prod}}(1+rb_{t})}
+#' \deqn{rp_{i}} - portfolio returns at period \deqn{i}
+#' \deqn{rb_{i}} - benchmark returns at period \deqn{i}
+#' \deqn{rs_{i}} - selection notional fund returns at period \deqn{i}
+#' \deqn{bs_{i}} - allocation notional fund returns at period \deqn{i}
+#' \deqn{T} - number of periods
+#'
+#' @aliases DaviesLaker
+#' @param Rp xts of portfolio returns
+#' @param wp xts of portfolio weights
+#' @param Rb xts of benchmark returns
+#' @param wb xts of benchmark weights
+#' @return This function returns the data.frame with original attribution effects
+#' and total attribution effects over multiple periods
+#' @author Andrii Babii
+#' @seealso \code{\link{Attribution}} \cr \code{\link{Menchero}} \cr
+#' \code{\link{Grap}} \cr \code{\link{Carino}} \cr
+#' \code{\link{Attribution.geometric}} \cr \code{\link{Frongello}}
+#' @references Bacon, C. \emph{Practical Portfolio Performance Measurement and
+#' Attribution}. Wiley. 2004. p. 201-204
+#'
+#' Davies, O. and Laker, D. (2001) Multiple-period performance attribution
+#' using the brinson model.Journal of Performance MeasurementFall, 1222.
+#' @keywords arithmetic attribution, Davies and Laker linking
+#' @examples
+#'
+#' data(attrib)
+#' DaviesLaker(Rp, wp, Rb, wb)
+#'
+#' @export
+DaviesLaker <-
+function(Rp, wp, Rb, wb)
+{ # @author Andrii Babii
+
+ # DESCRIPTION:
+ # Function to provide multi-period summary of attribution effects using
+ # Davies and Laker linking. Used internally by the Attribution function
+
+ # Inputs:
+ # Rp xts, data frame or matrix of portfolio returns
+ # wp vector, xts, data frame or matrix of portfolio weights
+ # Rb xts, data frame or matrix of benchmark returns
+ # wb vector, xts, data frame or matrix of benchmark weights
+
+ # Outputs:
+ # This function returns the data.frame with original attribution effects
+ # and total attribution effects over multiple periods
+
+ # FUNCTION:
+ rp = reclass(rowSums(Rp * wp), Rp)
+ rb = reclass(rowSums(Rb * wb), Rb)
+ colnames(rp) = "Total"
+ colnames(rb) = "Total"
+ bs = reclass(rowSums((wp * Rb[, 1:ncol(wp)])), Rp) # Allocation notional fund returns
+ rs = reclass(rowSums((wb * Rp[, 1:ncol(wb)])), Rp) # Selection notional fund returns
+ a = apply(1 + bs, 2, prod) - apply(1 + rb, 2, prod)
+ s = apply(1 + rs, 2, prod) - apply(1 + rb, 2, prod)
+ i = apply(1 + rp, 2, prod) - apply(1 + rs, 2, prod) - apply(1 + bs, 2, prod) + apply(1 + rb, 2, prod)
+
+ # Compute attribution effects (Brinson, Hood and Beebower model)
+ allocation = (wp - wb) * Rb
+ selection = wb * (Rp - Rb)
+ interaction = (wp - wb) * (Rp - Rb)
+ n = ncol(allocation) # number of segments
+ allocation = cbind(allocation, rowSums(allocation))
+ names(allocation)[n + 1] = "Total"
+ selection = cbind(selection, rowSums(selection))
+ names(selection)[n + 1] = "Total"
+ interaction = cbind(interaction, rowSums(interaction))
+ names(interaction)[n + 1] = "Total"
+
+ allocation = rbind(as.data.frame(allocation), c(rep(NA, ncol(allocation) - 1), a))
+ selection = rbind(as.data.frame(selection), c(rep(NA, ncol(selection) - 1), s))
+ interaction = rbind(as.data.frame(interaction), c(rep(NA, ncol(interaction) - 1), i))
+ rownames(allocation)[nrow(allocation)] = "Total"
+ rownames(selection)[nrow(selection)] = "Total"
+ rownames(interaction)[nrow(allocation)] = "Total"
+
+ excess.returns = rp - rb
+ rp.a = prod(1 + rp) - 1
+ rb.a = prod(1 + rb) - 1
+ aer.a = as.matrix(rp.a - rb.a) # Arithmetic (annualized) excess returns
+ rownames(aer.a) = "Total arithmetic"
+ excess.returns = rbind(as.matrix(excess.returns), aer.a)
+
+ result = list()
+ result[[1]] = excess.returns
+ result[[2]] = allocation
+ result[[3]] = selection
+ result[[4]] = interaction
+ names(result) = c("Excess returns", "Allocation", "Selection", "Interaction")
+ return(result)
+}
Modified: pkg/PortfolioAnalytics/sandbox/attribution/R/attribution.R
===================================================================
--- pkg/PortfolioAnalytics/sandbox/attribution/R/attribution.R 2012-06-24 17:05:36 UTC (rev 2053)
+++ pkg/PortfolioAnalytics/sandbox/attribution/R/attribution.R 2012-06-24 17:08:36 UTC (rev 2054)
@@ -5,10 +5,10 @@
#' portfolio. Equipped with weights and returns of portfolio segments, we
#' can dissect the value-added into useful components. This function is based
#' on the sector-based approach to the attribution. The workhorse is the
-#' Brinson model that explains the arithmetic difference between portfolio and
+#' Brinson model that explains the arithmetic difference between portfolio and
#' benchmark returns. That is it breaks down the arithmetic excess returns at
#' one level. If returns and weigths are available at the lowest level (e.g.
-#' for individual instruments), the aggregation up to the chosen level from the
+#' for individual instruments), the aggregation up to the chosen level from the
#' hierarchy can be done using Return.level function. The attribution effects
#' can be computed for several periods. The multi-period summary is obtained
#' using one of linking methods: Carino, Menchero, GRAP, Frongello. It also
@@ -39,11 +39,13 @@
#' Usually we have more then one period. In that case individual arithmetic
#' attribution effects should be adjusted using linking methods. Adjusted
#' arithmetic attribution effects can be summed up over time to provide the
-#' multi-period summary: \deqn{r-b=\overset{T}{\underset{t=1}{\sum}}\left(A_{t}'+S_{t}'+I_{t}'\right)}
+#' multi-period summary:
+#' \deqn{r-b=\overset{T}{\underset{t=1}{\sum}}\left(A_{t}'+S_{t}'+I_{t}'\right)}
#' , where \deqn{T} - number of periods; prime stands for the adjustment.
#' The geometric attribution effects do not suffer from the linking problem.
#' Moreover we don't have the interaction term. For more details about the
-#' geometric attribution see the documentation to \code{link{Attribution.geometric}}
+#' geometric attribution see the documentation to
+#' \code{link{Attribution.geometric}}
#' Finally, arithmetic annualized excess returns are computed as the
#' arithmetic difference between annualised portfolio and benchmark returns:
#' \deqn{AAER=r_{a}-b_{a}}; the geometric annualized excess returns are
@@ -51,9 +53,9 @@
#' and benchmark returns: \deqn{GAER=\frac{1+r_{a}}{1+b_{a}}-1}
#'
#' @aliases Attribution
-#' @param Rp xts, data frame or matrix of portfolio returns
+#' @param Rp T x n xts, data frame or matrix of portfolio returns
#' @param wp vector, xts, data frame or matrix of portfolio weights
-#' @param Rb xts, data frame or matrix of benchmark returns
+#' @param Rb T x n xts, data frame or matrix of benchmark returns
#' @param wb vector, xts, data frame or matrix of benchmark weights
#' @param method Used to select the priority between allocation and selection
#' effects in arithmetic attribution. May be any of: \itemize{ \item none -
@@ -70,6 +72,11 @@
#' Frongello's linking method
#' @param geometric TRUE/FALSE, whether to use geometric or arithmetic excess
#' returns for the attribution analysis
+#' @param adjusted TRUE/FALSE, whether to show original or smoothed attribution
+#' effects for each period
+#' @return returns a list with the following components: excess returns with
+#' annualized excess returns over all periods, attribution effects (allocation,
+#' selection and interaction)
#' @author Andrii Babii
#' @seealso \code{\link{Attribution.levels}}
#' @references Bacon, C. \emph{Practical Portfolio Performance Measurement and
@@ -87,21 +94,22 @@
#'
#' data(attrib)
#' Attribution(Rp, wp, Rb, wb, method = "top.down", linking = "carino")
-#' Attribution(Rp, wp, Rb, wb, geometric = TRUE)
#'
-#' @export
+#' @TODO fix bug with annualized excess returns, Brinson-Fachler, check if we can compute
+#' total effects for individual segments in Davies-Laker and Geometric
+#' @export
Attribution <-
function (Rp, wp, Rb, wb, method = c("none", "top.down", "bottom.up"),
-linking = c("carino", "menchero", "grap", "frongello"), geometric = FALSE)
+linking = c("carino", "menchero", "grap", "frongello", "davies.laker"), geometric = FALSE, adjusted = FALSE)
{ # @author Andrii Babii
# DESCRIPTION:
# Function to perform the attribution analysis.
# Inputs:
- # Rp xts, data frame or matrix of portfolio returns
+ # Rp T x n xts, data frame or matrix of portfolio returns
# wp vector, xts, data frame or matrix of portfolio weights
- # Rb xts, data frame or matrix of benchmark returns
+ # Rb T x n xts, data frame or matrix of benchmark returns
# wb vector, xts, data frame or matrix of benchmark weights
# Outputs:
@@ -141,45 +149,49 @@
# Adjust attribution effects using one of linking methods
if (linking == "carino"){
- allocation = Carino(rp, rb, allocation)
- selection = Carino(rp, rb, selection)
- interaction = Carino(rp, rb, interaction)
+ allocation = Carino(rp, rb, allocation, adjusted)
+ selection = Carino(rp, rb, selection, adjusted)
+ interaction = Carino(rp, rb, interaction, adjusted)
}
if (linking == "menchero"){
- allocation = Menchero(rp, rb, allocation)
- selection = Menchero(rp, rb, selection)
- interaction = Menchero(rp, rb, interaction)
+ allocation = Menchero(rp, rb, allocation, adjusted)
+ selection = Menchero(rp, rb, selection, adjusted)
+ interaction = Menchero(rp, rb, interaction, adjusted)
}
if (linking == "grap"){
- allocation = Grap(rp, rb, allocation)
- selection = Grap(rp, rb, selection)
- interaction = Grap(rp, rb, interaction)
+ allocation = Grap(rp, rb, allocation, adjusted)
+ selection = Grap(rp, rb, selection, adjusted)
+ interaction = Grap(rp, rb, interaction, adjusted)
}
if (linking == "frongello"){
- allocation = Frongello(rp, rb, allocation)
- selection = Frongello(rp, rb, selection)
- interaction = Frongello(rp, rb, interaction)
+ allocation = Frongello(rp, rb, allocation, adjusted)
+ selection = Frongello(rp, rb, selection, adjusted)
+ interaction = Frongello(rp, rb, interaction, adjusted)
}
if (geometric == TRUE){
attrib = Attribution.geometric(Rp, wp, Rb, wb)
}
- # Annualize excess returns
- rp.a = prod(1 + rp) - 1
- rb.a = prod(1 + rb) - 1
- if (geometric == FALSE){
+ if (linking == "davies.laker"){
+ attrib = DaviesLaker(Rp, wp, Rb, wb)
+ }
+
+ # Total arithmetic excess returns
+ rp.c = prod(1 + rp) - 1
+ rb.c = prod(1 + rb) - 1
+ if (geometric == FALSE | linking != "davies.laker"){
excess.returns = rp - rb
- aer.a = as.matrix(rp.a - rb.a) # Arithmetic (annualized) excess returns
- rownames(aer.a) = "Total arithmetic"
- excess.returns = rbind(as.matrix(excess.returns), aer.a)
+ aer = as.matrix(rp.c - rb.c)
+ rownames(aer) = "Total arithmetic"
+ excess.returns = rbind(as.matrix(excess.returns), aer)
}
# Select the appropriate result corresponding to the chosen method
- if (geometric == FALSE){
+ if (geometric == FALSE & linking != "davies.laker"){
result = list()
result[[1]] = excess.returns
result[[2]] = allocation
@@ -198,7 +210,7 @@
}
# Label the output
- if (method == "none" & geometric == FALSE){
+ if ((linking == "none" & geometric == FALSE) | linking == "davies.laker"){
names(result) = c("Excess returns", "Allocation", "Selection", "Interaction")
} else{
names(result) = c("Excess returns", "Allocation", "Selection")
More information about the Returnanalytics-commits
mailing list