How to Code the Money Flow Index (MFI) in Pine Script
Money flow, positive/negative periods, and overbought/oversold context
MFI classifies price-times-volume amounts by whether the selected source rose or fell from the previous bar. It does not identify buyer-initiated trades, institutional orders or actual net cash entering an asset. This guide provides a Pine v6 example with explicit missing-data rules, 80/20 reference levels and confirmed alerts.
What Is the Money Flow Index?
MFI scales positive directional flow relative to positive plus negative directional flow into a 0–100 oscillator when prices and volume meet the calculation assumptions. Raw flow is selected source × bar volume. Rising-source bars contribute to the positive sum, falling-source bars to the negative sum, and unchanged-source bars to neither.
TradingView documents the typical-price formula. Calling the output buying or selling pressure is an interpretation of aggregated bars, not a measurement of trade aggressors. A high reading does not prove accumulation or predict a reversal.
Why Traders Use This Indicator
- Compare the amounts assigned to rising-source and falling-source bars.
- Define reference-level events using the same classification on each window.
- Compare MFI with a separately calculated price-only RSI.
| Parameter | Default | Description |
|---|---|---|
| Length | 14 | Number of directional-flow observations in the window. The example requires a complete valid window plus the preceding source observation. |
| Overbought / oversold | 80 / 20 | Illustrative reference levels, not a buy/sell recommendation. Lower must be below upper, and both must lie from 0 to 100. |
| Volume source | volume | The chart feed supplies volume. Tick counts and traded units are different measures; missing volume is not zero. |
| Typical price | hlc3 | The example uses hlc3 and requires positive source values throughout its window. Changing source changes the classification. |
How MFI Is Calculated
Typical price TP = (high + low + close) / 3. Raw flow = TP × volume. Let P be the n-bar sum of raw flow when TP rises, and N the sum when TP falls. Unchanged TP adds nothing to either sum.
For P + N > 0, MFI = 100 × P / (P + N). This equals 100 − 100 / (1 + P/N) when N is positive, and makes the one-sided limits explicit: positive-only flow gives 100 and negative-only flow gives 0. With both sums zero there is no directional-flow ratio.
Hypothetical P = 300 and N = 100 gives MFI 75; reversing the amounts gives 25. These are arithmetic examples, not reported market observations. Multiplying all volumes by the same positive factor leaves the ratio unchanged.
The script calls ta.mfi but displays no value until every observation in the window has positive current/previous source and nonnegative, available volume, and the classified-flow total is positive. It does not fill missing data with a neutral 50 or zero. This conservative display gate can differ from an ungated built-in indicator during gaps or warm-up.
Signal Interpretation
Above 80 and below 20 are reference states. The markers show a new confirmed crossing, not every bar that stays beyond a level. A rising MFI is not proof of buyer-initiated volume, and a reading below 40 does not establish institutional distribution.
Regular bullish divergence means price makes a lower low while MFI makes a higher low; the bearish counterpart uses a higher price high and lower MFI high. Neither is a reversal guarantee. No divergence detector is implemented here.
Lines and table values can update during an open bar. Markers, backgrounds and alert conditions wait for bar close. Create an alert in TradingView and recreate it after input or code changes. A historical marker does not prove live alert delivery.
Combining with Other Indicators
The Data Window includes RSI of the same selected source and length. MFI and RSI still use different weighting and aggregation, so their difference is not an isolated measure of volume’s causal effect. Adding VWAP, OBV or a price filter creates another rule to evaluate; it does not guarantee fewer false signals.
Writing Pine Script Manually
Challenges of Manual Coding
Specify unchanged-source bars and zero-flow windows.
Keep missing volume distinct from a valid zero-volume bar.
Use a consistent 0–100 scale for the line and columns.
Make plot controls, table missing states and confirmed alert rules agree.
//@version=6
indicator("MFI with explicit data and event boundaries", shorttitle="MFI rules", overlay=false)
length = input.int(14, "MFI length", minval=1)
src = input.source(hlc3, "Source")
ob = input.float(80, "Upper reference", minval=0, maxval=100)
os = input.float(20, "Lower reference", minval=0, maxval=100)
showHist = input.bool(true, "Show columns from 50")
showMid = input.bool(true, "Show 50 midline")
if os >= ob
runtime.error("Lower reference must be below upper reference.")
validBar = not na(src) and not na(src[1]) and src > 0 and src[1] > 0 and not na(volume) and volume >= 0
invalidCount = math.sum(validBar ? 0.0 : 1.0, length)
directionalFlow = validBar and src != src[1] ? src * volume : 0.0
flowTotal = math.sum(directionalFlow, length)
rawMfi = ta.mfi(src, length)
// Require a complete usable window and some classified flow.
mfi = invalidCount == 0 and flowTotal > 0 ? rawMfi : na
stateOb = not na(mfi) and mfi > ob
stateOs = not na(mfi) and mfi < os
rawOb = ta.crossover(mfi, ob)
rawOs = ta.crossunder(mfi, os)
rawMidUp = ta.crossover(mfi, 50)
rawMidDown = ta.crossunder(mfi, 50)
crossOb = barstate.isconfirmed and rawOb
crossOs = barstate.isconfirmed and rawOs
crossMid = barstate.isconfirmed and (rawMidUp or rawMidDown)
plot(mfi, "MFI", color=stateOb ? color.red : stateOs ? color.green : color.teal, linewidth=2)
hline(ob, "Upper reference", color=color.new(color.red, 40))
hline(os, "Lower reference", color=color.new(color.green, 40))
hline(50, "Mid", color=color.gray, linestyle=hline.style_dotted, display=showMid ? display.all : display.none)
plot(showHist ? mfi : na, "MFI columns from 50", style=plot.style_columns, histbase=50, color=mfi >= 50 ? color.new(color.teal, 70) : color.new(color.orange, 70))
plotshape(crossOb, "Upper cross", shape.triangledown, location.top, color.red, size=size.tiny)
plotshape(crossOs, "Lower cross", shape.triangleup, location.bottom, color.green, size=size.tiny)
bgcolor(crossMid ? color.new(color.blue, 92) : na)
rsi = ta.rsi(src, length)
plot(rsi, "RSI of same source - Data Window", display=display.data_window)
alertcondition(crossOb, "MFI upper reference cross", "MFI crossed above the selected upper reference at bar close.")
alertcondition(crossOs, "MFI lower reference cross", "MFI crossed below the selected lower reference at bar close.")
alertcondition(crossMid, "MFI midpoint cross", "MFI crossed 50 at bar close.")
var table summary = table.new(position.top_right, 1, 3)
if barstate.islast
table.cell(summary, 0, 0, na(mfi) ? "MFI: unavailable" : "MFI: " + str.tostring(mfi, "#.##"))
table.cell(summary, 0, 1, na(rsi) ? "RSI: unavailable" : "RSI: " + str.tostring(rsi, "#.##"))
table.cell(summary, 0, 2, na(mfi) ? "Check history, positive source and volume" : stateOb ? "Above upper reference" : stateOs ? "Below lower reference" : "Between references (inclusive)")Maintenance Note: The example uses chart volume and positive source prices, with a strict full-window data gate. Missing, negative-volume, nonpositive-price or zero-directional-flow windows display unavailable. Columns start at 50 on the same scale as the MFI line; RSI uses the same source in the Data Window. No trades, session filter or divergence detection are implemented.
Build with Pineify Visual Editor
Pineify lets you configure supported indicators and export Pine Script. Available settings and plan requirements vary by indicator. Compare the generated rules with the example before using its signals.
| Feature | Manual Pine Script | Pineify Visual Editor |
|---|---|---|
| MFI input | Set source and length in ta.mfi. | The MFI module exposes Source and Length with hlc3 and 14 defaults. |
| Custom data rules | Write validity gates and missing-value presentation. | Ask AI Coding Agent for explicit data and alert rules, then review the source. |
| Validation | Compare matching windows, inputs and feed volume. | Perform the same checks on generated output. |
Configure the existing MFI module and inspect its output.
Use supported conditions for explicit threshold rules.
Request custom missing-data or display behavior from AI Coding Agent.
Step-by-Step Tutorial
Add the MFI module
Choose the source and length; the visual module defaults to hlc3 and 14.
Review the generated indicator
Inspect its line and band settings. This page’s strict data gate and table are custom code, not assumed module features.
Specify custom requirements
Ask AI Coding Agent for the intended data gate, closing confirmation and display behavior.
Compare before creating alerts
Match chart source, timeframe and volume feed, then inspect available and unavailable windows.
Trading Strategies & Pro Tips
Threshold event study
Hold source, length and dates fixed. Compare event counts for predeclared reference levels without treating fewer events as improved returns.
Data-quality comparison
Compare windows with valid zero volume, missing volume and unchanged prices. The strict gate deliberately suppresses unusable ratios.
Separate strategy test
If studying entries from MFI, define exits, costs, sizing and a later evaluation sample. This indicator supplies no performance result.
Common Mistakes to Avoid
- Interpreting price-times-volume classification as actual buyer/seller aggressor data.
- Reporting missing MFI as a neutral reading.
- Treating unchanged source bars as both positive and negative flow.
- Comparing tick-volume and traded-volume feeds without naming the difference.
- Treating threshold crosses or indicator agreement as a profit guarantee.
Frequently Asked Questions
Build an MFI rule with explicit data assumptions
- Set source and length in the MFI module.
- Define missing-data and confirmation rules for custom code.
- Review the output against matching chart observations.
Disclaimer: Trading involves significant risk. The indicators, code, and strategies provided are for educational purposes only and do not constitute financial advice. Past performance is not indicative of future results.