← Back to Home
Technical Indicators Money Flow Index (MFI)

Technical Indicators Money Flow Index (MFI)

The Money Flow Index (MFI) is a technical oscillator that combines both price and volume data to measure buying and selling pressure. It is often referred to as the volume-weighted Relative Strength Index (RSI) because, while its calculation and interpretation are similar to the RSI, MFI incorporates volume, providing an arguably deeper insight into the strength behind price movements.

Theory: The MFI is calculated through a series of steps that transform raw price and volume data into a bounded oscillator (0-100):

  1. Calculate Typical Price (TP) for each period: The Typical Price is an average of the high, low, and closing prices for a given period. TP = \frac{(High + Low + Close)}{3}

  2. Calculate Raw Money Flow (RMF): This is the Typical Price multiplied by the volume for that period. It represents the total value of transactions for the period, adjusted by its typical price. RMF = TP \times Volume

  3. Determine Positive and Negative Money Flow: Over a specified lookback period (N, typically 14 periods):

    • Positive Money Flow (PMF): If the Typical Price of the current period is greater than the Typical Price of the previous period, its Raw Money Flow is considered Positive Money Flow. Sum all Positive Money Flows over N periods.
    • Negative Money Flow (NMF): If the Typical Price of the current period is less than the Typical Price of the previous period, its Raw Money Flow is considered Negative Money Flow. Sum all Negative Money Flows over N periods.
    • If the Typical Price is unchanged, that period’s Raw Money Flow is discarded.
  4. Calculate the Money Flow Ratio (MFR): This is the ratio of the N-period sum of Positive Money Flow to the N-period sum of Negative Money Flow. MFR = \frac{\sum \text{Positive Money Flow over N periods}}{\sum \text{Negative Money Flow over N periods}}

  5. Calculate the Money Flow Index (MFI): The MFI is then scaled to oscillate between 0 and 100 using a formula analogous to the RSI: MFI = 100 - \frac{100}{(1 + MFR)} If the N-period sum of Negative Money Flow is zero, MFR is considered infinite, and MFI is 100. If the N-period sum of Positive Money Flow is zero, MFR is zero, and MFI is 0.

Usage: The Money Flow Index is interpreted in a manner similar to the RSI, but its inclusion of volume can sometimes offer more robust signals.

TA-Lib Function: The Technical Analysis Library (TA-Lib) provides a function for calculating the Money Flow Index:

talib.MFI(high_prices, low_prices, close_prices, volume, timeperiod=14)

Code Example (Calculation & Plot with yfinance Data):

The Python code below demonstrates fetching HLCV data using yfinance, calculating the MFI, and plotting the price alongside the MFI indicator, including overbought, oversold, and midpoint lines.

import yfinance as yf
import talib
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

# --- 1. Data Fetching using yfinance ---
ticker_symbol = "NVDA"  # Example: NVIDIA Corporation
# Fetching a bit more data initially to ensure enough for indicator calculation start
data_start_date = "2022-11-01" # Ensure enough data for lookback period
plot_start_date = "2023-01-01" # Start plotting from here
data_end_date = "2024-05-01"

data = yf.download(ticker_symbol, start=data_start_date, end=data_end_date, auto_adjust=False, progress=False)

if data.empty or not all(col in data.columns for col in ['High', 'Low', 'Close', 'Volume']) or \
   any(data[col].isnull().all() for col in ['High', 'Low', 'Close', 'Volume']):
    print(f"Insufficient HLCV data found for {ticker_symbol}. Exiting.")
else:
    # Complying with user preference for droplevel
    if isinstance(data.columns, pd.MultiIndex):
        data.columns = data.columns.droplevel(level=1)

    # Prepare data: ensure no NaNs in HLCV for the period used by TA-Lib
    ohlcv_data = data[['High', 'Low', 'Close', 'Volume']].dropna()

    high_prices = ohlcv_data['High']
    low_prices = ohlcv_data['Low']
    close_prices = ohlcv_data['Close']
    volume_data = ohlcv_data['Volume'].astype(float) # Ensure volume is float


    # --- 2. Money Flow Index (MFI) Calculation ---
    time_period_mfi = 14 # Standard period for MFI

    # MFI requires HLCV data and sufficient lookback period.
    # TA-Lib will output NaNs for the initial 'timeperiod' entries.
    if len(close_prices) >= time_period_mfi :
        mfi_values = talib.MFI(
            high_prices, low_prices, close_prices, volume_data,
            timeperiod=time_period_mfi
        )
        indicator_name = f"MFI({time_period_mfi})"
        print(f"\n--- {indicator_name} - Money Flow Index for {ticker_symbol} ---")

        # For printing, filter out NaNs. For plotting, NaNs will result in gaps.
        valid_mfi = mfi_values[~np.isnan(mfi_values)]
        if len(valid_mfi) >= 5:
            print(f"Output {indicator_name} (last 5 valid): {valid_mfi[-5:].round(2)}")
        elif len(valid_mfi) > 0:
            print(f"Output {indicator_name} (all valid): {valid_mfi.round(2)}")
        else:
            print(f"Output {indicator_name}: No valid MFI values calculated (all NaNs).")

        # Filter data for the desired plotting period
        # Ensure mfi_values (which is a numpy array) is converted to a Pandas Series with the correct index
        # before trying to align with plot_ohlcv_data.index
        mfi_series = pd.Series(mfi_values, index=ohlcv_data.index)
        
        plot_ohlcv_data = ohlcv_data[ohlcv_data.index >= plot_start_date]
        plot_mfi_values = mfi_series[plot_ohlcv_data.index] # Align MFI series to the plotting data
        plot_date_index = plot_ohlcv_data.index
        plot_close_prices = plot_ohlcv_data['Close']


        # --- 3. Plotting ---
        if not plot_date_index.empty:
            fig, axes = plt.subplots(2, 1, figsize=(14, 10), sharex=True,
                                     gridspec_kw={'height_ratios': [3, 1]})

            # Plot Price
            axes[0].plot(plot_date_index, plot_close_prices, label='Close Price', color='blue')
            axes[0].set_title(f'{ticker_symbol} Price and {indicator_name}')
            axes[0].set_ylabel('Price')
            axes[0].legend(loc='upper left')
            axes[0].grid(True)

            # Plot Money Flow Index
            axes[1].plot(plot_date_index, plot_mfi_values, label=indicator_name, color='orange')
            axes[1].axhline(80, color='red', linestyle='--', linewidth=0.8, label='Overbought (80)')
            axes[1].axhline(50, color='gray', linestyle=':', linewidth=0.8, label='Midpoint (50)')
            axes[1].axhline(20, color='green', linestyle='--', linewidth=0.8, label='Oversold (20)')
            axes[1].set_ylim(0, 100) # MFI oscillates between 0 and 100
            axes[1].set_ylabel('MFI Value')
            axes[1].set_xlabel('Date')
            axes[1].legend(loc='center left', bbox_to_anchor=(1, 0.5)) # Place legend outside
            axes[1].grid(True)

            plt.tight_layout(rect=[0, 0, 0.9, 1]) # Adjust layout to make space for external legend
            plt.show()
        else:
             print(f"No data available for the plotting period starting {plot_start_date}.")


    else:
        print(f"\nSkipping MFI plot for {ticker_symbol}: Insufficient data (need >= {time_period_mfi} points after cleaning).")
        if not ohlcv_data.empty:
             print(f"Cleaned data available for {len(ohlcv_data)} periods. MFI period is {time_period_mfi}.")
Pasted image 20250603003827.png

Explanation of the Code:

  1. Import Libraries: Standard data science and plotting libraries are imported.
  2. Data Fetching:
    • yf.download() retrieves HLCV data. User preferences auto_adjust=False and droplevel are applied.
    • Checks ensure all necessary HLCV columns are present and contain data.
    • ohlcv_data = data[['High', 'Low', 'Close', 'Volume']].dropna() cleans the data by removing rows with any missing HLCV values.
    • Individual series for High, Low, Close, and Volume (as float) are prepared.
  3. Money Flow Index (MFI) Calculation:
    • time_period_mfi is set (typically 14).
    • A check if len(close_prices) >= time_period_mfi: ensures enough data for TA-Lib’s MFI calculation (TA-Lib will produce NaNs for the first timeperiod-1 calculations of money flow, and one more for the ratio, leading to timeperiod NaNs in the MFI output).
    • talib.MFI() computes the MFI values.
    • The last few valid MFI values are printed for quick review.
  4. Data Slicing for Plotting: Data is sliced to the plot_start_date for a cleaner chart. The MFI numpy array is converted to a Pandas Series with the correct index to allow for this alignment.
  5. Plotting:
    • plt.subplots(2, 1, ...) creates two stacked subplots.
    • Price Plot (axes[0]): Shows the closing prices.
    • MFI Plot (axes[1]): Displays the MFI.
      • axhline() adds horizontal lines at 80 (overbought), 50 (midpoint), and 20 (oversold) for easy reference.
      • set_ylim(0, 100) sets the y-axis scale for the MFI.
      • The legend is placed outside the plot for better visibility of the MFI lines.
    • plt.tight_layout() adjusts spacing, with rect to accommodate the external legend.
    • plt.show() displays the chart.
  6. Insufficient Data Handling: Appropriate messages are shown if data is insufficient.

By integrating volume into a momentum oscillator framework, the Money Flow Index offers traders a more comprehensive tool for gauging market strength and identifying potential turning points that might be missed by price-only indicators.