Skip to content

Instantly share code, notes, and snippets.

@timelyportfolio
Last active August 29, 2015 14:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save timelyportfolio/e5728c8c7fb45dbdb6e0 to your computer and use it in GitHub Desktop.
Save timelyportfolio/e5728c8c7fb45dbdb6e0 to your computer and use it in GitHub Desktop.
calculate Ekholm ActiveAlpha , ActiveBeta , SelectionShare , TimingShare in R

Anders Ekholm's Decomposition of Mutual Fund Returns

Calculate Ekholm SelctionShare & TimingShare in R based on TimelyPortfolio post SelectionShare & TimingShare | Masterfully Written by Delightfully Responsive Author.

Example with Fidelity Contrafund (FCNTX)

library(Quandl)
library(xts)
library(pipeR)

# get function from this gist
source(paste0(
  "https://gist.githubusercontent.com/timelyportfolio/e5728c8c7fb45dbdb6e0",
  "/raw/e124379f19225fcdee18f30cb848da6fc6cae764/ekholm.R"
))

f <- Quandl("KFRENCH/FACTORS_D",type = "xts") / 100

"FCNTX" %>>%
  getSymbols( from = "1896-01-01", auto.assign = F ) %>>%
  ( 
    structure(
      ROC( .[,6], n = 1, type  = "discrete" )
      ,dimnames = list(
        NULL
        ,gsub(x = colnames(.)[6], pattern  = "[\\.]Adjusted", replacement = "")
      )
    )
  ) %>>%
  merge(f) %>>% # Quandl("KFRENCH/FACTORS_D",type = "xts") / 100
  na.omit %>>%
  jensen_ekholm
# see post http://timelyportfolio.blogspot.com/2014/10/selectionshare-timingshare-masterfully.html
###### bibliography / reference ##############################################
# perform Ekholm (2012,2014) analysis on mutual fund return data
# Ekholm, A.G., 2012
# Portfolio returns and manager activity:
# How to decompose tracking error into security selection and market timing
# Journal of Empirical Finance, Volume 19, pp 349-358
# Ekholm, Anders G., July 21, 2014
# Components of Portfolio Variance:
# R2, SelectionShare and TimingShare
# Available at SSRN: http://ssrn.com/abstract=2463649
##############################################################################
# return a list with
# 1. a data.frame of ActiveAlpha, ActiveBeta, SelectionShare, and TimingShare
# 2. the first linear regression
jensen_ekholm <- function( data, ticker = NULL ){
library(pipeR)
if(is.null(ticker)) ticker <- colnames(data)[1]
# subtract risk free from manager return
# not sure if better to assume already done or not
data[,ticker] <- data[,ticker] - data[,"RF"]
# convert a guessed Mkt.Rf to Mkt.Rf to standardize
colnames(data)[grep(x=colnames(data),pattern="[Mkt,mkt,MKT][-,~,\\.][Rf,RF,rf]")] = "Mkt.RF"
as.formula ( paste0(ticker, " ~ Mkt.RF" ) ) %>>%
( lm( data = data, . ) -> jensenLM )
jensenLM %>>%
residuals %>>%
(. ^ 2 ) %>>%
(
data.frame(
data
, "fitted_sq" = .
, lapply(data[,2],function(x){
structure(
data.frame( as.numeric(x) ^ 2 )
, names = paste0(names(x),"_sq")
) %>>%
return
}) %>>% ( do.call( cbind, . ) )
) -> return_data_jensen
)
return_data_jensen %>>%
( lm( fitted_sq ~ Mkt.RF_sq, data = . ) )%>>%
coefficients %>>%
( . ^ (1/2) ) %>>%
t %>>%
(
structure(
data.frame(.),
names = c("ActiveAlpha", paste0("ActiveBeta_",colnames(.)[-1]))
)
) %>>%
(
data.frame(
.
, "SelectionShare" = .$ActiveAlpha ^ 2 / (var(return_data_jensen[,ticker]) * (nrow(return_data_jensen) - 1) / nrow(return_data_jensen))
, "TimingShare" = .$ActiveBeta_Mkt.RF_sq ^ 2* mean( return_data_jensen$Mkt.RF_sq ) / (var(return_data_jensen[,ticker]) * (nrow(return_data_jensen) - 1) / nrow(return_data_jensen))
)
) %>>%
(
list( "ekholm" = ., "linmod" = jensenLM )
) %>>%
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment