Introduction to PortfolioAnalytics
[This article was first published on FOSS Trading, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
portfolio.spec
, add.constraint
, and add.objective
. library(PortfolioAnalytics) data(edhec) returns <- edhec[, 1:6] funds <- colnames(returns)Here we create a portfolio object with
portfolio.spec
. The assets
argument is a required argument to the portfolio.spec
function. assets
can be a character vector with the names of the assets, a named numeric vector, or a scalar value specifying the number of assets. If a character vector or scalar value is passed in for assets
, equal weights will be created for the initial portfolio weights. init.portfolio <- portfolio.spec(assets = funds)The
portfolio
object is an S3 class that contains portfolio level data as well as the constraints and objectives for the optimization problem. You can see that the constraints and objectives lists are currently empty, but we will add sets of constraints and objectives with add.constraint
and add.objective
. print.default(init.portfolio) ## $assets ## Convertible Arbitrage CTA Global Distressed Securities ## 0.1667 0.1667 0.1667 ## Emerging Markets Equity Market Neutral Event Driven ## 0.1667 0.1667 0.1667 ## ## $category_labels ## NULL ## ## $weight_seq ## NULL ## ## $constraints ## list() ## ## $objectives ## list() ## ## $call ## portfolio.spec(assets = funds) ## ## attr(,"class") ## [1] "portfolio.spec" "portfolio"Here we add the full investment constraint. The full investment constraint is a special case of the leverage constraint that specifies the weights must sum to 1 and is specified with the alias
type="full_investment"
as shown below. init.portfolio <- add.constraint(portfolio = init.portfolio, type = "full_investment")Now we add box constraint to specify a long only portfolio. The long only constraint is a special case of a box constraint where the lower bound of the weights of each asset is equal to 0 and the upper bound of the weights of each asset is equal to 1. This is specified with
type="long_only"
as shown below. The box constraint also allows for per asset weights to be specified. init.portfolio <- add.constraint(portfolio = init.portfolio, type = "long_only")The following constraint types are supported:
- leverage
- box
- group
- position_limit1
- turnover2
- diversification
- return
- factor_exposure
- transaction_cost2
- Not supported for problems formulated as quadratic programming problems solved with
optimize_method="ROI"
. - Not supported for problems formulated as linear programming problems solved with
optimize_method="ROI"
.
init.portfolio
and adds the objectives specified below to minSD.portfolio
and meanES.portfolio
while leaving init.portfolio
unchanged. This is useful for testing multiple portfolios with different objectives using the same constraints because the constraints only need to be specified once and several new portfolios can be created using an initial portfolio object. # Add objective for portfolio to minimize portfolio standard deviation minSD.portfolio <- add.objective(portfolio=init.portfolio, type="risk", name="StdDev") # Add objectives for portfolio to maximize mean per unit ES meanES.portfolio <- add.objective(portfolio=init.portfolio, type="return", name="mean") meanES.portfolio <- add.objective(portfolio=meanES.portfolio, type="risk", name="ES")Note that the
name
argument in add.objective
can be any valid R function. Several functions are provided in the PerformanceAnalytics package that can be specified as the name
argument such as ES/ETL/CVaR, StdDev, etc. The following objective types are supported:- return
- risk
- risk_budget
- weight_concentration
add.constraint
and add.objective
functions were designed to be very flexible and modular so that constraints and objectives can easily be specified and added to portfolio
objects. PortfolioAnalytics provides a print
method so that we can easily view the assets, constraints, and objectives that we have specified for the portfolio. print(minSD.portfolio) ## ************************************************** ## PortfolioAnalytics Portfolio Specification ## ************************************************** ## ## Call: ## portfolio.spec(assets = funds) ## ## Assets ## Number of assets: 6 ## ## Asset Names ## [1] "Convertible Arbitrage" "CTA Global" "Distressed Securities" ## [4] "Emerging Markets" "Equity Market Neutral" "Event Driven" ## ## Constraints ## Number of constraints: 2 ## Number of enabled constraints: 2 ## Enabled constraint types ## - full_investment ## - long_only ## Number of disabled constraints: 0 ## ## Objectives ## Number of objectives: 1 ## Number of enabled objectives: 1 ## Enabled objective names ## - StdDev ## Number of disabled objectives: 0 print(meanES.portfolio) ## ************************************************** ## PortfolioAnalytics Portfolio Specification ## ************************************************** ## ## Call: ## portfolio.spec(assets = funds) ## ## Assets ## Number of assets: 6 ## ## Asset Names ## [1] "Convertible Arbitrage" "CTA Global" "Distressed Securities" ## [4] "Emerging Markets" "Equity Market Neutral" "Event Driven" ## ## Constraints ## Number of constraints: 2 ## Number of enabled constraints: 2 ## Enabled constraint types ## - full_investment ## - long_only ## Number of disabled constraints: 0 ## ## Objectives ## Number of objectives: 2 ## Number of enabled objectives: 2 ## Enabled objective names ## - mean ## - ES ## Number of disabled objectives: 0Now that we have portfolios set up with the desired constraints and objectives, we use
optimize.portfolio
to run the optimizations. The examples below use optimize_method="ROI"
, but several other solvers are supported including the following: - DEoptim (differential evolution)
- random portfolios
- sample
- simplex
- grid
- GenSA (generalized simulated annealing)
- pso (particle swarm optimization)
- ROI (R Optimization Infrastructure)
- Rglpk
- quadprog
optimize_method="ROI"
. # Run the optimization for the minimum standard deviation portfolio minSD.opt <- optimize.portfolio(R = returns, portfolio = minSD.portfolio, optimize_method = "ROI", trace = TRUE) print(minSD.opt) ## *********************************** ## PortfolioAnalytics Optimization ## *********************************** ## ## Call: ## optimize.portfolio(R = returns, portfolio = minSD.portfolio, ## optimize_method = "ROI", trace = TRUE) ## ## Optimal Weights: ## Convertible Arbitrage CTA Global Distressed Securities ## 0.0000 0.0652 0.0000 ## Emerging Markets Equity Market Neutral Event Driven ## 0.0000 0.9348 0.0000 ## ## Objective Measure: ## StdDev ## 0.008855The objective to maximize mean return per ES can be formulated as a linear programming problem and can be solved quickly with
optimize_method="ROI"
. # Run the optimization for the maximize mean per unit ES meanES.opt <- optimize.portfolio(R = returns, portfolio = meanES.portfolio, optimize_method = "ROI", trace = TRUE) print(meanES.opt) ## *********************************** ## PortfolioAnalytics Optimization ## *********************************** ## ## Call: ## optimize.portfolio(R = returns, portfolio = meanES.portfolio, ## optimize_method = "ROI", trace = TRUE) ## ## Optimal Weights: ## Convertible Arbitrage CTA Global Distressed Securities ## 0.0000 0.2940 0.2509 ## Emerging Markets Equity Market Neutral Event Driven ## 0.0000 0.4552 0.0000 ## ## Objective Measure: ## mean ## 0.006635 ## ## ## ES ## 0.01837The PortfolioAnalytics package provides functions for charting to better understand the optimization problem through visualization. The
plot
function produces a plot of of the optimal weights and the optimal portfolio in risk-return space. The optimal weights and chart in risk-return space can be plotted separately with chart.Weights
and chart.RiskReward
. plot(minSD.opt, risk.col="StdDev", chart.assets=TRUE, main="Min SD Optimization", ylim=c(0, 0.0083), xlim=c(0, 0.06))
plot(meanES.opt, chart.assets=TRUE, main="Mean ES Optimization", ylim=c(0, 0.0083), xlim=c(0, 0.16))This post demonstrates how to construct a portfolio object, add constraints, and add objectives for two simple optimization problems; one to minimize portfolio standard devation and another to maximize mean return per unit expected shortfall. We then run optimizations on both portfolio objects and plot the results of each portfolio optimization. Although this post demonstrates fairly simple constraints and objectives, PortfolioAnalytics supports complex constraints and objectives as well as many other features that will be covered in subsequent posts. The PortfolioAnalytics package is part of the ReturnAnalytics project on R-Forge. For additional examples and information, refer to the several vignettes and demos are provided in the package.
To leave a comment for the author, please follow the link and comment on their blog: FOSS Trading.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.