[R-SIG-Finance] [PortfolioAnalytics] optimize.portfolio.rebalancing with changing stock universe
Joshua Knipe
jo@hu@kn|pe @end|ng |rom gm@||@com
Tue Aug 6 10:03:33 CEST 2019
Hi Brian,
Thank you for your response - I was a bit unclear as to what exactly the
rebalancing loop entailed but that helped clear things up. Thank you also
for all the work you've done in developing both PerformanceAnalytics and
PortfolioAnalytics! Both have been essential in the research project I'm
working on at the moment.
I was also not aware of the 'combine.portfolios' and
'combine.optimizations' functions but those look like they are just what I
need!
I have included the rebalancing loop section of my code below if anyone
else needs it before you guys find the time to implement it in the package.
Kind regards
Josh
*Code:*
numWeeks = floor(as.duration(startDate %m+% weeks(52) %--%
last(dates))/dweeks(13))
for (i in 1:numWeeks){
portf <- add.constraint(portf, type="group",
#this is checking which stocks have Amihud values above the median
Amihud value at each rebalancing date
groups = list(which(weeklyAmihud[paste0(startDate
%m+% weeks(52+13*i))]
>as.numeric(mid[paste0(startDate %m+%
weeks(52+13*i))])) ),
#this is setting their max weight to be 0
group_min=c(0),
group_max=c(0),
group_labels=c("Illiquid"),
group_pos=c(1),
indexnum=3)
#will have to increase search_size when running on full dataset
portfolio.optimized <- optimize.portfolio(R = sjReturns[paste0(startDate
%m+% weeks(13*i),
"::",
startDate %m+%
weeks(52+13*i))],
portfolio = portf,
optimize_method = "random",
search_size = 500)
#get the weights at each rebalacing period and add to dataframe
extra <-extractWeights(portfolio.optimized)
rebal_weights <- rbind(rebal_weights,extra)
#set rowname to equal rebalancing date
rownames(rebal_weights)[i+1]<-paste0(startDate %m+% weeks(52+13*i))
}
#change first rowname to first rebalancing date
rownames(rebal_weights)[1]<- paste0(startDate %m+% weeks(52))
dates2 = as_date(rownames(rebal_weights))
rebal_weights <- xts(rebal_weights, order.by=dates2)
rebal_returns <- Return.portfolio(sjReturns, weights=rebal_weights)
On Sun, Aug 4, 2019 at 11:09 PM Brian G. Peterson <brian using braverock.com>
wrote:
> Joshua,
>
> The problem of assets becoming available or unavailable through time
> has been one we've been aware of for a long time.
>
> Ross' solution of building a custom loop certainly works, as you can
> call optimize.portfolio in your own loop and change either the 'assets'
> slot in the portfolio specification or the constraints matrix,
> constraining some assets to 0 position.
>
> We've been discussing this as one open package TODO with our 2019 GSoC
> Student, Shawn Feng of the University of Illinois, and are hoping that
> we may have a solution in the package code this month for a more
> general solution.
>
> We have identified a couple of possible general solutions. All revolve
> around making some aspect of the portfolios specification into a time
> series. Either the 'assets' slot in the portfolio spec could specify
> valid assets as a time series rather than the named vector that it is
> right now, the 'box_constraint' could take a time series and e.g. take
> NA as a constrain for unavailable assets, or the 'position_limit'
> constraint could be specified as a time series.
>
> My suspicion is that either changing the assets slot over time or
> allowing NA's in the box constraints are the most feasible solution,
> but we don't have any code to back that hypothesis up yet.
>
> As you point out indirectly, different analysts will have different
> goals for how to include or exclude specific assets at a particular
> point in time, so I think we will need to just support a time series
> methodology for defining the universe and then lett the user define
> their universe using their own criteria (e.g. your Amihud criteria).
>
> Unfortunately, we don't have working general code to solve this feature
> request just yet. Until then (hopefully soon), I'm afraid you'll need
> to adjust things manually and call 'optimize.portfolio' multiple times,
> on dates of your choosing.
>
> As for your desire to check multiple different benchmark portfolios,
> see help and examples for 'combine.portfolios' and
> 'combine.optimizations' to create an output object of type 'opt.list'.
> Most of the summary, print, plot, etc functions should handle these
> combined optimizations and give you reasonable output already.
>
> Regards,
>
> Brian
>
>
> On Sun, 2019-08-04 at 21:56 +0200, Joshua Knipe wrote:
> > I am using the PortfolioAnalytics package to run a multi-period
> > optimisation on a stock universe of just over 100 stocks but I'm
> > running
> > into some issues. I would like to exclude certain stocks at each
> > rebalancing date but have not been able to get it working thus far.
> >
> >
> > <a href="
> >
> http://r.789695.n4.nabble.com/optimize-portfolio-rebalancing-with-changing-dynamic-stock-universe-PortfolioAnalytics-td4753227.html
> > ">
> >
> http://r.789695.n4.nabble.com/optimize-portfolio-rebalancing-with-changing-dynamic-stock-universe-PortfolioAnalytics-td4753227.html
> > </a>
> >
> > This thread has a very similar issue and Ross Bennett (the creator of
> > this awesome package) mentions writing ones own rebalancing loop in
> > order to achieve an evolving universe of stocks. This sounds like the
> > solution but I am not sure how to implement that unfortunately.
> >
> >
> > I have calculated a measure of illiquidity for each stock (the
> > Amihud'sILLIQ value specifically) and have these in a separate file
> > which I am reading into R. The measures are weekly in order to match
> > the data I am using for the returns of the stocks. I have calculated
> > a vector of the median value of this measure for each week i.e. 160
> > medians for 160 weeks.
> >
> >
> > What I would like to do is exclude all the stocks which have a Amihud
> > value above this median from the rebalancing for that period i.e.
> > make sure they have 0 weighting if they are not liquid enough.
> >
> > I tried it initially with a penalty function which would just sum the
> > weights * Amihud values and then scale that value, but this has the
> > undesired effect of also penalising stocks below but close to the
> > median
> > value.
> >
> >
> > My end goal is to get the returns of certain portfolio strategies
> > (e.g. mean-var, min-var, equal weight etc) on this data set and then
> > compare how the returns change when these "illiquid stocks" are
> > excluded at each rebalancing period.
> >
> >
> > Any advice would be seriously appreciated! :)
> >
> >
> > <b>Data</b>
> >
> >
> > The Amihud values are in the following format (which is the same
> > format as
> > the price data):
> >
> >
> > Date. Stock 1. Stock
> > 2. Stock 3.
> > Stock 4. etc
> >
> > 2009-06-05. 1.057348e-06. 5.263602e-07 2.054617e-
> > 11. 6.470526e-11
> >
> > 2009-06-12. 1.057346e-06. 5.123452e-07 2.311231e-
> > 11. 6.381738e-11
> >
> > 2009-06-19. 1.034941e-06. 5.219238e-07 2.192929e-
> > 11. 6.238939e-11
> >
> >
> > <b>Code</b>
> >
> > An extract of the code I have thus far:
> >
> >
> > sjPrices =
> > as.data.frame(read_excel("ALSI_Cleaned_Weekly_Prices.xlsx",
> > sheet = 1, col_names = T,
> >
> > na = "", skip = 0))
> >
> > weeklyAmihud = as.data.frame(read_excel("weeklyAmihud.xlsx", sheet =
> > 1,
> > col_names = T,
> >
> > na = "", skip = 0))
> >
> >
> > #create vector of medians (uses function from matrixStats package)
> >
> > mid <- rowMedians(as.matrix(weeklyAmihud[, -1]))
> >
> >
> > dates = as_date(sjPrices[,1])
> >
> >
> > # remove the first column (of dates)
> >
> > sjPrices <- sjPrices[, -1]
> >
> > weeklyAmihud <- weeklyAmihud[, -1]
> >
> >
> > #create xts objects
> >
> > sjPrices <- xts(sjPrices, order.by=dates)
> >
> > weeklyAmihud <- xts(weeklyAmihud, order.by=dates)
> >
> >
> > sjReturns <- ROC(sjPrices)
> >
> >
> > #remove first row (0 returns)
> >
> > sjReturns <- sjReturns[-1,]
> >
> >
> > #this function does penalise the very illiquid stocks but has other
> > undesired side-effects
> >
> > AMIHUD <- function(sjReturns, weights, wAmihud){
> >
> > return(sum(weights*wAmihud)*100)
> >
> > }
> >
> >
> > portf <- portfolio.spec(colnames(sjReturns))
> >
> >
> > portf <- add.constraint(portf,type = "weight_sum", min_sum = 0.99,
> > max_sum
> > = 1.01)
> >
> > portf <- add.constraint(portf, type="long_only")
> >
> >
> > portf <- add.objective(portf, type = "risk", name = "StdDev")
> >
> > portf <- add.objective(portf, type="risk", name="AMIHUD",
> >
> > arguments=list(wAmihud=weeklyAmihud))
> >
> >
> > opt_rebal <- optimize.portfolio.rebalancing(sjReturns,
> >
> > portf,
> >
> > optimize_method="DEoptim"
> > ,
> >
> > rebalance_on="quarters",
> >
> > training_period=52,
> >
> > rolling_window=52,
> >
> > trace=TRUE, traceDE=5,
> > search_size=2000)
> >
> > [[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.
> --
> Brian G. Peterson
> ph: +1.773.459.4973
> im: bgpbraverock
>
>
[[alternative HTML version deleted]]
More information about the R-SIG-Finance
mailing list