I'm trying to fit the following model:
$y_t = \left[\begin{matrix} (1-w) & 1 & w \end{matrix}\right] \left[\begin{matrix} d_t \\ \mu_t \\ m_t \end{matrix}\right] + \mathcal{N}(0,\sigma_\eta^2) $
$ \left[\begin{matrix} d_{t+1} \\ \mu_{t+1} \\ m_{t+1} \end{matrix}\right] = \left[\begin{matrix} (1-\alpha) & \alpha & 0 \\ 0 & 1 & 0 \\ 0& 0 & 1 \end{matrix}\right] \left[\begin{matrix} d_t \\ \mu_t\\ m_t \end{matrix}\right] + \mathcal{N}\left(0,\left[\begin{matrix} \sigma_\varepsilon^2 & 0 & 0 \\ 0 & \sigma_\xi^2 & 0 \\ 0 & 0 & 0\end{matrix}\right]\right) $
Where $y_t$ is a weighted average of a state variable $d_t$ and an exogenous variable $m_t$, but I have trouble putting this into the proposed custom statespace models as proposed in https://www.statsmodels.org/dev/examples/notebooks/generated/statespace_custom_models.html.
I don't understand how to implement the exogenous variable $m_t$ into the state equation. Below is the code I have got so far, where $m_t$ is not yet integrated.
class TVRegressionExtended(sm.tsa.statespace.MLEModel):
def __init__(self, y_t, m_t):
exog = np.c_[m_t]
super(TVRegressionExtended, self).__init__(
endog=y_t, exog=exog, k_states=3,
initialization='diffuse')
#These have ok shape. Placeholders since I'm changing them
#in the update() function
self.ssm['design'] = np.array([1, 1, 1])
self.ssm['selection',:2,:2] = np.eye(2)
self.ssm['transition'] = np.array([[1, 1, 0],
[0, 1, 0],
[0, 0, 1]]) #{[0,0], [0,1]} = {1-alpha, alpha}
#will be changed through update
#Positive params
self.positive_parameters = slice(0, 3)
@property
def param_names(self):
return ['std.measure', 'std.return', 'std.mean',
'alpha','weight']
@property
def start_params(self):
params = np.r_[0.001, 0.001, 0.001, 0.8, 0.2]
return params
def transform_params(self, unconstrained):
constrained = unconstrained.copy()
constrained[self.positive_parameters] = constrained[self.positive_parameters]**2
return constrained
def untransform_params(self, constrained):
unconstrained = constrained.copy()
unconstrained[self.positive_parameters] = unconstrained[self.positive_parameters]**0.5
return unconstrained
def update(self, params, **kwargs):
params = super(TVRegressionExtended, self).update(params, **kwargs)
self['obs_cov', 0, 0] = params[0]
self['state_cov',:2,:2] = np.diag(params[1:3])
self['transition', 0, 0] = params[3]
self['transition', 0, 1] = 1-params[3]
self['design', 0,0] = 1-params[4]
self['design', 0,2] = params[4]
I think the solution is to time-vary the transition matrix in some way, but I can't seem to figure out how.