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

Simon Hovmark @imonhovm@rk @ending from gm@il@com
Mon Oct 22 17:18:42 CEST 2018


Thanks for your answers! I agree that my current solution was.. non-optimal.

The rebalancing loop around optimize.portfolio seems as the way to go. I’m
not that skilled in R yet and this is for a school project (hard deadline),
so I will probably go with Eric’s solution for now about dividing the data
into pieces determined by the rebalancing dates (yearly) and then sort away
does stocks not in an index at that given date. 

But the rebalancing loop could be a nice project for learning and if I get
to a decent result, I’ll post it here.

-Simon

> Den 19. okt. 2018 kl. 09.45 skrev Ross Bennett <rossbennett34 using gmail.com>:
> 
> Hi Simon,
> 
> A changing universe is not directly supported in PortfolioAnalytics, but it
> can absolutely be done. Eric Berger mentioned several of the key concerns
> with return histories of different lengths and an evolving universe of
> assets. The optimize.portfolio.rebalancing function is effectively a
> wrapper around optimize.portfolio. A solution to your problem with a
> dynamic universe is to write your own rebalancing loop. At each iteration,
> you can define the assets in the portfolio specification and the returns to
> use for that iteration.
> 
> This has come up before and I would like to add it to PortfolioAnalytics,
> but it has not risen to the top of my priority list. Feel free to open a
> feature request on https://github.com/braverock/PortfolioAnalytics <https://github.com/braverock/PortfolioAnalytics>. Also,
> patches always welcome.
> 
> Hope that helps.
> 
> Best,
> Ross
> 
> On Fri, Oct 19, 2018 at 4:48 AM Eric Berger <ericjberger using gmail.com <mailto:ericjberger using gmail.com>> wrote:
> 
>> 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 <mailto: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> <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 <mailto:R-SIG-Finance using r-project.org> mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-sig-finance <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]]
>> 
>> _______________________________________________
>> R-SIG-Finance using r-project.org <mailto:R-SIG-Finance using r-project.org> mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-sig-finance <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]]
> 
> _______________________________________________
> R-SIG-Finance using r-project.org <mailto:R-SIG-Finance using r-project.org> mailing list
> https://stat.ethz.ch/mailman/listinfo/r-sig-finance <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