Money Flow Index (MFI)
I. What is MFI
The Money Flow Index (MFI) is a technical analysis indicator jointly developed by Gene Quong and Avrum Soudack. MFI was first introduced in technical analysis literature in 1989 and has since gained widespread recognition in the trading community.
MFI belongs to the Volume Oscillator category of indicators and is often referred to as the “Volume-Weighted RSI” because it incorporates a volume factor on top of the traditional RSI framework. Unlike RSI, which is based solely on price movements, MFI simultaneously considers the direction of price changes and the accompanying volume, providing a more comprehensive measure of the intensity of money flowing in and out.
The default parameter is a period of , and the output value ranges from .
The key difference between MFI and RSI lies in the introduction of volume. For the same magnitude of price change, if it is accompanied by larger volume, MFI will produce a more extreme reading. This allows MFI to better capture market conditions where price and volume move in tandem.
II. Mathematical Principles and Calculation
2.1 Core Formulas
Step 1: Calculate the Typical Price
Where , , and are the high, low, and close prices on day , respectively.
Step 2: Calculate the Raw Money Flow
Where is the volume on day .
Step 3: Classify Positive and Negative Money Flow
When , the money flow for that day is counted as neither positive nor negative.
Step 4: Calculate the Money Flow Ratio
Step 5: Calculate the Money Flow Index (MFI)
2.2 Calculation Steps Summary
- Calculate the daily Typical Price
- Multiply by volume to get the Raw Money Flow
- Compare the current day’s with the previous day’s and classify as positive or negative money flow
- Sum the positive and negative money flows over the last days (default 14)
- Calculate the Money Flow Ratio , then plug into the formula to get
III. Python Implementation
import numpy as np
import pandas as pd
def money_flow_index(high: pd.Series, low: pd.Series,
close: pd.Series, volume: pd.Series,
period: int = 14) -> pd.Series:
"""
Calculate the Money Flow Index (MFI).
Parameters:
high : Series of high prices
low : Series of low prices
close : Series of close prices
volume : Series of volume
period : Lookback period, default 14
Returns:
Series of MFI values, range [0, 100]
"""
# 1. Typical Price
tp = (high + low + close) / 3.0
# 2. Raw Money Flow
raw_mf = tp * volume
# 3. Determine money flow direction
tp_diff = tp.diff()
positive_mf = pd.Series(np.where(tp_diff > 0, raw_mf, 0.0), index=tp.index)
negative_mf = pd.Series(np.where(tp_diff < 0, raw_mf, 0.0), index=tp.index)
# 4. Rolling sum
positive_sum = positive_mf.rolling(window=period).sum()
negative_sum = negative_mf.rolling(window=period).sum()
# 5. Money Flow Ratio and MFI
money_ratio = positive_sum / negative_sum.replace(0, np.nan)
mfi = 100.0 - 100.0 / (1.0 + money_ratio)
return mfi
# ============ Usage Example ============
if __name__ == '__main__':
np.random.seed(42)
n_days = 120
# Generate simulated OHLCV data
base_price = 50 + np.cumsum(np.random.randn(n_days) * 0.5)
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,
'volume': np.random.randint(50000, 500000, n_days).astype(float)
})
# Calculate MFI
df['mfi'] = money_flow_index(df['high'], df['low'], df['close'],
df['volume'], period=14)
print("=== MFI Calculation Results (last 15 rows) ===")
print(df[['close', 'volume', 'mfi']].tail(15).to_string())
# Generate trading signals
df['signal'] = np.where(df['mfi'] > 80, 'Overbought',
np.where(df['mfi'] < 20, 'Oversold', 'Neutral'))
print("\n=== Signal Statistics ===")
print(df['signal'].value_counts())
IV. Problems the Indicator Solves
4.1 Price-Volume Confirmation Analysis
MFI incorporates volume into the overbought/oversold assessment framework, answering a critical question: Is the current price movement supported by sufficient capital flow? If price rises but MFI fails to rise accordingly, the rally lacks volume confirmation and its sustainability is questionable.
4.2 Overbought/Oversold Detection
- MFI > 80: The market may be overbought. After sustained capital inflows, the potential for profit-taking increases.
- MFI < 20: The market may be oversold. After significant capital outflows, prices may have been pushed down excessively.
Similar to RSI, MFI can remain in overbought or oversold territory for extended periods during strong trends. Taking contrarian trades based solely on MFI readings carries significant risk. It is advisable to combine MFI with trend analysis.
4.3 Divergence Signals
MFI divergences are among its most valuable signals:
- Bearish Divergence: Price makes a new high, but MFI does not — upward momentum is weakening, a potential top may form.
- Bullish Divergence: Price makes a new low, but MFI does not — downward momentum is weakening, a potential bottom may form.
Because MFI incorporates volume information, its divergence signals are generally more reliable than pure RSI divergences.
4.4 Typical Trading Strategies
- Overbought/Oversold Strategy: Sell when MFI drops back below 80; buy when MFI rises back above 20.
- Divergence Strategy: Prepare to go short on bearish divergence; prepare to go long on bullish divergence.
- Centerline Crossover Strategy: MFI crossing above 50 is a bullish signal; crossing below 50 is a bearish signal.
- Failure Swing: Similar to RSI failure swings, MFI forms a high/low in the overbought/oversold zone and fails to break through.
V. Advantages, Disadvantages, and Use Cases
Advantages
| Advantage | Description |
|---|---|
| Combines price and volume | Considers both price movement and volume, providing richer information |
| Reliable divergence signals | Because it includes a volume factor, MFI divergences have higher predictive value than RSI divergences |
| Bounded indicator | Output is fixed within , making it easy to set standardized trading thresholds |
| Simple calculation | Clear logic, easy to understand and implement |
Disadvantages
| Disadvantage | Description |
|---|---|
| Lagging nature | The 14-period rolling window introduces some signal delay |
| Requires volume data | Limited applicability in markets without standardized volume data such as forex |
| False signals in strong trends | Like RSI, overbought/oversold signals may fail frequently in one-directional trends |
| Sensitive to volume anomalies | Sudden volume spikes (e.g., ex-dividend dates, IPO days) can cause significant indicator fluctuations |
Use Cases
- Best suited for: Stock and futures markets with reliable volume data; overbought/oversold detection in range-bound markets
- Moderately suited for: Use as a supplementary confirmation tool alongside trend indicators
- Not suited for: Forex markets (no centralized volume data); instruments with extremely low liquidity
Comparison with Similar Indicators
| Indicator | Volume | Output Range | Characteristics |
|---|---|---|---|
| MFI | Incorporated | 0—100 | Price-volume composite overbought/oversold indicator |
| RSI | Not considered | 0—100 | Momentum indicator based solely on price movement |
| OBV | Cumulative | Unbounded | Focuses on cumulative volume trends, not an oscillator |
| CMF | Period sum | -1 to 1 | Measures buying/selling pressure over a period |
Parameter Tuning Advice: The default 14-period is suitable for most daily chart analyses. Short-term traders may shorten it to 10 for more responsive signals; long-term investors may extend it to 21 to filter out noise. Overbought/oversold thresholds can be adjusted based on the characteristics of the instrument — use 90/10 for highly volatile instruments and 70/30 for less volatile ones.