[R-SIG-Finance] Static Portfolio Optimization
Thomas Etheber
etheber at gmx.de
Fri Oct 2 06:40:54 CEST 2009
Jorge Nieves schrieb:
> Hi,
>
> I tested Thomas' code, but I get an error message in windows R 9.2
> 1(2009-06-26).
>
> Error: class(data) == "timeSeries" is not TRUE
>
>
> I have already spoken with Thomas. He indicated that his code seems to
> work ok in LINUX. However, Thomas gets the same error message I get in
> windows.
>
>
I don't think the OS is relevant for the code. As I told Jorge the code
worked on an older R Version (R version 2.6.1).
Btw Dirk mentioned a nice alternative - the tseries package. I was
wondering, if one can also prespecify further restrictions to
portfolio.optim or is there just support for long-only portfolios?
As the results of the optimizer are often quite sensitive, one might
want to specify some minimum or maximum portfolio weights to get more
suitable results.
Hth,
Thomas
> I was wondering if anyone else has tested the code? Has anyone found a
> work around the problem? It just happens that I too have the need for
> this functionality.
>
> Any leads or recommendations will be highly appreciated.
>
>
>
> Jorge Nieves
>
>
> -----Original Message-----
> From: r-sig-finance-bounces at stat.math.ethz.ch
> [mailto:r-sig-finance-bounces at stat.math.ethz.ch] On Behalf Of Thomas
> Etheber
> Sent: Monday, September 28, 2009 02:29 PM
> To: Brian G. Peterson
> Cc: r-sig-finance at stat.math.ethz.ch; Jesse Velez
> Subject: Re: [R-SIG-Finance] Static Portfolio Optimization
>
> Brian G. Peterson wrote:
>
>> Jesse Velez wrote:
>>
>>> Is there any function or example in R or Rmetrics of static portfolio
>>>
>
>
>>> optimization, where I have a vector of expected returns for N assets
>>> and a expected covariance matrix of said N assets all at a fixed time
>>>
>
>
>>> (say generated from a MFM risk and return model).
>>>
>>> fPortfolio, Portfolio, portfolio.optim appear to all require time
>>> series of returns to generate the expected return and historical
>>> covariance matrix for use in creating weights.
>>>
>>> Ideally, I hope to find an example that allows easily allows
>>> Long/Short weights to make the portfolio market neutral (i.e.
>>> Summation of Weights =0).
>>>
>>>
>> All the implementations of Markowitz style mean/variance optmization
>> use quadprog in R.
>>
>> Plenty of information on the list archives from before all these
>> packages existed about using quadprog for optimization.
>>
>> Regards,
>>
>> - Brian
>>
>>
>
> Hi there,
>
> I also had the problem with fixed parameter inputs some time ago.
> Implementing methods to perform this tasks would certainly be a nice
> improvement of the library (as would be some help/error messages if the
> covariance matrix is not positive semidefinite).
> Although Brian's comment is helpful as usual, using basic quadprog
> sounds like reinventing the wheel, but might nevertheless be needed to
> solve your second task of a market-neutral portfolio.
>
> In order to use prespecified estimates as inputs I helped myself with
> overwriting some of the methods. It's not a nice solution, but it worked
> for me. You will find the methods attached below.
> I didn't check the code again, but I think it should work. Please note,
> some other methods of Rmetrics and fPortfolio might rely on the
> timeseries objects and might not work properly.
>
> Hth
> Thomas
>
>
> require(MBESS)
> require(fPortfolio)
> rm(list=ls())
> spec <- portfolioSpec()
> constraints <- NULL
>
> portfolioData <- function (data, spec = portfolioSpec()) {
> ans = NULL
> if(class(data) == "timeSeries") {
> data = sort(data)
> nAssets = dim(data)[2]
> statistics = portfolioStatistics(data, spec)
> tailRisk = spec at model$tailRisk
> ans <- new("fPFOLIODATA", data = list(series = data, nAssets =
> nAssets),
> statistics = statistics, tailRisk = tailRisk)
> }
> if(class(data) == "list") {
> statistics = list(mu = data$mu, Sigma = data$Sigma )
> attr(statistics, "estimator") = spec at model$estimator
> ans <- new("fPFOLIODATA", data = list( nAssets = length(data$mu)
> ), statistics = statistics, tailRisk = list() )
> }
> ans
> }
>
>
> ########################################################################
> ############
>
> .efficientConstrainedMVPortfolio <- function (data, spec, constraints) {
> if (!inherits(data, "fPFOLIODATA"))
> data = portfolioData(data, spec)
> mu = getMu(data)
> Sigma = getSigma(data)
> nAssets = getNumberOfAssets(data)
> targetAlpha = getTargetAlpha(spec)
> solver = getSolver(spec)
> stopifnot(solver == "quadprog" | solver == "Rdonlp2")
> if (solver == "quadprog") {
> portfolio = solveRQuadprog(data, spec, constraints)
> }
> else if (solver == "Rdonlp2") {
> portfolio = solveRDonlp2(data, spec, constraints)
> }
> weights = portfolio$weights
> attr(weights, "status") <- portfolio$status
> names(weights) = names(mu)
> targetReturn = matrix(as.numeric(mu %*% weights), nrow = 1)
> colnames(targetReturn) <- getEstimator(spec)[1]
> covTargetRisk = sqrt(as.numeric(weights %*% Sigma %*% weights))
> # x = getSeries(data)@Data %*% weights
> # VaR = quantile(x, targetAlpha, type = 1)
> # CVaR = VaR - 0.5 * mean(((VaR - x) + abs(VaR - x)))/targetAlpha
> # targetRisk = matrix(c(covTargetRisk, CVaR, VaR), nrow = 1)
> # colnames(targetRisk) <- c("cov", paste(c("CVaR.", "VaR."),
> # targetAlpha * 100, "%", sep = ""))
> targetRisk = matrix(c(covTargetRisk), nrow = 1)
> ## is needed to use the plotting functions....
> targetRisk = matrix(c(covTargetRisk, covTargetRisk ), nrow = 1)
> colnames(targetRisk) <- c( "cov", "dummy" )
> new("fPORTFOLIO", call = match.call(), data = list(data = data),
> spec = list(spec = spec), constraints =
> as.character(constraints),
> portfolio = list(weights = weights, targetReturn = targetReturn,
> targetRisk = targetRisk, targetAlpha = targetAlpha,
> status = portfolio$status), title = paste("Constrained MV
> Portfolio - Solver:",
> solver), description = .description()) }
>
> ########################################################################
> ############
>
> .minvarianceConstrainedMVPortfolio <- function (data, spec, constraints)
> {
> if (!inherits(data, "fPFOLIODATA"))
> data = portfolioData(data, spec)
> mu = getMu(data)
> Sigma = getSigma(data)
> nAssets = getNumberOfAssets(data)
> targetAlpha = getTargetAlpha(spec)
> .minVariancePortfolioFun = function(x, data, spec, constraints) {
> spec at portfolio$targetReturn = x
> ans = .efficientConstrainedMVPortfolio(data = data, spec = spec,
> constraints = constraints)
> f = getTargetRisk(ans)[1]
> attr(f, "targetReturn") <- getTargetReturn(ans)
> attr(f, "targetRisk") <- getTargetRisk(ans)[1]
> attr(f, "weights") <- getWeights(ans)
> f
> }
> minVar = optimize(.minVariancePortfolioFun, interval = range(mu),
> data = data, spec = spec, constraints = constraints,
> tol = .Machine$double.eps^0.5)
> weights = attr(minVar$objective, "weights")
> names(weights) = names(mu)
> targetReturn = spec at portfolio$targetReturn =
> as.numeric(attr(minVar$objective,
> "targetReturn"))
> targetReturn = matrix(targetReturn, nrow = 1)
> colnames(targetReturn) <- spec at model$estimator[1]
> covTargetRisk = as.numeric(attr(minVar$objective, "targetRisk"))
> # x = getSeries(data)@Data %*% weights
> # VaR = quantile(x, targetAlpha, type = 1)
> # CVaR = VaR - 0.5 * mean(((VaR - x) + abs(VaR - x)))/targetAlpha
> #targetRisk = matrix(c(covTargetRisk, CVaR, VaR), nrow = 1)
> #colnames(targetRisk) <- c("cov", paste(c("CVaR.", "VaR."),
> targetRisk = matrix(c(covTargetRisk), nrow = 1)
> ## is needed to use the plotting functions....
> targetRisk = matrix(c(covTargetRisk, covTargetRisk ), nrow = 1)
> colnames(targetRisk) <- c( "cov", "dummy" )
> new("fPORTFOLIO", call = match.call(), data = list(data = data),
> spec = list(spec = spec), constraints =
> as.character(constraints),
> portfolio = list(weights = weights, targetReturn = targetReturn,
> targetRisk = targetRisk, targetAlpha = targetAlpha,
> status = 0), title = "Minimum Variance Portfolio",
> description = .description())
> }
>
> show.fPORTFOLIO <- function (object)
> {
> cat("\nTitle:\n ")
> cat(getTitle(object), "\n")
> cat("\nCall:\n ")
> print.default(getCall(object))
> cat("\nPortfolio Weight(s):\n")
> weights = round(getWeights(object), digits = 4)
> if (length(weights) == 1) {
> cat(" ", weights, "\n")
> }
> else {
> print.table(weights)
> }
> cat("\nRiskBudget(s):\n")
> riskBudgets = round(getCovRiskBudgets(object), digits = 4)
> if (length(riskBudgets) == 1) {
> cat(" ", riskBudgets, "\n")
> }
> else {
> print.table(riskBudgets)
> }
> if (FALSE) {
> if (!is.na(getTailRiskBudgets(object))) {
> cat("\nRiskBudget(s):\n")
> riskBudgets = round(getTailRiskBudgets(object), digits = 4)
> if (length(riskBudgets) == 1) {
> cat(" ", riskBudgets, "\n")
> }
> else {
> print.table(riskBudgets)
> }
> }
> }
> targetReturn = object at portfolio$targetReturn
> targetRisk = object at portfolio$targetRisk
> spec = getSpec(object)
> cat("\nTarget Risk(s) and Return(s):\n")
> if (is.null(dim(targetReturn))) {
> targetReturn = matrix(targetReturn, nrow = 1)
> colnames(targetReturn) = getEstimator(spec)[1]
> }
> if (is.null(dim(targetRisk))) {
> targetRisk = matrix(targetRisk, nrow = length(targetRisk) )
> colnames(targetRisk) = getEstimator(spec)[2]
> }
> target = cbind(targetReturn, targetRisk)
> colnames(target) = c(colnames(targetReturn), colnames(targetRisk) )
> if (nrow(target) == 1) {
> print(target[1, ])
> }
> else {
> print(target)
> }
> cat("\nDescription:\n ")
> cat(getDescription(object), "\n")
> invisible(object)
> }
>
> setMethod("show", "fPORTFOLIO", show.fPORTFOLIO)
>
> ########################################################################
> ############
>
> .portfolioConstrainedMVFrontier <- function (data, spec, constraints) {
> if (!inherits(data, "fPFOLIODATA"))
> data = portfolioData(data, spec)
> mu = getMu(data)
> Sigma = getSigma(data)
> nAssets = getNumberOfAssets(data)
> targetAlpha = getTargetAlpha(spec)
> nFrontierPoints = getNFrontierPoints(spec)
> targetReturn = targetRisk = targetWeights = error = NULL
> Spec = spec
> solver = spec at solver$solver
> Spec at portfolio$weights = rep(1/nAssets, nAssets)
> k = 0
> solverType = spec at solver$solver
> status = NULL
> for (nTargetReturn in seq(min(mu), max(mu), length =
> nFrontierPoints)) {
> k = k + 1
> setTargetReturn(Spec) <- nTargetReturn
> nextPortfolio = .efficientConstrainedMVPortfolio(data = data,
> spec = Spec, constraints = constraints)
> Spec at portfolio$weights = nextPortfolio at portfolio$weights
> targetReturn = rbind(targetReturn,
> nextPortfolio at portfolio$targetReturn)
> targetRisk = rbind(targetRisk,
> nextPortfolio at portfolio$targetRisk)
> nextWeights = nextPortfolio at portfolio$weights
> names(nextWeights) = names(mu)
> status = c(status, nextPortfolio at portfolio$status)
> targetWeights = rbind(targetWeights, t(nextWeights))
> }
> Index = (1:length(status))[status == 0]
> weights = targetWeights
> colnames(weights) = names(mu)
> weights = weights[Index, ]
> DIM = dim(targetReturn)[2]
> targetReturn = targetReturn[Index, ]
> targetReturn = matrix(targetReturn, ncol = DIM)
> colnames(targetReturn) = getEstimator(spec)[1]
> targetRisk = targetRisk[Index, ]
> new("fPORTFOLIO", call = match.call(), data = list(data = data),
> spec = list(spec = spec), constraints =
> as.character(constraints),
> portfolio = list(weights = weights, targetReturn = targetReturn,
> targetRisk = targetRisk, targetAlpha = targetAlpha,
> status = status), title = "Constrained MV Frontier",
> description = .description())
> }
>
> ########################################################################
> ############
>
> # You should be able to specify the data in this form:
> mu <- c( 0.1, 0.08, 0.065)
> sigma <- c( 0.18, 0.12, 0.09 )
>
> correlationMatrix <- rbind( c( 1, 0.8, 0.9 ),
> c( 0.8, 1, 0.75),
> c( 0.9, 0.75, 1) )
>
> covarianceMatrix <- cor2cov(correlationMatrix, sigma )
>
>
> data = list( mu = mu, Sigma = covarianceMatrix )
>
> # And then do the optimisation
> frontier <- portfolioFrontier(data, spec = spec, constraints )
>
> _______________________________________________
> R-SIG-Finance at stat.math.ethz.ch mailing list
> https://stat.ethz.ch/mailman/listinfo/r-sig-finance
> -- Subscriber-posting only.
> -- If you want to post, subscribe first.
>
>
More information about the R-SIG-Finance
mailing list