#' calculate a traditional or modified Sharpe Ratio of Return over StdDev or #' VaR or ES #' #' The Sharpe ratio is simply the return per unit of risk (represented by #' variability). In the classic case, the unit of risk is the standard #' deviation of the returns. #' #' \deqn{\frac{\overline{(R_{a}-R_{f})}}{\sqrt{\sigma_{(R_{a}-R_{f})}}}} #' #' William Sharpe now recommends \code{\link{InformationRatio}} preferentially #' to the original Sharpe Ratio. #' #' The higher the Sharpe ratio, the better the combined performance of "risk" #' and return. #' #' As noted, the traditional Sharpe Ratio is a risk-adjusted measure of return #' that uses standard deviation to represent risk. #' #' The Sharpe Ratio can be used to measure both 'excess return' (over a risk-free #' rate) and 'differential return' (excess return over a benchmark). #' #' A number of papers now recommend using a "modified Sharpe" ratio using a #' Modified Cornish-Fisher VaR or CVaR/Expected Shortfall as the measure of #' Risk. #' #' We have extended this concept to create multivariate modified #' Sharpe-like Ratios for standard deviation, Gaussian VaR, modified VaR, #' Gaussian Expected Shortfall, and modified Expected Shortfall. See #' \code{\link{VaR}} and \code{\link{ES}}. You can pass additional arguments #' to \code{\link{VaR}} and \code{\link{ES}} via \dots{} The most important is #' probably the 'method' argument/ #' #' Most recently, we have added Downside Sharpe Ratio (DSR) (see \code{\link{DownsideSharpeRatio}}), a short name for what Ziemba (2005) #' called the "Symmetric Downside Risk Sharpe Ratio" and is defined as the ratio of the mean return #' to the square root of lower semivariance: #' #' \deqn{\frac{\overline{(R_{a}-R_{f})}}{\sqrt{2}SemiSD(R_a)}}. #' #' This function returns a traditional or modified Sharpe ratio for the same #' periodicity of the data being input (e.g., monthly data -> monthly SR) #' #' #' @aliases SharpeRatio.modified SharpeRatio #' @param R an xts, vector, matrix, data frame, timeSeries or zoo object of #' asset returns #' @param Rf risk free rate, in same period as your returns #' @param p confidence level for calculation, default p=.95 #' @param FUN one of "StdDev" or "VaR" or "ES" to use as the denominator #' @param weights portfolio weighting vector, default NULL, see Details in #' \code{\link{VaR}} #' @param annualize if TRUE, annualize the measure, default FALSE #' @param geometric utilize geometric chaining (TRUE) or simple/arithmetic chaining (FALSE) to aggregate returns, #' default FALSE #' @param SE TRUE/FALSE whether to ouput the standard errors of the estimates of the risk measures, default FALSE. #' @param SE.control Control parameters for the computation of standard errors. Should be done using the \code{\link{RPESE.control}} function. #' @param \dots any other passthru parameters to the VaR or ES functions #' @author Brian G. Peterson #' @seealso \code{\link{SharpeRatio.annualized}} \cr #' \code{\link{InformationRatio}} \cr \code{\link{TrackingError}} \cr #' \code{\link{ActivePremium}} \cr \code{\link{SortinoRatio}} \cr #' \code{\link{VaR}} \cr \code{\link{ES}} \cr #' @references Sharpe, W.F. The Sharpe Ratio,\emph{Journal of Portfolio #' Management},Fall 1994, 49-58. #' #' Laurent Favre and Jose-Antonio Galeano. Mean-Modified Value-at-Risk #' Optimization with Hedge Funds. Journal of Alternative Investment, Fall 2002, #' v 5. #' #' Ziemba, W. T. (2005). The symmetric downside-risk Sharpe ratio. The Journal of #' Portfolio Management, 32(1), 108-122. #' #' Jacquier, E., Kane, A., Marcus, A. [2003]. Geometric Mean or Arithmetic Mean: #' A Reconsideration. Financial Analysts Journal, November/December 2003, p. 46-53. #' ### keywords ts multivariate distribution models #' @examples #' #' data(managers) #' SharpeRatio(managers[, 1, drop = FALSE], Rf = .035 / 12, FUN = "StdDev") #' SharpeRatio(managers[, 1, drop = FALSE], Rf = managers[, 10, drop = FALSE], FUN = "StdDev") #' SharpeRatio(managers[, 1:6], Rf = .035 / 12, FUN = "StdDev") #' SharpeRatio(managers[, 1:6], Rf = managers[, 10, drop = FALSE], FUN = "StdDev") #' #' #' #' data(edhec) #' SharpeRatio(edhec[, 6, drop = FALSE], FUN = "VaR") #' SharpeRatio(edhec[, 6, drop = FALSE], Rf = .04 / 12, FUN = "VaR") #' SharpeRatio(edhec[, 6, drop = FALSE], Rf = .04 / 12, FUN = "VaR", method = "gaussian") #' SharpeRatio(edhec[, 6, drop = FALSE], FUN = "ES") #' #' # and all the methods #' SharpeRatio(managers[, 1:9], Rf = managers[, 10, drop = FALSE], FUN = c("StdDev", "VaR", "ES")) #' SharpeRatio(edhec, Rf = .04 / 12, FUN = c("StdDev", "VaR", "ES")) #' #' @export #' @rdname SharpeRatio SharpeRatio <- function(R, Rf = 0, p = 0.95, FUN = c("StdDev", "VaR", "ES", "SemiSD"), weights = NULL, annualize = FALSE, geometric = FALSE, SE = FALSE, SE.control = NULL, ...) { # @author Brian G. Peterson if (missing(FUN)) { FUN <- "StdDev" } # DESCRIPTION: # The Sharpe ratio is simply the return per unit of risk (represented by # variability). The higher the Sharpe ratio, the better the combined # performance of "risk" and return. # The Sharpe Ratio is a risk-adjusted measure of return that uses # standard deviation to represent risk. # A number of papers now recommend using a "modified Sharpe" ratio # using a Modified Cornish-Fisher VaR as the measure of Risk. # Inputs: # R: in this case, the function anticipates having a return stream as input, # rather than prices. # # Rf: the risk free rate MUST be in the same periodicity as the data going in. # # p: probability at which to calculate the modified risk measure (defaults to 95%) # Outputs: # This function returns a (modified) Sharpe ratio for the same periodicity of the # data being input (e.g., monthly data -> monthly SR) # @TODO: annualize using multiperiod VaR and ES calcs # FUNCTION: R <- checkData(R) if (!is.null(dim(Rf))) { Rf <- checkData(Rf) } dots <- list(...) if ("scale" %in% names(dots)) { scale <- dots$scale } else if (annualize) { # scale the Rf to the periodicity of the calculation freq <- periodicity(R) switch(freq$scale, minute = { stop("Data periodicity too high") }, hourly = { stop("Data periodicity too high") }, daily = { scale <- 252 }, weekly = { scale <- 52 }, monthly = { scale <- 12 }, quarterly = { scale <- 4 }, yearly = { scale <- 1 } ) } else { scale <- 1 # won't scale the Rf, will leave it at the same periodicity } # TODO: Consolidate annualized and regular SR calcs srm <- function(R, ..., Rf, p, FUNC, geometric) { FUNCT <- match.fun(FUNC) xR <- Return.excess(R, Rf) if (geometric) { ret <- prod(1 + na.omit(xR))^(1 / length(na.omit(xR))) - 1 } else { ret <- mean(xR, na.rm = TRUE) } dots <- list(...) dots$scale <- NULL SRM <- ret / do.call(FUNCT, c(list(R = xR, p = p, invert = FALSE), dots)) SRM } sra <- function(R, ..., Rf, p, FUNC, geometric) { xR <- Return.excess(R, Rf) dots <- list(...) dots$scale <- NULL if (FUNC == "StdDev") { risk <- do.call(StdDev.annualized, c(list(x = xR, scale = scale), dots)) } else { FUNCT <- match.fun(FUNC) risk <- do.call(FUNCT, c(list(R = xR, p = p, invert = FALSE), dots)) } SRA <- Return.annualized(xR, scale = scale, geometric = geometric) / risk SRA } i <- 1 if (is.null(weights)) { result <- matrix(nrow = length(FUN), ncol = ncol(R)) colnames(result) <- colnames(R) } else { result <- matrix(nrow = length(FUN)) } tmprownames <- vector() # Checking input if SE = TRUE if (SE) { if (!requireNamespace("RPESE", quietly = TRUE)) { warning("Package \"RPESE\" needed for standard errors computation. Please install it.", call. = FALSE ) SE <- FALSE } ses.full <- matrix(ncol = ncol(R), nrow = 0) } result.final <- matrix(nrow = ncol(R)) for (FUNCT in FUN) { # Setting the measure if (FUNCT == "StdDev") { SR.measure <- "SR" } else if (FUNCT == "ES") { SR.measure <- "ESratio" } else if (FUNCT == "VaR") { SR.measure <- "VaRratio" } else if (FUNCT == "SemiSD") { SR.measure <- "DSR" } # SE Computation if (SE) { # Setting the control parameters if (is.null(SE.control)) { SE.control <- RPESE.control(estimator = SR.measure) } # Computation of SE (optional) ses <- list() # For each of the method specified in se.method, compute the standard error for (mymethod in SE.control$se.method) { ses[[mymethod]] <- RPESE::EstimatorSE(R, estimator.fun = SR.measure, se.method = mymethod, cleanOutliers = SE.control$cleanOutliers, fitting.method = SE.control$fitting.method, freq.include = SE.control$freq.include, freq.par = SE.control$freq.par, a = SE.control$a, b = SE.control$b, alpha = 1 - p, rf = Rf, ... ) ses[[mymethod]] <- ses[[mymethod]]$se } ses.full <- rbind(ses.full, t(data.frame(ses))) } if (FUNCT == "SemiSD") { dots <- list(...) dots$scale <- NULL result[i, ] <- do.call(DownsideSharpeRatio, c(list(R = R, rf = Rf), dots)) } else { xR <- Return.excess(R, Rf) if (is.null(weights)) { if (annualize) { result[i, ] <- sapply(R, FUN = sra, Rf = Rf, p = p, FUNC = FUNCT, geometric = geometric, ...) } else { result[i, ] <- sapply(R, FUN = srm, Rf = Rf, p = p, FUNC = FUNCT, geometric = geometric, ...) } } else { weighted_xR <- xR %*% weights if (geometric) { ret <- prod(1 + na.omit(weighted_xR))^(1 / length(na.omit(weighted_xR))) - 1 if (annualize) { ret <- (1 + ret)^scale - 1 } } else { ret <- mean(weighted_xR, na.rm = TRUE) if (annualize) { ret <- ret * scale } } dots <- list(...) dots$scale <- NULL result[i, ] <- ret / do.call(match.fun(FUNCT), c(list(R = xR, Rf = Rf, p = p, weights = weights, portfolio_method = "single"), dots)) } } base_label <- if (geometric) "Geometric Sharpe Ratio" else "Sharpe Ratio" label_FUN <- if (FUNCT == "StdDev") "" else paste0(FUNCT, " ") tmprownames <- c(tmprownames, paste(if (annualize) "Annualized ", label_FUN, base_label, " (Rf=", round(scale * mean(Rf) * 100, 1), "%, p=", round(p * 100, 1), "%):", sep = "")) i <- i + 1 # increment counter } rownames(result) <- tmprownames if (SE) { return(rbind(result, ses.full)) } else { return(result) } } #' @export #' @rdname SharpeRatio SharpeRatio.modified <- function(R, Rf = 0, p = 0.95, FUN = c("StdDev", "VaR", "ES"), weights = NULL, ...) { .Deprecated("SharpeRatio", package = "PerformanceAnalytics", "The SharpeRatio.modified function has been deprecated in favor of a newer SharpeRatio wrapper that will cover both the classic case and a larger suite of modified Sharpe Ratios. This deprecated function may be removed from future versions") return(SharpeRatio(R = R, Rf = Rf, p = p, FUN = FUN, weights = weights, ...)) } ############################################################################### # R (https://r-project.org/) Econometrics for Performance and Risk Analysis # # Copyright (c) 2004-2026 Peter Carl and Brian G. Peterson # # This R package is distributed under the terms of the GNU Public License (GPL) # for full details see the file COPYING # # $Id$ # ###############################################################################