idzorek's method (#95)

This commit is contained in:
robertmartin8
2020-04-27 22:26:13 +08:00
parent cbec9b130f
commit fa0cadfb68
3 changed files with 22 additions and 15 deletions

View File

@@ -165,7 +165,11 @@ around a lot are harder to forecast! Hence PyPortfolioOpt does not require you t
\Omega = \tau * P \Sigma P^T
However, you are of course welcome to provide your own estimate. This is particularly applicable if your views are the output
Alternatively, we provide an implementation of Idzorek's method [1]_. This allows you to specify your view uncertainties as
percentage confidences. To use this, choose ``omega="idzorek"`` and pass a list of confidences (from 0 to 1) into the ``view_confidences``
parameter.
You are of course welcome to provide your own estimate. This is particularly applicable if your views are the output
of some statistical model, which may also provide the view uncertainty.
Another parameter that controls the relative weighting of the priors views is :math:`\tau`. There is a lot to be said about tuning
@@ -174,7 +178,7 @@ the sensible default :math:`\tau = 0.05`.
.. note::
If you use this default estimate of :math:`\Omega`, it turns out that the value of :math:`\tau` does not matter. This
If you use the default estimate of :math:`\Omega`, or ``omega="idzorek"``, it turns out that the value of :math:`\tau` does not matter. This
is a consequence of the mathematics: the :math:`\tau` cancels in the matrix multiplications.
@@ -231,4 +235,4 @@ References
.. [1] Idzorek T. A step-by-step guide to the Black-Litterman model: Incorporating user-specified confidence levels. In: Forecasting Expected Returns in the Financial Markets. Elsevier Ltd; 2007. p. 1738.
.. [2] Black, F; Litterman, R. Combining investor views with market equilibrium. The Journal of Fixed Income, 1991.
.. [3] Walters, Jay, The Factor Tau in the Black-Litterman Model (October 9, 2013). Available at SSRN: https://ssrn.com/abstract=1701467 or http://dx.doi.org/10.2139/ssrn.1701467
.. [4] Walters J. The Black-Litterman Model in Detail. SSRN Electron J. 2011;(February 2007):165.
.. [4] Walters J. The Black-Litterman Model in Detail (2014). SSRN Electron J.;(February 2007):165.

View File

@@ -104,6 +104,8 @@ class BlackLittermanModel(base_optimizer.BaseOptimizer):
Public methods:
- ``default_omega()`` - view uncertainty proportional to asset variance
- ``idzorek_method()`` - convert views specified as percentages into BL uncertainties
- ``bl_returns()`` - posterior estimate of returns
- ``bl_cov()`` - posterior estimate of covariance
- ``bl_weights()`` - weights implied by posterior returns
@@ -131,8 +133,8 @@ class BlackLittermanModel(base_optimizer.BaseOptimizer):
:param cov_matrix: NxN covariance matrix of returns
:type cov_matrix: pd.DataFrame or np.ndarray
:param pi: Nx1 prior estimate of returns, defaults to None.
Can instead pass "market" to use a market-implied prior (requires market_caps)
to be passed.
Can instead pass "market" to use a market-implied prior (requires market_caps
to be passed).
:type pi: np.ndarray, pd.Series, optional
:param absolute_views: a colleciton of K absolute views on a subset of assets,
defaults to None. If this is provided, we do not need P, Q.
@@ -145,16 +147,16 @@ class BlackLittermanModel(base_optimizer.BaseOptimizer):
Can instead pass "idzorek" to use Idzorek's method (requires
you to pass view_confidences). If omega="default" or None,
we set the uncertainty proportional to the variance.
:type omega: np.ndarray or Pd.DataFrame, optional
:type omega: np.ndarray or Pd.DataFrame, or string, optional
:param view_confidences: Kx1 vector of percentage view confidences (between 0 and 1),
required to compute omega via Idzorek's method.
:type view_confidences: np.ndarray, pd.Series, list,, optional
:type view_confidences: np.ndarray, pd.Series, list, optional
:param tau: the weight-on-views scalar (default is 0.05)
:type tau: float, optional
:param market_caps: (kwarg) market caps for the assets, required if pi="market"
:type market_caps: np.ndarray, pd.Series, optional
:param risk_aversion: risk aversion parameter, defaults to 1
:type risk_aversion: positive float, optional
:param market_caps: (kwarg) market caps for the assets, required if pi="market"
:type market_caps: np.ndarray, pd.Series, optional
:param risk_free_rate: (kwarg) risk_free_rate is needed in some methods
:type risk_free_rate: float, defaults to 0.02
"""
@@ -180,7 +182,7 @@ class BlackLittermanModel(base_optimizer.BaseOptimizer):
# Make sure all dimensions work
self._check_attribute_dimensions()
self._set_omega(omega, view_confidences, **kwargs)
self._set_omega(omega, view_confidences)
# Private intermediaries
self._tau_sigma_P = None
@@ -267,7 +269,7 @@ class BlackLittermanModel(base_optimizer.BaseOptimizer):
raise ValueError("risk_aversion should be a positive float")
self.risk_aversion = risk_aversion
def _set_omega(self, omega, view_confidences, **kawrgs):
def _set_omega(self, omega, view_confidences):
if isinstance(omega, pd.DataFrame):
self.omega = omega.values
elif isinstance(omega, np.ndarray):
@@ -336,8 +338,9 @@ class BlackLittermanModel(base_optimizer.BaseOptimizer):
@staticmethod
def idzorek_method(view_confidences, cov_matrix, pi, Q, P, tau, risk_aversion=1):
"""
Idzorek's method for creating the uncertainty matrix omega given user-specified
percentage confidences. We use the closed-form solution of Walters (2014).
Use Idzorek's method to create the uncertainty matrix given user-specified
percentage confidences. We use the closed-form solution described by
Jay Walters in The Black-Litterman Model in Detail (2014).
:param view_confidences: Kx1 vector of percentage view confidences (between 0 and 1),
required to compute omega via Idzorek's method.

View File

@@ -513,13 +513,13 @@ def test_idzorek_confidences_error():
with pytest.raises(ValueError):
#  Conf greater than 1
bl = BlackLittermanModel(
BlackLittermanModel(
S, pi=pi, absolute_views=views, omega="idzorek", view_confidences=[1.1] * 5
)
with pytest.raises(ValueError):
#  Conf less than zero
bl = BlackLittermanModel(
BlackLittermanModel(
S, pi=pi, absolute_views=views, omega="idzorek", view_confidences=[-0.1] * 5
)