66from __future__ import absolute_import , division
77
88import itertools
9-
109import numpy as np
1110from numpy import (sqrt , ones , zeros , isscalar , sign , ones_like , arange , empty , abs , array , finfo ,
1211 float64 , log , exp , floor )
@@ -37,6 +36,7 @@ class BootstrapRng(object):
3736 start : int
3837 Location of first forecast
3938 """
39+
4040 def __init__ (self , std_resid , start ):
4141 if start <= 0 or start > std_resid .shape [0 ]:
4242 raise ValueError ('start must be > 0 and <= len(std_resid).' )
@@ -1294,8 +1294,9 @@ class EWMAVariance(VolatilityProcess):
12941294
12951295 Parameters
12961296 ----------
1297- lam : float, optional
1298- Smoothing parameter. Default is 0.94
1297+ lam : {float, None}, optional
1298+ Smoothing parameter. Default is 0.94. Set to None to estimate lam
1299+ jointly with other model parameters
12991300
13001301 Attributes
13011302 ----------
@@ -1317,38 +1318,52 @@ class EWMAVariance(VolatilityProcess):
13171318
13181319 \sigma_t^{2}=\lambda\sigma_{t-1}^2 + (1-\lambda)\epsilon^2_{t-1}
13191320
1320- This model has no parameters since the smoothing parameter is fixed.
1321+ When lam is provided, this model has no parameters since the smoothing
1322+ parameter is treated as fixed. Sel lam to `None` to jointly estimate this
1323+ parameter when fitting the model.
13211324 """
13221325
13231326 def __init__ (self , lam = 0.94 ):
13241327 super (EWMAVariance , self ).__init__ ()
13251328 self .lam = lam
1326- self .num_params = 0
1327- if not 0.0 < lam < 1.0 :
1329+ self ._estimate_lam = lam is None
1330+ self .num_params = 1 if self ._estimate_lam else 0
1331+ if lam is not None and not 0.0 < lam < 1.0 :
13281332 raise ValueError ('lam must be strictly between 0 and 1' )
13291333 self .name = 'EWMA/RiskMetrics'
13301334
13311335 def __str__ (self ):
1332- descr = self .name + '(lam: ' + '{0:0.2f}' .format (self .lam ) + ')'
1336+ if self ._estimate_lam :
1337+ descr = self .name + '(lam: Estimated)'
1338+ else :
1339+ descr = self .name + '(lam: ' + '{0:0.2f}' .format (self .lam ) + ')'
13331340 return descr
13341341
13351342 def starting_values (self , resids ):
1336- return np .empty ((0 ,))
1343+ if self ._estimate_lam :
1344+ return np .array ([0.94 ])
1345+ return np .array ([])
13371346
13381347 def parameter_names (self ):
1348+ if self ._estimate_lam :
1349+ return ['lam' ]
13391350 return []
13401351
1341- def variance_bounds (self , resids , power = 2.0 ):
1342- return ones ((resids .shape [0 ], 1 )) * array ([- 1.0 , finfo (float64 ).max ])
1343-
13441352 def bounds (self , resids ):
1353+ if self ._estimate_lam :
1354+ return [(0 , 1 )]
13451355 return []
13461356
13471357 def compute_variance (self , parameters , resids , sigma2 , backcast ,
13481358 var_bounds ):
1349- return ewma_recursion (self .lam , resids , sigma2 , resids .shape [0 ], backcast )
1359+ lam = parameters [0 ] if self ._estimate_lam else self .lam
1360+ return ewma_recursion (lam , resids , sigma2 , resids .shape [0 ], backcast )
13501361
13511362 def constraints (self ):
1363+ if self ._estimate_lam :
1364+ a = ones ((1 , 1 ))
1365+ b = zeros ((1 ,))
1366+ return a , b
13521367 return np .empty ((0 , 0 )), np .empty ((0 ,))
13531368
13541369 def simulate (self , parameters , nobs , rng , burn = 500 , initial_value = None ):
@@ -1362,7 +1377,11 @@ def simulate(self, parameters, nobs, rng, burn=500, initial_value=None):
13621377
13631378 sigma2 [0 ] = initial_value
13641379 data [0 ] = sqrt (sigma2 [0 ])
1365- lam , one_m_lam = self .lam , 1.0 - self .lam
1380+ if self ._estimate_lam :
1381+ lam = parameters [0 ]
1382+ else :
1383+ lam = self .lam
1384+ one_m_lam = 1.0 - lam
13661385 for t in range (1 , nobs + burn ):
13671386 sigma2 [t ] = lam * sigma2 [t - 1 ] + one_m_lam * data [t - 1 ] ** 2.0
13681387 data [t ] = np .sqrt (sigma2 [t ]) * errors [t ]
@@ -1393,7 +1412,10 @@ def _simulation_forecast(self, parameters, resids, backcast, var_bounds, start,
13931412 paths .fill (np .nan )
13941413 shocks = np .empty ((t , simulations , horizon ))
13951414 shocks .fill (np .nan )
1396- lam = self .lam
1415+ if self ._estimate_lam :
1416+ lam = parameters [0 ]
1417+ else :
1418+ lam = self .lam
13971419
13981420 for i in range (start , t ):
13991421 std_shocks = rng ((simulations , horizon ))
0 commit comments