Market Facilitation Index (Bill Williams) — how much price movement
each unit of volume bought:
bwmfi = (high − low) / volume
Williams reads it against the change in volume, not on its own: a bar
where both the index and volume rose is a move the market is funding
("green"); one where the index rose while volume fell is a move on thin
participation ("fake"); and so on for the other two quadrants. The study
appends the index; the quadrant is a comparison a caller makes with it and
percentChange({ column: 'volume' }).
Appends one column. Reads high, low and volume, each named by an
option defaulting to its DEFAULT_OHLCV name.
The output is bwmfi, and the collision is the reason
moneyFlowIndex — Quong & Soudack's RSI-on-money-flow, an entirely
different indicator — already appends mfi, which is the abbreviation
both studies are published under. Two studies cannot share a default
output name: appending both to one series would throw, and whichever
landed first would silently define what a downstream 'mfi' column meant.
So this one defaults to bwmfi — Bill Williams' initials in front of
the abbreviation, which is what MetaTrader and several other packages call
it for exactly the same reason. The older study keeps mfi because it
shipped first and renaming it would break every caller. output overrides
either. (Same problem, same treatment as the two "RVI"s already in the
package: relativeVigorIndex keeps rvi and relativeVolatilityIndex
appends relVol.)
No scale option
The reading is the raw ratio, which on equity-sized volumes is a small
number (a 0.70-wide bar on 1500 shares is 0.00047). Vendors multiply by
a constant to bring it onto a legible axis, and they do not agree on which
— unlike easeOfMovement, whose 100_000_000 is a published
constant that StockCharts and ChartIQ share, and which is exposed here for
that reason. There is no such constant for this study, so adding a scale
knob would be inventing a default rather than matching one; a caller who
wants a legible axis multiplies the column, and a caller comparing against
a chart has to know that chart's factor either way.
No TA-Lib function; the oracle is a pandas replication.
Edges
No warm-up. Each bar's value comes from its own three inputs, so row
0 is defined. Length-preserving.
A bar with zero volume has no value — the division is x / 0, which
is ±Infinity and not a reading. undefined, the package's answer for
a zero denominator everywhere. The guard is live: the division is the
last thing before withColumn, which rejects an infinity loudly rather
than mapping it to a gap, so without it a halted bar would throw.
A flat bar (high === low) reads 0, not undefined — the
numerator is a genuine zero (the bar covered no ground) over a real
volume, so there is no 0/0 unless the volume is zero too, and that
case is caught by the guard above.
Linear in price and inversely proportional to volume: scaling every
price by k scales the reading by k, and scaling every volume by k
divides it by k. It is shift-invariant in price (the range is a
difference). All three pinned by property tests — "linear in price like
every other absolute study" is only two thirds of the story.
A gap in any of the three costs that bar and nothing else.
A negative range is reported honestly (redirect high/low at
crossed columns and the index goes negative); nothing clamps, as
barRangeValues documents.
Market Facilitation Index (Bill Williams) — how much price movement each unit of volume bought:
Williams reads it against the change in volume, not on its own: a bar where both the index and volume rose is a move the market is funding ("green"); one where the index rose while volume fell is a move on thin participation ("fake"); and so on for the other two quadrants. The study appends the index; the quadrant is a comparison a caller makes with it and
percentChange({ column: 'volume' }).Appends one column. Reads high, low and volume, each named by an option defaulting to its
DEFAULT_OHLCVname.The output is
bwmfi, and the collision is the reasonmoneyFlowIndex — Quong & Soudack's RSI-on-money-flow, an entirely different indicator — already appends
mfi, which is the abbreviation both studies are published under. Two studies cannot share a default output name: appending both to one series would throw, and whichever landed first would silently define what a downstream'mfi'column meant.So this one defaults to
bwmfi— Bill Williams' initials in front of the abbreviation, which is what MetaTrader and several other packages call it for exactly the same reason. The older study keepsmfibecause it shipped first and renaming it would break every caller.outputoverrides either. (Same problem, same treatment as the two "RVI"s already in the package:relativeVigorIndexkeepsrviandrelativeVolatilityIndexappendsrelVol.)No
scaleoptionThe reading is the raw ratio, which on equity-sized volumes is a small number (a 0.70-wide bar on 1500 shares is
0.00047). Vendors multiply by a constant to bring it onto a legible axis, and they do not agree on which — unlike easeOfMovement, whose100_000_000is a published constant that StockCharts and ChartIQ share, and which is exposed here for that reason. There is no such constant for this study, so adding ascaleknob would be inventing a default rather than matching one; a caller who wants a legible axis multiplies the column, and a caller comparing against a chart has to know that chart's factor either way.No TA-Lib function; the oracle is a pandas replication.
Edges
x / 0, which is±Infinityand not a reading.undefined, the package's answer for a zero denominator everywhere. The guard is live: the division is the last thing beforewithColumn, which rejects an infinity loudly rather than mapping it to a gap, so without it a halted bar would throw.high === low) reads0, notundefined— the numerator is a genuine zero (the bar covered no ground) over a real volume, so there is no0/0unless the volume is zero too, and that case is caught by the guard above.kscales the reading byk, and scaling every volume bykdivides it byk. It is shift-invariant in price (the range is a difference). All three pinned by property tests — "linear in price like every other absolute study" is only two thirds of the story.high/lowat crossed columns and the index goes negative); nothing clamps, as barRangeValues documents.