Skip to content
All library documents

On-Balance Volume Handling of Flat Price Days in R

Article Quant Q&A · Author: xkcd

Summary

The document examines how an R implementation of On-Balance Volume treats days when the closing price is unchanged. The cited function adds volume on price rises and subtracts volume otherwise, which means a flat day is handled like a decline. The discussion compares this behavior with reference definitions that assign no volume change when price is flat.

An alternative implementation is proposed that resets the daily contribution to zero whenever the rate of change is zero, then cumulatively sums the adjusted volume contributions. The response reports that the two series are highly correlated but can diverge, with the direction depending on market evolution; it also gives a particular example of a substantial difference. These observations illustrate why a small indicator convention can affect cumulative values. The comparison is not a broad validation across assets or periods, and the document does not establish a universal preferred implementation beyond the cited strict definition.

Key ideas

  • The shown OBV implementation subtracts volume when the price does not rise, including on flat days.
  • A strict flat-day convention assigns zero volume contribution when the close is unchanged.
  • The proposed alternative changes that case before computing the cumulative series.
  • Two OBV implementations may remain highly correlated while their levels diverge over time.
  • The reported comparison is limited to the example and does not establish behavior across all markets.

Tags

Full text
# OBV indicator calculation in R


# OBV indicator calculation in R












Here is a few references about OBV calculations:

- http://ta.mql4.com/indicators/volumes/on_balance_volume

- http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:on_balance_volume_obv

- http://en.wikipedia.org/wiki/On-balance_volume

When I navigate to the source code of OBV function in TTR package, I see this:

```
"OBV" <-
function(price, volume) {
    # On Balance Volume
    price <- try.xts(price, error=as.matrix)
    volume <- try.xts(volume, error=as.matrix)

    if(!(is.xts(price) && is.xts(volume))) {
        price <- as.vector(price)
        volume <- as.vector(volume)
    }
    obv <- c( volume[1], ifelse( ROC(price) > 0, volume, -volume )[-1] )
    obv <- cumsum( obv )
    if(is.xts(obv)) {
        obv <- xts(obv,index(price))
        colnames(obv) <- 'obv'
    }
    reclass( obv, price )
}
```

I see that the equality case (I mean the case occurs when today’s close is equal to yesterday’s close) in the reference web pages does not exist in OBV function implementation.

Is it a bug or an acceptance of the package? If it is a bug, where can I report the issue?

## Answer by Robert (score 2, accepted)

https://quant.stackexchange.com/a/17889

Yes, the function does not consider cases when the price is flat. The solution is very simple. Look at the OBV2 function below. The series from OBV and OBV2 are highly correlated, but the strict definition would be higher (smaller) depending on the market evolution. In the QQQ case that difference is about 50% 1. You could find the maintainer here: http://cran.r-project.org/web/packages/TTR/index.html

```
    OBV2 <-  function(price, volume) { #
    # On Balance Volume 2
    price <- try.xts(price, error=as.matrix)
    volume <- try.xts(volume, error=as.matrix)

    if(!(is.xts(price) && is.xts(volume))) {
       price <- as.vector(price)
      volume <- as.vector(volume)
   }
   obv <- c( volume[1], ifelse(ROC(price) > 0, volume, -volume)[-1] )
   obv[ROC(price)==0]<-0
   obv <- cumsum( obv )
   if(is.xts(obv)) {
     obv <- xts(obv,index(price))
     colnames(obv) <- 'obv2'
   }
   reclass( obv, price )
   }

   require("quantmod")  

   getSymbols('QQQ', src='yahoo',from='2012-01-01')
   chartSeries(QQQ,TA = NULL)
   addOBV()
   sobv=OBV(QQQ[,4],QQQ[,5])
   #addTA(sobv,on=3)
   head(cbind(QQQ,sobv))
   table(ROC(QQQ[,4])==0)

   sobv2=OBV2(QQQ[,4],QQQ[,5])
   addTA(sobv2,on=2,col="red")
   cor(sobv,sobv2)
   tail(cbind(sobv,sobv2,sobv2/sobv-1))
   chartSeries(sobv2,TA = NULL)
   addTA(sobv,on=1,col="red")
```

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.