Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/sandbox/RFinance2014/presentation.Rmd
1433 views
---
title : Complex Portfolio Optimization with PortfolioAnalytics subtitle : R/Finance 2014 author : Ross Bennett date : May 16, 2014 framework : io2012 # {io2012, html5slides, shower, dzslides, ...} ext_widgets : {rCharts: libraries/nvd3} widgets : mathjax mode : selfcontained
---
library(PortfolioAnalytics) require(methods)

Overview

  • Discuss Portfolio Optimization

  • Introduce PortfolioAnalytics

  • Demonstrate PortfolioAnalytics with Examples


Modern Portfolio Theory

"Modern" Portfolio Theory (MPT) was introduced by Harry Markowitz in 1952.

In general, MPT states that an investor's objective is to maximize portfolio expected return for a given amount of risk.

General Objectives

  • Maximize a measure of gain per unit measure of risk

  • Minimize a measure of risk

How do we define risk? What about more complex objectives and constraints?


Portfolio Optimization Objectives

  • Minimize Risk

    • Volatility

    • Tail Loss (VaR, ES)

    • Other Downside Risk Measure

  • Maximize Risk Adjusted Return

    • Sharpe Ratio, Modified Sharpe Ratio

    • Several Others

  • Risk Budgets

    • Equal Component Contribution to Risk (i.e. Risk Parity)

    • Limits on Component Contribution

  • Maximize a Utility Function

    • Quadratic, CRRA, etc.


PortfolioAnalytics Overview

PortfolioAnalytics is an R package designed to provide numerical solutions and visualizations for portfolio optimization problems with complex constraints and objectives.

  • Support for multiple constraint and objective types

  • An objective function can be any valid R function

  • Modular constraints and objectives

  • Support for user defined moment functions

  • Visualizations

  • Solver agnostic

  • Support for parallel computing


Support Multiple Solvers

Linear and Quadratic Programming Solvers

  • R Optimization Infrastructure (ROI)

    • GLPK (Rglpk)

    • Symphony (Rsymphony)

    • Quadprog (quadprog)

Global (stochastic or continuous solvers)

  • Random Portfolios

  • Differential Evolution (DEoptim)

  • Particle Swarm Optimization (pso)

  • Generalized Simulated Annealing (GenSA)


Random Portfolios

PortfolioAnalytics has three methods to generate random portfolios.

  1. The sample method to generate random portfolios is based on an idea by Pat Burns.

  2. The simplex method to generate random portfolios is based on a paper by W. T. Shaw.

  3. The grid method to generate random portfolios is based on the gridSearch function in the NMOF package.


Comparison of Random Portfolio Methods


Comparison of Random Portfolio Methods (Interactive!)

load("figures/rp_viz.rda") rp_viz$show('inline')

Random Portfolios: Simplex Method


Workflow: Specify Portfolio

args(portfolio.spec)

Initializes the portfolio object that holds portfolio level data, constraints, and objectives


Workflow: Add Constraints

args(add.constraint)

Supported Constraint Types

  • Sum of Weights

  • Box

  • Group

  • Factor Exposure

  • Position Limit

  • and many more


Workflow: Add Objectives

args(add.objective)

Supported Objective types

  • Return

  • Risk

  • Risk Budget

  • Weight Concentration


Workflow: Run Optimization

args(optimize.portfolio) args(optimize.portfolio.rebalancing)

Workflow: Analyze Results

VisualizationData Extraction
plotextractObjectiveMeasures
chart.ConcentrationextractStats
chart.EfficientFrontierextractWeights
chart.RiskRewardprint
chart.RiskBudgetsummary
chart.Weights

Stock Data Setup

Here we will look at portfolio optimization in the context of stocks.

  • Selection of large cap, mid cap, and small cap stocks from CRSP data

  • Weekly data from 1/7/1997 to 12/28/2010

  • 15 Large Cap

  • 15 Mid Cap

  • 5 Small Cap

equity.data <- cbind(largecap_weekly[,1:15], midcap_weekly[,1:15], smallcap_weekly[,1:5])

Distribution of Monthly Returns


Example 1: Market Neutral Portfolio

Here we consider a portfolio of stocks. Our objective is to maximize portfolio return with a target of 0.0015 and minimize portfolio StdDev with a target of 0.02 subject to dollar neutral, beta, box, and position limit constraints.


Specify Portfolio: Constraints

portf.dn <- portfolio.spec(stocks) # Add constraint such that the portfolio weights sum to 0* portf.dn <- add.constraint(portf.dn, type="weight_sum", min_sum=-0.01, max_sum=0.01) # Add box constraint such that no asset can have a weight of greater than # 20% or less than -20% portf.dn <- add.constraint(portf.dn, type="box", min=-0.2, max=0.2) # Add constraint such that we have at most 20 positions portf.dn <- add.constraint(portf.dn, type="position_limit", max_pos=20) # Add constraint such that the portfolio beta is between -0.25 and 0.25 betas <- t(CAPM.beta(equity.data, market, Rf)) portf.dn <- add.constraint(portf.dn, type="factor_exposure", B=betas, lower=-0.25, upper=0.25)

Specify Portfolio: Objectives

# Add objective to maximize portfolio return with a target of 0.0015 portf.dn.StdDev <- add.objective(portf.dn, type="return", name="mean", target=0.0015) # Add objective to minimize portfolio StdDev with a target of 0.02 portf.dn.StdDev <- add.objective(portf.dn.StdDev, type="risk", name="StdDev", target=0.02)

Run Optimization

# Generate random portfolios rp <- random_portfolios(portf.dn, 10000, "sample") # Run the optimization opt.dn <- optimize.portfolio(equity.data, portf.dn.StdDev, optimize_method="random", rp=rp, trace=TRUE)

Plot Results

plot(opt.dn, main="Dollar Neutral Portfolio", risk.col="StdDev", neighbors=10)


EDHEC Data Setup

Here we will look at portfolio optimization in the context of portfolio of hedge funds.

  • EDHEC-Risk Alternative Indexes monthly returns from 1/31/1997 to 1/31/2014

Relative ValueDirectional
Convertible Arbitrage (CA)CTA Global (CTAG)
Equity Market Neutral (EMN)Emerging Markets (EM)
Fixed Income Arbitrage (FIA)Global Macro (GM)
R <- edhec[,c("Convertible.Arbitrage", "Equity.Market.Neutral", "Fixed.Income.Arbitrage", "CTA.Global", "Emerging.Markets", "Global.Macro")] # Abreviate column names for convenience and plotting colnames(R) <- c("CA", "EMN", "FIA", "CTAG", "EM", "GM")

Monthly Returns


Example 2: Minimum Expected Shortfall

Consider an allocation to hedge funds using the EDHEC-Risk Alternative Index as a proxy. This will be an extended example starting with an objective to minimize modified expected shortfall, then add risk budget percent contribution limit, and finally add equal risk contribution limit.

  • Minimize Modified Expected Shortfall

  • Minimize Modified Expected Shortfall with Risk Budget Limit

  • Minimize Modified Expected Shortfall with Equal Risk Contribution


Specify Initial Portfolio

# Specify an initial portfolio funds <- colnames(R) portf.init <- portfolio.spec(funds) # Add constraint such that the weights sum to 1* portf.init <- add.constraint(portf.init, type="weight_sum", min_sum=0.99, max_sum=1.01) # Add box constraint such that no asset can have a weight of greater than # 40% or less than 5% portf.init <- add.constraint(portf.init, type="box", min=0.05, max=0.4) # Add return objective with multiplier=0 such that the portfolio mean # return is calculated, but does not impact optimization portf.init <- add.objective(portf.init, type="return", name="mean", multiplier=0)

Add Objectives

# Add objective to minimize expected shortfall portf.minES <- add.objective(portf.init, type="risk", name="ES") # Add objective to set upper bound on percentage component contribution portf.minES.RB <- add.objective(portf.minES, type="risk_budget", name="ES", max_prisk=0.3) # Relax box constraints portf.minES.RB$constraints[[2]]$max <- rep(1,ncol(R)) # Add objective to minimize concentration of modified ES # component contribution portf.minES.EqRB <- add.objective(portf.minES, type="risk_budget", name="ES", min_concentration=TRUE) # Relax box constraints portf.minES.EqRB <- add.constraint(portf.minES.EqRB, type="box", min=0.05, max=1, indexnum=2)

Run Optimization

# Combine the 3 portfolios portf <- combine.portfolios(list(minES=portf.minES, minES.RB=portf.minES.RB, minES.EqRB=portf.minES.EqRB)) # Run the optimization opt.minES <- optimize.portfolio(R, portf, optimize_method="DEoptim", search_size=5000, trace=TRUE, traceDE=0)

Plot in Risk-Return Space


Chart Risk Budgets

chart.RiskBudget(opt.minES[[2]], main="Risk Budget Limit", risk.type="percentage", neighbors=10) chart.RiskBudget(opt.minES[[3]], main="Equal ES Component Contribution", risk.type="percentage", neighbors=10)


Set Rebalancing Parameters and Run Backtest

# Set rebalancing frequency rebal.freq <- "quarters" # Training Period training <- 120 # Trailing Period trailing <- 72 bt.opt.minES <- optimize.portfolio.rebalancing(R, portf, optimize_method="DEoptim", rebalance_on=rebal.freq, training_period=training, trailing_periods=trailing, search_size=5000, traceDE=0)

Min ES Risk Contributions and Weights Through Time


Min ES Risk Budget Limit Risk Contributions and Weights Through Time


Min ES Equal Component Contribution Risk Contributions and Weights Through Time

--- &twocol

Min ES Equal Component Contribution Risk Contributions and Weights (interactive!)

load("figures/bt_w3.rda") load("figures/bt_rb3.rda")

*** =left

Percent Contribution to Risk

bt_rb3$set( height = 400 ,width = 450 ) bt_rb3$chart( stacked=T ) bt_rb3$setLib("nvd3") bt_rb3$setTemplate(afterScript="<script></script>") bt_rb3$show('inline')

*** =right

Weights

bt_w3$set( height = 400 ,width = 450 ) bt_w3$chart( stacked=T ) bt_w3$setLib("nvd3") bt_w3$setTemplate(afterScript="<script></script>") bt_w3$show('inline')

Compute Returns

ret.bt.opt <- do.call(cbind, lapply(bt.opt.minES, function(x) summary(x)$portfolio_returns)) colnames(ret.bt.opt) <- c("min ES", "min ES RB", "min ES Eq RB")

Chart Performance

charts.PerformanceSummary(ret.bt.opt)


Example 3: Maximize CRRA

Consider an allocation to hedge funds using the EDHEC-Risk Alternative Index as a proxy. Our objective to maximize the fourth order expansion of the Constant Relative Risk Aversion (CRRA) expected utility function as in the Boudt paper and Martellini paper. We use the same data as Example 3.

EUλ(w)=−λ2m(2)(w)+λ(λ+1)6m(3)(w)−λ(λ+1)(λ+2)24m(4)(w)EU_{\lambda}(w) = - \frac{\lambda}{2} m_{(2)}(w) + \frac{\lambda (\lambda + 1)}{6} m_{(3)}(w) - \frac{\lambda (\lambda + 1) (\lambda + 2)}{24} m_{(4)}(w)

Define a function to compute CRRA

CRRA <- function(R, weights, lambda, sigma, m3, m4){ weights <- matrix(weights, ncol=1) M2.w <- t(weights) %*% sigma %*% weights M3.w <- t(weights) %*% m3 %*% (weights %x% weights) M4.w <- t(weights) %*% m4 %*% (weights %x% weights %x% weights) term1 <- (1 / 2) * lambda * M2.w term2 <- (1 / 6) * lambda * (lambda + 1) * M3.w term3 <- (1 / 24) * lambda * (lambda + 1) * (lambda + 2) * M4.w out <- -term1 + term2 - term3 out }

Define a custom moment function

The default function for momentFUN is set.portfolio.moments. We need to write our own function to estimate the moments for our objective function.

crra.moments <- function(R, ...){ out <- list() out$mu <- colMeans(R) out$sigma <- cov(R) out$m3 <- PerformanceAnalytics:::M3.MM(R) out$m4 <- PerformanceAnalytics:::M4.MM(R) out }

Specify Portfolio

# Specify portfolio portf.crra <- portfolio.spec(funds) # Add constraint such that the weights sum to 1 portf.crra <- add.constraint(portf.crra, type="weight_sum", min_sum=0.99, max_sum=1.01) # Add box constraint such that no asset can have a weight of greater than # 40% or less than 5% portf.crra <- add.constraint(portf.crra, type="box", min=0.05, max=0.4) # Add objective to maximize CRRA portf.crra <- add.objective(portf.crra, type="return", name="CRRA", arguments=list(lambda=10))

"Dummy" Objectives

# Dummy objectives for plotting and/or further analysis portf.crra <- add.objective(portf.crra, type="return", name="mean", multiplier=0) portf.crra <- add.objective(portf.crra, type="risk", name="ES", multiplier=0) portf.crra <- add.objective(portf.crra, type="risk", name="StdDev", multiplier=0)

Run Optimization

opt.crra <- optimize.portfolio(R, portf.crra, optimize_method="DEoptim", search_size=5000, trace=TRUE, traceDE=0, momentFUN="crra.moments")
load("optimization_results/opt.crra.rda")
head(extractStats(opt.crra),4)

Chart Results

chart.RiskReward(opt.crra, risk.col="ES") chart.RiskReward(opt.crra, risk.col="StdDev")


Run Backtest and Compute Returns

bt.opt.crra <- optimize.portfolio.rebalancing(R, portf.crra, optimize_method="DEoptim", search_size=5000, trace=TRUE, traceDE=0, momentFUN="crra.moments", rebalance_on=rebal.freq, training_period=training, trailing_periods=trailing) ret.crra <- summary(bt.opt.crra)$portfolio_returns colnames(ret.crra) <- "CRRA"

Chart Weights Through Time

chart.Weights(bt.opt.crra, main="CRRA Weights", col=bluemono)


Chart Performance

charts.PerformanceSummary(cbind(ret.bt.opt, ret.crra), main="Optimization Performance")


Conclusion

  • Introduced the goals and summary of PortfolioAnalytics

  • Demonstrated the flexibility through examples

  • Exciting plans for GSOC 2014

    • Support for regime switching

    • Support for supervised learning

    • many more

Acknowledgements

Many thanks to...

  • Google: funding for Google Summer of Code (GSoC)

  • UW CF&RM Program: continued work on PortfolioAnalytics

  • GSoC Mentors: Brian Peterson, Peter Carl, Doug Martin, and Guy Yollin

  • R/Finance Committee


PortfolioAnalytics is on R-Forge in the ReturnAnalytics project

Source code for the slides

and view it here


Any Questions?