--- title: "TVMVP: Overview and Getting Started" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{TVMVP: Overview and Getting Started} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` # Time-Varying Minimum Variance Portfolio (TVMVP) The TVMVP package implements a method for estimating a time-dependent covariance matrix based on time series data using principal component analysis on kernel-weighted data. It also includes: \begin{itemize} \item A BIC-type information criterion for determining the optimal number of factors \item A hypothesis test for time-invariant covariance \item Rolling-window evaluation of portfolio \item Multiple portfolio optimization techniques \end{itemize} This package is an R implementation of the method proposed in Fan et al. (2024). The original authors provide a Matlab implementation at https://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). The approach to time-varying portfolio optimization follows Fan et al. (2024). The regularisation applied to the residual covariance matrix adopts the technique introduced by Chen et al. (2019). ## Example After installing the package, you attach the package by running the code: ```{r example} library(TVMVP) ``` For this example we will use simulated data, however most use cases for this package will be using financial data. This can be accessed using one of the many API's available in R and elsewhere. ```{r data} set.seed(123) uT <- 100 # Number of time periods up <- 20 # Number of assets returns <- matrix(rnorm(uT * up, mean = 0.001, sd = 0.02), ncol = up) ``` For this example we will give usage examples using the methods of the R6 class `TVMVP`, and a brief example of how to use the functions if this is your preferred method of implementation We start by initializing the object of class `TVMVP` and set the data: ```{r initialize} tvmvp_obj <- TVMVP$new() tvmvp_obj$set_data(returns) ``` Then we determine the number of factors and conduct the hypothesis test: ```{r hyptest} tvmvp_obj$determine_factors(max_m=5) tvmvp_obj$get_optimal_m() tvmvp_obj$hyptest(iB=10) # Use larger iB in practice tvmvp_obj ``` The function `determine_factors` uses a BIC-type information criterion in order to determine the optimal number of factors to be used in the model. More information can be seen in section 2.2 of the thesis. The input variables are the data matrix `returns`, the max number of factors to be tested `max_m`, and the bandwidth to be used `bandwidth.` The package offers the functionality of computing the bandwidth using Silverman's rule of thumb with the function `silverman()`, however other methods could be used. The function outputs the optimal number of factors `optimal_m`, and the values of the information criteria for the different number of factors `IC_values`. `hyptest` implements the hypothesis test of constant factor loadings introduced by Su & Wong (2017). Under some conditions, the test statistic $J$ follows a standard normal distribution under the null. However, the test have been proven to be somewhat unreliable in finite sample usage, which is why the option of computing a bootstrap p-value is included. More information can be found in section 2.3 in the thesis. The function take the input: a data matrix of multiple time series `returns`, the number of factors `m`, the number of bootstrap replications `iB`, and the kernel function `kernel_func`. The package offers the Epanechnikov kernel, however others could also be used. The next step, and the most relevant functionality is the portfolio optimization. The package offers two functions for this purpose: `rolling_time_varying_mvp` which implements a rolling window in order to evaluate the performance of a minimum variance portfolio implemented using the time-varying covariance matrix, and `predict_portfolio` which implements an out of sample prediction of the portfolio. Note that these functions expect log returns and log risk free rate. ```{r rolpred} mvp_result <- tvmvp_obj$rolling_time_varying_mvp( initial_window = 60, rebal_period = 5, max_factors = 10, return_type = "daily", rf = NULL ) mvp_result ``` The `rolling_time_varying_mvp` function takes the input: `returns` a $T\times p$ data matrix, `initial_window` which is the initial holding window used for estimation, `rebal_period` which is the length of the rebalancing period to be used in the evaluation, `max_factors` used in the determination of the optimal number of factors, `return_type` can be set to "daily", "weekly", and "monthly", and is used for annualization of the results, `kernel_func`, and `rf` which denotes the risk free rate, this can be input either as a scalar or at $(T-initialwindow)\times 1$ numerical vector. The function outputs relevant metrics for evaluation of the performance of the portfolio such as cumulative excess returns, standard deviation, and Sharpe ratio. ```{r pred} prediction <- tvmvp_obj$predict_portfolio(horizon = 21, min_return = 0.5, max_SR = TRUE) prediction weights <- prediction$getWeights("MVP") ``` The `predict_portfolio` functions makes out of sample predictions of the portfolio performance. The functions offers three different methods of portfolio optimization: Minimum variance, Minimum variance with minimum returns constraint, and maximum Sharpe ratio portfolio. The minimum variance portfolio is the default portfolio and will always be computed when running this function. The minimum returns constraint is set by imputing some `min_return`-value when running the function, important to note is that the minimum return constraint is set for the entire horizon and is not a daily constraint. The maximum SR portfolio is computed when `max_SR` is set to `TRUE.` If the pre-built functions does not fit your purpose, you can utilize the covariance function by running: ```{r cov} cov_mat <- tvmvp_obj$time_varying_cov() ``` Which outputs the covariance matrix weighted around the last observation in returns. Below you see an example of how to use the functions instead: ```{r functionex, eval=FALSE} # Initialize object tvmvp_obj <- TVMVP$new() tvmvp_obj$set_data(returns) # Determine number of factors m <- determine_factors(returns = returns, max_m = 10, bandwidth = silverman(returns))$optimal_m m # Run test of constant loadings hypothesis_test <- hyptest(returns = returns, m = m, B = 10, # Use larger B in practice ) # Rolling window evaluation mvp_result <- rolling_time_varying_mvp( 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-sample prediction <- predict_portfolio(obj = tvmvp_obj, horizon = 21, m = 10, kernel_func = epanechnikov_kernel, min_return=0.5, max_SR = TRUE, rf = 1e-04) prediction weights <- prediction$getWeights("MVP") # For custom portfolio optimization, compute the time dependent covariance: cov_mat <- time_varying_cov(obj = tvmvp_obj, m, 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 the class methods is neater as the necessary parameters are cached in the object. ## References Lillrank, E. (2025). A Time-Varying Factor Approach to Covariance Estimation. 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-varying minimum variance portfolio. Journal of Econometrics, 239(2), 105339. Chen, J., Li, D., & Linton, O. (2019). A new semiparametric estimation approach for large dynamic covariance matrices with multiple conditioning variables. Journal of Econometrics, 212(1), 155–176.