Using a time series of returns and any regular or irregular time series of weights for each asset, this function calculates the returns of a portfolio with the same periodicity of the returns data.

Return.portfolio(R, weights = NULL, wealth.index = FALSE,
  contribution = FALSE, geometric = TRUE, rebalance_on = c(NA, "years",
  "quarters", "months", "weeks", "days"), value = 1, verbose = FALSE, ...)

Arguments

R

An xts, vector, matrix, data frame, timeSeries or zoo object of asset returns

weights

A time series or single-row matrix/vector containing asset weights, as decimal percentages, treated as beginning of period weights. See Details below.

wealth.index

TRUE/FALSE whether to return a wealth index. Default FALSE

contribution

if contribution is TRUE, add the weighted return contributed by the asset in a given period. Default FALSE

geometric

utilize geometric chaining (TRUE) or simple/arithmetic (FALSE) to aggregate returns. Default TRUE.

rebalance_on

Default "none"; alternatively "daily" "weekly" "monthly" "annual" to specify calendar-period rebalancing supported by endpoints. Ignored if weights is an xts object that specifies the rebalancing dates.

value

The beginning of period total portfolio value. This is used for calculating position value.

verbose

If verbose is TRUE, return a list of intermediary calculations. See Details below.

any other passthru parameters. Not currently used.

Value

returns a time series of returns weighted by the weights parameter, or a list that includes intermediate calculations

Details

By default, this function calculates the time series of portfolio returns given asset returns and weights. In verbose mode, the function returns a list of intermediary calculations that users may find helpful, including both asset contribution and asset value through time.

When asset return and weights are matched by period, contribution is simply the weighted return of the asset. c_i = w_i * R_i Contributions are summable across the portfolio to calculate the total portfolio return.

Contribution cannot be aggregated through time. For example, say we have an equal weighted portfolio of five assets with monthly returns. The geometric return of the portfolio over several months won't match any aggregation of the individual contributions of the assets, particularly if any rebalancing was done during the period.

To aggregate contributions through time such that they are summable to the geometric returns of the portfolio, the calculation must track changes in the notional value of the assets and portfolio. For example, contribution during a quarter will be calculated as the change in value of the position through those three months, divided by the original value of the portfolio. Approaching it this way makes the calculation robust to weight changes as well. c_pi = V_(t-p)i - V_t)/V_ti

If the user does not specify weights, an equal weight portfolio is assumed. Alternatively, a vector or single-row matrix of weights that matches the length of the asset columns may be specified. In either case, if no rebalancing period is specified, the weights will be applied at the beginning of the asset time series and no further rebalancing will take place. If a rebalancing period is specified, the portfolio will be rebalanced to the starting weights at the interval specified.

Note that if weights is an xts object, then any value passed to rebalance_on is ignored. The weights object specifies the rebalancing dates, therefore a regular rebalancing frequency provided via rebalance_on is not needed and ignored. Return.portfolio will work only on daily or lower frequencies. If you are rebalancing intraday, you should be using a trades/prices framework like the blotter package, not a weights/returns framework.

Irregular rebalancing can be done by specifying a time series of weights. The function uses the date index of the weights for xts-style subsetting of rebalancing periods.

Weights specified for rebalancing should be thought of as "end-of-period" weights. Rebalancing periods can be thought of as taking effect immediately after the close of the bar. So, a March 31 rebalancing date will actually be in effect for April 1. A December 31 rebalancing date will be in effect on Jan 1, and so forth. This convention was chosen because it fits with common usage, and because it simplifies xts Date subsetting via endpoints.

In verbose mode, the function returns a list of data and intermediary calculations.

  • returns: The portfolio returns.

  • contribution: The per period contribution to portfolio return of each asset. Contribution is calculated as BOP weight times the period's return divided by BOP value. Period contributions are summed across the individual assets to calculate portfolio return

  • BOP.Weight: Beginning of Period (BOP) Weight for each asset. An asset's BOP weight is calculated using the input weights (or assumed weights, see below) and rebalancing parameters given. The next period's BOP weight is either the EOP weights from the prior period or input weights given on a rebalance period.

  • EOP.Weight: End of Period (BOP) Weight for each asset. An asset's EOP weight is the sum of the asset's BOP weight and contribution for the period divided by the sum of the contributions and initial weights for the portfolio.

  • BOP.Value: BOP Value for each asset. The BOP value for each asset is the asset's EOP value from the prior period, unless there is a rebalance event. If there is a rebalance event, the BOP value of the asset is the rebalance weight times the EOP value of the portfolio. That effectively provides a zero-transaction cost change to the position values as of that date to reflect the rebalance. Note that the sum of the BOP values of the assets is the same as the prior period's EOP portfolio value.

  • EOP.Value: EOP Value for each asset. The EOP value is for each asset is calculated as (1 + asset return) times the asset's BOP value. The EOP portfolio value is the sum of EOP value across assets.

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. Note that BOP and EOP position values are only computed when 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 BOP asset value; that quantity is divided by the BOP portfolio value. Across assets, those will sum to equal the geometric chained returns of the portfolio for that same time period. The function does not do this directly, however.

Note

This function was previously two functions: Return.portfolio and Return.rebalancing. Both function names are still exported, but the code is now common, and Return.portfolio is probably to be preferred.

References

Bacon, C. Practical Portfolio Performance Measurement and Attribution. Wiley. 2004. Chapter 2

See also

Return.calculate endpoints

Examples

data(edhec) Return.portfolio(edhec["1997",1:5], rebalance_on="quarters") # returns time series
#> portfolio.returns #> 1997-01-31 0.033400000 #> 1997-02-28 0.023762011 #> 1997-03-31 -0.001413340 #> 1997-04-30 0.003680000 #> 1997-05-31 0.017660872 #> 1997-06-30 0.025452430 #> 1997-07-31 0.036500000 #> 1997-08-31 -0.005136602 #> 1997-09-30 0.022049167 #> 1997-10-31 -0.010780000 #> 1997-11-30 -0.002621013 #> 1997-12-31 0.012985944
Return.portfolio(edhec["1997",1:5], rebalance_on="quarters", verbose=TRUE) # returns list
#> $returns #> portfolio.returns #> 1997-01-31 0.033400000 #> 1997-02-28 0.023762011 #> 1997-03-31 -0.001413340 #> 1997-04-30 0.003680000 #> 1997-05-31 0.017660872 #> 1997-06-30 0.025452430 #> 1997-07-31 0.036500000 #> 1997-08-31 -0.005136602 #> 1997-09-30 0.022049167 #> 1997-10-31 -0.010780000 #> 1997-11-30 -0.002621013 #> 1997-12-31 0.012985944 #> #> $contribution #> Convertible Arbitrage CTA Global Distressed Securities #> 1997-01-31 0.002380000 0.0078600000 0.0035600000 #> 1997-02-28 0.002408819 0.0059940275 0.0024031662 #> 1997-03-31 0.001510442 -0.0004248891 -0.0002337074 #> 1997-04-30 0.001720000 -0.0034000000 0.0006000000 #> 1997-05-31 0.003135294 -0.0002938187 0.0046568428 #> 1997-06-30 0.004252156 0.0016336242 0.0043610924 #> 1997-07-31 0.003860000 0.0118200000 0.0046800000 #> 1997-08-31 0.002635527 -0.0096662672 0.0029028423 #> 1997-09-30 0.002444218 0.0038748559 0.0070493383 #> 1997-10-31 0.002000000 -0.0019600000 -0.0012800000 #> 1997-11-30 0.000000000 0.0026626352 0.0010847819 #> 1997-12-31 0.001392218 0.0058170647 0.0014782579 #> Emerging Markets Equity Market Neutral #> 1997-01-31 0.015820000 0.0037800000 #> 1997-02-28 0.010964341 0.0019916567 #> 1997-03-31 -0.002576485 0.0003112995 #> 1997-04-30 0.002380000 0.0023800000 #> 1997-05-31 0.006351596 0.0038109577 #> 1997-06-30 0.011874480 0.0033310776 #> 1997-07-31 0.011200000 0.0049400000 #> 1997-08-31 -0.001344834 0.0003361293 #> 1997-09-30 0.004659301 0.0040214532 #> 1997-10-31 -0.011440000 0.0019000000 #> 1997-11-30 -0.007205240 0.0008368108 #> 1997-12-31 0.002942265 0.0013561387 #> #> $BOP.Weight #> Convertible Arbitrage CTA Global Distressed Securities #> 1997-01-31 0.2000000 0.2000000 0.2000000 #> 1997-02-28 0.1958390 0.2011419 0.1969808 #> 1997-03-31 0.1936464 0.2023282 0.1947562 #> 1997-04-30 0.2000000 0.2000000 0.2000000 #> 1997-05-31 0.2009804 0.1958792 0.1998645 #> 1997-06-30 0.2005734 0.1921911 0.2009720 #> 1997-07-31 0.2000000 0.2000000 0.2000000 #> 1997-08-31 0.1966811 0.2043608 0.1974723 #> 1997-09-30 0.2003458 0.1956998 0.2014097 #> 1997-10-31 0.2000000 0.2000000 0.2000000 #> 1997-11-30 0.2042013 0.2001981 0.2008855 #> 1997-12-31 0.2047379 0.2033939 0.2025011 #> Emerging Markets Equity Market Neutral #> 1997-01-31 0.2000000 0.2000000 #> 1997-02-28 0.2088446 0.1971937 #> 1997-03-31 0.2147071 0.1945622 #> 1997-04-30 0.2000000 0.2000000 #> 1997-05-31 0.2016380 0.2016380 #> 1997-06-30 0.2043800 0.2018835 #> 1997-07-31 0.2000000 0.2000000 #> 1997-08-31 0.2037627 0.1977231 #> 1997-09-30 0.2034629 0.1990818 #> 1997-10-31 0.2000000 0.2000000 #> 1997-11-30 0.1906148 0.2041002 #> 1997-12-31 0.1838916 0.2054756 #> #> $EOP.Weight #> Convertible Arbitrage CTA Global Distressed Securities #> 1997-01-31 0.1958390 0.2011419 0.1969808 #> 1997-02-28 0.1936464 0.2023282 0.1947562 #> 1997-03-31 0.1954330 0.2021890 0.1947978 #> 1997-04-30 0.2009804 0.1958792 0.1998645 #> 1997-05-31 0.2005734 0.1921911 0.2009720 #> 1997-06-30 0.1997416 0.1890138 0.2002366 #> 1997-07-31 0.1966811 0.2043608 0.1974723 #> 1997-08-31 0.2003458 0.1956998 0.2014097 #> 1997-09-30 0.1984151 0.1952691 0.2039618 #> 1997-10-31 0.2042013 0.2001981 0.2008855 #> 1997-11-30 0.2047379 0.2033939 0.2025011 #> 1997-12-31 0.2034876 0.2065290 0.2013644 #> Emerging Markets Equity Market Neutral #> 1997-01-31 0.2088446 0.1971937 #> 1997-02-28 0.2147071 0.1945622 #> 1997-03-31 0.2124308 0.1951493 #> 1997-04-30 0.2016380 0.2016380 #> 1997-05-31 0.2043800 0.2018835 #> 1997-06-30 0.2108869 0.2001210 #> 1997-07-31 0.2037627 0.1977231 #> 1997-08-31 0.2034629 0.1990818 #> 1997-09-30 0.2036323 0.1987216 #> 1997-10-31 0.1906148 0.2041002 #> 1997-11-30 0.1838916 0.2054756 #> 1997-12-31 0.1844387 0.2041802 #> #> $BOP.Value #> Convertible Arbitrage CTA Global Distressed Securities #> 1997-01-31 0.2000000 0.2000000 0.2000000 #> 1997-02-28 0.2023800 0.2078600 0.2035600 #> 1997-03-31 0.2048693 0.2140542 0.2060434 #> 1997-04-30 0.2112921 0.2112921 0.2112921 #> 1997-05-31 0.2131092 0.2077001 0.2119260 #> 1997-06-30 0.2164337 0.2073886 0.2168638 #> 1997-07-31 0.2213080 0.2213080 0.2213080 #> 1997-08-31 0.2255792 0.2343873 0.2264866 #> 1997-09-30 0.2286020 0.2233008 0.2298159 #> 1997-10-31 0.2332393 0.2332393 0.2332393 #> 1997-11-30 0.2355716 0.2309535 0.2317465 #> 1997-12-31 0.2355716 0.2340252 0.2329980 #> Emerging Markets Equity Market Neutral #> 1997-01-31 0.2000000 0.2000000 #> 1997-02-28 0.2158200 0.2037800 #> 1997-03-31 0.2271506 0.2058382 #> 1997-04-30 0.2112921 0.2112921 #> 1997-05-31 0.2138065 0.2138065 #> 1997-06-30 0.2205414 0.2178474 #> 1997-07-31 0.2213080 0.2213080 #> 1997-08-31 0.2337012 0.2267743 #> 1997-09-30 0.2321588 0.2271598 #> 1997-10-31 0.2332393 0.2332393 #> 1997-11-30 0.2198980 0.2354550 #> 1997-12-31 0.2115858 0.2364204 #> #> $EOP.Value #> Convertible Arbitrage CTA Global Distressed Securities #> 1997-01-31 0.2023800 0.2078600 0.2035600 #> 1997-02-28 0.2048693 0.2140542 0.2060434 #> 1997-03-31 0.2064673 0.2136047 0.2057962 #> 1997-04-30 0.2131092 0.2077001 0.2119260 #> 1997-05-31 0.2164337 0.2073886 0.2168638 #> 1997-06-30 0.2210221 0.2091514 0.2215698 #> 1997-07-31 0.2255792 0.2343873 0.2264866 #> 1997-08-31 0.2286020 0.2233008 0.2298159 #> 1997-09-30 0.2313909 0.2277221 0.2378595 #> 1997-10-31 0.2355716 0.2309535 0.2317465 #> 1997-11-30 0.2355716 0.2340252 0.2329980 #> 1997-12-31 0.2371735 0.2407183 0.2346988 #> Emerging Markets Equity Market Neutral #> 1997-01-31 0.2158200 0.2037800 #> 1997-02-28 0.2271506 0.2058382 #> 1997-03-31 0.2244247 0.2061675 #> 1997-04-30 0.2138065 0.2138065 #> 1997-05-31 0.2205414 0.2178474 #> 1997-06-30 0.2333548 0.2214419 #> 1997-07-31 0.2337012 0.2267743 #> 1997-08-31 0.2321588 0.2271598 #> 1997-09-30 0.2374752 0.2317484 #> 1997-10-31 0.2198980 0.2354550 #> 1997-11-30 0.2115858 0.2364204 #> 1997-12-31 0.2149712 0.2379808 #>
# with a weights object data(weights) # rebalance at the beginning of the year to various weights through time chart.StackedBar(weights)
x <- Return.portfolio(edhec["2000::",1:11], weights=weights,verbose=TRUE) chart.CumReturns(x$returns)
chart.StackedBar(x$BOP.Weight)
chart.StackedBar(x$BOP.Value)