,

On Balance Volume (OBV): Formula, Divergence and Python

Posted by

Updated May 2026: I’ve refreshed this OBV guide with a clearer formula explanation, more detailed notes on divergence and volume confirmation, and an updated Python chart tutorial.

Balanced scales image used to introduce the On Balance Volume indicator
OBV tries to put price and volume on the same scale of argument: are rising prices being backed by rising volume pressure, or not?
Table of Contents

    What Is On Balance Volume?

    On Balance Volume, usually shortened to OBV, is a volume-based indicator that keeps a running total of volume.

    The logic is straightforward. If price closes higher than the previous bar, that bar’s volume is added to OBV. If price closes lower, that bar’s volume is subtracted. If price closes unchanged, OBV stays the same.

    The idea is to watch whether volume is supporting the price move. If price is rising and OBV is rising too, volume is broadly confirming the move. If price is rising but OBV is falling, the rally may be less convincing because volume is not moving with price.

    I would not treat OBV as some sneaky early-warning system. It is still based on historical price and volume. It can help show accumulation, distribution and divergence, but the chart still needs context.

    In this guide I’ll walk through where OBV came from, how the formula works, how traders read OBV trends and divergence, and how to calculate and plot OBV in Python.

    Where OBV Comes From

    OBV was introduced by Joseph Granville in his 1963 book Granville’s New Key to Stock Market Profits.

    Granville’s basic belief was that volume often leads price. If volume starts building while price has not yet moved much, the market may be storing pressure before a larger move.

    That “volume before price” idea is why traders still look at OBV. They are not only asking whether price is going up or down. They are asking whether volume is confirming the move, quietly disagreeing with it, or warning that something is changing under the surface.

    This is also where some care is needed. OBV assigns the whole bar’s volume as positive or negative based only on whether the close rose or fell. That makes it easy to read, but it also means the indicator is fairly blunt.

    How On Balance Volume Is Calculated

    OBV is a cumulative indicator. It starts from an initial value, often zero, and then adds or subtracts each bar’s volume depending on whether the close rose or fell.

    Before the formula, here are the symbols:

    OBVₜ means the current OBV value.

    OBVₜ₋₁ means the previous OBV value.

    Vₜ means the current bar’s volume.

    Cₜ means the current close.

    Cₜ₋₁ means the previous close.

    OBV_t =
    \begin{cases}
    OBV_{t-1} + V_t, & \text{if } C_t > C_{t-1} \\
    OBV_{t-1} - V_t, & \text{if } C_t < C_{t-1} \\
    OBV_{t-1}, & \text{if } C_t = C_{t-1}
    \end{cases}

    OBV adds volume on up closes, subtracts volume on down closes, and does nothing when the close is unchanged.

    For example, if yesterday’s OBV was 1,000,000 and today closes higher on volume of 200,000, today’s OBV becomes 1,200,000.

    If the next bar closes lower on volume of 150,000, OBV falls to 1,050,000.

    The absolute OBV number is not usually the most important part. Because OBV is cumulative, its level depends on where the calculation started. Traders usually care more about the direction of the OBV line, trend breaks in OBV, and divergence between OBV and price.

    This is why two charting platforms can show slightly different OBV levels while still showing the same useful behaviour. If they start the calculation from different dates, the raw number may differ, but the rises, falls and divergences should look similar.

    How Traders Use OBV

    OBV is mainly useful as a confirmation and divergence tool.

    The first thing I look at is the direction of the OBV line. If price is rising and OBV is rising too, volume is broadly supporting the move. If price is rising but OBV is flat or falling, the rally may be weaker than it looks.

    The same applies on the downside. If price is falling and OBV is falling too, volume is confirming the sell-off. If price is falling but OBV starts rising, downside pressure may be fading.

    The second useful reading is divergence. A bullish OBV divergence appears when price makes a lower low but OBV makes a higher low. That can suggest selling pressure is weakening. A bearish OBV divergence appears when price makes a higher high but OBV makes a lower high. That can suggest the rally is not being backed by volume.

    I would not treat OBV divergence as a trade by itself, but it can be a warning sign. Price still needs to confirm the turn.

    Another practical use is watching OBV trend breaks. If OBV has been rising steadily and then breaks its own trendline before price does, it may be an early warning that participation is changing. The same can happen in reverse during a downtrend.

    One caveat matters for forex and CFDs. Exchange-traded stocks and futures have clearer volume data. Spot FX does not have one central exchange, so many platforms use tick volume or broker-provided volume instead. OBV can still be useful there, but the quality of the volume input matters.

    OBV readingWhat it showsHow I would read it
    Price rising, OBV risingVolume supports the rallyBullish confirmation
    Price rising, OBV fallingVolume does not confirm pricePossible bearish warning
    Price falling, OBV fallingVolume supports the sell-offBearish confirmation
    Price falling, OBV risingSelling pressure may be fadingPossible bullish warning
    OBV breaks its own trendlineVolume behaviour changes before priceEarly warning, not a trigger
    Large one-off volume spikeOBV may jump sharplyCheck the news or event behind it
    Common OBV readings and how traders interpret them

    OBV Strengths and Limitations

    OBV is useful because it gives volume a direction. Instead of looking at volume bars one by one, the indicator builds a running line that rises when volume is attached to up closes and falls when volume is attached to down closes.

    That makes OBV easy to compare with price. If both are moving in the same direction, volume is broadly confirming the trend. If they start to disagree, the divergence is worth investigating.

    The weakness is that OBV is blunt. It assigns the full bar’s volume as positive or negative based only on whether the close rose or fell. It does not care where the close sits inside the day’s range. A tiny up close on huge volume is still added. A tiny down close on huge volume is still subtracted.

    OBV can also be distorted by one-off volume spikes. Earnings, index rebalances, contract rolls, corporate actions, or sudden news can push the line sharply and make the next few readings harder to interpret.

    The absolute OBV number is not usually the point. The trend, slope, divergence and breaks in the OBV line are usually more useful than the raw value.

    StrengthWhy it helps
    Simple calculationEasy to understand and code
    Combines price direction with volumeShows whether volume is backing the move
    Useful for divergenceCan warn when price and volume stop agreeing
    Trend confirmationRising price plus rising OBV is cleaner than rising price alone
    Works across timeframesCan be used on daily, intraday or weekly charts where volume data is available
    Main strengths of the OBV indicator
    WeaknessWhy it matters
    Blunt volume treatmentAll volume is added or subtracted based only on close direction
    Sensitive to volume spikesOne event can distort the line
    Arbitrary starting pointThe absolute OBV value depends on where the calculation begins
    Volume quality variesSpot FX and CFD volume may not match exchange volume
    Needs price contextOBV alone does not define entry, stop or target
    Main limitations of the OBV indicator

    OBV vs Accumulation/Distribution Line and Other Volume Indicators

    OBV is not the only volume-based indicator traders use. The closest comparison is the Accumulation/Distribution Line, because both try to turn price and volume into a running measure of buying or selling pressure.

    Chaikin Money Flow is another useful comparison. CMF looks at where price closes inside the high-low range and weights that by volume over a lookback period. OBV is simpler: it only checks whether the close was higher or lower than the previous close, then adds or subtracts the full bar’s volume.

    Money Flow Index takes a different route again. It combines price and volume into a bounded oscillator, so traders often read it more like a volume-weighted RSI.

    Raw volume bars and volume moving averages are simpler still. They show how much activity occurred, but they do not give that activity a cumulative bullish or bearish direction by themselves.

    IndicatorMain inputWhat it tries to showMain weakness
    OBVClose vs previous close + volumeWhether volume is accumulating on up closes or down closesIgnores where price closed inside the bar
    Accumulation/Distribution LineClose location inside high-low range + volumeWhether volume is leaning toward accumulation or distributionMore complex and can disagree with OBV
    Chaikin Money FlowMoney flow volume over a lookback periodBuying or selling pressure over recent barsCan be distorted by gaps and close-location quirks
    Money Flow IndexTypical price + volumeVolume-weighted momentum / stretched conditionsCan give false overbought or oversold readings in trends
    Volume moving averageRaw volume smoothed over timeWhether activity is high or low versus normalNo directional signal by itself
    How OBV compares with other volume-based indicators

    OBV Key Takeaways Before We Code

    • OBV is a cumulative volume indicator.
    • It adds volume when price closes higher and subtracts volume when price closes lower.
    • The raw OBV value depends on the starting point, so the direction and shape of the line matter more than the absolute number.
    • Rising price with rising OBV supports a bullish reading.
    • Rising price with falling OBV can warn that volume is not confirming the move.
    • Falling price with falling OBV supports a bearish reading.
    • Falling price with rising OBV can warn that selling pressure may be fading.
    • OBV divergence is useful, but it still needs price confirmation.
    • Large volume spikes can distort OBV.
    • OBV works best when the volume data is reliable, which is easier with exchange-traded stocks and futures than with decentralised spot FX.
    • The Python tutorial below calculates OBV and plots it under a candlestick chart.

    Coding OBV in Python and Plotting the Chart

    Now we can build the On Balance Volume indicator in Python.

    I am going to keep this as a step-by-step tutorial rather than dropping in one large script. Each Python-labelled block goes into the same file, in order. By the end, we will have downloaded market data, calculated OBV, and plotted it below a candlestick chart.

    For this example I use SPY so the chart has clean daily price and exchange-volume data from Yahoo Finance. The same logic can be tested on other markets, but remember that volume quality varies. Exchange-traded stocks and futures usually have cleaner volume than decentralised spot FX or many CFD feeds.

    Step 1: Install the Python libraries

    Bash
    python -m pip install yfinance pandas mplfinance matplotlib

    On some Windows machines, this version works instead:

    Bash
    py -m pip install yfinance pandas mplfinance matplotlib

    Step 2: Create the file and import the libraries

    Create a new Python file and save it as:

    obv_indicator.py

    At the top of the file, add:

    Python
    import pandas as pd
    import yfinance as yf
    import mplfinance as mpf
    from matplotlib.lines import Line2D

    pandas stores the price data in a table and lets us calculate OBV.

    yfinance downloads the market data.

    mplfinance draws the candlestick chart.

    Line2D lets us create a clean legend for the OBV line.

    Step 3: Add the settings

    Next, add a small settings section near the top of the file.

    Python
    ticker = "SPY"
    chart_title = "SPDR S&P 500 ETF"
    
    start_date = "2025-05-01"
    end_date = "2026-05-01"

    ticker is the Yahoo Finance symbol.

    chart_title is the title printed on the chart.

    The dates use YYYY-MM-DD format. yfinance treats the end date as a cut-off, so you can push it one trading day later if you want the most recent available bar included.

    Step 4: Download the market data

    Python
    data = yf.download(
        ticker,
        start=start_date,
        end=end_date,
        auto_adjust=True,
        progress=False,
        multi_level_index=False
    )
    
    if data.empty:
        raise RuntimeError("No data was downloaded. Check the ticker symbol and date range.")
    
    if isinstance(data.columns, pd.MultiIndex):
        data.columns = data.columns.get_level_values(0)
    
    data.index = pd.DatetimeIndex(data.index)

    This downloads open, high, low, close and volume data.

    auto_adjust=True keeps the price series adjusted where applicable.

    progress=False removes the download progress bar.

    multi_level_index=False keeps the columns easier to work with.

    The final line makes sure the index is treated as dates, which mplfinance expects when plotting.

    Step 5: Define the OBV function

    Python
    def calculate_obv(data):
        close = data["Close"]
        volume = data["Volume"]
    
        obv = pd.Series(0, index=data.index, dtype="float64")
    
        for i in range(1, len(data)):
            if close.iloc[i] > close.iloc[i - 1]:
                obv.iloc[i] = obv.iloc[i - 1] + volume.iloc[i]
            elif close.iloc[i] < close.iloc[i - 1]:
                obv.iloc[i] = obv.iloc[i - 1] - volume.iloc[i]
            else:
                obv.iloc[i] = obv.iloc[i - 1]
    
        return obv

    The function checks each close against the previous close.

    If the close is higher, that bar’s volume is added.

    If the close is lower, that bar’s volume is subtracted.

    If the close is unchanged, OBV stays where it was.

    Step 6: Calculate OBV

    Now call the function and add OBV to the data table.

    Python
    data["OBV"] = calculate_obv(data)
    
    plot_data = data.dropna(subset=["OBV"])

    Think of data as a spreadsheet. It already has Open, High, Low, Close and Volume columns. This step adds a new column called OBV.

    Step 7: Define the OBV chart line

    Next we tell mplfinance how to draw the OBV line below the price chart.

    Python
    obv_plot = [
        mpf.make_addplot(
            plot_data["OBV"],
            panel=2,
            color="blue",
            width=1.2,
            ylabel="OBV"
        )
    ]

    panel=2 places OBV below the price and volume panels.

    The blue line is the running OBV total.

    Step 8: Create the chart

    Now create the candlestick chart and add the OBV panel.

    Python
    fig, axes = mpf.plot(
        plot_data,
        type="candle",
        style="yahoo",
        volume=True,
        addplot=obv_plot,
        panel_ratios=(3, 1, 1.4),
        title=f"{chart_title} with On Balance Volume",
        figsize=(11, 7),
        returnfig=True
    )
    
    fig.subplots_adjust(
        left=0.07,
        right=0.90,
        top=0.92,
        bottom=0.16,
        hspace=0.05
    )

    type="candle" gives us the candlestick chart.

    volume=True adds the volume panel.

    addplot=obv_plot adds the OBV line.

    panel_ratios controls the relative size of the price, volume and OBV panels.

    subplots_adjust gives the chart extra room so the right-hand labels and angled dates are not clipped.

    Step 9: Add the legend and show the chart

    Finally, add a legend, save the image and show the chart.

    Python
    obv_axis = axes[4] if len(axes) > 4 else axes[-1]
    
    legend_items = [
        Line2D([], [], color="blue", label="OBV")
    ]
    
    obv_axis.legend(handles=legend_items, loc="upper left")
    
    fig.savefig("obv_indicator_chart.png", dpi=150, bbox_inches="tight")
    
    mpf.show()

    fig.savefig() saves the chart as a PNG image in the same folder as the script.

    mpf.show() opens the chart window.

    Step 10: Run the script

    Save obv_indicator.py by pressing Ctrl+S.

    The easiest route is usually to click the play button in the top-right corner of VS Code. If that works, the chart window should open.

    You can also run it from the terminal. Open Terminal > New Terminal, move into the folder where you saved the script, then run:

    Bash
    python obv_indicator.py

    On some Windows setups, use:

    Bash
    py obv_indicator.py

    Your chart should show SPY candlesticks at the top, volume underneath, and an OBV panel below that. The exact shape will depend on the ticker and date range you choose but should look something like mine seen below:

    VS Code screenshot showing a Python-generated SPY candlestick chart with volume and an OBV indicator panel below
    SPY price chart with On Balance Volume plotted from the Python script. Price makes a strong recovery into the right side of the chart, while OBV has not clearly returned to its earlier high, showing why traders watch OBV for volume confirmation as well as direction.

    In this example, OBV broadly confirms the earlier advance because the line rises with price. Later, after the sharp pullback and recovery, price pushes toward new highs while OBV is still below its earlier peak. That does not automatically mean the rally must fail, but it is the kind of non-confirmation OBV traders would notice.

    If you want to double check your result, bring up the same chart and timeframe on say, Yahoo Finance website and add the OBV indicator to it. I can confirm their OBV line looks identical in behaviour to what we have here.

    Once the script works, start changing the inputs.

    To change the market, edit:

    Python
    ticker = "SPY"
    chart_title = "SPDR S&P 500 ETF"

    To change the date range, edit:

    Python
    start_date = "2025-05-01"
    end_date = "2026-05-01"

    Try the script on a liquid stock, ETF or futures proxy first. If you use it on forex or CFDs, check what kind of volume your data source is actually providing. Spot FX platforms often use tick volume rather than centralised exchange volume.

    Further Reading

    For the original OBV source, start with Granville’s book. For practical comparison, it is also worth reading up on the Accumulation/Distribution Line and other volume-based indicators like Chaikin Money Flow.

    Granville, J. (1963). Granville’s New Key to Stock Market Profits. Prentice-Hall.