TurningPoints#

class cultivars.spectral.cycles.TurningPoints(*, convention='quarterly', window=None, min_phase=None, min_cycle=None)[source]

Bases: object

Date peaks and troughs with the Bry-Boschan / Harding-Pagan rules.

Three rules, applied in order, make a chronology from a series. A candidate peak is a local maximum over a two-sided window,

\[y_t > y_{t \pm k}, \qquad k = 1, \dots, \texttt{window},\]

and a candidate trough its mirror; candidates are then thinned to a strictly alternating sequence, the highest of consecutive peaks and the lowest of consecutive troughs surviving; and turns are removed in pairs until every phase lasts at least min_phase and every peak-to-peak or trough-to-trough cycle at least min_cycle observations. The two named conventions are the triples the literature uses at quarterly and monthly frequency, and any of the three can be overridden.

Parameters:
  • convention (str) – "quarterly" for Harding-Pagan’s (2, 2, 5) – window, minimum phase, minimum cycle – or "monthly" for Bry-Boschan’s (5, 6, 15).

  • window (int | None) – Override the local-extremum half-width.

  • min_phase (int | None) – Override the shortest phase.

  • min_cycle (int | None) – Override the shortest cycle.

Variables:
  • _window – The resolved local-extremum half-width.

  • _min_phase – The resolved shortest phase.

  • _min_cycle – The resolved shortest cycle.

Raises:

SpecificationError – If the convention is unknown or an override is not positive.

Note

The rules are a smoothing device and their strength is the triple, not the frequency label. The quarterly defaults allow a two-observation phase and a five-observation cycle, which on an unsmoothed series with a little noise near a turn will date a spurious short phase inside the true one – two peaks a few observations apart where there is one. The remedy is the "monthly" triple, a larger min_phase, or a smoothing pass upstream, and the phases table of the result makes the short phase visible so the choice is informed. The rules act on the level: a series that trends will have longer expansions than contractions by construction, which is the classical-cycle reading and not a defect; a growth-cycle chronology needs the cycle component from a band-pass filter as input instead.

See also

References

Bry, G., & Boschan, C. (1971). Cyclical Analysis of Time Series: Selected Procedures and Computer Programs. NBER.

Harding, D., & Pagan, A. (2002). Dissecting the cycle: A methodological investigation. Journal of Monetary Economics, 49(2), 365-381.

Example

>>> import numpy as np
>>> t = np.arange(120.0)
>>> y = 0.01 * t + 0.5 * np.sin(2 * np.pi * t / 24)
>>> res = TurningPoints().date(y)
>>> res.n_cycles, bool(res.contraction.mean() > 0.3)
(4, True)

A little noise on a 40-period cycle lets the quarterly triple date a spurious short phase at one trough; the monthly triple, or a longer minimum phase, does not:

>>> rng = np.random.default_rng(0)
>>> noisy = np.sin(2 * np.pi * t / 40) + 0.1 * rng.standard_normal(120)
>>> TurningPoints().date(noisy).peaks
array([11, 48, 53, 89])
>>> TurningPoints(convention="monthly").date(noisy).peaks
array([11, 48, 89])
>>> TurningPoints(min_phase=6).date(noisy).peaks
array([11, 53, 89])

Private attributes#