Skip to content
All library documents

Implementing Rolling Rogers–Satchell Volatility from OHLC Data

Article Quant Q&A · Author: Steven Semeraro

Summary

The document discusses debugging a rolling Rogers–Satchell volatility estimate computed from daily open, high, low, and close data. The response rewrites the estimator as a per-period quantity: add the products of log high-to-close and high-to-open ratios, and log low-to-close and low-to-open ratios. For each rolling window, take the mean of these daily quantities and then its square root. This separates the single-period calculation from the rolling aggregation and avoids needing a nested calculation over the full history for every observation.

The author reports that an implementation of this formula in R produced nearly identical values to the Rogers–Satchell calculation in a standard technical analysis package for sample rolling estimates. This comparison supports the formula structure, but the discussion does not diagnose the original Go result against supplied input data. It also does not address annualization choices, missing or invalid OHLC values, or indexing conventions, all of which can affect comparisons between implementations.

Key ideas

  • The Rogers–Satchell daily term uses logarithmic ratios involving each period’s high, low, open, and close.
  • A rolling estimate takes the mean of the daily terms in the window and then applies a square root.
  • Precomputing the daily terms makes the rolling calculation easier to structure and inspect.
  • The response reports agreement with a package implementation, but provides no matched Go input data or diagnosis of the original discrepancy.
  • Annualization and data handling conventions can affect comparisons across volatility implementations.

Tags

Full text
# Rogers Satchell Volatility


# Rogers Satchell Volatility












I am trying to implement Roger Satchell volatility in Go, but my results do not match reality... I have been at this all day, but cannot find my error. The 30 day Rogers Satchell vol is at 8.75%, but my output is 0.004858435700980119... The formula can be found here: https://portfolioslab.com/tools/rogers-satchell

```
func getRogersSatchell(class OHLC, period_length int) Volatilities {

    var vol Volatilities

    for i := period_length; i < len(class.close); i++ {

        var sum float64

        for j := i; j > (i - period_length); j-- {

            x1 := math.Log(class.high[j] / class.close[j])
            x2 := math.Log(class.high[j] / class.open[j])
            x3 := math.Log(class.low[j] / class.close[j])
            x4 := math.Log(class.low[j] / class.open[j])

            sum += (x1 * x2) + (x3 * x4)

        }

        volatility := math.Sqrt(sum / float64(period_length))

        vol.rogers_satchell = append(vol.rogers_satchell, volatility)

    }

    return vol
}
```
```

## Answer by Pleb (score 3)

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

## An answer with R and pseudo-code:

As pointed out by @markleeds, there is no need for two for-loops, since you can vectorize the outer loop. You only need the last for-loop if you want to do rolling Roger-Satchell volatility estimates. I cannot code in `Go`, but I can provide you with some pseudo-code.

Let your OHLC data be defined as $X \in \mathbb{R}^{T\times 4}$, where each column is respectively the daily open, high, low and close. That is, $X$ is a matrix with the time-dimension, $t=1,\ldots,T$, as the rows and OHLC as the columns. Constructing some pseudo-code, your Golang function should have similar structure as the snippet below:

```
function RSVol(OHLC, n){

  ""Initialise RSVol to store numeric values:""
  RSVol = Vector()
  
  ""These are now vectors of dimension T x 1:""
  open = OHLC[,1] 
  high = OHLC[,2] 
  low = OHLC[,3] 
  close = OHLC[,4] 

  ""the inner part of the mean:""
  inner = log(high/close) * log(high/open) + log(low/close) * log(low/open)

  ""Doing a rolling mean depending on n:""
  for(i=n:length(open); i++){

    RSVol[i] =  sqrt(mean(inner[i+1-n:i])

  }

  return(RSVol)
}
```

Implementing the above pseudo-code in `R` and comparing my function to the Rogers Satchell estimator in the `TTR` package produce the same results:

```
library(TTR)

#first 6 rolling estimates with n=10.

myfunc <- RSVol(OHLC,10)[11:16] 
TTR_RSVol <- volatility(OHLC, n = 10, calc = "rogers.satchell", N = 1, mean0 = FALSE)[11:16]

data.frame(myfunc = myfunc, TTR_func = TTR_RSVol)
```

The near identical results seen above, gives some validity to my pseudo-code and `R` code. I have provided my `R` function in an appendix below. I hope this helps with the proper implementation of your Rogers Satchell estimator in `Go`. If not, then please edit your question and provide some example data or where to get it. Then we can do some output matching between the constructed functions.

#### Appendix: R code

I have provided my R code below for better understanding.

```
RSVol <- function(OHLC, n){

  open <- OHLC[,1]
  high <- OHLC[,2]
  low <- OHLC[,3]
  close <- OHLC[,4]

  RSVol <- numeric()

  firstpart <- log(high/close) * log(high/open)
  lastpart <- log(low/close) * log(low/open)

  inner <- firstpart + lastpart

  #calculating rolling mean:

  for(i in n:nrow(OHLC)){

    RSVol[i] <- sqrt(mean(inner[(i+1-n):i]))
  }

 return(RSVol)
}
```

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.