push_sga | R Documentation |
Update the trailing eigen values and eigen vectors of streaming asset return data, with a row of new returns, using the SGA algorithm.
push_sga(retsn, eigenval, eigenvec, eigenret, meanv, varv, lambda, gamma)
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. |
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.
Void (no return value - modifies the trailing eigen values, eigen vectors, the return means, and the return variances in place).
## 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)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.