Use map() rowise in R

Viewed 70

I have a data.frame that I am currently applying a for loop to in order to get my desired outcome. However, I am not happy with using a for loop and seem to run into weird errors every once in awhile. I am looping over each row and calculating the greeks of an option given the values in each row. There is also an "if else" statement that decides if i use the put option formula or call option formula

Here is what I am currently using to get the desired output. I was hoping there would be a cleaner way to do this using map() or some other function. Thanks

library(tidyverse)
library(derivmkts)


df = structure(list(pc = c("C", "P", "C", "P", "C", "P", "C", "P", 
"C", "P"), spot = c(100, 100, 100, 100, 100, 100, 100, 100, 100, 
100), Strike = c(98, 98, 98, 98, 98, 98, 98, 98, 98, 98), iv = c(0.3, 
0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3), dte = c(10, 10, 
10, 10, 10, 10, 10, 10, 10, 10)), class = "data.frame", row.names = c(NA, 
-10L))

head(df)
 pc spot Strike  iv dte
1   C  100     98 0.3  10
2   P  100     98 0.3  10
3   C  100     98 0.3  10
4   P  100     98 0.3  10
5   C  100     98 0.3  10

#if the pc value is "P" use bsput() otherwise use bscall()
#create list

l = list()
for(i in 1:nrow(df)){
  
  if(df$pc[i] == "P"){
    l[[i]] = greeks(bsput(df$spot[i], df$Strike[i], df$iv[i], 0, df$dte[1]/252, 0), complete = T)
  } else {
    l[[i]] = greeks(bscall(df$spot[i], df$Strike[i], df$iv[i], 0, df$dte[1]/252, 0), complete = T)
  }
  
  
}

l = do.call(rbind, l)
head(l)
 s  k   v r         tt d funcname  Premium      Delta       Vega         Rho      Theta         Psi     Elast      Gamma
1 100 98 0.3 0 0.03968254 0   bscall 3.493478  0.6435398 0.07426992  0.02415099 -0.0769152 -0.02553729  18.42118 0.06238675
2 100 98 0.3 0 0.03968254 0    bsput 1.493478 -0.3564602 0.07426992 -0.01473790 -0.0769152  0.01414525 -23.86780 0.06238672
3 100 98 0.3 0 0.03968254 0   bscall 3.493478  0.6435398 0.07426992  0.02415099 -0.0769152 -0.02553729  18.42118 0.06238675
4 100 98 0.3 0 0.03968254 0    bsput 1.493478 -0.3564602 0.07426992 -0.01473790 -0.0769152  0.01414525 -23.86780 0.06238672
5 100 98 0.3 0 0.03968254 0   bscall 3.493478  0.6435398 0.07426992  0.02415099 -0.0769152 -0.02553729  18.42118 0.06238675
6 100 98 0.3 0 0.03968254 0    bsput 1.493478 -0.3564602 0.07426992 -0.01473790 -0.0769152  0.01414525 -23.86780 0.06238672

I am having a hard time breaking away from a for loop in this situation and would appreciate some help. Thank you kindly

1 Answers

In R, when you need repeat a calculation on each row in a data.frame - and the calculation does not depend on the preceding/succeeding row, you should do it with vectorization. Looking up greeks, it tells us that is supports vectorization.

But, with your if-else setup, you need to do a bit of subsetting. The biggest issue is preserving order:

df$i <- 1:nrow(df)

dte1 <- df$dte[1]/252
df <- df[order(df$pc),]
rows <- df$pc == 'C'

greeks.C <- greeks(bsput(df$spot[rows], df$Strike[rows], df$iv[rows], 0, dte1, 0), complete=T)
greeks.C$i <- df$i[rows]
rows <- df$pc == 'P'
greeks.P <- greeks(bscall(df$spot[rows], df$Strike[rows], df$iv[rows], 0, dte1, 0), complete=T)
greeks.P$i <- df$i[rows]

result <- rbind(greeks.C, greeks.P)
result[order(result$i),]

     s  k   v r         tt d funcname  Premium      Delta       Vega         Rho      Theta         Psi     Elast      Gamma  i
1  100 98 0.3 0 0.03968254 0    bsput 1.493478 -0.3564602 0.07426992 -0.01473790 -0.0769152  0.01414525 -23.86780 0.06238672  1
6  100 98 0.3 0 0.03968254 0   bscall 3.493478  0.6435398 0.07426992  0.02415099 -0.0769152 -0.02553729  18.42118 0.06238675  2
2  100 98 0.3 0 0.03968254 0    bsput 1.493478 -0.3564602 0.07426992 -0.01473790 -0.0769152  0.01414525 -23.86780 0.06238672  3
7  100 98 0.3 0 0.03968254 0   bscall 3.493478  0.6435398 0.07426992  0.02415099 -0.0769152 -0.02553729  18.42118 0.06238675  4
3  100 98 0.3 0 0.03968254 0    bsput 1.493478 -0.3564602 0.07426992 -0.01473790 -0.0769152  0.01414525 -23.86780 0.06238672  5
8  100 98 0.3 0 0.03968254 0   bscall 3.493478  0.6435398 0.07426992  0.02415099 -0.0769152 -0.02553729  18.42118 0.06238675  6
4  100 98 0.3 0 0.03968254 0    bsput 1.493478 -0.3564602 0.07426992 -0.01473790 -0.0769152  0.01414525 -23.86780 0.06238672  7
9  100 98 0.3 0 0.03968254 0   bscall 3.493478  0.6435398 0.07426992  0.02415099 -0.0769152 -0.02553729  18.42118 0.06238675  8
5  100 98 0.3 0 0.03968254 0    bsput 1.493478 -0.3564602 0.07426992 -0.01473790 -0.0769152  0.01414525 -23.86780 0.06238672  9
10 100 98 0.3 0 0.03968254 0   bscall 3.493478  0.6435398 0.07426992  0.02415099 -0.0769152 -0.02553729  18.42118 0.06238675 10
Related