Money Flow Index — rsi computed on money flow instead of
price:
typicalPrice = (high + low + close) /3 rawMoneyFlow = typicalPrice · volume positive =Σ rawMoneyFlow where typicalPrice rose over `period` negative =Σ rawMoneyFlow where typicalPrice fell MFI=100 · positive / (positive + negative)
A bounded 0…100 oscillator, read for the same overbought / oversold /
divergence signals as RSI, but with each bar's move weighted by the money
that changed hands on it — which is why it is sometimes called
"volume-weighted RSI". Appends one column.
Two differences from RSI, both real
The window is a plain sum, not Wilder's smoothing. RSI averages its
gains and losses with (prev·(n−1) + x)/n, which never forgets; MFI
sums the last period flows and drops the rest. So MFI's answer depends
only on the window, and a gap leaves it once the window passes — the
asymmetry atr/rsi document from the other side.
Direction comes from the typical price, not the close. A bar whose
close rose but whose range fell can be a down-flow bar.
The sums are two rollingMeanValues passes over the up-flow and
down-flow arrays. Means rather than sums because the kernel exists and the
shared 1/periodcancels in the ratio — the same trick
rollingWeightedMeanValues uses — so nothing is lost and no second
window loop is written.
Definition, verified
TA-Lib's MFI, exactly on gap-free bars: cross-checked bar-for-bar in
the oracle fixture at period 14 and 5 (agreement to 2.8e-14, identical
warm-up masks). An unchanged typical price contributes to neither sum,
which is TA-Lib's rule too (its C code adds to posSumMF on > and to
negSumMF on <, and to neither on equality).
Edges
Warm-up is period rows, not period − 1 — the first bar has no
previous typical price, so the first window of periodchanges closes
on bar period. Same off-by-one rsi and atr have, and
TA-Lib's own lookback.
A window with no money flow at all → undefined. Reachable two
ways: every typical price in the window unchanged (nothing rose or
fell), or no volume at all. 0 / 0 has no relative strength, which is
exactly the call rsi makes on a flat window. TA-Lib reports
0 for this case — measured (0.7.1): a 20-bar flat series at
period 5 gives 0, and so does a rising series with zero volume.
0 is MFI's most bearish possible reading, for a window that showed
no direction at all.
TA-Lib also reports 0 whenever the window's total flow is below
1.0, which is a magnitude guard rather than a definition: measured
on a strictly rising 20-bar series with volume 1e-9 per bar, TA-Lib
returns 0 where the answer is 100. This study has no such threshold
— a market denominated in small units is still a market — so the two
disagree there by the whole range of the indicator. (Real money flow is
a price times a share count; the case does not arise on equity data,
which is presumably why it has survived in TA-Lib.)
All up → 100, all down → 0, both agreeing with TA-Lib.
A gap in any input costs two windows' worth: the bar itself and the
bar after it (whose direction reads the missing typical price), and
every window containing either. It recovers once they leave.
Invariant under scaling price and under scaling volume — a ratio of
flows, so both cancel. Pinned by property tests, with the 0…100 bound.
Money Flow Index — rsi computed on money flow instead of price:
A bounded
0…100oscillator, read for the same overbought / oversold / divergence signals as RSI, but with each bar's move weighted by the money that changed hands on it — which is why it is sometimes called "volume-weighted RSI". Appends one column.Two differences from RSI, both real
(prev·(n−1) + x)/n, which never forgets; MFI sums the lastperiodflows and drops the rest. So MFI's answer depends only on the window, and a gap leaves it once the window passes — the asymmetryatr/rsidocument from the other side.The sums are two rollingMeanValues passes over the up-flow and down-flow arrays. Means rather than sums because the kernel exists and the shared
1/periodcancels in the ratio — the same trick rollingWeightedMeanValues uses — so nothing is lost and no second window loop is written.Definition, verified
TA-Lib's
MFI, exactly on gap-free bars: cross-checked bar-for-bar in the oracle fixture atperiod14 and 5 (agreement to2.8e-14, identical warm-up masks). An unchanged typical price contributes to neither sum, which is TA-Lib's rule too (its C code adds toposSumMFon>and tonegSumMFon<, and to neither on equality).Edges
periodrows, notperiod − 1— the first bar has no previous typical price, so the first window ofperiodchanges closes on barperiod. Same off-by-one rsi and atr have, and TA-Lib's own lookback.undefined. Reachable two ways: every typical price in the window unchanged (nothing rose or fell), or no volume at all.0 / 0has no relative strength, which is exactly the call rsi makes on a flat window. TA-Lib reports0for this case — measured (0.7.1): a 20-bar flat series atperiod 5gives0, and so does a rising series with zero volume.0is MFI's most bearish possible reading, for a window that showed no direction at all.0whenever the window's total flow is below1.0, which is a magnitude guard rather than a definition: measured on a strictly rising 20-bar series with volume1e-9per bar, TA-Lib returns0where the answer is100. This study has no such threshold — a market denominated in small units is still a market — so the two disagree there by the whole range of the indicator. (Real money flow is a price times a share count; the case does not arise on equity data, which is presumably why it has survived in TA-Lib.)100, all down →0, both agreeing with TA-Lib.0…100bound.