70

I have a data set of stock prices that have already been rounded to 2 decimal places (1234.56). I am now trying to round to a specific value which is different for each stock. Here are some examples:

Current Stock Price         Minimum Tick Increment       Desired Output
  123.45                            .50                      123.50
  155.03                            .10                      155.00
  138.24                            .50                      138.00
  129.94                            .10                      129.90
   ...                              ...                       ...

I'm not really sure how to do this but am open to suggestions.

Ari B. Friedman
  • 71,271
  • 35
  • 175
  • 235
screechOwl
  • 27,310
  • 61
  • 158
  • 267

4 Answers4

96

Probably,

round(a/b)*b

will do the work.

> a <- seq(.1,1,.13)
> b <- c(.1,.1,.1,.2,.3,.3,.7)
> data.frame(a, b, out = round(a/b)*b)
     a   b out
1 0.10 0.1 0.1
2 0.23 0.1 0.2
3 0.36 0.1 0.4
4 0.49 0.2 0.4
5 0.62 0.3 0.6
6 0.75 0.3 0.6
7 0.88 0.7 0.7
kohske
  • 65,572
  • 8
  • 165
  • 155
  • 37
    FWIW, `round_any` in the `plyr` package is a nice function implementing this very algorithm. It also takes an additional argument `f`, with choices `"round"`, `"ceiling"`, or `"floor"`. – Josh O'Brien Dec 29 '11 at 17:35
  • @JoshO'Brien - You should make this a separate answer, as people often don't look in the comments – Adam_G Dec 08 '16 at 22:58
  • @Adam_G If you think it'd help others, do feel free to add such an answer. I'll check back to upvote it and start its march upwards towards greater visibility ;) – Josh O'Brien Dec 08 '16 at 23:06
20

I'm not familiar with R the language, but my method should work with any language with a ceiling function. I assume it's rounded UP to nearest 0.5:

a = ceiling(a*2) / 2

if a = 0.4, a = ceiling(0.4*2)/2 = ceiling(0.8)/2 = 1/2 = 0.5
if a = 0.9, a = ceiling(0.9*2)/2 = ceiling(1.8)/2 = 2/2 = 1
joran
  • 169,992
  • 32
  • 429
  • 468
ledmirage
  • 309
  • 1
  • 3
  • 6
    It is maybe better to write `a = ceiling(a / 0.5) * 0.5` since `a * 2` = `a / 0.5` and `x / 2` = `x * 0.5` – Bechir Barkallah Nov 02 '17 at 09:52
  • 2
    Also, you can replace `ceiling` with `floor` in this code to round down to the nearest 0.5. – coip Feb 15 '18 at 21:57
  • `if a = 0.4, a = ...` Does former R versions allow comma. This does not work anymore. – Julien Oct 09 '22 at 07:28
  • This does not answer the question since it was required to round to the nearest value, sometimes up and sometimes down – Julien Oct 09 '22 at 07:31
16

Like what JoshO'Brien said in the comments: round_any in the package plyr works very well!

> library(plyr)
> stocks <- c(123.45, 155.03, 138.24, 129.94)
> round_any(stocks,0.1)
[1] 123.4 155.0 138.2 129.9
> 
> round_any(stocks,0.5)
[1] 123.5 155.0 138.0 130.0
> 
> round_any(stocks,0.1,f = ceiling)
[1] 123.5 155.1 138.3 130.0
> 
> round_any(stocks,0.5,f = floor)
[1] 123.0 155.0 138.0 129.5

Read more here: https://www.rdocumentation.org/packages/plyr/versions/1.8.4/topics/round_any

winanonanona
  • 306
  • 2
  • 6
6

The taRifx package has just such a function:

> library(taRifx)
> roundnear( seq(.1,1,.13), c(.1,.1,.1,.2,.3,.3,.7) )
[1] 0.1 0.2 0.3 0.4 0.6 0.6 0.7

In your case, just feed it the stock price and the minimum tick increment as its first and second arguments, and it should work its magic.

N.B. This has now been deprecated. See comment.

Ari B. Friedman
  • 71,271
  • 35
  • 175
  • 235
  • should `0.36` for the ticks `0.1` be `0.4`? – kohske Dec 29 '11 at 07:51
  • 1
    I think rounding 0.36 to the nearest 0.1 increment should lead to 0.4. – Paul Hiemstra Dec 29 '11 at 09:32
  • 2
    Good point. The algorithm used is embarrassingly convoluted compared to kohske's solution: frac = vec/roundvec; retvec = vec - (frac - floor(frac)) * roundvec . Given that this functionality already exists in plyr, I'll likely deprecate roundnear and point people towards round_any. – Ari B. Friedman Dec 31 '11 at 06:52