Skip to content

pct_change Method

The pct_change() method calculates percentage change between consecutive elements, essential for financial analysis.

Basic Usage

Calculate period-over-period percentage change.

1. Simple pct_change

import pandas as pd
import yfinance as yf

df = yf.Ticker('WMT').history(start='2020-01-01', end='2020-01-10')
df = df[['Close']]

df['pct_change'] = df['Close'].pct_change()
print(df)
                 Close  pct_change
Date                              
2020-01-02  116.459999         NaN
2020-01-03  116.279999   -0.001546
2020-01-06  116.230003   -0.000430
2020-01-07  116.849998    0.005333
2020-01-08  116.220001   -0.005392

2. Formula

\[r_D = \frac{P_t - P_{t-1}}{P_{t-1}} = \frac{P_t}{P_{t-1}} - 1\]

3. First Value is NaN

No previous value to compare with.

periods Parameter

Calculate change over multiple periods.

1. Daily (Default)

df['daily_return'] = df['Close'].pct_change(periods=1)

2. Weekly

df['weekly_return'] = df['Close'].pct_change(periods=5)

3. Monthly

df['monthly_return'] = df['Close'].pct_change(periods=21)

Discrete vs Log Returns

Different return calculations.

1. Discrete Returns

# Standard percentage change
df['discrete_return'] = df['Close'].pct_change()

2. Log Returns

import numpy as np

df['log_return'] = np.log(df['Close'] / df['Close'].shift(1))

3. Relationship

\[r_C = \log\frac{P_t}{P_{t-1}} \approx \frac{P_t}{P_{t-1}} - 1 = r_D\]

For small changes, log and discrete returns are approximately equal.

Cumulative Returns

Calculate total return over time.

1. From pct_change

df['daily_return'] = df['Close'].pct_change()
df['cum_return'] = (1 + df['daily_return']).cumprod() - 1

2. Direct Calculation

df['cum_return'] = df['Close'] / df['Close'].iloc[0] - 1

3. Total Return

total_return = df['Close'].iloc[-1] / df['Close'].iloc[0] - 1

Rolling Statistics

Combine with rolling windows.

1. Rolling Volatility

df['volatility'] = df['Close'].pct_change().rolling(21).std() * np.sqrt(252)

2. Rolling Average Return

df['avg_return'] = df['Close'].pct_change().rolling(21).mean()

3. Sharpe Ratio (Simplified)

returns = df['Close'].pct_change()
sharpe = returns.mean() / returns.std() * np.sqrt(252)

Multiple Columns

Apply to entire DataFrame.

1. All Columns

df = yf.Ticker('WMT').history(start='2020-01-01', end='2020-12-31')
returns = df.pct_change()

2. Selected Columns

price_cols = ['Open', 'High', 'Low', 'Close']
returns = df[price_cols].pct_change()

3. Correlation of Returns

returns.corr()

fill_method Parameter

Handle missing values.

1. Forward Fill (Default)

df['return'] = df['Close'].pct_change(fill_method='ffill')

2. No Fill

df['return'] = df['Close'].pct_change(fill_method=None)

3. With Missing Data

# If data has gaps, fill_method controls behavior
df['Close'].fillna(method='ffill').pct_change()

Financial Analysis Example

Complete return analysis.

1. Load Data

df = yf.Ticker('SPY').history(period='1y')

2. Calculate Returns

df['daily_return'] = df['Close'].pct_change()
df['cum_return'] = (1 + df['daily_return']).cumprod() - 1

3. Summary Statistics

print(f"Mean Daily Return: {df['daily_return'].mean():.4%}")
print(f"Daily Volatility: {df['daily_return'].std():.4%}")
print(f"Total Return: {df['cum_return'].iloc[-1]:.2%}")
print(f"Annualized Return: {df['daily_return'].mean() * 252:.2%}")
print(f"Annualized Volatility: {df['daily_return'].std() * np.sqrt(252):.2%}")

Compare to Manual Calculation

Verify pct_change formula.

1. pct_change

df['pct'] = df['Close'].pct_change()

2. Manual

df['manual'] = (df['Close'] - df['Close'].shift(1)) / df['Close'].shift(1)

3. Verify Equal

print(df['pct'].equals(df['manual']))  # True (ignoring NaN)

GroupBy with pct_change

Calculate returns by group.

1. Per-Stock Returns

# Multiple stocks in one DataFrame
df['return'] = df.groupby('ticker')['close'].pct_change()

2. Reset per Group

# Cumulative return per stock
df['cum_return'] = df.groupby('ticker')['return'].transform(
    lambda x: (1 + x).cumprod() - 1
)

3. Compare Stocks

# Pivot for comparison
pivot = df.pivot(columns='ticker', values='cum_return')