Balance of Power (Igor Livshin) — how much of the bar's range the
buyers or the sellers actually took:
bop = (close − open) / (high − low)
The body over the range. +1 is a bar that opened on its low and closed
on its high (buyers took the whole thing), −1 the mirror, 0 a bar that
closed where it opened however far it ranged in between. Bounded [−1, +1]
on real bars, because the body cannot exceed the range.
Appends one column, default 'bop'. Reads open, high, low and close,
each named by an option defaulting to its DEFAULT_OHLCV name.
One indicator, two conventions — the raw form ships (F-AMBIG)
TA-Lib's BOP is the raw per-bar ratio above, with no smoothing at
all; ChartIQ and several other packages draw it through a moving average,
because the raw line is noisy enough to be hard to read. Both are in
circulation and they are the same indicator, so this study ships the raw
form by default — that is the one an oracle can pin bar-for-bar
against TA-Lib — and exposes period to get the smoothed one:
maType is the shared MaType menu (spelled maType, not type,
because the average is an ingredient here rather than the output —
the keltner / envelope side of that split). It throws when passed
without a period: an option that silently does nothing is worse than an
error, and there is no sensible "smooth with an EMA but over no bars".
A flat bar is 0, not missing — and that is the algebra, not TA-Lib
high === low makes the denominator zero. It also makes the numerator
exactly zero on any real bar: a bar with no range traded at one price,
so its open and close are that price and close − open is 0. The value is
therefore 0 — the limit from either side, and the honest reading (no
side took anything, because there was nothing to take). This is the
clvValues rule and the same argument #699 settled there, not a
copy of TA-Lib's guard, though the two agree: TA-Lib returns 0.0 when
high − low < 1e-8.
The one deliberate delta is that threshold. TA-Lib treats any range under
1e-8 as flat; this study tests range === 0 exactly, so a bar with a
genuine but sub-1e-8 range reports the (large) ratio rather than 0.
At the scale of real prices such a bar is a rounding artefact either way;
the exact test is used because an epsilon that is right for dollars is
wrong for a column of basis points, and the oracle asserts the fixture
has no bar in the gap so the TA-Lib agreement is exact where it is
claimed. A redirectedopen or close (pointed at a smoothed column,
say) can put a non-zero body over a zero range; that reads 0 too, as
clvValues does — a bar with no range has nowhere to place anything.
Edges
No warm-up in the raw form: bar 0 is defined. With period, the
warm-up is the chosen average's own over the derived array (period − 1
for the window types, later for the composed ones — see
movingAverageValues).
Scale- AND shift-invariant: the body and the range are both
differences of prices, so a common multiplier cancels in the ratio and a
common offset cancels in each difference. This is the rsi side of
the scale pair, not the atr side — both pinned by property tests.
A gap in any of the four inputs costs that bar in the raw form, plus
whatever the chosen maType costs when smoothing (window types recover,
the ema family skips, smma and kama propagate).
The zero-range guard is at the output and therefore live: the
division is the last thing that happens before withColumn in the raw
form, and the guard is what stops ±Infinity reaching the carrying
maTypes in the smoothed one.
Balance of Power (Igor Livshin) — how much of the bar's range the buyers or the sellers actually took:
The body over the range.
+1is a bar that opened on its low and closed on its high (buyers took the whole thing),−1the mirror,0a bar that closed where it opened however far it ranged in between. Bounded[−1, +1]on real bars, because the body cannot exceed the range.Appends one column, default
'bop'. Reads open, high, low and close, each named by an option defaulting to itsDEFAULT_OHLCVname.One indicator, two conventions — the raw form ships (F-AMBIG)
TA-Lib's
BOPis the raw per-bar ratio above, with no smoothing at all; ChartIQ and several other packages draw it through a moving average, because the raw line is noisy enough to be hard to read. Both are in circulation and they are the same indicator, so this study ships the raw form by default — that is the one an oracle can pin bar-for-bar against TA-Lib — and exposesperiodto get the smoothed one:maTypeis the shared MaType menu (spelledmaType, nottype, because the average is an ingredient here rather than the output — thekeltner/envelopeside of that split). It throws when passed without aperiod: an option that silently does nothing is worse than an error, and there is no sensible "smooth with an EMA but over no bars".A flat bar is
0, not missing — and that is the algebra, not TA-Libhigh === lowmakes the denominator zero. It also makes the numerator exactly zero on any real bar: a bar with no range traded at one price, so its open and close are that price andclose − openis 0. The value is therefore0— the limit from either side, and the honest reading (no side took anything, because there was nothing to take). This is the clvValues rule and the same argument #699 settled there, not a copy of TA-Lib's guard, though the two agree: TA-Lib returns0.0whenhigh − low < 1e-8.The one deliberate delta is that threshold. TA-Lib treats any range under
1e-8as flat; this study testsrange === 0exactly, so a bar with a genuine but sub-1e-8range reports the (large) ratio rather than0. At the scale of real prices such a bar is a rounding artefact either way; the exact test is used because an epsilon that is right for dollars is wrong for a column of basis points, and the oracle asserts the fixture has no bar in the gap so the TA-Lib agreement is exact where it is claimed. A redirectedopenorclose(pointed at a smoothed column, say) can put a non-zero body over a zero range; that reads0too, asclvValuesdoes — a bar with no range has nowhere to place anything.Edges
period, the warm-up is the chosen average's own over the derived array (period − 1for the window types, later for the composed ones — see movingAverageValues).maTypecosts when smoothing (window types recover, theemafamily skips,smmaandkamapropagate).withColumnin the raw form, and the guard is what stops±Infinityreaching the carryingmaTypes in the smoothed one.