0

so I have a dataframe like this:

    head(TNX)
         date strike_price impl_volatility moneyness
1  1996-09-03        65000        0.192926 0.9431225
4  1996-09-03        65000        0.184757 0.9431225
6  1996-09-03        55000        0.190826 0.7980267
7  1996-09-03        60000        0.187024 0.8705746
9  1996-09-03        62500        0.189573 0.9068485
10 1996-09-03        72500        0.209731 1.0519443



tail(TNX)
             date strike_price impl_volatility moneyness
424834 2009-10-30        27500        0.646013 0.8107311
424835 2009-10-30        20000        1.261644 0.5896226
424836 2009-10-30        25000        0.835957 0.7370283
424837 2009-10-30        30000        0.462221 0.8844340
424844 2009-10-30        17500        1.512000 0.5159198
424845 2009-10-30        22500        1.038973 0.6633255

I want to calculate a measure of skew i.e. Imp. Vol(110%) - Imp. Vol(90%)

Suppose that IV110 is 0.9431225, that is the first value in the data above. IV90 is 0.7980267, the third value. Once I have these values, I want to compute 0.192926 - 0.190826 , that is Impl_volatility[IV110] - Impl_volatility[IV.90] This is the outcome I want in the new column.

In order to do so created subsets of the data given one unique date (anchor.date):

#plotting the volatility surface
anchor.date <- TNX[164522,1]


#keeping a dataset with a specific date so that I can plot the Volatility Smile and Surface
TNX.surface <- subset(TNX, date == anchor.date)

Then I did the following to compute the measure of skew:

IV.110 <- which(abs(TNX.surface$moneyness - 1.1) == min(abs(TNX.surface$moneyness - 1.1)))
IV.90 <- which(abs(TNX.surface$moneyness - 0.9) == min(abs(TNX.surface$moneyness - 0.9)))
skew <- TNX.surface[IV.110, 3] - TNX.surface[IV.90, 3]

However, I would like to extend this formula to the whole dataframe without working on subsets. In other words, I want to make the same calculation for the skew in the whole dataset so that I get the same result for each date (but different results throughout the different dates)

Is there a way to do so?

Thanks!

Update: Running the code I get this

> TNX <- setDT(TNX)

> View(TNX)
> TNX[, id110 := abs(moneyness - 1.1) == min(abs(moneyness - 1.1)), by = date]
> TNX[, id90  := abs(moneyness - 0.9) == min(abs(moneyness - 0.9)), by = date]
> TNX[, skew := impl_volatility[id110] - impl_volatility[id90], by = date][]
              date strike_price impl_volatility moneyness id110  id90      skew
     1: 1996-09-03        65000        0.192926 0.9431225 FALSE FALSE  0.005509
     2: 1996-09-03        65000        0.184757 0.9431225 FALSE FALSE  0.021010
     3: 1996-09-03        55000        0.190826 0.7980267 FALSE FALSE  0.020730
     4: 1996-09-03        60000        0.187024 0.8705746 FALSE FALSE  0.017199
     5: 1996-09-03        62500        0.189573 0.9068485 FALSE  TRUE  0.015333
    ---                                                                        
209806: 2009-10-30        20000        1.261644 0.5896226 FALSE FALSE -0.062087
209807: 2009-10-30        25000        0.835957 0.7370283 FALSE FALSE  0.019549
209808: 2009-10-30        30000        0.462221 0.8844340 FALSE  TRUE  0.191924
209809: 2009-10-30        17500        1.512000 0.5159198 FALSE FALSE        NA
209810: 2009-10-30        22500        1.038973 0.6633255 FALSE FALSE        NA



> warnings()
Warning messages:
1: In impl_volatility[id110] - impl_volatility[id90] :
  longer object length is not a multiple of shorter object length
2: In `[.data.table`(TNX, , `:=`(skew, impl_volatility[id110] -  ... :
  Supplied 6 items to be assigned to group 1 of size 49 in column 'skew' (recycled leaving remainder of 1 items).
3: In impl_volatility[id110] - impl_volatility[id90] :
  longer object length is not a multiple of shorter object length
4: In `[.data.table`(TNX, , `:=`(skew, impl_volatility[id110] -  ... :
  Supplied 6 items to be assigned to group 2 of size 50 in column 'skew' (recycled leaving remainder of 2 items).
5: In `[.data.table`(TNX, , `:=`(skew, impl_volatility[id110] -  ... :
  Supplied 4 items to be assigned to group 3 of size 49 in column 'skew' (recycled leaving remainder of 1 items).
Davide
  • 3
  • 5

1 Answers1

0

So, here I replicate your calculations using data.table, grouping by dates. As an example I am using your head an tail samples

library(data.table    
hh = setDT(read.table(text = "
date strike_price impl_volatility moneyness
  1996-09-03        65000        0.192926 0.9431225
  1996-09-03        65000        0.184757 0.9431225
  1996-09-03        55000        0.190826 0.7980267
  1996-09-03        60000        0.187024 0.8705746
  1996-09-03        62500        0.189573 0.9068485
 1996-09-03        72500        0.209731 1.0519443
 2009-10-30        27500        0.646013 0.8107311
 2009-10-30        20000        1.261644 0.5896226
 2009-10-30        25000        0.835957 0.7370283
 2009-10-30        30000        0.462221 0.8844340
 2009-10-30        17500        1.512000 0.5159198
 2009-10-30        22500        1.038973 0.6633255", header = T))

Given your update, see if this is what you want

# create your 110 indices to find the values
hh[, id110 := abs(moneyness - 1.1) == min(abs(moneyness - 1.1)), by = date]
hh[, id90  := abs(moneyness - 0.9) == min(abs(moneyness - 0.9)), by = date]
# calculate the skew by date
hh[, skew := impl_volatility[id110] - impl_volatility[id90], by = date][]

          date strike_price impl_volatility moneyness id110  id90     skew
 1: 1996-09-03        65000        0.192926 0.9431225 FALSE FALSE 0.020158
 2: 1996-09-03        65000        0.184757 0.9431225 FALSE FALSE 0.020158
 3: 1996-09-03        55000        0.190826 0.7980267 FALSE FALSE 0.020158
 4: 1996-09-03        60000        0.187024 0.8705746 FALSE FALSE 0.020158
 5: 1996-09-03        62500        0.189573 0.9068485 FALSE  TRUE 0.020158
 6: 1996-09-03        72500        0.209731 1.0519443  TRUE FALSE 0.020158
 7: 2009-10-30        27500        0.646013 0.8107311 FALSE FALSE 0.000000
 8: 2009-10-30        20000        1.261644 0.5896226 FALSE FALSE 0.000000
 9: 2009-10-30        25000        0.835957 0.7370283 FALSE FALSE 0.000000
10: 2009-10-30        30000        0.462221 0.8844340  TRUE  TRUE 0.000000
11: 2009-10-30        17500        1.512000 0.5159198 FALSE FALSE 0.000000
12: 2009-10-30        22500        1.038973 0.6633255 FALSE FALSE 0.000000
Felipe Alvarenga
  • 2,572
  • 1
  • 17
  • 36
  • Hi Felipe, first of all thanks a lot. However, when I try to run the code I get this error: Error: unexpected ',' in "TNX[, (IV.90 = min(abs(moneyness - 0.9))," – Davide Feb 07 '18 at 17:20
  • Probably you haven't switched to a data.table format. First, call data.table package `library(data.table)` , then transform your data set `TNX = setDT(TNX)`. This will allow you to perform the operations I proposed in the second chunk of the code – Felipe Alvarenga Feb 07 '18 at 17:29
  • I tried to rearrange it but it gives the following: Error in `[.data.frame`(TNX, , .(IV.90 = min(abs(moneyness - 0.9)), IV.110 = min(abs(moneyness - : unused argument (by = date) Ok, I'll try – Davide Feb 07 '18 at 17:31
  • It works. Thanks a lot. Just one more info as I am really using R since 3 days. How can I now paste all the skew result in the original dataframe so that the skew values are the same for each same date? Basically I want to explicit the skew value of each row, not only for one row for every subset – Davide Feb 07 '18 at 17:35
  • Felipe, I just realized that the computation is not correct. The skew should not be calculated as IV110 - IV90. In fact, it should be calculated as the value in the Implied Volatility column corresponding to IV110 minus that corresponding to IV90. How can I do that? :D – Davide Mar 08 '18 at 11:00
  • If you want to get the Implied Volatility, change change `moneyness` into `impl_volatility` when calculation the `IVx` columns – Felipe Alvarenga Mar 08 '18 at 12:38
  • The thing is that I have to calculate both. IV90 = min(abs(moneyness - 0.9) and IV110 = min(abs(moneyness - 1.1) are needed to find the moneyness values needed as reference. Then, per each different date I need to compute the difference in Impl Vol between the imp vol corresponding to IV110 and IV 90. That's why I don't know how to put everything together.. – Davide Mar 08 '18 at 13:24
  • Update the question with a sample of a desired output, that way I can better understand what you want – Felipe Alvarenga Mar 08 '18 at 14:12
  • Felipe, I have just added an update in bold characters. Hope you can help me! – Davide Mar 11 '18 at 04:08
  • Hi Felipe, and thanks again! Unfortunately I do not get the same output that you showed in the comment. Moreover I also get this warning: "There were 50 or more warnings (use warnings() to see the first 50)" See the result that I get in the update to my question. I hope you are still willing to help me! – Davide Mar 13 '18 at 02:22
  • Given your update, the last chunk of code I provided you does exactly that: implied volatility of IV.110 minus implied volatility of IV.90 by date. If the result if reached is not what you are looking for, than update the question so I can understand. If your codes does not match my result, probably there is a syntax error – Felipe Alvarenga Mar 13 '18 at 17:38