Chaikin Money Flow (CMF)
I. What is CMF
Chaikin Money Flow (CMF) is a technical analysis indicator developed by American financial analyst Marc Chaikin. CMF builds upon Chaikin’s own Accumulation/Distribution Line (A/D Line), but transforms the cumulative A/D Line into a bounded, period-based oscillator indicator.
CMF belongs to the Volume Oscillator category of indicators, with a default period parameter of (approximately one month of trading days). It measures the strength of buying and selling pressure over a given period by computing the volume-weighted close position within a fixed window.
The core idea behind CMF is: within a given period, if most trading days see the price close in the upper half of the intraday range accompanied by large volume, then CMF is positive, indicating that buying pressure dominates; conversely, CMF is negative, indicating that selling pressure dominates.
CMF can be viewed as a “normalized version” of the A/D Line — by dividing by total volume, it becomes bounded and thus allows for horizontal comparison across different instruments and time periods.
II. Mathematical Principles and Calculation
2.1 Core Formulas
Step 1: Calculate the Close Location Value (CLV)
CLV ranges from .
Step 2: Calculate Chaikin Money Flow (CMF)
Where is the lookback period (default 20) and is the volume on day .
2.2 Intuitive Understanding
The CMF calculation logic can be understood as follows:
- The numerator is the sum of “directional weighted volume,” with large contributions from days with high volume and high closing positions
- The denominator is the total volume sum, serving as a normalization factor
- The final result represents: the volume-weighted average capital flow direction over the past days
The theoretical range of CMF is , but extreme values are rarely reached in practice.
The key difference between CMF and the A/D Line: the A/D Line accumulates continuously from the starting point, with values growing ever larger or smaller; CMF is calculated as a ratio within a fixed window, always remaining within a bounded range. This makes CMF more suitable as a direct basis for trading signals.
2.3 Calculation Steps
- Calculate CLV for each day:
- Calculate CLV x Volume for each day (directional money flow)
- Within a rolling window of , sum CLV x Volume and Volume separately
- Divide the two sums to get CMF
III. Python Implementation
import numpy as np
import pandas as pd
def chaikin_money_flow(high: pd.Series, low: pd.Series,
close: pd.Series, volume: pd.Series,
period: int = 20) -> pd.Series:
"""
Calculate Chaikin Money Flow (CMF).
Parameters:
high : Series of high prices
low : Series of low prices
close : Series of close prices
volume : Series of volume
period : Lookback period, default 20
Returns:
Series of CMF values, theoretical range [-1, +1]
"""
# 1. Calculate CLV
hl_range = high - low
clv = pd.Series(
np.where(hl_range != 0,
(2.0 * close - low - high) / hl_range,
0.0),
index=close.index
)
# 2. CLV x Volume (directional money flow)
mf_volume = clv * volume
# 3. Rolling sum
mf_sum = mf_volume.rolling(window=period).sum()
vol_sum = volume.rolling(window=period).sum()
# 4. CMF = money flow sum / volume sum
cmf = mf_sum / vol_sum.replace(0, np.nan)
return cmf
# ============ Usage Example ============
if __name__ == '__main__':
np.random.seed(42)
n_days = 120
# Generate simulated OHLCV data
base_price = 60 + np.cumsum(np.random.randn(n_days) * 0.4)
df = pd.DataFrame({
'open': base_price + np.random.randn(n_days) * 0.3,
'high': base_price + np.abs(np.random.randn(n_days) * 1.0),
'low': base_price - np.abs(np.random.randn(n_days) * 1.0),
'close': base_price + np.random.randn(n_days) * 0.2,
'volume': np.random.randint(80000, 600000, n_days).astype(float)
})
# Ensure high >= close >= low
df['high'] = df[['open', 'high', 'close']].max(axis=1)
df['low'] = df[['open', 'low', 'close']].min(axis=1)
# Calculate CMF
df['cmf'] = chaikin_money_flow(df['high'], df['low'], df['close'],
df['volume'], period=20)
print("=== CMF Calculation Results (last 15 rows) ===")
print(df[['close', 'volume', 'cmf']].tail(15).to_string())
# Generate trading signals
df['pressure'] = np.where(df['cmf'] > 0.05, 'Buying Pressure',
np.where(df['cmf'] < -0.05, 'Selling Pressure', 'Neutral'))
print("\n=== Buying/Selling Pressure Statistics ===")
print(df['pressure'].value_counts())
# CMF zero-line crossover signals
df['cmf_prev'] = df['cmf'].shift(1)
df['cross_signal'] = np.where(
(df['cmf'] > 0) & (df['cmf_prev'] <= 0), 'Bullish Cross (above zero)',
np.where(
(df['cmf'] < 0) & (df['cmf_prev'] >= 0), 'Bearish Cross (below zero)',
'No Signal'))
crosses = df[df['cross_signal'] != 'No Signal'][['close', 'cmf', 'cross_signal']]
print("\n=== Zero-Line Crossover Signals ===")
print(crosses.to_string())
IV. Problems the Indicator Solves
4.1 Quantifying Buying/Selling Pressure
CMF transforms the abstract concept of “buying/selling pressure” into a clear numerical indicator:
- CMF > 0: Buying pressure dominated over the past days — net capital inflow
- CMF < 0: Selling pressure dominated over the past days — net capital outflow
- Larger absolute CMF value: Stronger pressure in the corresponding direction
4.2 Zero-Line Crossover Signals
CMF crossing the zero line is its most basic trading signal:
- CMF crosses from negative to positive (above zero): Buying forces begin to dominate, bullish signal
- CMF crosses from positive to negative (below zero): Selling forces begin to dominate, bearish signal
4.3 Trend Confirmation and Divergence
- Price rising + CMF > 0: The uptrend is supported by capital, the trend is healthy
- Price rising + CMF < 0: The rally lacks capital support, possibly a false rally
- Price falling + CMF > 0: Capital is still flowing in during the decline, possibly setting up a reversal
CMF tends to oscillate around the zero line during sideways consolidation, generating frequent false signals. It is recommended to set a buffer zone (e.g., ) and only confirm signals when CMF clearly breaks through the buffer.
4.4 Typical Trading Strategies
- Zero-Line Crossover Strategy: Buy when CMF crosses above zero, sell when it crosses below zero
- Strength Filter Strategy: Only go long when CMF > +0.10 and short when CMF < -0.10 (filtering weak signals)
- Trend Confirmation Strategy: Use CMF to confirm price trends — only enter when CMF direction aligns with the trend direction
- Multi-Timeframe Strategy: When daily CMF is positive, look for long opportunities on the hourly timeframe
V. Advantages, Disadvantages, and Use Cases
Advantages
| Advantage | Description |
|---|---|
| Bounded indicator | Values range within , making it easy to set standardized thresholds and compare across instruments |
| Clear signals | Above zero means buying pressure, below zero means selling pressure — judgment is intuitive |
| Combines price and volume | Simultaneously considers intraday price position and volume magnitude |
| Non-cumulative | Uses a fixed window, does not grow indefinitely like the A/D Line, easier to analyze |
Disadvantages
| Disadvantage | Description |
|---|---|
| Window length sensitivity | Different period parameters may produce different signals |
| Noisy during sideways markets | Tends to generate frequent false zero-line crossovers in trendless markets |
| Ignores gaps | Like the A/D Line, does not account for opening price and gap information |
| Extreme values are rare | In practice, it rarely reaches ; most of the time it stays within |
Use Cases
- Best suited for: Medium-term trend confirmation; assessing capital flow direction before and after breakouts
- Moderately suited for: Use alongside trend-following indicators to filter false breakouts
- Not suited for: Short-term high-frequency trading (the 20-period window is relatively slow); narrow range-bound markets
Comparison with Similar Indicators
| Indicator | Calculation Method | Output Range | Characteristics |
|---|---|---|---|
| CMF | CLV-weighted period average | Bounded, suitable for cross-instrument comparison | |
| A/D Line | CLV x Volume cumulative | Unbounded | Long-term cumulative trend, absolute values are meaningless |
| MFI | TP-weighted RSI structure | Has overbought/oversold zone concepts | |
| OBV | Full volume add/subtract | Unbounded | Simplest but crudest |
Parameter Tuning Advice: The default 20-period (one month) is suitable for daily chart medium-term analysis. For more responsive signals, shorten to 10 periods, but be aware of increased noise. For weekly analysis, keep the 20-period unchanged (representing approximately 5 months). The zero-line crossover buffer threshold should be adjusted based on the instrument’s volatility — use for highly volatile instruments and for less volatile ones.