Search code examples
rfunctionloopslapplyquantitative-finance

User defined function input to loop every row of data frame


Im trying to create my very own first project in R but have hit a roadblock.

I have a data frame such as below where every row represents dataset of a financial option.

type <- c("C", "C")
marketV <- c(1.1166, 1.911)
S <- c(20, 60)
K <- c(20, 56)
T <- c(0.333, 0.5)
df <- data.frame(type, marketV, S, K, T)

I made a user defined function to take this data frame as an input and works great when the data frame is one row long. However, I'm not sure how to have my function iterate through all the data frame rows and produce a result for all of them.

I'm new to R so I'm unsure whether I should be running a 'for' loop around or playing around with lapply, or if theres a simple syntax answer. I simply want the function to take the df as input, but repeat its calculation for n row, and produce n results. Thank you for the help in advance.

My current function code for a df with 1 row below as reference:


Solution

  • This is a corrected version of your program:

    df <- data.frame(type=c("C", "C"), marketV=c(1.1166, 1.911), S=c(20, 60), K=c(20, 56), T=c(0.333, 0.5))
    
    IV <- function(df) {
      # check if df has more then 1 row:
      if (nrow(df)>1) { message("!! nrow(df)>1 !!");  return(NA) }
    
      # Initializing of variables
      r <- 0
      sigma <- 0.3
      sigma_down <- 0.001
      sigma_up <- 1
      count <- 0
    
      type <- df$type; marketV <- df$marketV; S <- df$S; K <- df$K; T <- df$T
    
      d1 <- (log(S/K) + (sigma^2/2)*T)/(sigma*sqrt(T))
      d2 <- (log(S/K) - (sigma^2/2)*T)/(sigma*sqrt(T))
    
      if(type=="C") {
        V <- exp(-r*T)*(S*pnorm(d1) - K*pnorm(d2))
      } else {
        V <- exp(-r*T)*(K*pnorm(-d2) - S*pnorm(-d1)) }
    
      difference <- V - marketV
    
      # Root finding of sigma by Bisection method
      while(abs(difference)>0.001 && count<1000) {
        if(difference < 0) {
          sigma_down <- sigma
          sigma <- (sigma_up + sigma)/2 
        } else {
          sigma_up <- sigma
          sigma <- (sigma_down + sigma)/2
        }
    
        d1 <- (log(S/K) + (sigma^2/2)*T)/(sigma*sqrt(T))
        d2 <- d1 - sigma*sqrt(T)
    
        if(type=="C") {
          V <- exp(-r*T)*(S*pnorm(d1) - K*pnorm(d2))
        } else {
          V <- exp(-r*T)*(K*pnorm(-d2) - S*pnorm(-d1)) }
    
        difference <- V - marketV
        count <- count + 1
      }
      if(count == 1000){
        return(NA)          # If sigma to satisfy Black76 price cannot be found
      } else{
        return(sigma)
      }
    }
    
    sapply(split(df, seq(nrow(df))), IV)
    

    The main thing is to run row by row through the dataframe. This is done by

    sapply(split(df, seq(nrow(df))), IV)
    

    In your original function are many errors: the biggest is accessing to S, K and so on. You might thinking taking the values from the dataframe df. But in fact you were taking the values from the workspace! I corrected this by redefining:

    type <- df$type; marketV <- df$marketV; S <- df$S; K <- df$K; T <- df$T
    

    I inserted a test for the number of rows in df, so you will get:

    > IV(df)
    !! nrow(df)>1 !!
    [1] NA
    

    Here is a cleaned up version of your program:

    df <- data.frame(type=c("C", "C"), marketV=c(1.1166, 1.911), S=c(20, 60), K=c(20, 56), T=c(0.333, 0.5))
    
    IV2 <- function(type, marketV, S, K, T) {
      r <- 0; sigma <- 0.3
      sigma_down <- 0.001; sigma_up <- 1
      count <- 0
    
      if(type=="C") {
        f.sig <- function(sigma)  {
          d1 <- (log(S/K) + (sigma^2/2)*T)/(sigma*sqrt(T))
          d2 <- d1 - sigma*sqrt(T)
          exp(-r*T)*(S*pnorm(d1) - K*pnorm(d2)) - marketV
        } 
      } else {
        f.sig <- function(sigma)  {
          d1 <- (log(S/K) + (sigma^2/2)*T)/(sigma*sqrt(T))
          d2 <- d1 - sigma*sqrt(T)
          exp(-r*T)*(K*pnorm(-d2) - S*pnorm(-d1)) - marketV
        }
      }
      ifelse(f.sig(sigma_down)*f.sig(sigma_up) < 0, uniroot(f.sig, c(sigma_down,sigma_up))$root, NA) # sigma
    }
    
    sapply(split(df, seq(nrow(df))), do.call, what="IV2")