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.
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.
| State | BW MFI | Volume | Direct observation |
|---|---|---|---|
| Green | Higher | Higher | More range per volume unit with more volume. |
| Fade (brown) | Lower | Lower | Less range per volume unit with less volume. |
| Fake (blue) | Higher | Lower | More range per volume unit despite lower volume. |
| Squat (pink) | Lower | Higher | Less 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.
| Bar | High | Low | Volume | BW MFI | State |
|---|---|---|---|---|---|
| A | 102 | 100 | 100 | 2 / 100 = 0.020 | Baseline |
| B | 104 | 101 | 120 | 3 / 120 = 0.025 | Green |
| C | 103 | 102 | 80 | 1 / 80 = 0.0125 | Fade |
| D | 104 | 102 | 50 | 2 / 50 = 0.040 | Fake |
| E | 105 | 102 | 100 | 3 / 100 = 0.030 | Squat |
| F | 106 | 103 | 100 | 3 / 100 = 0.030 | Neutral: ties |
| G | 105 | 104 | 0 | Undefined | Unavailable |
| H | 106 | 104 | 100 | 2 / 100 = 0.020 | No 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.
- For a completed bar, divide its high-low range by its volume and compare with the Data Window.
- Check the previous bar and verify both comparisons against the state table.
- Create an alert for the required BW MFI condition and select Once Per Bar Close. The plotted live bar may change before it closes.
- 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 AgentFrequently 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.
- MetaTrader 5: BW MFI formula and four combinations
- MetaQuotes: Market Facilitation Index implementation and colors
- TradingView: Money Flow (MFI)
- TradingView: Missing, zero, and tick volume
- TradingView Pine Script: Bar states and confirmed bars
Educational information, not investment advice. No state guarantees a reversal, continuation, or profitable trade.