How Portfolio Returns Reflect Weights and Rebalancing Dates
Summary
The document explains how a portfolio return function can combine asset returns with a dated series of portfolio weights. It describes aligning the return and weight data, selecting the matching asset columns, and starting the calculation only once initial weights are available. When weights are supplied less frequently than returns, the method carries the portfolio through the intervening periods: asset values change with returns, their values are summed, and the portfolio return is measured against the period’s starting value.
The discussion distinguishes a portfolio whose holdings drift between specified weight dates from a calculation that resets weights at each supplied rebalancing date. It gives a stepwise account of updating position values and notes that the example’s output can be reproduced by repeated calculations over intervals. The source is an explanation of package behavior rather than a general derivation, and it does not fully resolve every question about cumulative return interpretation. Date alignment, column names, and the timing convention for weights matter when applying the method to other data.
Key ideas
- Portfolio returns are calculated by combining asset returns with corresponding portfolio weights.
- When weight observations are less frequent than returns, holdings evolve through the intervening periods.
- Portfolio value is updated from each asset’s return, then aggregated to calculate the period return.
- Supplied weight dates define when the portfolio is reset to target allocations.
- Correctly matching dates and asset columns is essential to interpreting the output.
Tags
Full text
# How do Return.portfolio and Return.rebalancing work in Performance Analytics in R?
# How do Return.portfolio and Return.rebalancing work in Performance Analytics in R?
I have a question about the function `Return.portfolio`/`Return.rebalancing` from the Performance Analytics package in R.
I take the example described in the package:
```
> data(edhec)
> data(weights)
> Return.portfolio(edhec,weights = weights)
portfolio.returns
2000-01-31 0.0115135339
2000-02-29 0.0218963077
2000-03-31 0.0093379014
2000-04-30 0.0037485690
2000-05-31 0.0056601357
2000-06-30 0.0140301727
2000-07-31 0.0043295816
2000-08-31 0.0190997787
2000-09-30 0.0014645727
2000-10-31 0.0014264155
2000-11-30 0.0061304707
2000-12-31 0.0201417025
2001-01-31 0.0150594011
2001-02-28 0.0066011872
2001-03-31 0.0131395159
2001-04-30 0.0007491561
2001-05-31 0.0091626407
2001-06-30 -0.0000527803
2001-07-31 0.0020738201
2001-08-31 0.0102713727
2001-09-30 0.0002531717
2001-10-31 0.0142380976
2001-11-30 -0.0048429083
2001-12-31 0.0061645640
2002-01-31 0.0093372403
2002-02-28 -0.0011217258
2002-03-31 0.0063415238
2002-04-30 0.0082130861
2002-05-31 0.0058782220
2002-06-30 0.0007565192
2002-07-31 -0.0059246865
2002-08-31 0.0072696705
2002-09-30 0.0026434591
2002-10-31 0.0014298494
2002-11-30 0.0105008400
2002-12-31 0.0127186414
2003-01-31 0.0159481947
2003-02-28 0.0092381495
2003-03-31 0.0001639493
2003-04-30 0.0113937775
2003-05-31 0.0199355028
2003-06-30 0.0020659339
2003-07-31 -0.0039260851
2003-08-31 0.0035691334
2003-09-30 0.0114224214
2003-10-31 0.0116788871
2003-11-30 0.0069773935
2003-12-31 0.0117366500
2004-01-31 0.0137408298
2004-02-29 0.0086731496
2004-03-31 0.0030241495
2004-04-30 -0.0031369461
2004-05-31 -0.0006375207
2004-06-30 0.0039463036
2004-07-31 0.0010463350
2004-08-31 0.0022005523
2004-09-30 0.0065116125
2004-10-31 0.0042086646
2004-11-30 0.0164591318
2004-12-31 0.0094498415
2005-01-31 0.0030113644
2005-02-28 0.0103238498
2005-03-31 0.0008083756
2005-04-30 -0.0052241413
2005-05-31 0.0020622011
2005-06-30 0.0081079582
2005-07-31 0.0118744372
2005-08-31 0.0073621313
2005-09-30 0.0101843734
2005-10-31 -0.0012149988
2005-11-30 0.0076005987
2005-12-31 0.0089111835
2006-01-31 0.0193600000
2006-02-28 0.0050290768
2006-03-31 0.0122895863
2006-04-30 0.0161541728
2006-05-31 0.0028728086
2006-06-30 0.0008591674
2006-07-31 0.0029350825
2006-08-31 0.0061800530
2006-09-30 0.0020263120
2006-10-31 0.0128266559
2006-11-30 0.0129600658
2006-12-31 0.0126486355
2007-01-31 0.0106456451
2007-02-28 0.0105816673
2007-03-31 0.0082080685
2007-04-30 0.0120657529
2007-05-31 0.0130340469
2007-06-30 0.0054403426
2007-07-31 -0.0001698053
2007-08-31 -0.0096513313
2007-09-30 0.0156251014
2007-10-31 0.0171940678
2007-11-30 -0.0113391902
2007-12-31 0.0030447149
2008-01-31 -0.0120408215
2008-02-29 0.0045617517
2008-03-31 -0.0188804492
2008-04-30 0.0121140702
2008-05-31 0.0127356881
2008-06-30 -0.0003266534
2008-07-31 -0.0118233426
2008-08-31 -0.0064733095
2008-09-30 -0.0478450597
2008-10-31 -0.0630740252
2008-11-30 -0.0354050961
2008-12-31 -0.0046962342
2009-01-31 0.0089404911
2009-02-28 -0.0027223978
2009-03-31 0.0050820481
2009-04-30 0.0229829814
2009-05-31 0.0374323984
2009-06-30 0.0111071893
2009-07-31 0.0255805068
2009-08-31 0.0179835194
Warning message:
In Return.portfolio(edhec, weights = weights) :
number of assets in beginning_weights is less than number of columns in returns, so subsetting returns.
> sum(as.numeric(edhec[151,1:11])*as.numeric(weights[8,]))
[1] 0.02614121
>
```
How are these returns calculated using `Return.portfolio`? In weights are two column missing compared with edhec. That's the reason why I took
```
edhec[151,1:11]
```
Moreover, we see that weights is a `xts` object with just 8 rows. Does `Return.portfolio` check the dates and take the right weights for that period? Moreover, what is the difference to `Return.rebalancing`?
Is it correct, that if we would sum up the first 10 elements of
```
Return.portfolio(edhec,weights = weights)
```
we would get the total return at time $t=10$?
Reference: the software package in use is R programming language is used for data analysis and visualization including statistics and graphics. R is an integrated suite of software facilities for data manipulation, calculation and graphical display. The R project is Open Source, available at `http://www.r-project.org/`
Additionally, the R statistical program has a considerable repository of projects available to the whole community, available at `https://r-forge.r-project.org/` One of the projects is ReturnAnalytics -- Performance and risk analysis of financial time series, including packages PerformanceAnalytics and PortfolioAnalytics. That project is available via anonymous access: `svn checkout svn://svn.r-forge.r-project.org/svnroot/returnanalytics/`
## Answer by Kyle Balkissoon (score 4, accepted)
https://quant.stackexchange.com/a/14703
I'm going to separate your question in two.
The key thing you're asking is that how does Return.rebalancing treat your different frequencied and number of asset return and weight objects.
### Data munging:
It subsets the first ncol(weight) columns of R (as ncol(edhec) > ncol(weights)
ncol R is now 11. Checks if the first date in R is less than the first date date in W If true it subsets R from 2000-01-02/" onwards nrow(R) is now 116 as you cannot have a return series before the initial weights.
### Data processing:
It then calls Return.portfolio.geometric, which just multiplies the returns by the weights for those two matrices.
As weights are annual and edhec is monthly.
It needs to calculate inbetween years
So it grabs the return series for the inbetween period.
Loops through all of the return subseries calculating the weights * the previous amount in the return period (essentially floating it and rebalancing on the weight matrix). It takes the total value of each period in the return series and divides it by the starting value in the period to calculate the periodic return.
A simple demonstration is as follows.
- Take initial equity value (1)
- Take rebalancing year initial weight
- Calculate end of period equity (initial equity * weight * return)
- Calculate return for period
- Repeat two on each rebalancing date as specified in the weight matrix. eop_value[k, ] = (1 + coredata(returns[j, ])) * bop_value[k, ] eop_value_total[k] = sum(eop_value[k, ]) ret[k] = eop_value_total[k]/end_value - 1 end_value = eop_value_total[k]
The above code calculates the new total equity for each position and sums it up.
So it is akin to your weights floating and then resetting on each date in the weights matrix.
## Answer by vanguard2k (score 3)
https://quant.stackexchange.com/a/14694
I found out that the upper time series is the result of a call
```
> tail(Return.rebalancing(edhec,weights))
portfolio.returns
2009-03-31 0.005082048
2009-04-30 0.022982981
2009-05-31 0.037432398
2009-06-30 0.011107189
2009-07-31 0.025580507
2009-08-31 0.017983519
```
(by optical comparison. ;-) )
A glance into the code reveals that the outpout is a result of successive calls (for loop) to `Return.portfolio()`, each taking as input the return timeseries between two different dates and the `weight` vector corresponding to the starting date of the time interval.
In short: It creates a time series of a rebalanced portfolio where the rebalancing dates and weights are given by `weights`.
Thats how the returns are calculated by `Return.portfolio()`.
Also, for the two additional columns issue I found out, that `Return.portfolio()` has a line where it selects the right columns, effectively doing something like `edhec[,colnames(weights[1,])]`Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.