[R-SIG-Finance] optimize.portfolio.rebalancing with changing/dynamic stock universe [PortfolioAnalytics]

Eric Berger ericjberger @ending from gm@il@com
Fri Oct 19 11:48:08 CEST 2018


I see a few problems with your approach
1. Providing incorrect returns data for stocks when they are NOT in the
index won't work because you need the historical co-movements of the stock
with the rest of the investable universe. e.g. for Sharpe-Ratio
(Mean-Variance) optimization, if the stock first entered the index on July
1, you will need accurate returns data for at least the size of the window
used to compute a covariance for July 1 - e.g. if a 12-month window then
for the full year prior to the first entry into the index.
2. If your optimization problem allows negative weights (i.e. short
positions), then clearly using extreme negative returns for a stock will
identify it as a good candidate for inclusion on the short side.

Possible approach:
Major index membership changes relatively infrequently. e.g. the S&P500
membership is reconstituted annually.
If your 1/0 data shows that changes are infrequent you might be able to
simply perform several runs with each run having a "constant" investable
universe for the rebalancing dates for that run. Then stitch together the
results from the different runs.

Another approach:
Contact the authors of the package to see if they have suggestions. You are
raising a standard concern and they may have addressed it or have thought
about how to deal with it.

Regards,
Eric




On Fri, Oct 19, 2018 at 12:14 AM Simon Hovmark <simonhovmark using gmail.com>
wrote:

> I am using the PortfolioAnalytics package to run a multi-period
> optimization on a quite large stock universe (14 European indicies ~ 800
> stocks) but I’ve run into a problem. All examples and vignettes using the
> package has a fixed stock universe over the backtest period (like EDHEC)
> while I’ve a dynamic universe. For example, stock XYZ might have been in an
> index from may, 2002 to October 2007 and after that excluded from the
> index. However, the optimizer is only allowed to include stock XYZ in the
> optimization if it was part of an index at the rebalance date.
>
> From my understanding, it is not possible to set up a custom constraint
> (like it is with objectives) to say that, stock XYZ should only be included
> in the optimization rebalancing if the rebalancing date is between may,
> 2002 to October 2007. Does anybody have an idea how to solve this?
>
> Data
> I’ve a dataset (daily data) with a 1 if the stocks were in their
> respective index at the date and a 0 if they were not (see last sentence).
> Alternatively, I also have a list like the below with the precise dates:
>
> Name            Entry            Exit
> SBMO-NL        2003-03-03     2015-03-20
> SMBO-NL        2016-03-21     2018-03-16
> TA-NL           2008-03-26     2008-06-27
> TLNL-NL          2000-12-29     2002-03-01
> TLNL-NL          2004-03-02     2005-10-10
>
> My returns series have the returns for the stocks for the complete listing
> period (not dependent on the stock being in an index or not). My current
> (very very ugly) work-around was to multiply the 1/0 matrix and the return
> matrix, so I only had returns for the periods when the stocks where in an
> index, and then replace all 0/NAs with -100. This -100 would penalize
> stocks outside of an index to such a degree, that it would not be included
> in the index. However, this is ugly and incorrect plus it does not work.
>
> Code
> This is not my exact code but see this as an example of a simple
> optimization:
>
> returns <- read_excel("R", sheet = 1, col_names = TRUE)
> returns <- xts(returns[,-1], order.by = as.Date(paste(returns$Dato,
> format = "%Y.%m.%d")))
> returns <- Return.calculate(returns, method = "log")
> returns <- returns[-1,]
>
> fund.names <- colnames(returns)
> tranch1 <- portfolio.spec(assets = fund.names)
>
>  # Constraints
> tranch1 <- add.constraint(portfolio = tranch1, type = "leverage")
> tranch1 <- add.constraint(portfolio = tranch1, type = "long_only")
>
> # Objective
> tranch1 <- add.objective(portfolio=tranch1, type="return", name="mean")
> tranch1 <- add.objective(portfolio=tranch1, type="risk", name="StdDev")
>
> tranch1_opt <- optimize.portfolio.rebalancing(R=returns, portfolio=tranch1,
>                                            optimize_method="DEoptim",
>                                            #momentFUN = tranch1_boudt,
>                                            #momentargs=ac.moments,
>                                            rebalance_on = “year”,
>                                            training_period = 26,
>                                            rolling_window = 26,
>                                            trace=TRUE, traceDE=5,
> search_size=2000)
>
> Here is some data from my sample (dput):
> structure(c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46.276, 46.327, 46.122, 46.924,
> 46.071, 46.856, 47.351, 45.645, 46.003, 47.436, 48.358, 49.501,
> 49.364, 49.433, 48.597, 48.204, 47.061, 47.266, 47.436, 49.211,
> 50.729, 51.514, 51.19, 49.996, 51.156, 51.856, 51.412, 52.385,
> 55.797, 55.371, 54.176, 53.784, 52.896, 53.511, 54.603, 55.115,
> 54.654, 52.658, 52.692, 54.603, 54.569, 56.258, 54.944, 54.654,
> 54.552, 54.603, 53.954, 53.852, 54.262, 54.262, 0, 0, 0, 0, 0,
> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
> 0, 0, 0, 123.067, 122.712, 123.422, 127.323, 127.855, 128.032,
> 124.84, 117.215, 121.826, 120.939, 117.747, 122.358, 119.875,
> 114.91, 115.619, 113.846, 116.328, 118.634, 119.698, 120.407,
> 119.166, 118.811, 120.584, 120.584, 120.584, 119.875, 119.166,
> 120.584, 123.422, 121.294, 119.52, 123.244, 122.89, 125.018,
> 126.082, 125.55, 126.082, 126.259, 125.55, 126.614, 126.082,
> 130.692, 132.288, 132.465, 134.061, 131.047, 131.401, 133.884,
> 134.771, 141.155, 38.773, 39.16, 39.419, 41.067, 40.356, 41.131,
> 41.099, 39.548, 40.453, 40.13, 39.419, 42.327, 42.392, 43.425,
> 43.684, 44.976, 44.944, 44.976, 44.136, 44.362, 43.813, 43.878,
> 43.942, 44.298, 44.912, 45.881, 45.235, 45.558, 47.658, 47.173,
> 45.59, 46.786, 47.335, 47.561, 47.27, 48.337, 47.82, 46.883,
> 45.396, 47.432, 47.917, 48.434, 48.66, 48.983, 48.983, 48.627,
> 49.015, 50.728, 51.697, 51.859), .Dim = c(50L, 5L), .Dimnames = list(
>     NULL, c("BAER-CH-B4R2R5", "BALN-CH-7124594", "CFR-CH-BCRWZ1",
>     "CIBN-CH-5196744", "CLN-CH-7113990")), index = structure(c(883353600,
> 883440000, 883526400, 883699200, 883958400, 884131200, 884217600,
> 884304000, 884563200, 884649600, 884736000, 884822400, 884908800,
> 885168000, 885254400, 885340800, 885427200, 885513600, 885772800,
> 885859200, 885945600, 886032000, 886118400, 886377600, 886464000,
> 886550400, 886636800, 886723200, 886982400, 887068800, 887155200,
> 887241600, 887328000, 887587200, 887673600, 887760000, 887846400,
> 887932800, 888192000, 888278400, 888364800, 888451200, 888537600,
> 888796800, 888883200, 888969600, 889056000, 889142400, 889401600,
> 889488000), tzone = "UTC", tclass = c("POSIXct", "POSIXt")), class =
> c("xts",
> "zoo"), .indexCLASS = c("POSIXct", "POSIXt"), tclass = c("POSIXct",
> "POSIXt"), .indexTZ = "UTC", tzone = "UTC”)
>
> As an alternative, I have also uploaded a full index here (
> https://ufile.io/0cxn6 <https://ufile.io/0cxn6>) where the first sheet is
> the 1/0 matrix, the second the full return matrix and the third is the 1/0
> matrix times the full return matrix.
>
>         [[alternative HTML version deleted]]
>
> _______________________________________________
> R-SIG-Finance using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-sig-finance
> -- Subscriber-posting only. If you want to post, subscribe first.
> -- Also note that this is not the r-help list where general R questions
> should go.
>

	[[alternative HTML version deleted]]



More information about the R-SIG-Finance mailing list