6
6
from __future__ import absolute_import , division
7
7
8
8
import itertools
9
-
10
9
import numpy as np
11
10
from numpy import (sqrt , ones , zeros , isscalar , sign , ones_like , arange , empty , abs , array , finfo ,
12
11
float64 , log , exp , floor )
@@ -37,6 +36,7 @@ class BootstrapRng(object):
37
36
start : int
38
37
Location of first forecast
39
38
"""
39
+
40
40
def __init__ (self , std_resid , start ):
41
41
if start <= 0 or start > std_resid .shape [0 ]:
42
42
raise ValueError ('start must be > 0 and <= len(std_resid).' )
@@ -1294,8 +1294,9 @@ class EWMAVariance(VolatilityProcess):
1294
1294
1295
1295
Parameters
1296
1296
----------
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
1299
1300
1300
1301
Attributes
1301
1302
----------
@@ -1317,38 +1318,52 @@ class EWMAVariance(VolatilityProcess):
1317
1318
1318
1319
\sigma_t^{2}=\lambda\sigma_{t-1}^2 + (1-\lambda)\epsilon^2_{t-1}
1319
1320
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.
1321
1324
"""
1322
1325
1323
1326
def __init__ (self , lam = 0.94 ):
1324
1327
super (EWMAVariance , self ).__init__ ()
1325
1328
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 :
1328
1332
raise ValueError ('lam must be strictly between 0 and 1' )
1329
1333
self .name = 'EWMA/RiskMetrics'
1330
1334
1331
1335
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 ) + ')'
1333
1340
return descr
1334
1341
1335
1342
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 ([])
1337
1346
1338
1347
def parameter_names (self ):
1348
+ if self ._estimate_lam :
1349
+ return ['lam' ]
1339
1350
return []
1340
1351
1341
- def variance_bounds (self , resids , power = 2.0 ):
1342
- return ones ((resids .shape [0 ], 1 )) * array ([- 1.0 , finfo (float64 ).max ])
1343
-
1344
1352
def bounds (self , resids ):
1353
+ if self ._estimate_lam :
1354
+ return [(0 , 1 )]
1345
1355
return []
1346
1356
1347
1357
def compute_variance (self , parameters , resids , sigma2 , backcast ,
1348
1358
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 )
1350
1361
1351
1362
def constraints (self ):
1363
+ if self ._estimate_lam :
1364
+ a = ones ((1 , 1 ))
1365
+ b = zeros ((1 ,))
1366
+ return a , b
1352
1367
return np .empty ((0 , 0 )), np .empty ((0 ,))
1353
1368
1354
1369
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):
1362
1377
1363
1378
sigma2 [0 ] = initial_value
1364
1379
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
1366
1385
for t in range (1 , nobs + burn ):
1367
1386
sigma2 [t ] = lam * sigma2 [t - 1 ] + one_m_lam * data [t - 1 ] ** 2.0
1368
1387
data [t ] = np .sqrt (sigma2 [t ]) * errors [t ]
@@ -1393,7 +1412,10 @@ def _simulation_forecast(self, parameters, resids, backcast, var_bounds, start,
1393
1412
paths .fill (np .nan )
1394
1413
shocks = np .empty ((t , simulations , horizon ))
1395
1414
shocks .fill (np .nan )
1396
- lam = self .lam
1415
+ if self ._estimate_lam :
1416
+ lam = parameters [0 ]
1417
+ else :
1418
+ lam = self .lam
1397
1419
1398
1420
for i in range (start , t ):
1399
1421
std_shocks = rng ((simulations , horizon ))
0 commit comments