[R-SIG-Finance] Constrained portfolio optimization with DEoptim

Kristian Lind kristian.langgaard.lind at gmail.com
Thu Oct 20 13:00:55 CEST 2016


Hi Brian*,*

Thank you for your reply. It has been very helpful.

I have, as you suggested, tried to set my problem up within
PortfolioAnalytics.

I have formulated the constrained optimization using two custom objective
functions.

One calculating a risk measure.

objectfunc <- function(R, weights, Nassets)

myfun <- function(x,y){rowSums(x*y)}

PF.Ret <- matrix(data = NA, nrow = nrow(R), ncol = ncol(R)/Nassets)

for(i in 1:(ncol(R)/Nassets))

{

  j <- i*Nassets-(Nassets-1)

  PF.Ret[,i] = myfun(R[,j:(j+Nassets-1)],weights)

}

date <- index(R)

PF.Ret <- xts(PF.Ret, date)

PF.Ret <- log(1+PF.Ret)

list <- list()

for (i in 1:ncol(PF.Ret))

{

  list[[i]] <- apply.yearly(PF.Ret[,i], sum)

}

PF.Ret.Yearly <- matrix(data = unlist(list), nrow=10, ncol = 1000,
byrow=FALSE)

matrix1 <- matrix(data= NA, nrow= 10, ncol= 1)

for (i in 1:10)

{

  mean.ret <- mean(PF.Ret.Yearly[i,])

  sorted <- sort(PF.Ret.Yearly[i,])

  ES_5_pct <- mean(sorted[1:ceiling(length(sorted)*.05)])

  matrix1[i,1] <- -( mean.ret -ES_5_pct)

}

YOY_Shortfall_Risk <- mean(matrix1)

return(YOY_Shortfall_Risk)

}

Another calculating the deviation between a set target return and the
portfolio return given the weights. Deviation from the target return is
penalized.

retcons <- function(R, weights, targetreturn, Nassets){

  myfun <- function(x,y){rowSums(x*y)}

  PF.Ret <- matrix(data = NA, nrow = nrow(R), ncol = ncol(R)/Nassets)

  for(i in 1:(ncol(R)/Nassets))

  {

    j <- i*Nassets-(Nassets-1)

    PF.Ret[,i] = myfun(R[,j:(j+Nassets-1)],weights)

  }

  date <- index(R)

  PF.Ret <- xts(PF.Ret, date)

  PF.Ret <- log(1+PF.Ret)

  PF.Ret.Ann <- Return.annualized(PF.Ret, scale = 4)

  PF.Ret.Dev <- abs(mean(PF.Ret.Ann)-targetreturn)

  return(PF.Ret.Dev*1e6)

  }

Portfolio specification:

pf <- portfolio.spec(assets = 3)

pf <- add.constraint(portfolio=pf, type="leverage", min_sum=0.99,
max_sum=1.01)

pf <- add.constraint(portfolio=pf, type="long_only"

pf <- add.objective(portfolio = pf, name = "objectfunc", type = "risk",
arguments= list(Nassets=length(pf$assets)))

pf <- add.objective(portfolio = pf, name = "retcons", type = "return",
arguments= list(targetreturn = 0.04, Nassets=length(pf$assets)))

Optimizing portfolio:

pf.opt <- optimize.portfolio(R, portfolio = pf, optimize_method =
"DEoptim", search_size = 500, trace = FALSE)

When I try to run this I receive the following error message:

objective name objectfunc generated an error or warning: Error in
`[.xts`(R, , j:(j + Nassets - 1)) : subscript out of bounds

objective name retcons generated an error or warning: Error in `[.xts`(R, ,
j:(j + Nassets - 1)) : subscript out of bounds

I can’t figure out why because the functions are working as they should and
the subscript remains within bounds.

If I try to apply DEoptim() directly to the functions one by one this works
without any problems. This leads me to believe that the two objectives are
somehow formulated wrong.

Any advice would be very helpful.

Thanks.

Kristian

Below is some test data. These are returns for 3 assets over 2 distinct
scenarios.



        0001Asset1           0001Asset2      0001Asset3
                  0002Asset1       0002Asset2         0002Asset3

2016-03-31               0.0009770000       0.016740000     0.016579000
          -0.023776400     -0.0041489000     0.001512000

2016-06-30              -0.0029404272       0.007377501
0.015908257                0.043515031      0.0007250080     0.001240125

2016-09-30               0.0104448377      -0.019819554
0.015738547                0.050726217      0.0313854548     0.001350281

2016-12-31              -0.0062679854       0.010671942
0.016125757               -0.004518026     -0.0117857549     0.001689061

2017-03-31              -0.0079445226      -0.044670060
-0.004612912                0.001194696     -0.0058016987     0.052340217

2017-06-30              -0.0443293966      -0.019210789    -0.004226186
           0.021539797     -0.0179612891     0.054908697

2017-09-30               0.0237102390       0.011401810
-0.003435808               -0.011847182     -0.0126964053     0.056605700

2017-12-31              -0.0015399460       0.035813794
-0.002748625               -0.019542495      0.0101302728     0.058266442

2018-03-31              -0.0113292330       0.007312157
0.056380215               -0.010737433     -0.0069353566     0.045971561

2018-06-30              -0.0096110793      -0.002711140
    0.056623046               -0.003262799      0.0008645106     0.047599867

2018-09-30               0.0094151500      -0.024227124
0.058750803               -0.005936063      0.0023834633     0.048860875

2018-12-31               0.0191824507      -0.010843099
0.060146334               -0.036474625      0.0081957339     0.050592614

2019-03-31               0.0216149159      -0.012509716
-0.005685334               -0.016999378      0.0039543321     0.057437136

2019-06-30              -0.0353713241      -0.027056842
-0.005359282               -0.001568024      0.0055240254     0.056829074

2019-09-30               0.0068256915       0.033676676
-0.005547267               -0.005307774      0.0558182435     0.056924521

2019-12-31               0.0402950042       0.008506863
-0.005229621               -0.008069375      0.0104593718     0.058275726

2020-03-31              -0.0236441279       0.002491410
-0.035715118               -0.013556053     -0.0092781424     0.035725279

2020-06-30              -0.0227378309       0.040566982
-0.036422326               -0.018606615      0.0213017461     0.035333312

2020-09-30              -0.0331522369      -0.013661001
-0.035461805                0.013950153     -0.0062701658     0.035735389

2020-12-31              -0.0022381617       0.004761732
-0.034474179               -0.007912498      0.0449173126     0.035830771

2021-03-31              -0.0123584293      -0.023198797
-0.094912448               -0.024782130      0.0126045150     0.013769555

2021-06-30              -0.0230952138      -0.037092732
-0.096008937               -0.012783368      0.0202277100     0.013955651

2021-09-30              -0.0382849524      -0.039174543
-0.096453235                0.011270169     -0.0004279631     0.014892660

2021-12-31               0.0192312397      -0.042090156
-0.094958812               -0.003473503      0.0197412514     0.015052186

2022-03-31              -0.0176720249      -0.051753716
-0.002995036                0.011147463      0.0061838217     0.076329091

2022-06-30               0.0171345591      -0.047152874
-0.003502619               -0.021507033      0.0245421282     0.078357061

2022-09-30              -0.0058656456      -0.051551676
-0.003696614               -0.003655445     -0.0096960956     0.082151077

2022-12-31              -0.0170921376      -0.066373600
-0.003710194                0.021982228      0.0415787788     0.083333940

2023-03-31               0.0163444872      -0.004762518
0.041507377               -0.026366926      0.0203368716     0.048861009

2023-06-30              -0.0208268986      -0.015490012
0.041058936                0.003762363      0.0189784762     0.051571131

2023-09-30              -0.0004284279      -0.002227971
0.040723178               -0.005698759      0.0233511708     0.055240586

2023-12-31               0.0141513274      -0.023746263
0.041881996               -0.022127398      0.0182298784     0.057153451

2024-03-31               0.0105922202      -0.009016968
0.037171059               -0.016926364      0.0488771263     0.067117695

2024-06-30               0.0245418561       0.004764987
0.038838652               -0.010630231      0.0416277761     0.069258579

2024-09-30               0.0116387526       0.016551947
0.038733564                0.032021448      0.0528662570     0.072442630

2024-12-31              -0.0415150970       0.002499012     0.039572718
              0.067227381      0.0440336173     0.073641408

2025-03-31              -0.0315214326       0.023107293
-0.056239231               -0.038364755      0.0214378006     0.009960962

2025-06-30              -0.0153207849       0.011894464
-0.056741703                0.022417838      0.0340254762     0.013183042

2025-09-30              -0.0375576999       0.059433097
-0.056916400               -0.008105189      0.0429868190     0.014451492

2025-12-31              -0.0253597219       0.042178684
-0.055637987                0.033767714      0.0166919155     0.021603579

Den tirsdag den 4. oktober 2016 skrev Brian G. Peterson <brian at braverock.com
>:

> On Tue, 2016-10-04 at 13:04 +0200, Kristian Lind wrote:
> > Hi guys,
> >
> > I’m working on a portfolio optimization problem
> >
> > The problem I’m trying to solve is of the form Min risk s.t. return = X
> >
> > For each asset I have simulated 1000 paths for the development in asset
> > prices over 10 years.
> >
> > The risk measure I’d like to minimize is YoY shortfall risk, but could be
> > any risk metric that takes the information from the scenarios into
> > consideration.
> >
> > Likewise, the return is the mean annualized return over all the
> scenarios.
> >
> > I have tried solving this problem using DEoptim, where deviations from
> the
> > required return is penalized. Similar to the approach applied here:
> > https://cran.r-project.org/web/packages/DEoptim/vignettes/
> > DEoptimPortfolioOptimization.pdf
> >
> > I am unable to achieve convergence where the constraint is fulfilled.
> >
> > My object function is of the form
> >
> > Obj <- function(Return data, portfolio weights, target return){
> >
> > Normalize weights to 1
> > calculate portfolio return
> > calculate risk metric
> > calculate deviation from target return
> > return (risk metric + deviation from target return*1e6)
> >
> > }
> >
> > Any pointers on how to formulate and solve this problem would be much
> > appreciated.
>
> You haven't provided a reproducible example, making it hard to help you.
>
> You can easily do this type of optimization with PortfolioAnalytics,
> including the use of DEoptim, pso, GenSA, or random search as a global
> solver.  The modular objective function of PortfolioAnalytics should
> allow you to specify your problem pretty easily.  You'll need to pass in
> your 'scenarios', and use functions in your objective that expect this
> data and know how to apply weights to it, but that should be pretty
> simple.
>
> To get to a general answer to your question, you need to determine a few
> things.
>
> Is there a solution that meets your constraints?  Many portfolios are
> over-constrained, and are unable to meet the objectives as defined.  In
> these cases you need to be able to relax constraints to get to the
> closest solution.  It often helps to plot the unconstrained and
> constrained feasible spaces (e.g. with random portfolios from
> PortfolioAnalytics) to see if you've overconstrained things.
>
> You don't appear to be using 'fnMap' to apply your full investment
> (cardinality) constraint.  Using this tells DEoptim what the final
> parameter values were, and doesn't hide them inside your custom
> objective.
>
> You're attempting to perform a penalized optimization with:
>
> return (risk metric + deviation from target return*1e6)
>
> Is this the right weighting/penalty between your objectives? Typically,
> if you have no significant preference between your objectives, you want
> to use a multiplier first to get them to similar overall scale.  Then
> you want to separately penalize (with a large multiplier) deviation from
> your constraint.  In this case, you are penalizing overshooting and
> missing below the return in the same way.  This will give the optimizer
> very little indication on direction to improve the solution.  It can
> also make sense to plot the path the optimizer takes to see if you're
> getting close to a solution.
>
> Your use of 'scenarios' could be messing you up.  DEoptim permutes
> 'parameters', which are typically weights in portfolio optimization
> space.  It then applies the objective function passing the parameters
> into the objective. You've said that you're using a annualized mean
> across the scenarios and an annualized shortfall risk across the
> scenarios.  You're losing quite a lot of dimensionality by reducing 1000
> scenarios on each asset to one number.  Doing simple linear combinations
> of these will not take things like covariances into account, even though
> by saying that you care about shortfall risk, I'd assume what you really
> want is *portfolio* shortfall.  I would be concerned that the loss of
> dimensionality suggested by your description would make it difficult to
> get a realistic solution.
>
> There are several more things that could cause this to fail to converge.
> I've covered the most likely ones, but further investigation would
> require a reproducible example.
>
> Regards,
>
> Brian
>
>
> --
> Brian G. Peterson
> http://braverock.com/brian/
> Ph: 773-459-4973
> IM: bgpbraverock
>
>
>
>
>

	[[alternative HTML version deleted]]



More information about the R-SIG-Finance mailing list