0Pricing
Pandas & NumPy Academy · 강의

지수 가중 이동 평균

금융 분석에서 표준적으로 사용하는 ewm(span=)으로 최근 값에 더 큰 가중치를 부여하는 지수 평활을 적용합니다.

지수 가중 이동 평균은(는) CoddyKit의 무료 Pandas & NumPy Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Pandas & NumPy Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

The Problem with Simple Moving Averages

A simple moving average treats all n observations in the window equally — a price from 30 days ago contributes the same as yesterday's price. But for predicting near-term values, recent observations are more informative than old ones. An Exponentially Weighted Moving Average (EWMA) solves this by assigning exponentially decreasing weights to older observations: yesterday counts the most, the day before counts slightly less, and so on back to the beginning of the series.

import pandas as pd
import numpy as np

np.random.seed(42)
prices = pd.Series(
    100 + np.cumsum(np.random.normal(0.5, 2, 30)),
    index=pd.date_range('2024-01-01', periods=30)
)

df = pd.DataFrame({'price': prices})
df['SMA_7'] = df['price'].rolling(7).mean()
df['EWM_span7'] = df['price'].ewm(span=7).mean()
print(df.tail(5).round(2))

How EWMA Weighting Works

EWMA computes each value as a weighted combination of the current observation and the previous EWMA: EWM_t = alpha * x_t + (1 - alpha) * EWM_{t-1}. The alpha (smoothing factor) determines how quickly weights decay — a large alpha (close to 1) responds quickly to recent changes (less smoothing), a small alpha (close to 0) is slow to respond (more smoothing). The weights form a geometric series: the most recent value has weight alpha, the previous has alpha*(1-alpha), and so on.

import numpy as np

# Manually show EWMA weights
alpha = 0.3
n_points = 8
weights = [alpha * (1 - alpha)**i for i in range(n_points)]

print(f'Alpha = {alpha}')
print(f'Weights (most recent first):')
for i, w in enumerate(weights):
    print(f'  t-{i}: {w:.4f}')
print(f'Sum of shown weights: {sum(weights):.4f} (converges to 1.0)')

The ewm() Method and span Parameter

Pandas implements EWMA through Series.ewm(). The most intuitive parameter is span, which is analogous to a simple moving average window: alpha = 2 / (span + 1). A span of 10 approximately corresponds to a 10-period SMA but with exponentially decaying weights instead of equal weights. Use ewm(span=n).mean() to get the EWMA, and ewm(span=n).std() for exponentially weighted volatility.

import pandas as pd
import numpy as np

np.random.seed(0)
data = pd.Series(
    np.random.normal(100, 10, 50),
    index=pd.date_range('2024-01-01', periods=50)
)

df = pd.DataFrame({'value': data})
df['EWM_3'] = df['value'].ewm(span=3).mean()
df['EWM_10'] = df['value'].ewm(span=10).mean()
df['EWM_20'] = df['value'].ewm(span=20).mean()

print('Alpha values:')
for span in [3, 10, 20]:
    alpha = 2 / (span + 1)
    print(f'  span={span} → alpha={alpha:.3f}')
print(df.tail(5).round(2))

The halflife Parameter

The halflife parameter defines how many periods it takes for the weight to decrease by half. If halflife=5, a value from 5 periods ago has half the weight of the current value. The relationship is: alpha = 1 - exp(log(0.5) / halflife). Halflife is often more intuitive than span or alpha because it directly expresses the 'memory' of the average in business terms — for example, 'prices from 2 weeks ago should have half the influence of today's price'.

import pandas as pd
import numpy as np

np.random.seed(5)
prices = pd.Series(
    100 + np.cumsum(np.random.normal(0, 2, 30)),
    index=pd.date_range('2024-01-01', periods=30)
)

df = pd.DataFrame({'price': prices})
# halflife=5: weight halves every 5 days
df['EWM_hl5'] = df['price'].ewm(halflife=5).mean()
# halflife=14: weight halves every 14 days (longer memory)
df['EWM_hl14'] = df['price'].ewm(halflife=14).mean()

print(df.tail(5).round(2))

The alpha Parameter Directly

You can also set the smoothing factor directly with ewm(alpha=). Alpha must be between 0 and 1 (exclusive). A high alpha like 0.8 gives very little smoothing — the EWMA tracks the raw signal closely. A low alpha like 0.1 gives heavy smoothing — the EWMA changes slowly and lags behind sudden shifts. Choosing the right alpha depends on the trade-off between responsiveness (detecting real trend changes quickly) and stability (ignoring random noise).

import pandas as pd
import numpy as np

np.random.seed(3)
data = pd.Series(
    [100]*20 + [120]*20,  # sudden level shift at row 20
    dtype=float
) + np.random.normal(0, 2, 40)

df = pd.DataFrame({'signal': data})
df['alpha_0.1'] = df['signal'].ewm(alpha=0.1).mean()  # slow
df['alpha_0.5'] = df['signal'].ewm(alpha=0.5).mean()  # medium
df['alpha_0.9'] = df['signal'].ewm(alpha=0.9).mean()  # fast

print('After the level shift (rows 20-25):')
print(df.iloc[18:26].round(2))

EWMA for Volatility: ewm().std()

ewm(span=).std() computes an exponentially weighted standard deviation. This is the basis of the EWMA volatility model used in financial risk management (also known as the RiskMetrics model with decay factor lambda=0.94). Exponentially weighted volatility responds faster to volatility spikes than a simple rolling std because it assigns more weight to recent high-variance observations.

import pandas as pd
import numpy as np

np.random.seed(42)
# Simulate returns: quiet period then volatile period
returns = pd.Series(
    np.concatenate([
        np.random.normal(0, 0.01, 60),
        np.random.normal(0, 0.04, 60)  # 4x more volatile
    ]),
    index=pd.date_range('2024-01-01', periods=120)
)

df = pd.DataFrame({'returns': returns})
df['rolling_vol'] = df['returns'].rolling(20).std()
df['ewm_vol'] = df['returns'].ewm(span=20).std()

print('Volatility comparison (transition at row 60):')
print(df.iloc[58:65].round(5))

MACD: Combining Two EWMAs

The MACD (Moving Average Convergence Divergence) is a classic financial indicator built from two EWMAs. It is the difference between a fast (short-span) EWMA and a slow (long-span) EWMA of the price. When the MACD crosses zero from below, it signals potential upward momentum (a buy signal); crossing from above signals downward momentum. MACD is a perfect example of applying two EWMAs to derive a derived indicator.

import pandas as pd
import numpy as np

np.random.seed(7)
prices = pd.Series(
    100 + np.cumsum(np.random.normal(0.3, 2, 100)),
    index=pd.date_range('2024-01-01', periods=100)
)

df = pd.DataFrame({'price': prices})
df['EMA_12'] = df['price'].ewm(span=12).mean()  # fast
df['EMA_26'] = df['price'].ewm(span=26).mean()  # slow
df['MACD'] = df['EMA_12'] - df['EMA_26']
df['Signal'] = df['MACD'].ewm(span=9).mean()   # signal line

print('MACD values (last 8 rows):')
print(df[['price', 'MACD', 'Signal']].tail(8).round(2))

EWMA with Time-Based Halflife

Pandas 1.1+ supports specifying halflife, span, and com as time offsets (e.g. halflife='7D') when working with a DatetimeIndex. This enables proper EWMA on non-uniform time series — for example, if you have hourly data with gaps on weekends, a halflife of '7D' means the weight truly halves every 7 calendar days regardless of the number of rows in that period.

import pandas as pd
import numpy as np

np.random.seed(0)
# Business-day data (no weekends)
biz_dates = pd.bdate_range('2024-01-01', periods=20)
prices = pd.Series(100 + np.cumsum(np.random.randn(20)), index=biz_dates)

# halflife as a time offset (7 calendar days)
ewm_7d = prices.ewm(halflife='7D', times=biz_dates).mean()
# halflife as row count (7 rows)
ewm_7rows = prices.ewm(halflife=7).mean()

df = pd.DataFrame({'price': prices, 'hl_7D': ewm_7d, 'hl_7rows': ewm_7rows})
print(df.round(2))

Choosing Between EWMA, Rolling, and Expanding

Summary of when to use each:

  • Rolling(n).mean(): all n recent observations equally weighted — good for simple trailing metrics and when all recent periods matter equally.
  • ewm(span=n).mean(): exponentially weighted — best when you want smoothing that responds more to recent changes, commonly used in finance and signal processing.
  • expanding().mean(): all historical data with equal weight — best for YTD or all-time statistics where forgetting old data is not acceptable.

Visualising EWMA vs SMA

Plotting EWMA and SMA together on a time series chart makes the difference in their responsiveness visible. The EWMA reacts more quickly to sudden level changes because it has not 'forgotten' all previous observations — the short-span EWMA will turn faster than an SMA with the same nominal window. This makes EWMA preferable in forecasting applications where capturing trend direction quickly is more valuable than maximum noise reduction.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
prices = pd.Series(
    np.concatenate([
        100 + np.cumsum(np.random.normal(0.3, 1.5, 50)),
        130 + np.cumsum(np.random.normal(-0.3, 1.5, 50))
    ]),
    index=pd.date_range('2024-01-01', periods=100)
)

df = pd.DataFrame({'price': prices})
df['SMA_10'] = df['price'].rolling(10).mean()
df['EWMA_10'] = df['price'].ewm(span=10).mean()

df.plot(figsize=(12, 5), title='SMA vs EWMA — EWMA reacts faster to trend reversals')
plt.ylabel('Price')
plt.axvline(x=df.index[50], color='red', linestyle='--', label='Trend change')
plt.legend()
plt.show()

EWMA in Business Applications

Beyond finance, EWMA is widely used in product analytics and operations: customer lifetime value smoothing (recent behaviour predicts future spend better than old behaviour), server latency monitoring (an exponentially smoothed latency metric sounds false alarms faster than a rolling mean), and inventory demand forecasting (recent sales weeks should outweigh data from six months ago). The universal principle is: wherever recency matters, EWMA outperforms simple averaging.

Quick Check

Test your understanding of exponentially weighted moving averages from this lesson.

Lesson Recap

In this lesson you learned: ewm(span=) applies exponentially decaying weights so recent observations matter more, alpha controls responsiveness (high = fast, low = smooth), and the halflife parameter expresses memory in business-meaningful terms. EWMA outperforms SMA when detecting trend reversals quickly is important. Next up we explore rank and percentile calculations within groups using groupby().rank() and pd.qcut.

자주 묻는 질문

“지수 가중 이동 평균” 강의는 무료인가요?

네 — “지수 가중 이동 평균” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Pandas & NumPy Academy 강의 전체를 잠금 해제할 수 있습니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“지수 가중 이동 평균”에서 뭘 배우나요?

금융 분석에서 표준적으로 사용하는 ewm(span=)으로 최근 값에 더 큰 가중치를 부여하는 지수 평활을 적용합니다. 브라우저에서 직접 실행하는 실습 코드로 Pandas & NumPy Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Pandas & NumPy Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Pandas & NumPy Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“지수 가중 이동 평균” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Pandas & NumPy Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Pandas & NumPy Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 이동 창
  2. 확장 창
  3. 지수 가중 이동 평균
  4. 그룹 내 순위와 백분위
← Pandas & NumPy Academy(으)로 돌아가기