Guide 11 min read

Volume Analysis with OBV and MFI: A Developer's Guide

How to use On-Balance Volume and Money Flow Index to confirm trends and spot reversals. Includes API integration examples and practical trading signals.

7Sections
7Code samples
11Min read
GuideCategory

Why Volume Matters

Price tells you what happened. Volume tells you how much conviction was behind it. A breakout on high volume is far more likely to sustain than one on thin volume. Volume indicators quantify this relationship, giving your algorithms an additional confirmation layer.

The TickAtlas API provides two key volume indicators: On-Balance Volume (OBV) for cumulative volume flow, and Money Flow Index (MFI) for a volume-weighted momentum oscillator.

On-Balance Volume (OBV)

OBV was introduced by Joe Granville in 1963. The logic is simple: on up days, the full volume is added to a running total. On down days, the full volume is subtracted. The direction of OBV, not its absolute value, is what matters.

Shell On-Balance Volume (OBV)
If Close > Previous Close:
    OBV = Previous OBV + Volume
If Close < Previous Close:
    OBV = Previous OBV - Volume
If Close == Previous Close:
    OBV = Previous OBV

OBV Rising + Price Rising

Healthy uptrend confirmed by volume. Stay long.

OBV Falling + Price Rising

Bearish divergence. The rally lacks conviction and may reverse.

Fetching OBV via API

Shell Fetching OBV via API
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/indicator?symbol=XAUUSD&indicator=OBV&timeframe=H4"

Response:

JSON Fetching OBV via API
{
  "success": true,
  "data": {
    "symbol": "XAUUSD",
    "timeframe": "H4",
    "indicator": "OBV",
    "value": 1548230,
    "bid": 2190.50,
    "ask": 2190.80,
    "updated_at": 1787229614,
    "server_time": "2026-08-20T12:40:14+00:00"
  }
}

Money Flow Index (MFI)

MFI is often called the "volume-weighted RSI." It uses both price and volume to measure buying and selling pressure. Like RSI, it oscillates between 0 and 100, with readings above 80 indicating overbought conditions and below 20 indicating oversold.

Shell Money Flow Index (MFI)
Typical Price = (High + Low + Close) / 3
Raw Money Flow = Typical Price * Volume

If Typical Price > Previous Typical Price:
    Positive Money Flow += Raw Money Flow
Else:
    Negative Money Flow += Raw Money Flow

Money Flow Ratio = Positive MF / Negative MF  (over 14 periods)
MFI = 100 - (100 / (1 + Money Flow Ratio))
Shell Money Flow Index (MFI)
curl -H "X-API-Key: YOUR_API_KEY" \
  "https://tickatlas.com/v1/indicator?symbol=XAUUSD&indicator=MFI_14&timeframe=H4"
JSON Money Flow Index (MFI)
{
  "success": true,
  "data": {
    "symbol": "XAUUSD",
    "timeframe": "H4",
    "indicator": "MFI_14",
    "value": 72.34,
    "bid": 2190.50,
    "ask": 2190.80,
    "updated_at": 1787229614,
    "server_time": "2026-08-20T12:40:14+00:00"
  }
}

Python: Volume Confirmation System

Here is a complete system that uses OBV trend direction and MFI levels to confirm or reject trade signals from other indicators:

Python Python: Volume Confirmation System
import requests
from typing import Optional

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://tickatlas.com/v1"

def fetch_indicator(symbol: str, indicator: str, timeframe: str) -> dict:
    resp = requests.get(
        f"{BASE_URL}/indicator",
        headers={"X-API-Key": API_KEY},
        params={"symbol": symbol, "indicator": indicator, "timeframe": timeframe},
    )
    resp.raise_for_status()
    return resp.json()["data"]

def volume_confirmation(
    symbol: str, timeframe: str, proposed_direction: str
) -> dict:
    """Check if volume supports a proposed trade direction."""
    obv_data = fetch_indicator(symbol, "OBV", timeframe)
    mfi_data = fetch_indicator(symbol, "MFI_14", timeframe)

    obv = obv_data["value"]
    mfi = mfi_data["value"]

    # For a real system, compare OBV to its own moving average
    # Here we use the MFI level as primary and OBV as secondary
    confirms = False
    reasons = []

    if proposed_direction == "long":
        if mfi < 80:
            confirms = True
            reasons.append(f"MFI at {mfi:.1f} — not overbought")
        else:
            reasons.append(f"MFI at {mfi:.1f} — OVERBOUGHT, caution")

        if mfi < 30:
            reasons.append("MFI oversold — strong buy signal from volume")

    elif proposed_direction == "short":
        if mfi > 20:
            confirms = True
            reasons.append(f"MFI at {mfi:.1f} — not oversold")
        else:
            reasons.append(f"MFI at {mfi:.1f} — OVERSOLD, caution")

        if mfi > 80:
            reasons.append("MFI overbought — strong sell signal from volume")

    return {
        "symbol": symbol,
        "direction": proposed_direction,
        "volume_confirms": confirms,
        "mfi": mfi,
        "obv": obv,
        "reasons": reasons,
    }

# Example: check if a long signal on XAUUSD has volume support
result = volume_confirmation("XAUUSD", "H4", "long")
print(f"Volume confirms: {result['volume_confirms']}")
for reason in result["reasons"]:
    print(f"  - {reason}")

OBV vs MFI: When to Use Each

Use OBV for trend confirmation

OBV is best at confirming whether a trend has genuine buying or selling pressure behind it. Compare OBV direction with price direction to spot divergences.

Use MFI for overbought/oversold

MFI works like RSI but includes volume weighting. It is better at identifying exhaustion points where buying or selling pressure is running out.

Use both together for confluence

When OBV confirms the trend direction and MFI is not at an extreme, you have strong volume confluence for a continuation trade.

Related Reading

Run this against live data.

Every account starts pay-as-you-go with $2.50 of credit and no card. Paste the key into the samples above and the requests work unchanged.

Prefer the API to the article

Build it instead of reading about it.

Create a key, run the first request, then extend one layer at a time. Every account starts pay-as-you-go with $2.50 of credit — no card required.