|
| 1 | +import numpy as np |
| 2 | +import pytest |
| 3 | +from numpy.testing import assert_allclose |
| 4 | + |
| 5 | +from linearmodels.asset_pricing.model import LinearFactorModelGMM |
| 6 | +from linearmodels.tests.asset_pricing._utility import generate_data, get_all |
| 7 | + |
| 8 | + |
| 9 | +@pytest.fixture(params=['numpy', 'pandas']) |
| 10 | +def data(request): |
| 11 | + return generate_data(nportfolio=10, output=request.param) |
| 12 | + |
| 13 | + |
| 14 | +def test_linear_model_gmm_moments_jacobian(data): |
| 15 | + mod = LinearFactorModelGMM(data.portfolios, data.factors) |
| 16 | + res = mod.fit(cov_type='robust', disp=0, debiased=False) |
| 17 | + params = np.r_[res.betas.values.ravel(), |
| 18 | + res.risk_premia.values.ravel(), |
| 19 | + mod.factors.ndarray.mean(0)] |
| 20 | + mod_mom = mod._moments(params[:, None], True) |
| 21 | + |
| 22 | + mom = [] |
| 23 | + p = mod.portfolios.ndarray |
| 24 | + f = mod.factors.ndarray |
| 25 | + n = f.shape[0] |
| 26 | + fc = np.c_[np.ones((n, 1)), f] |
| 27 | + mu = f.mean(0)[None, :] |
| 28 | + lam = res.risk_premia.values[None, :] |
| 29 | + x = f - mu + lam |
| 30 | + b = res.betas.values |
| 31 | + for i in range(p.shape[1]): |
| 32 | + eps = p[:, i:(i + 1)] - x @ b[[i]].T |
| 33 | + for j in range(fc.shape[1]): |
| 34 | + mom.append(eps * fc[:, [j]]) |
| 35 | + mom.append(f - mu) |
| 36 | + mom = np.hstack(tuple(mom)) |
| 37 | + |
| 38 | + mod_jac = mod._jacobian(params, True) |
| 39 | + jac = np.zeros((mom.shape[1], params.shape[0])) |
| 40 | + nport, nf = p.shape[1], f.shape[1] |
| 41 | + # 1,1 |
| 42 | + jac[:(nport * (nf + 1)), :nport * nf] = np.kron(np.eye(nport), fc.T @ x / n) |
| 43 | + # 1, 2 |
| 44 | + col = [] |
| 45 | + for i in range(nport): |
| 46 | + col.append(fc.T @ np.ones((n, 1)) @ b[[i]] / n) |
| 47 | + col = np.vstack(tuple(col)) |
| 48 | + jac[:(nport * (nf + 1)), nport * nf:nport * nf + nf] = col |
| 49 | + # 1, 3 |
| 50 | + col = [] |
| 51 | + for i in range(nport): |
| 52 | + col.append(-fc.T @ np.ones((n, 1)) @ b[[i]] / n) |
| 53 | + col = np.vstack(tuple(col)) |
| 54 | + jac[:(nport * (nf + 1)), -nf:] = col |
| 55 | + # 2,2 |
| 56 | + jac[-nf:, -nf:] = np.eye(nf) |
| 57 | + |
| 58 | + assert_allclose(mom, mod_mom) |
| 59 | + assert_allclose(jac, mod_jac) |
| 60 | + |
| 61 | + me = mom - mom.mean(0)[None, :] |
| 62 | + s = me.T @ me / n |
| 63 | + s = (s + s.T) / 2 |
| 64 | + cov = np.linalg.inv(jac.T @ np.linalg.inv(s) @ jac) / n |
| 65 | + cov = (cov + cov.T) / 2 |
| 66 | + assert_allclose(np.diag(cov), np.diag(res.cov), rtol=5e-3) |
| 67 | + get_all(res) |
| 68 | + |
| 69 | + |
| 70 | +@pytest.mark.skip |
| 71 | +def test_linear_model_gmm_smoke_iterate(data): |
| 72 | + mod = LinearFactorModelGMM(data.portfolios, data.factors) |
| 73 | + res = mod.fit(cov_type='robust', disp=5, steps=20) |
| 74 | + get_all(res) |
| 75 | + |
| 76 | + |
| 77 | +@pytest.mark.skip |
| 78 | +def test_linear_model_gmm_smoke_risk_free(data): |
| 79 | + mod = LinearFactorModelGMM(data.portfolios, data.factors, risk_free=True) |
| 80 | + res = mod.fit(cov_type='robust', disp=10) |
| 81 | + get_all(res) |
| 82 | + |
| 83 | + |
| 84 | +@pytest.mark.skip |
| 85 | +def test_linear_model_gmm_kernel_smoke(data): |
| 86 | + mod = LinearFactorModelGMM(data.portfolios, data.factors) |
| 87 | + res = mod.fit(cov_type='kernel', disp=10) |
| 88 | + get_all(res) |
| 89 | + |
| 90 | + |
| 91 | +@pytest.mark.skip |
| 92 | +def test_linear_model_gmm_kernel_bandwidth_smoke(data): |
| 93 | + mod = LinearFactorModelGMM(data.portfolios, data.factors) |
| 94 | + res = mod.fit(cov_type='kernel', bandwidth=10, disp=10) |
| 95 | + get_all(res) |
| 96 | + |
| 97 | + |
| 98 | +@pytest.mark.skip |
| 99 | +def test_linear_model_gmm_cue_smoke(data): |
| 100 | + mod = LinearFactorModelGMM(data.portfolios, data.factors, risk_free=True) |
| 101 | + res = mod.fit(cov_type='robust', disp=10, use_cue=True) |
| 102 | + get_all(res) |
0 commit comments