Skip to content

Commit

Permalink
fgx uses gross returns
Browse files Browse the repository at this point in the history
  • Loading branch information
a91quaini committed Apr 5, 2024
1 parent 7947b63 commit 239219b
Show file tree
Hide file tree
Showing 21 changed files with 4,443 additions and 40 deletions.
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
^cran-comments\.md$
^CRAN-SUBMISSION$
^readme.bib
^data-raw$
22 changes: 18 additions & 4 deletions R/data.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#' Test Asset Excess Returns - monthly observations from `01/1970` to `12/2021`
#' Test Asset Excess Returns - monthly observations from `07/1963` to `02/2024`
#'
#' Monthly excess returns on the `25` Size/Book-to-Market double sorted portfolios
#' and the `17` industry portfolios from `01/1970` to `12/2021`.
#' and the `17` industry portfolios from `07/1963` to `02/2024`.
#'
#' @format ## `returns`
#' A data frame with `624` rows and `43` columns:
Expand All @@ -12,9 +12,9 @@
#' @source <https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html>
"returns"

#' Factors - monthly observations from `01/1970` to `12/2021`
#' Factors - monthly observations from `07/1963` to `02/2024`
#'
#' Monthly observations from `01/1970` to `12/2021` of
#' Monthly observations from `07/1963` to `02/2024` of
#' the Fama-French `5` factors and the momentum factor.
#'
#' @format ## `factors`
Expand All @@ -25,3 +25,17 @@
#' }
#' @source <https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html>
"factors"

#' Risk free - monthly observations from `07/1963` to `02/2024`
#'
#' Monthly observations from `07/1963` to `02/2024` of
#' the US risk free asset.
#'
#' @format ## `risk_free`
#' A data frame with `624` rows and `2` columns:
#' \describe{
#' \item{Date}{Date in yyyymm format}
#' \item{...}{risk free observations}
#' }
#' @source <https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html>
"risk_free"
41 changes: 24 additions & 17 deletions R/fgx_factors_test.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
#' pre-whiten the series by fitting a VAR(1),
#' i.e., a vector autoregressive model of order 1.
#'
#' @param returns A `n_observations x n_returns`-dimensional matrix of test asset
#' excess returns.
#' @param gross_returns A `n_observations x n_returns`-dimensional matrix of test asset
#' gross returns.
#' @param control_factors A `n_observations x n_control_factors`-dimensional
#' matrix of control or benchmark factors.
#' @param new_factors A `n_observations x n_new_factors`-dimensional
Expand All @@ -50,16 +50,19 @@
#' control_factors = intrinsicFRP::factors[,2:4]
#' new_factors = intrinsicFRP::factors[,5:7]
#' returns = intrinsicFRP::returns[,-1]
#' RF = intrinsicFRP::risk_free[,-1]
#'
#' gross_returns = returns + 1 + RF
#'
#' output = FGXFactorsTest(
#' returns,
#' gross_returns,
#' control_factors,
#' new_factors
#' )
#'
#' @export
FGXFactorsTest = function(
returns,
gross_returns,
control_factors,
new_factors,
n_folds = 5,
Expand All @@ -69,18 +72,21 @@ FGXFactorsTest = function(
# check function arguments
if (check_arguments) {

CheckData(returns, control_factors)
CheckData(gross_returns, control_factors)
stopifnot("`new_factors` must contain numeric values" = is.numeric(new_factors))
stopifnot("`new_factors` contains more variables (columns) than observations (rows)" = nrow(new_factors) > ncol(new_factors))
stopifnot("`new_factors` must not contain missing values (NA/NaN)" = !anyNA(new_factors))
stopifnot("`n_folds` must be numeric" = is.numeric(n_folds))

}

# set number of new factors
n_new = ncol(new_factors)

# compute moments of data
avg_returns = colMeans(returns)
cov_returns_control_factors = stats::cov(returns, control_factors)
cov_returns_new_factors = stats::cov(returns, new_factors)
avg_returns = colMeans(gross_returns)
cov_returns_control_factors = stats::cov(gross_returns, control_factors)
cov_returns_new_factors = stats::cov(gross_returns, new_factors)

# first lasso selection:
# lasso regression of average returns on the covariances between returns
Expand All @@ -98,7 +104,7 @@ FGXFactorsTest = function(
# lasso regression of each covariance between new factors and returns on
# covariances between control factors and returns
# take the union of the first and all second step selections
for (ii in 1:ncol(new_factors)) {
for (ii in 1:n_new) {

second_lasso = glmnet::cv.glmnet(
x = cov_returns_control_factors,
Expand All @@ -118,16 +124,17 @@ FGXFactorsTest = function(
# OLS regression of average returns on covariances between new factors and returns
# and on the covariances between the selected control factors and returns.
# the selected control factors are the union of the first and all second step selections.
covariances = cbind(
predictors = cbind(
matrix(1, ncol(gross_returns), 1),
cov_returns_new_factors,
cov_returns_control_factors[, idx_selected, drop=FALSE]
)

# cross_sectional_fit = stats::lm(avg_returns ~ covariances)
# compute the SDF coefficients
sdf_coefficients = solve(
t(covariances) %*% covariances,
t(covariances) %*% avg_returns
t(predictors) %*% predictors,
t(predictors) %*% avg_returns
)

## Estimate the Newey-West type covariance estimator of the new factors'
Expand All @@ -138,7 +145,7 @@ FGXFactorsTest = function(
control_factors = control_factors[,idx_selected]
cov_selected = c()

for (ii in 1:ncol(new_factors)) {
for (ii in 1:n_new) {

lasso_fit = glmnet::cv.glmnet(
x = control_factors,
Expand All @@ -159,19 +166,19 @@ FGXFactorsTest = function(

# compute the Newey-West type covariance estimator
covariance = .Call(`_intrinsicFRP_FGXThreePassCovarianceCpp`,
returns,
gross_returns,
control_factors,
new_factors,
sdf_coefficients,
sdf_coefficients[-1],
cov_selected
)

# extract the standard errors
standard_errors = sqrt(diag(covariance)) / sqrt(nrow(returns))
standard_errors = sqrt(diag(covariance)) / sqrt(nrow(gross_returns))

# return a list containing the new factors' SDF coefficients and corresponding
# standard errors
output = list(sdf_coefficients[1:ncol(new_factors)], standard_errors, idx_selected)
output = list(sdf_coefficients[1 + 1:n_new], standard_errors, idx_selected)
names(output) = c("sdf_coefficients", "standard_errors", "controls_selected")

return(output)
Expand Down
11 changes: 9 additions & 2 deletions R/sdf_coefficients.R
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,20 @@ SDFCoefficients = function(
}

# compute the FRP estimate and, eventually, their standard errors
return(.Call(`_intrinsicFRP_SDFCoefficientsCpp`,
output = .Call(`_intrinsicFRP_SDFCoefficientsCpp`,
returns,
factors,
misspecification_robust,
include_standard_errors,
hac_prewhite,
target_level_gkr2014_screening
))
)

if (target_level_gkr2014_screening > 0) {
# Transform c++ indices (starting at 0) into R indices (starting at 1).
output$selected_factor_indices = output$selected_factor_indices + 1
}

return(output)

}
Loading

0 comments on commit 239219b

Please sign in to comment.