Exponential Moving Average of Volatility

Hello All :slight_smile:

Currently I am computing a 1y rolling moving average of volatility as : PctDev(252, 1, 0, 0, true)

I would like to compute the exponential moving average over 1y for volatility. The EMA function in P123 seems only to accept price as input. How can I come about this?

Thanks in advance :slight_smile:

You may try this one:
100 * 15.87 * Pow( LoopSum( "Pow(Close(CTR)/Close(CTR+1)-1, 2) * Pow(0.9921, CTR)" , 252 ) / LoopSum( "Pow(0.9921, CTR)" , 252 ) , 0.5 )

or this version optimised for speed:
100 * 15.87 * Pow( LoopSum( "Pow(Close(CTR)/Close(CTR+1)-1, 2) * Pow(0.9921, CTR)" , 252 ) / 109.3 , 0.5 )

Note: I haven't fully debugged this, so please double-check the logic. I verified this against the Python code below and the results appear consistent, aside from some minor discrepancies.

Here is the python code:

import pandas as pd
import numpy as np

## download prices ##
## https://stooq.com/q/d/?f=20241230&t=20251230&s=kep.us&c=0##

df = pd.read_csv('kep_us_d.csv')

# --- 1. Calculate the 1-Year EMA Volatility ---

# Step A: Calculate Daily Returns
# We use simple returns (Close / PrevClose - 1) to match P123 logic
df['Returns'] = df['Close'].pct_change()

# Step B: Calculate Squared Returns (Variance Proxy)
# In risk modeling (like RiskMetrics), it is standard to assume the mean daily return is 0
# for the variance calculation to make it more reactive.
df['Squared_Returns'] = df['Returns'] ** 2

# Step C: Calculate Exponential Moving Average of Variance
# span=252 implies a 1-year lookback weighting.
# adjust=True ensures the weights are normalized (sum to 1), same as the LoopSum denominator logic.
df['Variance_EMA'] = df['Squared_Returns'].ewm(span=252, adjust=True).mean()

# Step D: Convert Variance to Volatility (Standard Deviation)
# Take square root of variance
df['Daily_Vol_EMA'] = np.sqrt(df['Variance_EMA'])

# Step E: Annualize
# Multiply by sqrt(252) and by 100 for percentage
df['Volatility_EMA_1Y_Pct'] = df['Daily_Vol_EMA'] * np.sqrt(252) * 100

# --- Display Results ---
print(df[['Close', 'Returns', 'Volatility_EMA_1Y_Pct']].tail())