################################ IMPORTANT ##################################### # # This code has been replaced, extended, and deprecated by the # PerformanceAnalytics Econometrics for Performance and Risk Analysis # # summary available here: # http://braverock.com/brian/R/PerformanceAnalytics-package.html # ################################################################################ # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General # Public License along with this library; if not, # go here: http://www.gnu.org/licenses/gpl.html # or write to the # Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, # MA 02111-1307 USA # Copyright 2006 Brian G. Peterson ################################################################################ # FUNCTIONS: # moment.third # moment.fourth # CoSkewness # CoKurtosis # BetaCoVariance # BetaCoV (wrapper for BetaCoVariance) # SystematicBeta (wrapper for BetaCoVariance) # BetaCoSkewness # BetaCoS (wrapper for BetaCoSkewness) # SystematicSkewness (wrapper for BetaCoSkewness) # BetaCoKurtosis # BetaCoK (wrapper for BetaCoKurtosis) # SystematicKurtosis (wrapper for BetaCoKurtosis) # VaR # VaR.Beyond # VaR.column # VaR.CornishFisher # VaR.Marginal # modifiedVaR (wrapper for VaR.CornishFisher) # ################################################################################ ################################################################################ # The following functions are intended to replicate calculations for # taking higher moments of hedge fund returns into account in analyzing # particular investments. Most of the formulae are taken from various EDHEC # research papers. # All returns are assumed to be on a monthly scale! # The argument r is the monthly return time series ! # @todo add modifiers for Risk-free rate, presumed to be zero in these functions # @todo add ability to account for multidimensionality of # systematic beta, systematic skewness, and systematic kurtosis # Check to see if the required libraries are loaded if(!require("fBasics", quietly=TRUE)) { stop("package", sQuote("fBasics"), "is needed. Stopping") } if(!require("fPortfolio", quietly=TRUE)) { stop("package", sQuote("fPortfolio"), "is needed. Stopping") } # ------------------------------------------------------------------------------ moment.third= function(Ri,na.rm=FALSE) { # @author Brian G. Peterson # Description: # The third mathematical moment of the return function. # Favre and Renaldo use this as separate from skewness in developing a # four-moment CAPM model # # as defined in: # Favre, L. and Renaldo, A., October 2003 # How to Price Hedge Funds: From Two- to Four-Moment CAPM # UBS and Edhec Business School # Setup Ri = as.vector(Ri) if(na.rm) { Ri <- Ri[!is.na(Ri)] } # FUNCTION: S = (mean((Ri-mean(Ri)^3)))^(1/3) result = S # Return Value: result } # ------------------------------------------------------------------------------ moment.fourth= function(Ri,na.rm=FALSE) { # @author Brian G. Peterson # Description: # The fourth mathematical moment of the return function. # Favre and Renaldo use this as separate from kurtosis in developing a # four-moment CAPM model # # as defined in: # Favre, L. and Renaldo, A., October 2003 # How to Price Hedge Funds: From Two- to Four-Moment CAPM # UBS and Edhec Business School # Setup Ri = as.vector(Ri) if(na.rm) { Ri <- Ri[!is.na(Ri)] } # FUNCTION: K = (mean((Ri-mean(Ri)^4)))^(1/4) result = K # Return Value: result } # ------------------------------------------------------------------------------ CoSkewness = function(Ri, Ra, na.rm=FALSE) { # @author Brian G. Peterson # Description: # CoSkewness is the product of the third higher moments of two assets, # as defined in # Martellini L. and Ziemann V., 2005, # Marginal Impacts on Portfolio Distributions, # Working Paper, Edhec Risk and Asset Management Research Centre # and in: # Martellini L., Vaissie M., Ziemann V., October 2005, # Investing in Hedge Funds: # Adding Value through Active Style Allocation Decisions # Edhec Risk and Asset Management Research Centre # Ri = return vector of initial portfolio # Ra = return vector of asset being considered for addition to portfolio # Setup Ri = as.vector(Ri) Ra = as.vector(Ra) if(na.rm) { Ri <- Ri[!is.na(Ri)] Ra <- Ra[!is.na(Ra)] } # FUNCTION: # CoSkewness of two assets CoS = mean((Ri - mean(Ri))*((Ra-mean(Ra))^2)) result = CoS # Return Value: result } # ------------------------------------------------------------------------------ CoKurtosis = function(Ri, Ra, na.rm=FALSE) { # @author Brian G. Peterson # Description: # CoKurtosis is the product of the fourth higher moments of two assets, # as defined in # Martellini L. and Ziemann V., 2005, # Marginal Impacts on Portfolio Distributions, # Working Paper, Edhec Risk and Asset Management Research Centre # and in: # Martellini L., Vaissie M., Ziemann V., October 2005, # Investing in Hedge Funds: # Adding Value through Active Style Allocation Decisions # Edhec Risk and Asset Management Research Centre # Ri = return vector of initial portfolio # Ra = return vector of asset being considered for addition to portfolio # Setup Ri = as.vector(Ri) Ra = as.vector(Ra) if(na.rm) { Ri <- Ri[!is.na(Ri)] Ra <- Ra[!is.na(Ra)] } # FUNCTION: # CoKurtosis of two assets CoK = mean((Ri - mean(Ri))*((Ra-mean(Ra))^3)) result = CoK # Return Value: result } # ------------------------------------------------------------------------------ BetaCoVariance = function(Ri, Ra, na.rm=FALSE) { # @author Brian G. Peterson # Description: # Beta covariance is the beta of an asset to the variance and covariance # of an initial portfolio. Used to determine diversification potential. # also called "systematic beta" by several papers # # as defined in # Favre, L. and Renaldo, A., October 2003 # How to Price Hedge Funds: From Two- to Four-Moment CAPM # UBS and Edhec Business School # Equation [5] p. 10 # Ri = return vector of initial portfolio # Ra = return vector of asset being considered for addition to portfolio # Setup Ri = as.vector(Ri) Ra = as.vector(Ra) if(na.rm) { Ri <- Ri[!is.na(Ri)] Ra <- Ra[!is.na(Ra)] } # FUNCTION: # CovarianceBeta of two assets covB = cov(Ra,Ri)/var(Ri) result = covB # Return Value: result } BetaCoV = function(Ri, Ra, na.rm=FALSE) { # wrapper function with a shorter name result = BetaCoVariance(Ri, Ra, na.rm) # Return Value: result } SystematicBeta = function(Ri, Ra, na.rm=FALSE) { # wrapper function with a shorter name result = BetaCoVariance(Ri, Ra, na.rm) # Return Value: result } # ------------------------------------------------------------------------------ BetaCoSkewness = function(Ri, Ra, na.rm=FALSE) { # @author Brian G. Peterson # Description: # Beta CoSkewness is the beta of an asset to the skewness # of an initial portfolio. Used to determine diversification potential. # also called "systematic skewness" or "systematic co-skewness" # by several papers. # as defined in # Favre, L. and Renaldo, A., October 2003 # How to Price Hedge Funds: From Two- to Four-Moment CAPM # UBS and Edhec Business School # Equation [5] p. 10 # Ri = return vector of initial portfolio # Ra = return vector of asset being considered for addition to portfolio # Setup Ri = as.vector(Ri) Ra = as.vector(Ra) if(na.rm) { Ri <- Ri[!is.na(Ri)] Ra <- Ra[!is.na(Ra)] } # FUNCTION: # systematic skewness of two assets skB = CoSkewness(Ra,Ri)/(mean(Ri-mean(Ri)^3)) result = skB # Return Value: result } BetaCoS = function(Ri, Ra, na.rm=FALSE) { # wrapper function with a shorter name result = BetaCoSkewness(Ri, Ra, na.rm) # Return Value: result } SystematicSkewness = function(Ri, Ra, na.rm=FALSE) { # wrapper function with a shorter name result = BetaCoSkewness(Ri, Ra, na.rm) # Return Value: result } # ------------------------------------------------------------------------------ BetaCoKurtosis = function( Ri, Ra, na.rm=FALSE, method=c("moment", "excess", "fisher") ) { # @author Brian G. Peterson # Description: # Beta CoKurtosis is the beta of an asset to the kurtosis # of an initial portfolio. Used to determine diversification potential. # Also called "systematic kurtosis" or "systematic cokurtosis" by several papers. # # as defined in # Martellini L., Vaissie M., Ziemann V., October 2005, # Investing in Hedge Funds: # Adding Value through Active Style Allocation Decisions # Edhec Risk and Asset Management Research Centre # Ri = return vector of initial portfolio # Ra = return vector of asset being considered for addition to portfolio # Setup Ri = as.vector(Ri) Ra = as.vector(Ra) if(na.rm) { Ri <- Ri[!is.na(Ri)] Ra <- Ra[!is.na(Ra)] } # FUNCTION: # Beta CoKurtosis of two assets ktB = CoKurtosis(Ra,Ri)/kurtosis(Ri, na.rm ,method ) #method = c("excess", "moment", "fisher") result = ktB # Return Value: result } BetaCoK = function( Ri, Ra, na.rm=FALSE, method=c("moment", "excess", "fisher") ) { # wrapper function with a shorter name result = BetaCoKurtosis(Ri, Ra, na.rm, method) # Return Value: result } SystematicKurtosis = function( Ri, Ra, na.rm=FALSE, method=c("moment", "excess", "fisher") ) { # wrapper function with a shorter name result = BetaCoKurtosis(Ri, Ra, na.rm, method) # Return Value: result } # ------------------------------------------------------------------------------ VaR.CornishFisher = function(R, p=0.99, modified = TRUE, column=1) { # @author Brian G. Peterson (completed/debugged fn) # @author Diethelm Wuertz (prototype function) # Description: # The limitations of mean Value-at-Risk are well covered in the literature. # Laurent Favre and Jose-Antonio Galeano published a paper in the # Fall 2002, volume 5 of the Journal of Alternative Investment, # "Mean-Modified Value-at-Risk optimization With Hedge Funds", # that proposed a modified VaR calculation that takes the higher moments # of non-normal distributions (skewness, kurtosis) into account, and # collapses to standard (traditional) mean-VaR if the return stream follows a # standard distribution. # This measure is now widely cited and used in the literature, # and is usually referred to as "Modified VaR" or "Modified Cornish-Fisher VaR" # Diethelm Wuertz's original function was called monthlyVaR, but did not # contain the required modifications to get to a monthly or an annualized number. # I have converted it to VaR.CornishFisher, and made the assumption of p=0.99, with an option for p=0.95 and # a collapse to normal mean VaR. # FUNCTION: # compute zc for the probability we want if ( p >= 0.51 ) { # looks like p was a percent like .99 p = 1-p } zc = qnorm(p) # data type conditionals if (class(R) == "numeric") { y = as.matrix(R) } if (class(R) == "matrix") { y = R[, column] } if (class(R) == "data.frame") { y = R[, column] } if (class(R) == "timeSeries") { y = R@Data[, column] } if (class(R) == "vector") { y = array(R=R) } class(R) r = as.vector(y) if (!is.numeric(r)) stop("The selected column is not numeric") if (modified) { s = skewness(r) #skewness of the distribution k = kurtosis(r) #(excess) kurtosis Zcf = zc + (((zc^2-1)*s)/6) + (((zc^3-3*zc)*k)/24) + (((2*zc^3)-(5*zc)*s^2)/36) VaR = mean(r) - (Zcf * sqrt(var(r))) } else { # should probably add risk-free-rate skew here? VaR = mean(r) - (zc * sqrt(var(r))) } result = VaR # Return Value: result } # ------------------------------------------------------------------------------ VaR = function(R, p=0.99, column=1, modified=FALSE) { # @author Peter Carl # replaces VaR() in RMetrics, but results are the same # Description: # This is a wrapper function for modified VaR, most likely to be used with # metrics related to VaR, such as Beyond VaR. This function returns what will # someday be referred to as "Traditional VaR". # FUNCTION: VaR.CornishFisher(R = R, p = p, modified, column = column) } modifiedVaR = function(R, p=0.99, column=1, modified=TRUE) { # @author Brian G. Peterson # Description: # This is a wrapper function for modified VaR, most likely to be used with # metrics related to VaR, such as Beyond VaR. This function returns what will # someday be referred to as "Traditional VaR". # FUNCTION: VaR.CornishFisher(R = R, p = p, modified, column = column) } # ------------------------------------------------------------------------------ VaR.Beyond = function (R, periods = 1) {# @author Peter Carl # @author Brian G. Peterson (R-algorithm/testing) # Description: # Beyond VaR purports to estimate average loss beyond VaR. Please note # that your milage will vary; expect that values obtained from the normal # distribution differs radically from the real situation. # BeyondVaR is described in theoretical detail in the paper: # as defined in: # Gaussel, N., Legras, J., Longin, F., and Rabemananjara, R. # "Beyond the VaR Horizon" # 2001, Quants Review No. 37 # Assumes an input of regular period returns. # FUNCTION: if (class(R) == "numeric") { #single column data BVaR = VaR(R) * periods^(1/(mean(R)-1)) result = BVaR } else { #multi-column data if (class(R) == "timeSeries") { R = R@Data } if (class(R) == "vector") { R = array(R=R) } class(R) columns = ncol(R) columnnames=colnames(R) for(column in 1:columns) { r = as.vector(R[,column]) if (!is.numeric(r)) stop("The selected column is not numeric") BVaR = VaR(r) * periods^(1/(mean(r)-1)) BVaR=array(BVaR) if (column==1) { #create data.frame result=data.frame(BVaR=BVaR) } else { BVaR=data.frame(BVaR=BVaR) result=cbind(result,BVaR) } } #end columns loop colnames(result)<-columnnames } # end data type conditionals # Return Value: result } # ------------------------------------------------------------------------------ VaR.column = function(R, p=0.99, modified = TRUE,firstcolumn=1) { # @author Brian G. Peterson # Description: #Wrapper function to handle multi-column VaR calculations # data type conditionals if (class(R) == "numeric") { R = as.matrix(R) } if (class(R) == "matrix") { R = R } if (class(R) == "data.frame") { R = R } if (class(R) == "timeSeries") { R = R@Data } if (class(R) == "vector") { R = array(R=R) } class(R) columns = ncol(R) columnnames=colnames(R) for(column in firstcolumn:columns) { r = as.vector(R[,column]) if (!is.numeric(r)) stop("The selected column is not numeric") VaR = VaR.CornishFisher(r,p,modified) #result = VaR VaR=array(VaR) if (column==firstcolumn) { #create data.frame result=data.frame(VaR=VaR) } else { VaR=data.frame(VaR=VaR) result=cbind(result,VaR) } } #end columns loop colnames(result)<-columnnames # Return Value: result } # ------------------------------------------------------------------------------ VaR.Marginal = function(R, p=0.99, modified = TRUE, weightingvector) { # @author Brian G. Peterson # Description: # Function to implement Marginal VaR # # R Returns of your components # p probability to calculate VaR over # modified use modified VaR or traditional VaR # weightingvector to calculate portfolio returns with # # @returns data frame with total VaR of the portfolio plus Marginal VaR for each component # Setup # data type conditionals if (class(R) == "numeric") { R = as.matrix(R) } if (class(R) == "matrix") { R = R } if (class(R) == "data.frame") { R = R } if (class(R) == "timeSeries") { R = R@Data } if (class(R) == "vector") { R = array(R=R) } class(R) if (ncol(weightingvector) != ncol(R)) stop ("The Weighting Vector and Return Collection do not have the same number of Columns.") columns = ncol(R) columnnames=c("PortfolioVaR",colnames(R)) # Function # first, get the numbers for the whole portfolio portfolioR = pfolioReturn(R,weightingvector) portfolioVaR = VaR.CornishFisher(portfolioR,p,modified) pVaR = array (portfolioVaR) result=data.frame(pVaR=pVaR) for(column in 1:columns) { # calculate a multiplication factor, because the results don't seem to make sense # unless the weighting vector always equals the same sum weightfactor = sum(weightingvector)/sum(weightingvector[,-column]) # if we do need it # weightfactor = 1 # if we don't need it subportfolioR = pfolioReturn(R[ ,-column],weightingvector[ ,-column]*weightfactor) subportfolioVaR = VaR.CornishFisher(subportfolioR,p,modified) marginalVaR = subportfolioVaR - portfolioVaR mVaR = array(marginalVaR) mVaR = data.frame(mVaR=mVaR) result=cbind(result,mVaR) } #end columns loop # check our result # this check would be used for Incremental/Component VaR, not Marginal VaR # if (portfolioVaR != sum(result[,-1])) warning (paste("The VaR of the portfolio ",portfolioVaR," does not match the sum of VaR.Marginal's ",sum(result[,-1]))) colnames(result)<-columnnames # Return Value: result } # end function VaR.Marginal ################################################################################ # $Log: extra_moments.R,v $ # Revision 1.11 2007/03/05 13:24:24 brian # - add deprecated messages to top of file with link to PerformanceAnalytics # # Revision 1.10 2007/02/01 12:38:53 brian # - consolidate StdDev and std fns in performance-analytics.R # Bug 890 # # Revision 1.9 2007/01/30 19:17:24 brian # - change function from Incremental to Marginal VaR, previously incorrectly named # Bug 843 # # Revision 1.8 2007/01/30 15:50:16 brian # - standardize function names in preparation for packaging # Bug 890 # # Revision 1.7 2007/01/26 13:23:16 brian # - update comments for parameters and returns on functions # # Revision 1.6 2006/11/29 21:34:36 brian # - change the method for omega to avoid ecdf fatal error # Bug 840 # # Revision 1.5 2006/10/15 14:03:57 brian # - fix typo on weightfactor modifier for portfolio instrument weights # - turn off weightfactor adjustment by default # # Revision 1.4 2006/10/14 16:38:43 brian # - initial revision of VaR.Marginal function, insufficiently tested # Bug 843 # # Revision 1.3 2006/09/12 14:01:04 brian # - add VaR.column and VaR.Beyond calculations # - merge minor changes # # Revision 1.2 2006/09/12 13:07:27 peter # - snapshot 2006-08-23 # # Revision 1.1 2006/09/12 12:17:53 brian # - initial revision posted to r-sig-finance list # ################################################################################