knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 3.4)
PeerPerformance evaluates the performance of investment funds relative to
their peers, with a correction for luck that is robust to false discoveries.
For each fund $i$ it estimates three peer performance ratios that sum to
one:
The estimators implement the methodology of Ardia and Boudt (2018, Journal of Banking & Finance); the modified Sharpe ratio test follows Ardia and Boudt (2015, Finance Research Letters). A naive percentile rank ignores that many funds may be statistically indistinguishable; the false-discovery-rate (FDR) correction of Storey (2002) corrects for this.
library(PeerPerformance) data("hfdata") # 60 monthly returns for 100 anonymized hedge funds dim(hfdata)
alphaScreening() runs all pairwise tests and returns the three ratios for
each fund. With factors = NULL it compares raw returns; supply a factors
matrix to compare risk-adjusted alphas.
set.seed(1234) rets <- hfdata[, 1:15] sc <- alphaScreening(rets, control = list(nCore = 1)) round(rbind(pipos = sc$pipos, pizero = sc$pizero, pineg = sc$pineg), 3)[, 1:6]
The three ratios sum to one for every fund. A summary() method ranks the
funds and reports the win/loss counts:
summary(sc, top = 3)
The ratios are point estimates; confint() attaches confidence intervals by a
nonparametric peer (pairwise) bootstrap that resamples each fund's peers:
set.seed(1234) round(confint(sc, parm = "pipos")[1:6, ], 3)
The plot() method reproduces the Ardia and Boudt (2018) screening plot
(funds sorted by performance; stacked out-/equal-/under-performance bars with
the naive percentile-rank diagonal):
plot(alphaScreening(hfdata[, 1:30], control = list(nCore = 1)))
round(sharpe(rets[, 1:6]), 3) round(msharpe(rets[, 1:6], level = 0.95), 3)
Equality of two funds' (modified) Sharpe ratios is tested with
sharpeTesting() / msharpeTesting(). The asymptotic test is the default; a
studentized bootstrap (recommended for short or autocorrelated series) is
requested with control = list(type = 2).
res <- msharpeTesting(hfdata[, 1], hfdata[, 2], level = 0.95) c(dmsharpe = res$dmsharpe, tstat = res$tstat, pval = res$pval)
sharpeScreening() and msharpeScreening() build the peer performance ratios
from Sharpe (resp. modified Sharpe) comparisons instead of alphas.
The Y argument (or the convenience wrapper targetPeerPerformance()) screens
a chosen fund, or subset of funds, against a separate universe.
focal <- hfdata[, 1] peers <- hfdata[, 11:40] res_xy <- alphaScreening(focal, Y = peers, control = list(nCore = 1)) round(c(pizero = res_xy$pizero, pipos = res_xy$pipos, pineg = res_xy$pineg), 3)
All screening/testing functions share a control list. Common fields include
nCore (parallel cores), lambda (the $\lambda$ threshold for $\hat\pi^0$,
NULL = data-driven), gammaPos/gammaNeg (the one-sided thresholds, default
0.4/0.6), hac (HAC standard errors), and for the Sharpe/mSR routines
type (asymptotic/bootstrap), nBoot, and bBoot. See ?alphaScreening.
Note that with the data-driven lambda (the default) the bias correction of
$\hat\pi^0$ dominates the run time on large universes. Setting
control = list(fastAdjust = TRUE) inverts it in vectorised form and is
several times faster, at the price of differing from the published code path
by a few $10^{-5}$; and setting a fixed lambda skips the selection entirely.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.