push_sga: Update the trailing eigen values and eigen vectors of...

View source: R/RcppExports.R

push_sgaR Documentation

Update the trailing eigen values and eigen vectors of streaming asset return data, with a row of new returns, using the SGA algorithm.

Description

Update the trailing eigen values and eigen vectors of streaming asset return data, with a row of new returns, using the SGA algorithm.

Usage

push_sga(retsn, eigenval, eigenvec, eigenret, meanv, varv, lambda, gamma)

Arguments

retsn

A vector of new asset returns.

eigenval

A vector of eigen values.

eigenvec

A matrix of eigen vectors.

eigenret

A vector of eigen portfolio returns.

meanv

A vector of trailing means of asset returns.

varv

A vector of the trailing asset variances.

lambda

A decay factor which multiplies the past mean and variance.

gamma

A numeric gain factor which multiplies the past eigenelements.

Details

The function push_sga() updates the trailing eigen values, eigen vectors, and the eigen portfolio returns of streaming asset returns, with a row of new data, using the SGA algorithm. It updates the eigenelements in place, without copying the data in memory.

The streaming asset returns r_t contain multiple columns and the parameter retsn represents a single row of r_t - the asset returns at time t. The elements of the vectors retsn, meanv, and varv represent single rows of data with multiple columns.

The function push_sga() accepts pointers to the arguments eigenval, eigenvec, meanv, and varv, and it overwrites the old values with the new values. It performs the calculation in place, without copying the data in memory, which can significantly increase the computation speed for large matrices.

First, the function push_sga() updates the trailing means \bar{r}_t and variances \sigma^2_t of the streaming asset returns r_t by recursively weighting present and past values using the decay factor \lambda:

\bar{r}_t = \lambda \bar{r}_{t-1} + (1-\lambda) r_t

\sigma^2_t = \lambda \sigma^2_{t-1} + (1-\lambda) (r_t - \bar{r}_t)^2

The past values \bar{r}_{t-1} and \sigma^2_{t-1} are passed in by reference through the variables meanv and varv. The updated values are then passed out by reference.

These recursive formulas are equivalent to the exponentially weighted moving averages of the streaming asset returns r_t.

It then calculates a vector of the eigen portfolio returns:

r^{eigen}_t = \strong{v}_{t-1} \frac{r_t}{\sigma_{t-1}}

Where \strong{v}_{t-1} is the matrix of previous eigen vectors that are passed by reference through the parameter eigenvec. The eigen returns r^{eigen}_t are the returns of the eigen portfolios, with weights equal to the eigen vectors \strong{v}_{t-1}. The eigen weights are applied to the asset returns scaled by their volatilities. The eigen returns r^{eigen}_t are passed by reference through the parameter eigenret.

The function push_sga() then standardizes the columns of the new returns:

\hat{r}_t = \frac{r_t - \bar{r}_t}{\sigma_t}

Finally, the vector of eigen values \Lambda_{j, t} and the matrix of eigen vectors \strong{v}_{j, t} (j is the column index) are then updated using the SGA algorithm:

\Lambda_{j, t} = (1-\gamma) \Lambda_{j, t-1} + \gamma \phi_{j, t-1}

\strong{v}_{j, t} = \strong{v}_{j, t-1} + \gamma \phi_{j, t-1} (\hat{r}_{t} - \phi_{j, t-1} \strong{v}_{j, t-1} - 2 \sum_{i=1}^{j-1} \phi_{i, t-1} \strong{v}_{i, t-1})

Where \phi_{j, t-1} = \hat{r}_{t} \strong{v}_{j, t-1} are the matrix products of the new data times the previous eigen vectors.

The gain factor \gamma determines the strength of the updates, with larger \gamma values giving more weight to the new data. If the asset returns are not stationary, then applying more weight to the new returns reduces the bias of the trailing eigen vectors, but it also increases their variance. Simulation can be used to find the value of the \gamma parameter to achieve the best bias-variance tradeoff.

A description of the SGA algorithm can be found in the package onlinePCA and in the Online PCA paper.

The function push_sga() is written in RcppArmadillo C++ code and it calls the Armadillo function arma::qr_econ() to perform the QR decomposition, to calculate the eigen vectors.

Value

Void (no return value - modifies the trailing eigen values, eigen vectors, the return means, and the return variances in place).

Examples

## Not run: 
# Calculate a time series of returns
retp <- na.omit(rutils::etfenv$returns[, c("IEF", "VTI", "DBC")])
# Calculate the covariance of returns without the last row
nrows <- NROW(retp)
retss <- retp[-nrows]
HighFreq::calc_scale(retss)
meanv <- colMeans(retss)
varv <- sapply(retss, var)
covmat <- cov(retss)
ncols <- NCOL(retss)
# Calculate the eigen decomposition using RcppArmadillo
eigenval <- numeric(ncols) # Allocate eigen values
eigenvec <- matrix(numeric(ncols^2), nc=ncols) # Allocate eigen vectors
HighFreq::calc_eigen(covmat, eigenval, eigenvec)
# Update the eigen decomposition using SGA
eigenret <- numeric(NCOL(retp))
HighFreq::push_sga(retsn=retp[nrows], 
  eigenval=eigenval, eigenvec=eigenvec, 
  eigenret=eigenret, meanv=meanv, varv=varv, lambda=0.9, gamma=0.1)

## End(Not run)


algoquant/HighFreq documentation built on Feb. 9, 2024, 8:15 p.m.