Skip to content

BUG: Fix the layout of the standard errors of LinearFactorModelGMM - #788

Merged
bashtage merged 4 commits into
mainfrom
lm71-fix-gmm-factor-cue
Oct 12, 2026
Merged

bashtage merged 4 commits into
mainfrom
lm71-fix-gmm-factor-cue

Conversation

@bashtage

Copy link
Copy Markdown
Owner

GMMFactorModelResults.std_errors stacked the standard errors of the alphas on top of the
standard errors of the loadings, and reshaped the vector to one row for each portfolio.
Row i of the table then held the alphas of portfolios i(k+1) to i(k+1)+k instead of the
alpha and the loadings of portfolio i, where k is the number of factors. The cells of
the table were wrong for every model with more than one portfolio, and so were tstats,
pvalues and the loadings in full_summary, which are computed from std_errors.

For a model with 6 portfolios and 2 factors, the loading of the first portfolio on the
first factor, 0.7037, had a standard error of 0.00143, which is the standard error of the
alpha of the second portfolio, where the standard error in cov is 0.0270. Its t-statistic
was 491 instead of 26. The alphas and the standard errors of the risk premia were not
affected, and neither were the other result classes.

The standard errors of the alphas are now the first column and the standard errors of
the loadings of each portfolio follow in the other columns, as they do for
LinearFactorModel and TradedFactorModel.

The test compares the table with the standard errors in cov, found from the names of the
parameters, and with the standard errors of the alphas. It fails without the change for
one and for three factors, with and without a risk-free rate.

LinearFactorModelGMM(...).fit(use_cue=True) minimizes the continuously updated objective
n g' W(theta)^-1 g, where W is the covariance of the moments at theta. It then reported
the objective with the weight matrix of the starting values, which is not the statistic
that was minimized and is larger than it. In simulated samples with 150 observations,
8 portfolios and 2 factors the reported J was 0.4% to 8% above the minimum of the
objective (8.77 against 8.40 in the example of the test).

The J statistic of the CUE is now the objective that the optimizer minimized.

The test minimizes the objective directly with the moment conditions written out, and
compares the minimum with the statistic. It fails without the change.
opt_options is documented as the options that are passed to scipy.optimize.minimize, and all
of its inputs except fun, x0 and args can be overridden. Only the first minimization used
it. The later steps of the estimator (steps > 1) and the minimization of the continuously
updated objective (use_cue=True) were run with the default optimizer and only maxiter, so
that method, tol, bounds, a user callback and the other options were ignored after the
first step. For example, opt_options={"method": "Nelder-Mead"} used Nelder-Mead for the
first step and BFGS for the second.

The options are now passed to every call of minimize, with the same override rules as for
the first step. Fits that do not pass opt_options are unchanged.

The test records the arguments of every call to minimize for steps=3 and for the CUE, and
fails without the change.
…r-cue

# Conflicts:
#	linearmodels/tests/asset_pricing/test_linear_factor_gmm.py
from scipy.optimize import minimize

from linearmodels.asset_pricing.model import LinearFactorModelGMM
import linearmodels.asset_pricing.model as model_module
@codecov

codecov Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.59%. Comparing base (6cbd30b) to head (bfa9c30).
⚠️ Report is 67 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #788      +/-   ##
==========================================
+ Coverage   99.58%   99.59%   +0.01%     
==========================================
  Files         128      128              
  Lines       24188    24500     +312     
  Branches     1809     1824      +15     
==========================================
+ Hits        24087    24401     +314     
+ Misses         40       39       -1     
+ Partials       61       60       -1     
Flag Coverage Δ
adder 99.57% <100.00%> (+0.01%) ⬆️
subtractor 99.57% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@bashtage
bashtage merged commit ac40d98 into main Oct 12, 2026
9 of 10 checks passed
@bashtage
bashtage deleted the lm71-fix-gmm-factor-cue branch October 12, 2026 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants