# Portfolio Optimisation in R

For this tutorial, both minimum-variance and mean-variance will be taught. The PortfolioAnalytics package will be used extensively throughout as it allows for a simple workflow for portfolio optimisations. The first part of the code is to define that a portfolio optimisation problem exists. The only variable that needs to be defined is the names of the components of the portfolio. It will then print out a summary of the portfolio defined so far.

port <- portfolio.spec(assets = colnames((stockReturns)))
port
## **************************************************
## PortfolioAnalytics Portfolio Specification
## **************************************************
##
## Call:
## portfolio.spec(assets = colnames((stockReturns)))
##
## Number of assets: 2
## Asset Names


Next, you’d want to add some constraints to the portfolio. Popular ones would be full_investment, meaning that the sum of the assets must equal 100%, weight_sum, which constrains the total weight of the portfolio to a specific percentage, box, which allows for a minimum and maximum weight for individual assets, and long_only, where assets weights can only be positive. In this example, full_weights, long_only and box will be used. When you print a summary of the port object, it will now show the constraints.

port <- add.constraint(portfolio = port,
type = "full_investment")
type = "long_only")
type = "box",
min = 0.0,
max = 0.7)
port
## **************************************************
## PortfolioAnalytics Portfolio Specification
## **************************************************
##
## Call:
## portfolio.spec(assets = colnames((stockReturns)))
##
## Number of assets: 2
## Asset Names
##
## Constraints
## Enabled constraint types
##      - full_investment
##      - long_only
##      - box


Finally, you’ll want to add the objective metric to optimise. To do this, add.objective is used. To maximise the objective, one specifies the type argument to “return”; to minimise the objective, one specifies the type argument to “risk”. The first example will be for a minimum variance portfolio, so the type will be risk and the metric (argument name) that we are looking to minimise is the standard deviation. To reduce code, the portfolio port will be duplicated for portMinVar.

portMinVar <- port
type = "risk",
name = "StdDev")
portMinVar
## **************************************************
## PortfolioAnalytics Portfolio Specification
## **************************************************
##
## Call:
## portfolio.spec(assets = colnames((stockReturns)))
##
## Number of assets: 2
## Asset Names
##
## Constraints
## Enabled constraint types
##      - full_investment
##      - long_only
##      - box
##
## Objectives:
## Enabled objective names
##      - StdDev


Now the objective has been added. To do it for mean-variance, there would be 2 objectives: maximise returns (mean sample returns) whilst minimising standard deviation. Below is the example code:

portMeanVar <- port
type = "risk",
name = "StdDev")
type = "return",
name = "mean")
portMeanVar
## **************************************************
## PortfolioAnalytics Portfolio Specification
## **************************************************
##
## Call:
## portfolio.spec(assets = colnames((stockReturns)))
##
## Number of assets: 2
## Asset Names
##
## Constraints
## Enabled constraint types
##      - full_investment
##      - long_only
##      - box
##
## Objectives:
## Enabled objective names
##      - StdDev
##      - mean


You will notice that there are now two objectives. Finally, the portfolios are going to be optimised and the returns compared. The arguments are the portfolio specified, the returns of each asset and the optimisation method. Generally, random works best as it is a global optimisation problem. One can then extract the weights and create portfolio returns using the Return.portfolio function.

set.seed(10260)
minVarOpt <- optimize.portfolio(R = stockReturns,
portfolio = portMinVar,
optimize_method = "random")
## Leverage constraint min_sum and max_sum are restrictive,
##               consider relaxing. e.g. 'full_investment' constraint should be min_sum=0.99 and max_sum=1.01
## Warning: executing %dopar% sequentially: no parallel backend registered
extractWeights(minVarOpt)
##          0.43          0.57
minVarReturns <- Return.portfolio(stockReturns, weight = extractWeights(minVarOpt), rebalance_on = "months")
table.AnnualizedReturns(R = minVarReturns, Rf = 0.1/250)
##                               portfolio.returns
## Annualized Return                        0.1745
## Annualized Std Dev                       0.2100
## Annualized Sharpe (Rf=10.08%)            0.2951


Let’s repeat for mean-variance optimisation and compare performance.

set.seed(10260)
meanVarOpt <- optimize.portfolio(R = stockReturns,
portfolio = portMeanVar,
optimize_method = "random")
## Leverage constraint min_sum and max_sum are restrictive,
##               consider relaxing. e.g. 'full_investment' constraint should be min_sum=0.99 and max_sum=1.01
extractWeights(meanVarOpt)