Search code examples
rstring-matching

Converting Treasury note prices (32nds, 64ths, 128th) to decimal


I wish to convert US Treasury Note futures prices to decimals (so 127-01+ = 127 + 1/32 + 1/64, and 127-01 1/4 = 127 + 1/32 + 1/128 etc).

I have had some success with cases where a fraction is present, but i'm failing when a fraction does not follow the big figure.

The source of the failure is that strsplit does not return an NA or empty object - so the order of the bits gets knocked about, and subsequent fractions are all wrong as a result.

Here's my case:

ty1 <- c("127-03", "126-31", "126-31+", "127-04+", "127-02+", "127-00+")
ty2 <- c("127-03", "126-31", "127-04+", "127-02+", "127-00+", "127", 
         "127-01 1/4", "128-01 3/4")

ty1_dec <- c(127+3/32, 126+31/32, 126+31/32+1/64, 127+4/32+1/64, 
             127+2/32+1/64, 127+0/32+1/64)
ty2_dec <- c(127+3/32, 126+31/32, 127+04/32+1/64, 127+2/32+1/64, 
             127+0/32+1/64, 127, 127+1/32+0/64+1/128, 128+1/32+1/64+1/128) 

tFrac2Dec <-function(x){
    hyphSplit <- strsplit(x, "-")
    splitMatx <- matrix(unlist(hyphSplit), ncol=2, byrow=TRUE)
    fracs <- t(apply(splitMatx[,2, drop=F], 1, function(X) substring(X, c(1,3), c(2,3))))
    splitMatx[,2] <-  (as.numeric(fracs[,1]) + ifelse(fracs[,2] == "+", 0.5, 0))/32
    fracEval <- function(y){
        eval(parse(text=paste(y[1], "+", y[2])))
    }
    apply(splitMatx,1,fracEval)
}

So things work for ty1 as all prices have - and a following fraction.

R> tFrac2Dec(ty1) == ty1_dec
[1] TRUE TRUE TRUE TRUE TRUE TRUE

R> tFrac2Dec(ty1)
[1] 127.0938 126.9688 126.9844 127.1406 127.0781 127.0156

But when there is a price that is only the big figure it fails.

> tFrac2Dec(ty2) == ty2_dec
Error in parse(text = paste(y[1], "+", y[2])) : 
  <text>:1:4: unexpected numeric constant
1: 01 1
       ^
In addition: Warning message:
In matrix(unlist(hyphSplit), ncol = 2, byrow = TRUE) :
  data length [15] is not a sub-multiple or multiple of the number of rows [8]

I can see that it's due to the first strsplit step, but i cannot figure the solution. I've fiddled about with some if type solutions but nothing is working.

Is there a simple way to do this?


Solution

  • Something like this?

    tFrac2Dec <- function(x) {
      hyphSplit <- strsplit(x, "-")
      ch1 <- sapply(hyphSplit,`[`, 1)
      ch2 <- sapply(hyphSplit,`[`, 2)
      x32 <- as.integer(substring(ch2, 1, 2))
      x128 <- rep(0, length(ch1))
      x128[grep("\\+$", ch2)] <- 2
      x128[grep("1/4", ch2, fixed=TRUE)] <- 1
      x128[grep("3/4", ch2, fixed=TRUE)] <- 3
      dec <- x32/32 + x128/128
      dec[is.na(dec)] <- 0
      as.integer(ch1) + dec
    }
    
    tFrac2Dec(ty1)
    ## [1] 127.0938 126.9688 126.9844 127.1406 127.0781 127.0156
    tFrac2Dec(ty2)
    ## [1] 127.0938 126.9688 127.1406 127.0781 127.0156 127.0000 127.0312