The TVMVP package implements a method of estimating a time dependentcovariance matrix based on time series data using principal componentanalysis on kernel weighted data. The package also includes a hypothesistest of time-invariant covariance, and methods for implementing thetime-dependent covariance matrix in a portfolio optimization setting.This package is an R implementation of the method proposed in Fan etal. (2024). The original authors provide a Matlab implementation athttps://github.com/RuikeWu/TV-MVP.
The local PCA method, method for determining the number of factors,and associated hypothesis test are based on Su and Wang (2017). Theapproach to time-varying portfolio optimization follows Fan etal. (2024). The regularisation applied to the residual covariance matrixadopts the technique introduced by Chen et al. (2019).
You can install the development version of TVMVP fromGitHub with:
devtools::install_gitbub("erilill/TV-MVP")provided that the package “devtools” has been installedbeforehand.
After installing the package, you attach the package by running thecode:
library(TVMVP)For this example we will use simulated data, however most use casesfor this package will be using financial data. This can be accessedusing one of the many API’s available in R and elsewhere.
set.seed(123)uT<-100# Number of time periodsup<-20# Number of assetsreturns<-matrix(rnorm(uT* up,mean =0.001,sd =0.02),ncol = up)For this example we will give usage examples using the methods of theR6 classTVMVP, and a brief example of how to use thefunctions if this is your preferred method of implementation
We start by initializing the object of classTVMVP andset the data:
tvmvp_obj<- TVMVP$new()tvmvp_obj$set_data(returns)#> ℹ data set "16.22 kB" with 100 rows and 20 columnsThen we determine the number of factors and conduct the hypothesistest:
tvmvp_obj$determine_factors(max_m=5)#> ! use default Silverman bandwidth#> ℹ using max_m = 5 and bandwidth = 0.200158593074818#> [1] 1tvmvp_obj$get_optimal_m()#> [1] 1tvmvp_obj$hyptest(iB=10)# Use larger iB in practice#> Computing ■■■■■■■ 20% | ETA: 8s#> Computing ■■■■■■■■■■ 30% | ETA: 7sComputing ■■■■■■■■■■■■■ 40% | ETA: 6sComputing ■■■■■■■■■■■■■■■■ 50% | ETA: 5sComputing ■■■■■■■■■■■■■■■■■■■ 60% | ETA: 4sComputing ■■■■■■■■■■■■■■■■■■■■■■ 70% | ETA: 3sComputing ■■■■■■■■■■■■■■■■■■■■■■■■■ 80% | ETA: 2sComputing ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 90% | ETA: 1s J_pT = 34.7556, p-value = 0.0000: Strong evidence that the covariance is time-varying.tvmvp_obj#> ℹ Object of TVMVP#> data set "16.22 kB" with 100 rows and 20 columns#> - bandwidth = 0.200158593074818#> - max_m = 5#> - optimal_m = 1#> - test statistic = 34.7556191258208 with bootstrap p-value = 0#> run `get_optimal_m()`The functiondetermine_factors uses a BIC-typeinformation criterion in order to determine the optimal number offactors to be used in the model. More information can be seen in section2.2 of the thesis. The input variables are the data matrixreturns, the max number of factors to be testedmax_m, and the bandwidth to be usedbandwidth.The package offers the functionality of computing the bandwidth usingSilverman’s rule of thumb with the functionsilverman(),however other methods could be used. The function outputs the optimalnumber of factorsoptimal_m, and the values of theinformation criteria for the different number of factorsIC_values.
hyptest implements the hypothesis test of constantfactor loadings introduced by Su & Wong (2017). Under someconditions, the test statistic\(J\)follows a standard normal distribution under the null. However, the testhave been proven to be somewhat unreliable in finite sample usage, whichis why the option of computing a bootstrap p-value is included. Moreinformation can be found in section 2.3 in the thesis. The function takethe input: a data matrix of multiple time seriesreturns,the number of factorsm, the number of bootstrapreplicationsiB, and the kernel functionkernel_func. The package offers the Epanechnikov kernel,however others could also be used.
The next step, and the most relevant functionality is the portfoliooptimization. The package offers two functions for this purpose:expanding_tvmvp which implements a expanding window inorder to evaluate the performance of a minimum variance portfolioimplemented using the time-varying covariance matrix, andpredict_portfolio which implements an out of sampleprediction of the portfolio.
Note that these functions expect log returns and log risk freerate.
mvp_result<- tvmvp_obj$expanding_tvmvp(initial_window =60,rebal_period =5,max_factors =10,return_type ="daily",rf =NULL)mvp_result#>#> ── Expanding Window Portfolio Analysis ─────────────────────────────────────────#> ────────────────────────────────────────────────────────────────────────────────#>#> ── Summary Metrics ──#>#> Method CER MER SD SR MER_ann#> Time-Varying MVP 0.1491042 0.003727605 0.008475585 0.4398050 0.9393564#> Equal Weight 0.1382776 0.003456941 0.004270192 0.8095516 0.8711491#> SD_ann#> 0.13454575#> 0.06778719#> ────────────────────────────────────────────────────────────────────────────────#> ── Detailed Components ──#>#> The detailed portfolio outputs are stored in the following elements:#> - Time-Varying MVP: Access via `$TVMVP`#> - Equal Weight: Access via `$Equal`plot(mvp_result)
Theexpanding_tvmvp function takes the input:returns a\(T\times p\)data matrix,initial_window which is the initial holdingwindow used for estimation,rebal_period which is thelength of the rebalancing period to be used in the evaluation,max_factors used in the determination of the optimal numberof factors,return_type can be set to “daily”, “weekly”,and “monthly”, and is used for annualization of the results,kernel_func, andrf which denotes the riskfree rate, this can be input either as a scalar or at
prediction<- tvmvp_obj$predict_portfolio(horizon =21,min_return =0.5,max_SR =TRUE)prediction#>#> ── Portfolio Optimization Predictions ──────────────────────────────────────────#> ────────────────────────────────────────────────────────────────────────────────#>#> ── Summary Metrics ──#>#> Method expected_return risk sharpe#> Minimum Variance Portfolio 0.03355982 0.01843029 0.3973543#> Maximum SR Portfolio 0.06666808 0.02597654 0.5600503#> Return-Constrained Portfolio 0.50000000 0.25855695 0.4219919#> ────────────────────────────────────────────────────────────────────────────────#> ── Detailed Components ──#>#> The detailed portfolio outputs are stored in the following elements:#> - MVP: Use object$MVP#> - Maximum Sharpe Ratio Portfolio: Use object$max_SR#> - Minimum Variance Portfolio with Return Constraint: Use object$MVPConstrainedweights<- prediction$getWeights("MVP")Thepredict_portfolio functions makes out of samplepredictions of the portfolio performance. The functions offers threedifferent methods of portfolio optimization: Minimum variance, Minimumvariance with minimum returns constraint, and maximum Sharpe ratioportfolio. The minimum variance portfolio is the default portfolio andwill always be computed when running this function. The minimum returnsconstraint is set by imputing somemin_return-value whenrunning the function, important to note is that the minimum returnconstraint is set for the entire horizon and is not a daily constraint.The maximum SR portfolio is computed whenmax_SR is set toTRUE.
If the pre-built functions does not fit your purpose, you can utilizethe covariance function by running:
cov_mat<- tvmvp_obj$time_varying_cov()Which outputs the covariance matrix weighted around the lastobservation in returns.
Below you see an example of how to use the functions instead:
# Determine number of factorsm<-determine_factors(returns = returns,max_m =10,bandwidth =silverman(returns))$optimal_mm# Run test of constant loadingshypothesis_test<-hyptest(returns = returns,m = m,B =10,# Use larger B in practice )# Expanding window evaluationmvp_result<-expanding_tvmvp(obj = tvmvp_obj,initial_window =60,rebal_period =5,max_factors =10,return_type ="daily",kernel_func = epanechnikov_kernel,rf =1e-04)mvp_result# Optimize weights and predict performance out-of-sampleprediction<-predict_portfolio(obj = tvmvp_obj,horizon =21,m =10,kernel_func = epanechnikov_kernel,min_return=0.5,max_SR =TRUE,rf =1e-04)predictionweights<- prediction$getWeights("MVP")# For custom portfolio optimization, compute the time dependent covariance:cov_mat<-time_varying_cov(obj = tvmvp_obj,max_factors =5,bandwidth =silverman(returns),kernel_func = epanechnikov_kernel,M0 =10,rho_grid =seq(0.005,2,length.out =30),floor_value =1e-12,epsilon2 =1e-6,full_output =FALSE)These have the same functionality as the methods, however using theclass methods is neater as the necessary parameters are cached in theobject.
Lillrank, E. (2025). A Time-Varying Factor Approach to CovarianceEstimation.
Su, L., & Wang, X. (2017). On time-varying factor models:Estimation and testing. Journal of Econometrics, 198(1), 84–101.
Fan, Q., Wu, R., Yang, Y., & Zhong, W. (2024). Time-varyingminimum variance portfolio. Journal of Econometrics, 239(2), 105339.
Chen, J., Li, D., & Linton, O. (2019). A new semiparametricestimation approach for large dynamic covariance matrices with multipleconditioning variables. Journal of Econometrics, 212(1), 155–176.