Skip to content

EWMA

quantflow.ta.EWMA pydantic-model

Bases: BaseModel

Exponentially Weighted Moving Average filter for time series data.

This implementation uses the standard EWMA formula:

\[ \begin{equation} s_t = \alpha x_t + (1 - \alpha) s_{t-1} \end{equation} \]

where \(\alpha\) is the smoothing factor derived from the period parameter. To match SuperSmoother characteristics, the formula is:

\[ \begin{equation} \alpha = \frac{2}{\text{period} + 1} \end{equation} \]

This provides frequency response similar to a simple moving average and approximates the smoothing characteristics of higher-order filters.

Example

import pandas as pd
ewma = EWMA(period=10)
df = pd.DataFrame({"value": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]})
df["ewma"] = df["value"].apply(ewma.update)

For online updates:

ewma = EWMA(period=10)
for value in [1, 2, 3, 4, 5]:
    smoothed = ewma.update(value)
    print(smoothed)

Fields:

period pydantic-field

period = 10

Characteristic period for the smoothing filter (must be >= 1)

tau pydantic-field

tau = None

Optional asymmetric smoothing filter

current_value property

current_value

Get the most recent smoothed value, if available.

alpha property

alpha

Get the smoothing factor (alpha) used by the filter.

from_half_life classmethod

from_half_life(half_life, tau=None)

Create an EWMA using half-life semantics instead of period.

The half-life represents the time for weight to decay to 0.5.

\[ \alpha = 1 - \exp\left(-\frac{\ln(2)}{\text{half life}}\right) \]
Source code in quantflow/ta/ewma.py
@classmethod
def from_half_life(cls, half_life: float, tau: float | None = None) -> Self:
    r"""Create an EWMA using half-life semantics instead of period.

    The half-life represents the time for weight to decay to 0.5.

    $$
    \alpha = 1 - \exp\left(-\frac{\ln(2)}{\text{half life}}\right)
    $$
    """
    # Calculate equivalent period that produces the desired half-life behavior
    # From: alpha = 1 - exp(-ln(2) / half_life)
    # And: alpha = 2 / (period + 1)
    # We solve: 2 / (period + 1) = 1 - exp(-ln(2) / half_life)
    alpha = 1.0 - math.exp(-log2 / half_life)
    period = int(2.0 / alpha - 1)
    return cls(period=max(1, period), tau=tau)

update

update(value)

Update the filter with a new value and return the smoothed result.

PARAMETER DESCRIPTION
value

New data point to add to the filter

TYPE: float

RETURNS DESCRIPTION
float

Smoothed value using the EWMA algorithm

Source code in quantflow/ta/ewma.py
def update(self, value: float) -> float:
    """Update the filter with a new value and return the smoothed result.

    Args:
        value: New data point to add to the filter

    Returns:
        Smoothed value using the EWMA algorithm
    """
    self._count += 1

    if self._count == 1:
        # Initialize with first value
        self._smoothed = value
    else:
        alpha = self._alpha
        if self.tau is not None:
            # Apply asymmetric smoothing if tau is set
            if value > self._smoothed:
                alpha *= self.tau
            else:
                alpha *= 1.0 - self.tau
        # Apply EWMA formula: S[t] = α * X[t] + (1 - α) * S[t-1]
        self._smoothed += alpha * (value - self._smoothed)

    return self._smoothed