Bill Williams BW MFI

Bill Williams Market Facilitation Index on TradingView

The Market Facilitation Index divides a bar's high-low range by its volume. Its four states compare changes in that ratio and volume with the previous bar. BW MFI measures range per volume unit, without indicating price direction. It is different from the Money Flow Index oscillator.

BW MFI = (high - low) / volume

Range 3, volume 120: BW MFI = 0.025 price units per volume unit.

Copy the Pine Script example

Read the four states

Compare BW MFI itself, not just the raw range. The rules follow the MetaTrader definition. This example uses green, brown, blue, and pink, following the palette in the MetaQuotes implementation. Check the legend when using another script; authors can choose different colors.

Each comparison is against the previous bar.
StateBW MFIVolumeDirect observation
GreenHigherHigherMore range per volume unit with more volume.
Fade (brown)LowerLowerLess range per volume unit with less volume.
Fake (blue)HigherLowerMore range per volume unit despite lower volume.
Squat (pink)LowerHigherLess range per volume unit despite higher volume.

None of these comparisons uses the close, an order book, or trader identities. A green bar can accompany a falling price. The label "fake" does not prove manipulation, and a squat does not predict the direction of the next move.

Calculate one sequence bar by bar

These invented bars use consistent price and volume units. They are a calculation fixture, not market history or a backtest.

The same sequence exercises all four states, ties, and a volume gap.
BarHighLowVolumeBW MFIState
A1021001002 / 100 = 0.020Baseline
B1041011203 / 120 = 0.025Green
C103102801 / 80 = 0.0125Fade
D104102502 / 50 = 0.040Fake
E1051021003 / 100 = 0.030Squat
F1061031003 / 100 = 0.030Neutral: ties
G1051040UndefinedUnavailable
H1061041002 / 100 = 0.020No valid prior bar

E is the useful counterexample: its range rises from 2 to 3, but volume doubles from 50 to 100. The ratio falls from 0.040 to 0.030, so E is a squat. Classifying raw range changes instead would incorrectly label E green.

F has no strict increase or decrease and stays neutral. G has no defined ratio. H has a valid ratio but cannot be compared with G. The script does not skip backward across missing bars.

Check the volume denominator first

TradingView reports that some feeds supply no volume and others supply tick volume, a count of price updates. Inspect your exact symbol, provider, and timeframe in the Volume pane before using BW MFI. See TradingView's volume guidance.

  • Zero or missing volume makes the division unusable. The example returns na; replacing missing volume with 1 would create an artificial value.
  • Positive volume with a zero range produces a valid zero. Direct comparisons still work without dividing by the previous BW MFI.
  • Tick volume changes the unit to price range per update. It does not measure the number of traded shares or contracts.
  • Absolute values depend on price units and volume units. Compare a consistent feed and timeframe; do not apply one universal threshold across instruments.

Pine Script v6 with explicit missing-data rules

Paste the full example into TradingView's Pine Editor, save, and add it to the chart. It plots a histogram in a separate pane and provides four selectable alert conditions. The Data Window includes numeric state codes alongside the raw ratio.

Copy Pine Script

//@version=6
indicator("Bill Williams Market Facilitation Index", shorttitle="BW MFI", overlay=false, precision=8)

hasVolume = not na(volume) and volume > 0
bwMfi = hasVolume ? (high - low) / volume : na
canCompare = not na(bwMfi) and not na(bwMfi[1])
isGreen = canCompare and bwMfi > bwMfi[1] and volume > volume[1]
isFade = canCompare and bwMfi < bwMfi[1] and volume < volume[1]
isFake = canCompare and bwMfi > bwMfi[1] and volume < volume[1]
isSquat = canCompare and bwMfi < bwMfi[1] and volume > volume[1]

stateColor = isGreen ? color.lime : isFade ? color.rgb(139, 69, 19) : isFake ? color.blue : isSquat ? color.fuchsia : color.gray
plot(bwMfi, "Range / volume", color=stateColor, style=plot.style_columns)
// State codes: 0 = tie or no previous valid bar; 1 = green; 2 = fade; 3 = fake; 4 = squat.
stateCode = na(bwMfi) ? na : isGreen ? 1 : isFade ? 2 : isFake ? 3 : isSquat ? 4 : 0
plot(stateCode, "State code", display=display.data_window)

alertcondition(isGreen and barstate.isconfirmed, "BW MFI green", "BW MFI and volume increased on a closed bar.")
alertcondition(isFade and barstate.isconfirmed, "BW MFI fade", "BW MFI and volume decreased on a closed bar.")
alertcondition(isFake and barstate.isconfirmed, "BW MFI fake", "BW MFI increased and volume decreased on a closed bar.")
alertcondition(isSquat and barstate.isconfirmed, "BW MFI squat", "BW MFI decreased and volume increased on a closed bar.")

var table status = table.new(position.top_right, 1, 1)
if barstate.islast
    stateText = na(bwMfi) ? "BW MFI unavailable: check volume" : not canCompare ? "No previous valid bar" : isGreen ? "Green" : isFade ? "Fade" : isFake ? "Fake" : isSquat ? "Squat" : "Neutral: unchanged value"
    table.cell(status, 0, 0, stateText, text_color=color.white, bgcolor=color.new(color.black, 15))

This is a reference implementation with its own documented policy: ties are gray and missing volume is unavailable. The MetaQuotes source carries prior direction through ties and scales range by the symbol's point size. Do not expect identical values or colors on every edge case. Colors here are descriptive states, not trade entries.

  1. For a completed bar, divide its high-low range by its volume and compare with the Data Window.
  2. Check the previous bar and verify both comparisons against the state table.
  3. Create an alert for the required BW MFI condition and select Once Per Bar Close. The plotted live bar may change before it closes.
  4. If testing a strategy, define entries, exits, position sizing, costs, and a separate validation period. This indicator contains no orders or performance results.

BW MFI versus Money Flow Index

Money Flow Index uses typical price multiplied by volume, separates positive and negative flow over a lookback window, and converts their ratio to a 0 to 100 scale. Its common 20 and 80 levels have no corresponding meaning for BW MFI.TradingView documents that separate calculation.

Pine Script's ta.mfi() is Money Flow Index. For that oscillator, use the Money Flow Index guide. For the ratio on this page, use high, low, and volume directly.

Customize the conditions with Pineify

Give the Pine Script AI Coding Agent this example and a precise change request: "Keep BW MFI separate from Money Flow Index. Preserve the zero-volume and tie policies. Add a selectable alert for each closed-bar state and explain the resulting code. Run a syntax check."

Review generated changes against the worked sequence before using them. Syntax validation checks code; it does not validate data quality, trading performance, or your chosen rules.

Open Pine Script AI Coding Agent

Frequently asked questions

Is Market Facilitation Index the same as Money Flow Index?

No. Bill Williams BW MFI divides the current high-low range by volume. Money Flow Index uses typical price and volume over a lookback window and returns a 0 to 100 oscillator. Pine Script ta.mfi() calculates Money Flow Index, so it is not the formula used in this example.

What does a squat bar mean?

BW MFI fell while volume rose relative to the previous bar. This says range per unit of volume fell; the raw high-low range may still have increased. It supplies no bullish or bearish direction by itself.

Which settings does BW MFI need?

The raw formula has no moving-average length. This example compares each reading with the immediately preceding bar and uses no smoothing. Changing the chart timeframe changes the bars and their volume, so it changes the calculation.

Can I use Market Facilitation Index with forex tick volume?

You can calculate it when the selected feed provides positive tick volume. The denominator then counts price updates rather than traded shares or contracts. Results describe that feed and should not be interpreted as consolidated market volume.

Why are bars blank or gray in the example?

Missing or nonpositive volume produces no BW MFI value. A valid value is gray when the preceding bar is unavailable or when either comparison is unchanged. The status table and Data Window distinguish these cases. A zero range with positive volume is a valid zero reading, but a zero-height histogram column is not visible.

Can the color change before the bar closes?

Yes. High, low, and volume can change during the open bar. The example plots those live values but requires barstate.isconfirmed for its alert conditions. Create the alert in TradingView and select Once Per Bar Close. Closed-bar alerts do not establish a trading edge.

Sources and scope

Source definitions checked on October 17, 2026. The sequence and missing-data policy are documented examples created for this page.

Educational information, not investment advice. No state guarantees a reversal, continuation, or profitable trade.