Markets: A Rigorous Course

Exercise · m11_taylor.py

Taylor rule and a growth/inflation regime classifier

Read notes.md 11.5–11.6 and 11.13 first. Run: cd exercises && .venv/bin/python -m pytest modules/M11-macro-rates-fx/tests/test_m11_taylor.py

All rates and gaps in percent (e.g. 3.7 means 3.7%).

Tests (7)

  • test_taylor_1993_values
  • test_worked_examples_in_notes
  • test_inertial_path_converges_to_rule
  • test_fisher
  • test_classify_regime_quadrants
  • test_regime_average_returns_recover_known_means
  • test_surprises_from_levels

Theory: M11 notes. Run with Ctrl/⌘+Enter.

not run yet

Not saved: sign up to keep your code
"""M11 exercise: Taylor rule and a growth/inflation regime classifier.

Read notes.md §11.5–11.6 and §11.13 first. Run:
    cd exercises && .venv/bin/python -m pytest modules/M11-macro-rates-fx/tests/test_m11_taylor.py

All rates and gaps in percent (e.g. 3.7 means 3.7%).
"""

from __future__ import annotations

import numpy as np
import pandas as pd

REGIMES = ("goldilocks", "reflation", "stagflation", "deflationary_bust")


def taylor_rate(
    inflation: float,
    output_gap: float,
    r_star: float = 2.0,
    pi_star: float = 2.0,
    a_pi: float = 0.5,
    a_y: float = 0.5,
) -> float:
    """Taylor (1993) rule, eq. (11.15):
        i = r_star + inflation + a_pi (inflation - pi_star) + a_y * output_gap
    Must work elementwise on numpy arrays."""
    raise NotImplementedError


def inertial_taylor_path(
    inflation: np.ndarray,
    output_gap: np.ndarray,
    i0: float,
    rho: float = 0.8,
    **kw,
) -> np.ndarray:
    """Smoothed rule, eq. (11.16): i_t = rho i_{t-1} + (1 - rho) taylor_rate(pi_t, gap_t, **kw),
    with i_{-1} = i0. Return the array i_0..i_{n-1}."""
    raise NotImplementedError


def taylor_gap(policy_rate: float, inflation: float, output_gap: float, **kw) -> float:
    """policy_rate - taylor_rate(inflation, output_gap, **kw), in pp."""
    raise NotImplementedError


def ex_post_real_rate(nominal: float, inflation: float, exact: bool = False) -> float:
    """Fisher equation (11.12), in percent:
        exact=False: nominal - inflation
        exact=True:  100 * ((1 + nominal/100) / (1 + inflation/100) - 1)"""
    raise NotImplementedError


def classify_regime(growth_surprise, inflation_surprise) -> np.ndarray:
    """Elementwise four-quadrant classification (§11.13):
        growth >= 0 and inflation <  0 -> 'goldilocks'
        growth >= 0 and inflation >= 0 -> 'reflation'
        growth <  0 and inflation >= 0 -> 'stagflation'
        growth <  0 and inflation <  0 -> 'deflationary_bust'
    Accept scalars or array-likes; return a 1-d numpy array of strings (dtype object)."""
    raise NotImplementedError


def surprises_from_levels(series: pd.Series, window: int = 12) -> pd.Series:
    """Surprise proxy: x_t minus the mean of x_{t-window}..x_{t-1}.
    The first `window` values are NaN."""
    raise NotImplementedError


def regime_average_returns(regimes, returns: pd.DataFrame) -> pd.DataFrame:
    """Mean of each column of `returns` conditional on the regime label of each row.
    Index: the regimes that occur, ordered as in REGIMES (index name 'regime').
    Columns: the asset columns of `returns`."""
    raise NotImplementedError

No runs yet

The stub's functions raise NotImplementedError until you write them. Fill in one, press Run tests, and watch its tests turn green.

Reference solution

Available after your first run, with an account approved for code runs.

Create a free account

Reading is open to everyone. An account keeps your progress, answers, notes and code drafts, and gives you the study plan, the journals and the simulator. Running code needs an account approved for it.