Path: blob/master/vignettes/risk_budget_optimization.Rnw
1433 views
\documentclass[a4paper]{article}1\usepackage[round]{natbib}2\usepackage{bm}3\usepackage{verbatim}4\usepackage[latin1]{inputenc}56\usepackage{url}78\let\proglang=\textsf9\newcommand{\pkg}[1]{{\fontseries{b}\selectfont #1}}10\newcommand{\R}[1]{{\fontseries{b}\selectfont #1}}11\newcommand{\email}[1]{\href{mailto:#1}{\normalfont\texttt{#1}}}12\newcommand{\E}{\mathsf{E}}13\newcommand{\VAR}{\mathsf{VAR}}14\newcommand{\COV}{\mathsf{COV}}15\newcommand{\Prob}{\mathsf{P}}1617\renewcommand{\topfraction}{0.85}18\renewcommand{\textfraction}{0.1}19\renewcommand{\baselinestretch}{1.5}20\setlength{\textwidth}{15cm} \setlength{\textheight}{22cm} \topmargin-1cm \evensidemargin0.5cm \oddsidemargin0.5cm2122\usepackage[latin1]{inputenc}23% or whatever2425\usepackage{lmodern}26\usepackage[T1]{fontenc}27% Or whatever. Note that the encoding and the font should match. If T128% does not look nice, try deleting the line with the fontenc.2930% \VignetteIndexEntry{Portfolio Optimization with CVaR budgets in PortfolioAnalytics}3132\begin{document}33\SweaveOpts{concordance=TRUE}3435\title{Portfolio Optimization with CVaR budgets in PortfolioAnalytics}36\author{Kris Boudt, Peter Carl and Brian Peterson }37\date{June 1, 2010}3839\maketitle40\tableofcontents414243\bigskip4445\section{General information}4647Risk budgets are a central tool to estimate and manage the portfolio risk allocation. They decompose total portfolio risk into the risk contribution of each position. \citet{BoudtCarlPeterson2010} propose several portfolio allocation strategies that use an appropriate transformation of the portfolio Conditional Value at Risk (CVaR) budget as an objective or constraint in the portfolio optimization problem. This document explains how risk allocation optimized portfolios can be obtained under general constraints in the \verb"PortfolioAnalytics" package of \citet{PortfolioAnalytics}.4849\verb"PortfolioAnalytics" is designed to provide numerical solutions for portfolio problems with complex constraints and objective sets comprised of any R function. It can e.g.~construct portfolios that minimize a risk objective with (possibly non-linear) per-asset constraints on returns and drawdowns \citep{CarlPetersonBoudt2010}. The generality of possible constraints and objectives is a distinctive characteristic of the package with respect to RMetrics \verb"fPortfolio" of \citet{fPortfolioBook}. For standard Markowitz optimization problems, use of \verb"fPortfolio" rather than \verb"PortfolioAnalytics" is recommended.5051\verb"PortfolioAnalytics" solves the following type of problem52\begin{equation} \min_w g(w) \ \ s.t. \ \53\left\{ \begin{array}{l} h_1(w)\leq 0 \\ \vdots \\ h_q(w)\leq 0. \end{array} \right. \label{optimproblem}\end{equation} \verb"PortfolioAnalytics" first merges the objective function and constraints into a penalty augmented objective function54\begin{equation} L(w) = g(w) + \mbox{penalty}\sum_{i=1}^q \lambda_i \max(h_i(w),0), \label{eq:constrainedobj} \end{equation}55where $\lambda_i$ is a multiplier to tune the relative importance of the constraints. The default values of penalty and $\lambda_i$ (called \verb"multiplier" in \verb"PortfolioAnalytics") are 10000 and 1, respectively.5657The minimum of this function is found through the \emph{Differential Evolution} (DE) algorithm of \citet{StornPrice1997} and ported to R by \citet{MullenArdiaGilWindoverCline2009}. DE is known for remarkable performance regarding continuous numerical problems \citep{PriceStornLampinen2006}. It has recently been advocated for optimizing portfolios under non-convex settings by \citet{Ardia2010} and \citet{Yollin2009}, among others. We use the R implementation of DE in the \verb"DEoptim" package of \citet{DEoptim}.5859The latest version of the \verb"PortfolioAnalytics" package can be downloaded from R-forge through the following command:60\begin{verbatim}61install.packages("PortfolioAnalytics", repos="http://R-Forge.R-project.org")62\end{verbatim}6364Its principal functions are:65\begin{itemize}66\item \verb"portfolio.spec(assets)": the portfolio specification starts with creating a \verb"portfolio" object with information about the assets. The first argument \verb"assets" is either a number indicating the number of portfolio assets or a vector holding the names of the assets. The \verb"portfolio" object is a list holding the constraints and objectives.6768\item \verb"add.constraint(portfolio, type)": Constraints are added to the \verb"portfolio" object by the function \verb"add.constraint". Basic constraint types include leverage constraints that specify the sum of the weights have to be between \verb"min_sum" and \verb"max_sum" and box constraints where the asset weights have to be between \verb"min" and \verb"max".6970\item \verb"add.objective(portfolio, type, name)": New objectives are added to the \verb"portfolio" objected with the function \verb"add.objective". Many common risk budget objectives and constraints are prespecified and can be identified by specifying the \verb"type" and \verb"name".7172\item \verb"constrained_objective(w, R, portfolio)": given the portfolio weight and return data, it evaluates the penalty augmented objective function in (\ref{eq:constrainedobj}).7374\item \verb"optimize.portfolio(R, portfolio)": this function returns the portfolio weight that solves the problem in (\ref{optimproblem}). {\it R} is the multivariate return series of the portfolio components.7576\item \verb"optimize.portfolio.rebalancing(R, portfolio, rebalance_on, trailing_periods)": this function solves the multiperiod optimization problem. It returns for each rebalancing period the optimal weights and allows the estimation sample to be either from inception or a moving window.7778\end{itemize}7980Next we illustrate these functions on monthly return data for bond, US equity, international equity and commodity indices, which are the first 4 series81in the dataset \verb"indexes". The first step is to load the package \verb"PortfolioAnalytics" and the dataset. An important first note is that some of the functions (especially \verb" optimize.portfolio.rebalancing") requires the dataset to be a \verb"xts" object \citep{xts}.828384<<echo=FALSE>>=85options(width=80)86@8788<<echo=TRUE>>=89library(PortfolioAnalytics)90library(DEoptim)91library(robustbase)92data(indexes)93class(indexes)94indexes <- indexes[,1:4]95head(indexes,2)96tail(indexes,2)97@9899In what follows, we first illustrate the construction of the penalty augmented objective function. Then we present the code for solving the optimization problem.100101\section{Setting of the objective function}102103\subsection{Weight constraints}104105<<echo=TRUE, tidy=FALSE>>=106# Create the portfolio specification object107Wcons <- portfolio.spec( assets = colnames(indexes) )108# Add box constraints109Wcons <- add.constraint( portfolio=Wcons, type='box', min = 0, max=1 )110# Add the full investment constraint that specifies the weights must sum to 1.111Wcons <- add.constraint( portfolio=Wcons, type="full_investment")112@113114Given the weight constraints, we can call the value of the function to be minimized. We consider the case of no violation and a case of violation. By default, \verb"normalize=TRUE" which means that if the sum of weights exceeds \verb"max_sum", the weight vector is normalized by multiplying it with \verb"sum(weights)/max_sum" such that the weights evaluated in the objective function satisfy the \verb"max_sum" constraint.115<<echo=TRUE, tidy=FALSE>>=116constrained_objective( w = rep(1/4,4) , R = indexes, portfolio = Wcons)117constrained_objective( w = rep(1/3,4) , R = indexes, portfolio = Wcons)118constrained_objective( w = rep(1/3,4) , R = indexes, portfolio = Wcons,119normalize=FALSE)120@121122The latter value can be recalculated as penalty times the weight violation, that is: $10000 \times 1/3.$123124\subsection{Minimum CVaR objective function}125126Suppose now we want to find the portfolio that minimizes the 95\% portfolio CVaR subject to the weight constraints listed above.127128<<echo=TRUE, tidy=FALSE>>=129ObjSpec = add.objective( portfolio = Wcons , type="risk",name="CVaR",130arguments=list(p=0.95), enabled=TRUE)131@132133The value of the objective function is:134<<echo=TRUE, tidy=FALSE>>=135constrained_objective( w = rep(1/4,4) , R = indexes, portfolio = ObjSpec)136@137138This is the CVaR of the equal-weight portfolio as computed by the function \verb"ES" in the \verb"PerformanceAnalytics" package of \citet{ Carl2007}139<<echo=TRUE, tidy=FALSE>>=140library(PerformanceAnalytics)141out<-ES(indexes, weights = rep(1/4,4),p=0.95,142portfolio_method="component")143out$MES144@145All arguments in the function \verb"ES" can be passed on through \verb"arguments". E.g. to reduce the impact of extremes on the portfolio results, it is recommended to winsorize the data using the option clean="boudt".146147<<echo=TRUE, tidy=FALSE>>=148out<-ES(indexes, weights = rep(1/4,4),p=0.95, clean="boudt",149portfolio_method="component")150out$MES151@152153For the formulation of the objective function, this implies setting:154<<echo=TRUE, tidy=FALSE>>=155ObjSpec = add.objective( portfolio = Wcons , type="risk",name="CVaR",156arguments=list(p=0.95,clean="boudt"), enabled=TRUE)157constrained_objective( w = rep(1/4,4) , R = indexes[,1:4] , portfolio = ObjSpec)158@159160An additional argument that is not available for the moment in \verb"ES" is to estimate the conditional covariance matrix through the constant conditional correlation model of \citet{Bollerslev90}.161162For the formulation of the objective function, this implies setting:163<<echo=TRUE, tidy=FALSE>>=164ObjSpec = add.objective( portfolio = Wcons , type="risk",name="CVaR",165arguments=list(p=0.95,clean="boudt"),166enabled=TRUE, garch=TRUE)167constrained_objective( w = rep(1/4,4) , R = indexes[,1:4] , portfolio = ObjSpec)168@169170\subsection{Minimum CVaR concentration objective function}171172Add the minimum 95\% CVaR concentration objective to the objective function:173<<echo=TRUE, tidy=FALSE>>=174ObjSpec = add.objective( portfolio = Wcons , type="risk_budget_objective",175name="CVaR", arguments=list(p=0.95, clean="boudt"),176min_concentration=TRUE, enabled=TRUE)177@178179The value of the objective function is:180<<echo=TRUE, tidy=FALSE>>=181constrained_objective( w = rep(1/4,4) , R = indexes,182portfolio = ObjSpec, trace=TRUE)183@184185We can verify that this is effectively the largest CVaR contribution of that portfolio as follows:186<<echo=TRUE, tidy=FALSE>>=187ES(indexes[,1:4],weights = rep(1/4,4),p=0.95,clean="boudt",188portfolio_method="component")189@190191\subsection{Risk allocation constraints}192193We see that in the equal-weight portfolio, the international equities and commodities investment cause more than 30\% of total risk. We could specify as a constraint that no asset can contribute more than 30\% to total portfolio risk with the argument \verb"max_prisk=0.3". This involves the construction of the following objective function:194195<<echo=TRUE, tidy=FALSE>>=196ObjSpec = add.objective( portfolio = Wcons , type="risk_budget_objective",197name="CVaR", max_prisk = 0.3,198arguments=list(p=0.95,clean="boudt"), enabled=TRUE)199constrained_objective( w = rep(1/4,4) , R = indexes, portfolio = ObjSpec)200@201202This value corresponds to the penalty parameter which has by default the value of 10000 times the exceedances: $ 10000*(0.045775103+0.054685023)\approx 1004.601.$203204\section{Optimization}205206The penalty augmented objective function is minimized through Differential Evolution. Two parameters are crucial in tuning the optimization: \verb"search_size" and \verb"itermax". The optimization routine207\begin{enumerate}208\item First creates the initial generation of \verb"NP = search_size/itermax" guesses for the optimal value of the parameter vector, using the \verb"random_portfolios" function generating random weights satisfying the weight constraints.209\item Then DE evolves over this population of candidate solutions using alteration and selection operators in order to minimize the objective function. It restarts \verb"itermax" times.210\end{enumerate}211It is important that \verb"search_size/itermax" is high enough. It is generally recommended that this ratio is at least ten times the length of the weight vector. For more details on the use of DE strategy in portfolio allocation, we refer the212reader to \citet{Ardia2010}.213214\subsection{Minimum CVaR portfolio under an upper 40\% CVaR allocation constraint}215216The portfolio object and functions needed to obtain the minimum CVaR portfolio under an upper 40\% CVaR allocation objective are the following:217<<echo=TRUE, tidy=FALSE>>=218# Create the portfolio specification object219ObjSpec <- portfolio.spec(assets=colnames(indexes[,1:4]))220# Add box constraints221ObjSpec <- add.constraint(portfolio=ObjSpec, type='box', min = 0, max=1)222# Add the full investment constraint that specifies the weights must sum to 1.223ObjSpec <- add.constraint(portfolio=ObjSpec, type="weight_sum",224min_sum=0.99, max_sum=1.01)225# Add objective to minimize CVaR226ObjSpec <- add.objective(portfolio=ObjSpec, type="risk", name="CVaR",227arguments=list(p=0.95, clean="boudt"))228# Add objective for an upper 40% CVaR allocation229ObjSpec <- add.objective(portfolio=ObjSpec, type="risk_budget_objective",230name="CVaR", max_prisk=0.4,231arguments=list(p=0.95, clean="boudt"))232@233234After the call to these functions it starts to explore the feasible space iteratively and is shown in the output. Iterations are given as intermediate output and by default every iteration will be printed. We set \verb"traceDE=5" to print every 5 iterations and \verb"itermax=50" for a maximum of 50 iterations.235236<<echo=TRUE, tidy=FALSE>>=237set.seed(1234)238out <- optimize.portfolio(R=indexes, portfolio=ObjSpec,239optimize_method="DEoptim", search_size=2000,240traceDE=5, itermax=50, trace=TRUE)241print(out)242@243244245If \verb"trace=TRUE" in \verb"optimize.portfolio", additional output from the DEoptim solver is included in the \verb"out" object created by \verb"optimize.portfolio". The additional elements in the output are \verb"DEoptim_objective_results" and \verb"DEoutput". The \verb"DEoutput" element contains output from the function \verb"DEoptim". The \verb"DEoptim_objective_results" element contains the weights, value of the objective measures, and other data at each iteration.246247<<echo=TRUE>>=248names(out)249# View the DEoptim_objective_results information at the last iteration250out$DEoptim_objective_results[[length(out$DEoptim_objective_results)]]251252# Extract stats from the out object into a matrix253xtract <- extractStats(out)254dim(xtract)255head(xtract)256@257258It can be seen from the charts that although US Bonds has a higher weight allocation, the percentage contribution to risk is the lowest of all four indexes.259260<<tidy=FALSE, fig.height=4, fig.width=6>>=261plot.new()262chart.Weights(out)263@264265<<tidy=FALSE, fig.height=4, fig.width=6>>=266plot.new()267chart.RiskBudget(out, risk.type="pct_contrib", col="blue", pch=18)268@269270271\subsection{Minimum CVaR concentration portfolio}272273The functions needed to obtain the minimum CVaR concentration portfolio are the following:274275<<echo=TRUE, tidy=FALSE>>=276# Create the portfolio specification object277ObjSpec <- portfolio.spec(assets=colnames(indexes))278# Add box constraints279ObjSpec <- add.constraint(portfolio=ObjSpec, type='box', min = 0, max=1)280# Add the full investment constraint that specifies the weights must sum to 1.281ObjSpec <- add.constraint(portfolio=ObjSpec, type="weight_sum",282min_sum=0.99, max_sum=1.01)283# Add objective for min CVaR concentration284ObjSpec <- add.objective(portfolio=ObjSpec, type="risk_budget_objective",285name="CVaR", arguments=list(p=0.95, clean="boudt"),286min_concentration=TRUE)287288set.seed(1234)289out <- optimize.portfolio(R=indexes, portfolio=ObjSpec,290optimize_method="DEoptim", search_size=5000,291itermax=50, traceDE=5, trace=TRUE)292@293294295This portfolio has the near equal risk contribution characteristic:296<<echo=TRUE, tidy=FALSE>>=297print(out)298299# Verify results with ES function300ES(indexes[,1:4], weights=out$weights, p=0.95, clean="boudt",301portfolio_method="component")302@303304The 95\% CVaR percent contribution to risk is near equal for all four indexes. The neighbor portfolios can be plotted to view other near optimal portfolios. Alternatively, the contribution to risk in absolute terms can plotted by setting \verb"risk.type="absolute".305306<<tidy=FALSE, fig.height=4.5, fig.width=6>>=307plot.new()308chart.RiskBudget(out, neighbors=25, risk.type="pct_contrib",309col="blue", pch=18)310@311312313\subsection{Dynamic optimization}314315Dynamic rebalancing of the risk budget optimized portfolio is possible through the function \verb"optimize.portfolio.rebalancing". Additional arguments are \verb"rebalance_on" which indicates the rebalancing frequency (years, quarters, months). The estimation is either done from inception (\verb"trailing_periods=0") or through moving window estimation, where each window has \verb"trailing_periods" observations. The minimum number of observations in the estimation sample is specified by \verb"training_period". Its default value is 36, which corresponds to three years for monthly data.316317As an example, consider the minimum CVaR concentration portfolio, with estimation from inception and monthly rebalancing. Since we require a minimum estimation length of total number of observations -1, we can optimize the portfolio only for the last two months.318319<<echo=TRUE, tidy=FALSE>>=320set.seed(1234)321out <- optimize.portfolio.rebalancing(R=indexes, portfolio=ObjSpec,322optimize_method="DEoptim", search_size=5000,323rebalance_on="quarters",324training_period=nrow(indexes)-12,325traceDE=0)326@327328329The output of \verb"optimize.portfolio.rebalancing" in the \verb"opt_rebalancing" slot is a list of objects created by \verb"optimize.portfolio", one for each rebalancing period.330331<<echo=TRUE>>=332names(out)333names(out$opt_rebalancing[[1]])334out335@336337The \verb"summary" method provides a brief output of the optimization result along with return and risk measures.338<<echo=TRUE>>=339opt.summary <- summary(out)340names(opt.summary)341opt.summary342@343344The optimal weights for each rebalancing period can be extracted fron the object with \verb"extractWeights" and are charted with \verb"chart.Weights".345346<<echo=TRUE>>=347extractWeights(out)348plot.new()349chart.Weights(out, colorset=bluemono)350@351352353Also, the value of the objective function at each rebalancing date is extracted with \verb"extractObjectiveMeasures".354<<echo=TRUE>>=355head(extractObjectiveMeasures(out))356@357358359The first and last observation from the estimation sample:360<<echo=TRUE>>=361out$opt_rebalancing[[1]]$data_summary362out$opt_rebalancing[[2]]$data_summary363@364365The component contribution to risk at each rebalance date can be charted with \verb"chart.RiskBudget". The component contribution to risk in absolute or percentage.366<<echo=TRUE>>=367plot.new()368chart.RiskBudget(out, match.col="CVaR", risk.type="percentage", col=bluemono)369@370371<<echo=TRUE>>=372plot.new()373chart.RiskBudget(out, match.col="CVaR", risk.type="absolute", col=bluemono)374@375376Of course, DE is a stochastic optimizer and typically will only find a near-optimal solution that depends on the seed. The function \verb"optimize.portfolio.parallel" in \verb"PortfolioAnalytics" allows to run an arbitrary number of portfolio sets in parallel in order to develop "confidence bands" around your solution. It is based on Revolution's \verb"foreach" package \citep{foreach}.377378\bibliographystyle{abbrvnat}379\bibliography{PA}380381382\end{document}383384385386