Title: | Burns Statistics Financial |
---|---|
Description: | A suite of functions for finance, including the estimation of variance matrices via a statistical factor model or Ledoit-Wolf shrinkage. |
Authors: | Burns Statistics |
Maintainer: | Pat Burns <[email protected]> |
License: | Unlimited |
Version: | 1.3 |
Built: | 2024-10-31 21:20:31 UTC |
Source: | CRAN |
Computes (and possibly generates a contour plot of) the alpha proxy – a measure of the effect that volatility and correlation have on the utility of the investor. As the name might suggest, it is in the same units as alpha (that is, expected returns).
alpha.proxy(weight = 0.2, vol.man = 0.2, vol.bench = 0.2, vol.other = 0.2, cor.man = 0.2, cor.bench = 0.2, plot.it = TRUE, transpose = FALSE, ...)
alpha.proxy(weight = 0.2, vol.man = 0.2, vol.bench = 0.2, vol.other = 0.2, cor.man = 0.2, cor.bench = 0.2, plot.it = TRUE, transpose = FALSE, ...)
weight |
a number or vector of the fraction of the value of the investor's entire portfolio that is given to the manager. |
vol.man |
a number or vector giving the volatility of the manager's portfolio. |
vol.bench |
a number or vector giving the volatility of the benchmark. |
vol.other |
a number or vector giving the volatility of the rest of the portfolio. |
cor.man |
a number or vector giving the correlation between the manager's portfolio and the rest of the investor's portfolio. |
cor.bench |
a number or vector giving the correlation between the benchmark and the rest of the investor's portfolio. |
plot.it |
logical value.
If |
transpose |
logical value.
If |
... |
additional arguments to |
a vector of the alpha proxies (in basis points) if less than 2 of the first 6 arguments have length more than 1.
Otherwise it is a list (returned invisibly if plot.it
is TRUE
)
with the following components:
x |
one of the vectors of inputs. |
y |
the other vector of inputs. |
z |
a matrix of the computed alpha proxies where rows correspond to
the values in |
call |
a character string of the image of the command that created the object. |
if plot.it
is TRUE
, then a contour plot is created.
An error occurs if more than 2 of the first 6 arguments have length greater than 1.
The first 6 arguments are the variables that determine the alpha proxy. The investor is faced with the decision of hiring the manager for some portion (the weight) of the portfolio rather than using a replication of the benchmark. If the alpha proxy is positive, then the volatility and correlation of the manager's portfolio is improving whatever outperformance the manager may have (or is offsetting the losses).
This help was last revised 2010 January 05.
Burns, Patrick (2003). "Portfolio Sharpening". Working Paper, Burns Statistics http://www.burns-stat.com/.
# return vector of alpha proxies alpha.proxy(weigh=.05, vol.man=.17, cor.man=seq(0, .2, len=21)) # create a contour plot alpha.proxy(weigh=.05, vol.man=seq(.15, .25, len=20), cor.man=seq(0, .2, len=21)) # commands used to create figures in the paper alpha.proxy(vol.man=seq(.15, .25, len=50), weight=seq(.01, .7, leng=60), color.palette=partial.rainbow(start=0, end=.32)) alpha.proxy(cor.man=seq(0, .3, len=50), weight=seq(.01, .7, leng=60), color.palette=partial.rainbow(start=.07)) alpha.proxy(cor.man=seq(0, .3, len=50), vol.man=seq(.15, .25, leng=60), color.palette=partial.rainbow(start=0))
# return vector of alpha proxies alpha.proxy(weigh=.05, vol.man=.17, cor.man=seq(0, .2, len=21)) # create a contour plot alpha.proxy(weigh=.05, vol.man=seq(.15, .25, len=20), cor.man=seq(0, .2, len=21)) # commands used to create figures in the paper alpha.proxy(vol.man=seq(.15, .25, len=50), weight=seq(.01, .7, leng=60), color.palette=partial.rainbow(start=0, end=.32)) alpha.proxy(cor.man=seq(0, .3, len=50), weight=seq(.01, .7, leng=60), color.palette=partial.rainbow(start=.07)) alpha.proxy(cor.man=seq(0, .3, len=50), vol.man=seq(.15, .25, leng=60), color.palette=partial.rainbow(start=0))
Creates a variance matrix based on the principal components of the variables that have no missing values.
factor.model.stat(x, weights = seq(0.5, 1.5, length.out = nobs), output = "full", center = TRUE, frac.var = 0.5, iter.max = 1, nfac.miss = 1, full.min = 20, reg.min = 40, sd.min = 20, quan.sd = 0.9, tol = 0.001, zero.load = FALSE, range.factors = c(0, Inf), constant.returns.okay = FALSE, specific.floor = 0.1, floor.type = "quantile", verbose=2)
factor.model.stat(x, weights = seq(0.5, 1.5, length.out = nobs), output = "full", center = TRUE, frac.var = 0.5, iter.max = 1, nfac.miss = 1, full.min = 20, reg.min = 40, sd.min = 20, quan.sd = 0.9, tol = 0.001, zero.load = FALSE, range.factors = c(0, Inf), constant.returns.okay = FALSE, specific.floor = 0.1, floor.type = "quantile", verbose=2)
x |
required.
A numeric matrix.
The rows are observations and the columns are the variables.
In finance, this will be a matrix of returns where the rows are
times and the columns are assets.
For the default value of |
weights |
a vector of observation weights, or Equal weights can be specified with Otherwise, the length must be equal to either
the original number of rows
in |
output |
a character string indicating the form of the result.
It must partially match one of: |
center |
either a logical value or a numeric vector with length equal to
the number of columns in |
frac.var |
a control on the number of factors to use – the number of factors
is chosen so that the factors account for (just over) |
iter.max |
the maximum number of times to iterate the search for principal factors of the variables with complete data. |
nfac.miss |
a vector of integers giving the number of factors to use in regressions
for variables with missing values.
The number of factors used is equal to the i-th element of
|
full.min |
an integer giving the minimum number of variables that must have complete data. |
reg.min |
the minimum number of non-missing values for a variable in order for a regression to be performed on the variable. |
sd.min |
the minimum number of non-missing values for a variable in order for the standard deviation to be estimated from the data. |
quan.sd |
the quantile of the standard deviations to use for the standard deviation of variables that do not have enough data for the standard deviation to be estimated. |
tol |
a number giving the tolerance for the principal factor convergence
(using the assets with full data).
If the maximum change in uniquenesses (in the correlation scale) is
less than |
zero.load |
a logical value.
If |
range.factors |
a numeric vector that gives the maximum and minimum number of factors that are allowed to be used. |
constant.returns.okay |
a logical vector: if if the true variance is thought to be non-zero, then
a better alternative to setting this to |
specific.floor |
a number indicating how much uniquenesses should be adjusted upwards.
The meaning of this number depends on the value of the
|
floor.type |
a character string that partially matches one of:
If the value is If the value is |
verbose |
a number indicating the level of warning messages desired. This currently controls warnings: If at least 1, then a warning will be issued if all the values
in If at least 1, then a warning will be issued if there are any
assets with constant returns (unless If at least 2, then a warning will be issued if there are any specific variances that are adjusted from being negative. |
if output
is "full"
, then a variance matrix with dimensions
equal to the number of columns in the input x
.
This has two additional attributes: number.of.factors
that says
how many factors are used in the model, and timestamp
that gives
the date and time that the object was created.
if output
is "systematic"
, then a matrix with dimensions
equal to the number of columns in the input x
that contains
the systematic portion of the variance matrix.
if output
is "specific"
, then a diagonal matrix with dimensions
equal to the number of columns in the input x
that contains
the specific variance portion of the variance matrix.
The full variance matrix is the sum of the systematic and specific matrices.
If output
is "factor"
, then an object of class
"statfacmodBurSt"
which is a list with components:
loadings |
a matrix of the loadings for the correlation matrix. |
uniquenesses |
the uniquenesses for the correlation matrix. That is, the proportion of the variance that is not explained by the factors. Note that if there are uniquenesses that have been modified
via the |
sdev |
the standard deviations for the variables. Note that if there are uniquenesses that have been modified
via the |
constant.names |
A character vector giving the names of the variables that are constant (if any). |
cumulative.variance.fraction |
numeric vector giving the cumulative fraction of the variance explained by (all) the factors. |
timestamp |
character string giving the date and time the calculation was completed. |
call |
an image of the call that created the object. |
Observations that are missing on all variables are deleted. Then a principal components factor model is estimated with the variables that have complete data.
For variables that have missing values, the standard deviation is estimated when there are enough obeservations otherwise a given quantile of the standard deviations of the other assets is used as the estimate. The loadings for these variables are set to be either the average loading for the variables with no missing data, or zero. The loadings for the most important factors are modified by performing a regression with the non-missing data for each variable (if there is enough data to do the regression).
The treatment of variables with missing values can be quite important.
You may well benefit from specializing how missing values are handled to
your particular problem.
To do this, set the output to "factor"
– then you can modify the
loadings (and per force the uniquenesses), and the standard deviations to
fit your situation.
This may include taking sectors and countries into account, for example.
The default settings for missing value treatment are suitable for creating a variance matrix for long-only portfolio optimization – high volatility and average correlation. Take note that the proper treatment of missing values is HIGHLY dependent on the use to which the variance matrix is to be put.
OBSERVATION WEIGHTS. Time weights are quite helpful for estimating variances from returns. The default weighting seems to perform reasonably well over a range of situations.
FACTOR MODEL TO FULL MODEL.
This class of object has a method for fitted
which
returns the variance matrix corresponding to the factor model representation.
The default value for weights
assumes that the last row is the most
recent observation and the first observation is the most ancient observation.
The method of handling missing values used in the function has not been well studied. It seems not to be the worst approach, but undoubtedly can be improved.
The default method of boosting the result away from singularity is completely unstudied. For optimization it is wise to move away from singularity, just how to do that best seems like a research question.
This help was last revised 2014 March 09.
Burns Statistics
fitted.statfacmodBurSt
,
var.shrink.eqcor
, cov.wt
,
slideWeight
.
## Not run: varian1 <- factor.model.stat(retmat) varfac <- factor.model.stat(retmat, nfac=0, zero=TRUE, output="fact") varian2 <- fitted(varfac) # get matrix from factor model varian3 <- factor.model.stat(retmat, nfac=rep(c(5,3,1), c(20,40,1))) ## End(Not run)
## Not run: varian1 <- factor.model.stat(retmat) varfac <- factor.model.stat(retmat, nfac=0, zero=TRUE, output="fact") varian2 <- fitted(varfac) # get matrix from factor model varian3 <- factor.model.stat(retmat, nfac=rep(c(5,3,1), c(20,40,1))) ## End(Not run)
Takes a statistical factor model object and produces the variance matrix that it represents.
## S3 method for class 'statfacmodBurSt' fitted(object, output = "full", ...)
## S3 method for class 'statfacmodBurSt' fitted(object, output = "full", ...)
object |
an object of class |
output |
a character string that must partially match one of:
|
... |
not used, but allows methods for inheriting objects to have additional arguments. |
a numeric matrix of the variance represented by the factor model, or the systematic or specific variance portion of the model.
This has two additional attributes:
number.of.factors |
the number of factors used in the model. |
timestamp |
the date and time at which the model was originally created. |
This help was last revised 2012 February 12.
Burns Statistics
## Not run: varfac <- factor.model.stat(retmat, zero=TRUE, output="factor") # perhaps modify loadings and uniquenesses for missing values varian2 <- fitted(varfac) # get variance matrix from factor model specif <- fitted(varfac, output="specific") # diagonal matrix ## End(Not run)
## Not run: varfac <- factor.model.stat(retmat, zero=TRUE, output="factor") # perhaps modify loadings and uniquenesses for missing values varian2 <- fitted(varfac) # get variance matrix from factor model specif <- fitted(varfac, output="specific") # diagonal matrix ## End(Not run)
Returns a function suitable as the color.palette
argument
to filled.contour
that contains a specified portion of the
rainbow.
partial.rainbow(start = 0, end = 0.35)
partial.rainbow(start = 0, end = 0.35)
start |
a number giving where the colors should start. Valid numbers range from 0 (red) to 1 (also red). |
end |
a number giving where the colors should end. Valid numbers range from 0 (red) to 1 (also red). |
a function similar to rainbow
but with the start
and end
arguments (possibly) changed.
This function was made to facilitate the construction of contour
plots in the alpha.proxy
function, but is of general use.
This help was last revised 2010 January 05.
Burns, Patrick (2003). "Portfolio Sharpening". Working Paper, Burns Statistics http://www.burns-stat.com/.
rainbow
, filled.contour
, alpha.proxy
.
ap1 <- alpha.proxy(cor.man=seq(0, .3, len=50), vol.man=seq(.15, .25, leng=60), plot=FALSE) filled.contour(ap1, color.palette=partial.rainbow(start=.05, end=.3))
ap1 <- alpha.proxy(cor.man=seq(0, .3, len=50), vol.man=seq(.15, .25, leng=60), plot=FALSE) filled.contour(ap1, color.palette=partial.rainbow(start=.05, end=.3))
Returns a vector of weights between 1 and 0 (inclusive). The general form is: some recent weights are 1, some early weights are 0, and weights between these vary linearly. It is allowable for no points to be specified as 0 or 1.
slideWeight(n, fractions = c(0, 1), observations = NULL, locations = NULL)
slideWeight(n, fractions = c(0, 1), observations = NULL, locations = NULL)
n |
the length of the result – the number of observations. |
fractions |
length 2 numeric vector giving the fraction of the way
between 0 and This is ignored if |
observations |
length 2 numeric vector giving the number of observations that should be 1 and the number of observations that should have any weight. The smaller is taken to be the former and the larger as the latter. |
locations |
length 2 numeric vector giving the locations (subscripts) for the ends of the linear slide. The smaller number is the index of the last 0, the larger is the index of the last value smaller than 1. |
a numeric vector of length n
with values within the range
of 0 and 1 (inclusive).
The values are non-decreasing – meaning put more weight on more
recent observations.
The arguments fractions
, observations
and locations
are all to control where the ends of the weights strictly between 0 and 1 are.
Only one of them is used.
locations
takes precedence.
fractions
is used if neither of the other two are given.
This is suitable to give as the weights
argument to
var.shrink.eqcor
and factor.model.stat
.
This help was last revised 2014 March 09.
var.shrink.eqcor
, factor.model.stat
.
# examples assume number of observations is 200 # all weights either 0 or 1 rollwin50 <- slideWeight(200, observations=c(50,50)) # 50 with full weight, 100 more with partial weight swght50.150 <- slideWeight(200, observations=c(50, 150)) # approximately default weights of var.shrink.eqcor and factor.model.stat lindec3 <- slideWeight(200, fractions=c(-1/2, 3/2))
# examples assume number of observations is 200 # all weights either 0 or 1 rollwin50 <- slideWeight(200, observations=c(50,50)) # 50 with full weight, 100 more with partial weight swght50.150 <- slideWeight(200, observations=c(50, 150)) # approximately default weights of var.shrink.eqcor and factor.model.stat lindec3 <- slideWeight(200, fractions=c(-1/2, 3/2))
Returns a three-dimensional array given one or more matrices and instructions on how to combine them.
threeDarr(..., rep = 1, union = TRUE, slicenames = NULL)
threeDarr(..., rep = 1, union = TRUE, slicenames = NULL)
... |
one or more matrices. |
rep |
an integer saying how many times to replicate the slices. |
union |
logical value: if |
slicenames |
a character vector with length equal to the number of slices in the resulting array. |
an array with the first two dimensions being the union or intersection of the first two dimensions of the input matrices, and third dimension equal to the number of input matrices times the number of replications.
The full name of arguments rep
, union
and slicenames
must be given (no abbreviations)
because they come after the three-dots construct.
This help was last revised 2012 January 22.
More general functionality of this sort can be found in the
abind
package.
## Not run: multiple.var <- threeDarr(var1, var2, slicenames=c("standardVar", "crashVar")) reparr <- threeDarr(matrix1, rep=3) ## End(Not run)
## Not run: multiple.var <- threeDarr(var1, var2, slicenames=c("standardVar", "crashVar")) reparr <- threeDarr(matrix1, rep=3) ## End(Not run)
Takes a variance matrix (or 3-dimensional array) and a vector of weights for the benchmark. An object like the input is returned which includes a new asset representing the benchmark.
var.add.benchmark(variance, benchmark.weights, name = "benchmark", sum.to.one = TRUE)
var.add.benchmark(variance, benchmark.weights, name = "benchmark", sum.to.one = TRUE)
variance |
required.
A variance matrix or a three-dimensional array
where each slice of the third dimension is a variance matrix.
This must have dimnames which specify the assets, and it must
include all of the assets named in |
benchmark.weights |
required. A named vector giving the weights of the constituents of the benchmark. |
name |
character string to be used as the asset name for the benchmark. |
sum.to.one |
logical vector stating whether to check and enforce that
|
a matrix or array similar to the input variance
, but including
an additional asset.
The (absolute value of) the weights ideally sum to one. You can give it weights that do not sum to one (perhaps they sum to 100 or the market cap of the benchmark), but you will get a warning that the weights are being adjusted.
If your "benchmark" is something that doesn't sum to 1 (such as
portfolio weights minus benchmark weights), then set the sum.to.one
argument to FALSE
.
This help was last revised 2012 January 20.
var.relative.benchmark
, var.shrink.eqcor
,
factor.model.stat
, threeDarr
.
## Not run: varian.ben <- var.add.benchmark(varian, ftse.constituents, "ftse100") ## End(Not run) var.orig <- array(c(400, 32, 24, 32, 64, 9.6, 24, 9.6, 144), c(3,3), list(c("equities", "bonds", "commodities"), c("equities", "bonds", "commodities"))) var.aa <- var.add.benchmark(var.orig, c(equities=.6, bonds=.4), "e60b40")
## Not run: varian.ben <- var.add.benchmark(varian, ftse.constituents, "ftse100") ## End(Not run) var.orig <- array(c(400, 32, 24, 32, 64, 9.6, 24, 9.6, 144), c(3,3), list(c("equities", "bonds", "commodities"), c("equities", "bonds", "commodities"))) var.aa <- var.add.benchmark(var.orig, c(equities=.6, bonds=.4), "e60b40")
Returns a matrix (or 3-dimensional array) with dimensions one smaller than the input. The returned variance is relative to the benchmark.
var.relative.benchmark(variance, benchmark)
var.relative.benchmark(variance, benchmark)
variance |
required. A variance matrix or a three-dimensional array where each slice of the third dimension is a variance matrix. |
benchmark |
required.
A character string naming which asset in |
a matrix or array similar to the input variance
, but with one
less asset and containing variances that are relative to that asset.
There is a call
attribute which gives the command that created
the object (and hence the benchmark to which the object is relative).
This help was last revised 2012 January 20.
var.add.benchmark
, var.shrink.eqcor
,
factor.model.stat
, threeDarr
.
var.orig <- array(c(400, 32, 24, 32, 64, 9.6, 24, 9.6, 144), c(3,3), list(c("equities", "bonds", "commodities"), c("equities", "bonds", "commodities"))) var.aa <- var.add.benchmark(var.orig, c(equities=.6, bonds=.4), "e60b40") var.rel <- var.relative.benchmark(var.aa, "e60b40")
var.orig <- array(c(400, 32, 24, 32, 64, 9.6, 24, 9.6, 144), c(3,3), list(c("equities", "bonds", "commodities"), c("equities", "bonds", "commodities"))) var.aa <- var.add.benchmark(var.orig, c(equities=.6, bonds=.4), "e60b40") var.rel <- var.relative.benchmark(var.aa, "e60b40")
Returns a variance matrix that shrinks towards the equal correlation matrix – a Ledoit-Wolf estimate.
var.shrink.eqcor(x, weights = seq(0.5, 1.5, length = nt), shrink = NULL, center = TRUE, vol.shrink = 0, sd.min = 20, quan.sd = 0.9, tol = 1e-4, compatible = FALSE, verbose=2)
var.shrink.eqcor(x, weights = seq(0.5, 1.5, length = nt), shrink = NULL, center = TRUE, vol.shrink = 0, sd.min = 20, quan.sd = 0.9, tol = 1e-4, compatible = FALSE, verbose=2)
x |
required.
A numeric matrix.
The rows are observations and the columns are the variables.
In finance, this will be a matrix of returns where the rows are
times and the columns are assets.
For the default value of |
weights |
a numeric vector giving the observation weights, or Equal weights can be specified with Otherwise, this must be a
vector of non-negative numbers that is as long as the number
of observations (rows of |
shrink |
either |
center |
either a single logical value, or a numeric vector as long as
the number of columns of |
vol.shrink |
a number between zero and one (inclusive) that says how much to shrink the standard deviations towards the mean standard deviation. |
sd.min |
a single integer giving the minimum number of observations needed
in a column of |
quan.sd |
a single number in the range of zero to one (inclusive) that says what quantile of the (used) standard deviations to use as the estimate of standard deviation for columns without enough (or any) data. |
tol |
a single number indicating how large the smallest eigenvalues
of the answer should be.
All eigenvalues are made to be no smaller than |
compatible |
a logical value.
If |
verbose |
a number indicating the level of warning messages desired. This currently controls only one warning: If at least 1, then a warning will be issued if all the values
in |
an estimate of the variance matrix of x
.
The sample variance is shrunk towards equal correlation.
This has two additional attributes:
shrink |
the estimated or input amount of shrinkage towards the equal correlation matrix from the sample variance. |
timedate |
the date and time at which the computation was done. |
Time weights are quite helpful for estimating variances from returns. The default weighting seems to perform reasonably well over a range of situations. However, time weighting was not studied for this estimator.
The default value for weights
assumes that the last row is the most
recent observation and the first observation is the most ancient observation.
The method of handling missing values used in the function has not been studied (at all).
The method of boosting the result away from singularity is completely unstudied. For optimization it is wise to move away from singularity, just how to do that best seems like a research question. The method used boosts the smallest eigenvalues, it might be better to increase the diagonal.
This help was last revised 2014 March 09.
Burns Statistics
Olivier Ledoit and Michael Wolf (2004) "Honey, I shrunk the sample covariance matrix". The Journal of Portfolio Management, volume 30, number 4.
factor.model.stat
, cov.wt
,
slideWeight
.
## Not run: var1 <- var.shrink.eqcor(return.matrix) var.unweighted <- var.shrink.eqcor(return.matrix, weights=1) ## End(Not run)
## Not run: var1 <- var.shrink.eqcor(return.matrix) var.unweighted <- var.shrink.eqcor(return.matrix, weights=1) ## End(Not run)