Optimization and Walk-Forward with PortfolioTesteR

knitr::opts_chunk$set(collapse=TRUE, comment="#>", fig.width=7, fig.height=5, dpi=96, cache=FALSE, message=FALSE, warning=FALSE)
set.seed(1)
heavy <- identical(Sys.getenv("NOT_CRAN"), "true")

library(PortfolioTesteR)
data(sample_prices_weekly)

# ---- Grid optimization ----
builder_opt <- function(prices, params, ...) {
  sel <- filter_top_n(calc_momentum(prices, params$lookback), params$n_top)
  weight_equally(sel)
}

grid_opt <- if (heavy) {
  list(lookback = seq(6, 26, by = 2), n_top = c(5, 10, 15))
} else {
  list(lookback = c(8, 12, 26), n_top = c(5, 10))
}

opt <- run_param_grid(
  prices  = sample_prices_weekly,
  grid    = grid_opt,
  builder = builder_opt,
  metric  = NULL,                  # defaults to metric_sharpe()
  name_prefix = "MOM",
  verbose = FALSE,
  light_mode = TRUE,
  precompute_returns = TRUE
)

plot(opt, type = "line", params = "lookback")

# ---- Walk-forward ----
builder_wf <- function(prices, params, ...) {
  weight_equally(filter_top_n(calc_momentum(prices, params$lookback), params$n_top))
}

grid_wf <- if (heavy) {
  list(lookback = c(8, 12, 26, 40), n_top = c(5, 10, 15))
} else {
  list(lookback = c(8, 12), n_top = c(5, 10))
}

wf <- run_walk_forward(
  prices      = sample_prices_weekly,
  grid        = grid_wf,
  builder     = builder_wf,
  metric      = NULL,              # defaults to metric_sharpe()
  is_periods  = 52,
  oos_periods = 26,
  step        = 26,
  verbose     = FALSE,
  light_mode  = TRUE,
  precompute_all = TRUE,
  builder_args = list()
)

plot(wf, type = "parameters")

plot(wf, type = "is_oos", metric = "OOS_Score")

plot(wf, type = "equity")

sessionInfo()
## R version 4.6.1 (2026-06-24)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 26.04.1 LTS
## 
## Matrix products: default
## BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so;  LAPACK version 3.12.0
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## time zone: Etc/UTC
## tzcode source: system (glibc)
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] data.table_1.18.6.1   PortfolioTesteR_0.1.4 rmarkdown_2.32       
## 
## loaded via a namespace (and not attached):
##  [1] cli_3.6.6        knitr_1.52       rlang_1.3.0      xfun_0.61       
##  [5] otel_0.2.0       jsonlite_2.0.0   zoo_1.9-1        xts_0.14.3      
##  [9] TTR_0.24.4       buildtools_1.0.0 ranger_0.18.0    htmltools_0.5.9 
## [13] maketools_1.3.2  sys_3.4.3        sass_0.4.10      glmnet_5.1      
## [17] grid_4.6.1       evaluate_1.0.5   jquerylib_0.1.4  fastmap_1.2.0   
## [21] foreach_1.5.2    yaml_2.3.12      lifecycle_1.0.5  compiler_4.6.1  
## [25] codetools_0.2-20 Rcpp_1.1.2       lattice_0.23-1   digest_0.6.39   
## [29] xgboost_3.2.1.1  R6_2.6.1         splines_4.6.1    shape_1.4.6.1   
## [33] curl_8.1.0       bslib_0.12.0     Matrix_1.7-6     tools_4.6.1     
## [37] iterators_1.0.14 survival_3.8-12  cachem_1.1.0