Money Flow Index: The MFI Rule, Read From the Source
The money flow index is usually introduced as a volume-weighted RSI, and that shorthand is close enough to be useful and loose enough to hide the two decisions that actually matter. Vike computes it as batch_mfi, part of the volume family in our engine.
Both hidden decisions are ties. One decides what happens when a bar's typical price matches the bar before it, and the other decides what the indicator returns when a whole window has nothing falling in it. This page reads both off the crate source, measures how often each fires across 356,886 daily bars, and then scores the textbook 80/20 trade honestly.
What the money flow index measures
Take a bar's high, low and close, average them, and multiply by volume. That product is the bar's raw money flow — an approximation of the money that changed hands, using a price the bar actually spent time near rather than the single instant it happened to end on.
Now classify. If the typical price rose against the previous bar's, the whole product joins the buying pile; if it fell, the selling pile. Sum each pile over fourteen bars, take the ratio, and squash it onto a zero-to-a-hundred scale.
Where RSI compares the size of gains against losses, this compares the money behind them. A tiny move on enormous turnover outweighs a large move on nothing, which is exactly the property people want from a volume indicator and exactly the property OBV refuses to give them, since OBV counts a bar's volume in full regardless of how far price travelled.
The exact MFI formula our engine runs
batch_mfi runs. The middle branch is the tie nobody documents: an unchanged typical price sends the bar’s entire money flow to neither sum.Most descriptions stop at "volume-weighted RSI". Here is the arithmetic underneath.
How Vike computes it.batch_mfibuildstp[i] = (high + low + close) / 3andrmf[i] = tp[i] * volume[i]for every bar. From barperiodonward it walks the window backwards, addingrmf[j]toposwheretp[j] > tp[j-1]and tonegwheretp[j] < tp[j-1], then returns100 - 100/(1 + pos/neg)— or a flat100.0whennegcame out at zero. Default period is fourteen.
I ported that from the crate source and checked it against the Python original the crate was ported from, over 292 symbols and 356,886 daily bars. Largest absolute difference across every position: zero. No position was defined in one series and missing in the other.
Notice the loop bound. It starts at i = period, not period - 1, because each bar in the window is compared with its predecessor — so a fourteen-period reading needs fifteen bars, and the first value lands on bar fourteen. One more than the parameter suggests, and enough to shift a chart if you assumed otherwise.
The two ties the formula throws away
A tie is where implementations diverge, and this one has two of them.
First tie, per bar. When tp[j] exactly equals tp[j-1], neither branch matches, so that bar's raw money flow — which can be an enormous number — is dropped from both sums rather than added to both. Across the tape this fires on 895 of 356,886 bars, or 0.251%. Notably rarer than the tied close that OBV discards, at 0.786%, and for a plain reason: an average of three prices reproduces itself far less often than one price does.
Second tie, per window. When nothing in fourteen bars had a falling typical price, neg is zero and the formula would divide by it, so the source short-circuits and returns exactly 100.0. That branch also catches the case where pos is zero too — a window of perfectly flat prices would read maximum, which is a strange thing for a dead market to say about itself.
Does it happen? The value 100.0 appeared on 39 readings out of 352,798. On every single one, pos was large: BTC hit it on 2017-12-07 and again the next day, mid-parabola, on roughly 920 million dollars of buying. The dead-market branch fired zero times in nine years of bars. Reachable in theory, unobserved in practice, and now you know which.
Where 80 and 20 sit in the real distribution
Everyone quotes 80 and 20 as symmetric extremes. I've repeated that pairing from memory for years, so I measured where the lines really sit.
Across 352,798 readings, the fifth percentile landed at 24.5 and the ninety-fifth at 81.5, with the median at 54.1. So the upper line is roughly where the top twentieth begins, but the lower one is well inside the bottom twentieth rather than at its edge.
Count the crossings and the asymmetry sharpens. Readings at or above 80 occurred 22,219 times; readings at or below 20 occurred 8,809 times. Overbought prints two and a half times as often as oversold on this sample, which is what a market with a long upward drift and periodic vertical melt-ups looks like through a bounded oscillator. Treating those two lines as mirror images will hand you far more sell signals than buy signals and let you believe that is the market talking.
How to trade the MFI crossings
Here is the rule I tested, tightly enough to be proven wrong: buy when the reading crosses back up through 20, sell when it crosses back down through 80.
Outcomes resolve first-touch over the next ten bars inside a symmetric eight percent bracket, so break-even sits at 50% before fees, and any bar tagging both levels is scored a loss. That identical bracket then runs on every bar in the sample. Without the base rate it produces, a win rate is just a number with nothing to lean on.
Crossings up through 20 fired 2,751 times and resolved 49.4% winners. An arbitrary long entry on those same bars: 49.4%. Identical to the decimal place, which is a cleaner nothing than I expected to find.
Crossings down through 80 fired more than twice as often, 5,611 times, and resolved 48.1% against a random short's 48.9%. Slightly worse than nothing.
Where the money flow index fails
Publishing a zero is the point of running the test, so here is what those numbers mean rather than an excuse for them.
The oversold signal carries no edge whatsoever under this bracket, and the overbought signal is mildly negative. My reading is that the bounded scale is doing the damage: a strong trend pins the indicator against its ceiling for weeks, and every crossing back below 80 during that stretch is a sell into strength. When I see a reading camped above 80 for a fortnight, I skip its next crossing without looking further. The failures below are exactly that shape — EPIC and KAITO both crossed down and kept rising.
Volume quality is the other problem, and it is specific to crypto. Every figure here rests on exchange-reported volume, which is a number a venue publishes about itself. Spot volume on a major pair is credible enough; the same field on a thin listing is not, and the indicator has no way to tell the difference because it never sees anything except that column and three prices.
Frequently asked questions
Is the money flow index just RSI with volume? Not quite. Both squash a ratio onto the same scale, but this one compares typical prices rather than closes, and weights each bar by turnover. Read the RSI breakdown and the difference in inputs becomes obvious.
What is the best MFI period? Fourteen is the default, and every measurement here uses it. Shortening it produces more crossings, and since the crossings tested at no edge, more of them is not an improvement.
Why does my chart show no MFI value for the first fortnight? Because there is none. Fifteen bars are needed before the first reading exists, and returning nothing beats returning a partial number dressed up as a real one.
Can the MFI actually reach 100? Yes, and it did 39 times in this sample — always because every bar in the window rose or held, never because the window was flat.
Which volume indicator should I pair it with? Something that splits the column differently. The accumulation distribution line weights by position inside the bar's own range, so it disagrees with this one in ways worth examining, much as the SMI disagrees with RSI on momentum.
This is educational material, not financial advice. Every number here comes from bars that have already closed, past behavior generalizes poorly, and trading carries real risk of loss — size any position so that being wrong stays affordable.