דלגו לתוכן
פתיחת RaamTrade

OBV — On-Balance Volume

תוכן זה אינו זמין עדיין בשפה שלך.

Granville’s running total of volume signed by the close’s direction. Unbounded and path-dependent: the level is meaningless — only the slope and divergences against price carry information.

Signature

OBV(period, on=<source>)
Argument Type Required Notes
period int Param or literal Yes SMA smoothing of the line. 1 returns the raw accumulator. Bounds 1–200.
on= symbol No Source symbol. Defaults to the trade symbol. Reads close and volume.

Formula

$$ \text{OBV}t = \text{OBV}{t-1} + \begin{cases} +V_t & C_t > C_{t-1} \ -V_t & C_t < C_{t-1} \ 0 & C_t = C_{t-1} \end{cases} $$

Warmup

Starts at 0 on the first bar. As an accumulator it resets per run — and per walk-forward window, which is real behaviour worth knowing before reading it inside one.

Reading the value

obv.value
obv.value > obv.value_at(20) # slope over 20 bars

Example

class ObvConfirm(Strategy):
"""Breakout confirmed by rising on-balance volume."""
trade = Symbol()
sizing = FixedCapital()
def execute(self):
obv = OBV(1, on=self.trade)
dh = DonchianHighTrue(20, on=self.trade)
if self.trade.close >= dh.value_at(1) and obv.value > obv.value_at(10) and self.trade.is_flat:
self.buy(self.trade, reason="Breakout with volume")
if obv.value < obv.value_at(10) and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason="Volume rolled over")

Notes

  • Joe Granville, Granville’s New Key to Stock Market Profits (1963).
  • The running total starts at zero where TA-Lib seeds OBV with the first bar’s volume, so ours is TA-Lib’s minus that one constant on every bar — every increment is identical, which leaves a comparison against OBV’s own past unaffected and one against an absolute level not.