0
$\begingroup$

I have the options data for a stock -

structure(list(Curr_Date = structure(c(18904L, 18904L, 18904L, 
18904L, 18904L, 18904L, 18904L, 18904L, 18904L), class = c("IDate", 
"Date")), ticker = c("GOLD", "GOLD", "GOLD", "GOLD", "GOLD", 
"GOLD", "GOLD", "GOLD", "GOLD"), ExpDate = structure(c(18915L, 
18915L, 19013L, 19013L, 19013L, 19377L, 19377L, 19377L, 19377L
), class = c("IDate", "Date")), Strike = c(18, 30, 10, 30, 40, 
10, 18, 30, 40), Option_Type = c("calls", "calls", "calls", "calls", 
"calls", "calls", "calls", "calls", "calls"), OI = c(3570L, 341L, 
723L, 68772L, 26302L, 1731L, 15662L, 37274L, 13215L), Vol = c(1L, 
1L, 5L, 40L, 1L, 1L, 2L, 4L, 5L), ask = c(0.56, 0.01, 8.6, 0.07, 
0.04, 10, 2.8, 0.51, 0.21), bid = c(0.54, 0, 8.2, 0.06, 0.03, 
8.05, 2.58, 0.48, 0.2), StockPrice = c(18.23, 18.23, 18.23, 18.23, 
18.23, 18.23, 18.23, 18.23, 18.23), days2exp = c(0.0301369863013699, 
0.0301369863013699, 0.298630136986301, 0.298630136986301, 0.298630136986301, 
1.2958904109589, 1.2958904109589, 1.2958904109589, 1.2958904109589
), calculated_price = c(0.53, 0, 8.27, 0, 0, 8.5, 2.87, 0.36, 
0.06)), row.names = c(NA, -9L), class = c("data.table", "data.frame"
), .internal.selfref = <pointer: 0x562667c9eac0>)

which looks like -

    Curr_Date ticker    ExpDate Strike Option_Type    OI Vol   ask  bid StockPrice   days2exp calculated_price
1: 2021-10-04   GOLD 2021-10-15     18       calls  3570   1  0.56 0.54      18.23 0.03013699             0.53
2: 2021-10-04   GOLD 2021-10-15     30       calls   341   1  0.01 0.00      18.23 0.03013699             0.00
3: 2021-10-04   GOLD 2022-01-21     10       calls   723   5  8.60 8.20      18.23 0.29863014             8.27
4: 2021-10-04   GOLD 2022-01-21     30       calls 68772  40  0.07 0.06      18.23 0.29863014             0.00
5: 2021-10-04   GOLD 2022-01-21     40       calls 26302   1  0.04 0.03      18.23 0.29863014             0.00
6: 2021-10-04   GOLD 2023-01-20     10       calls  1731   1 10.00 8.05      18.23 1.29589041             8.50
7: 2021-10-04   GOLD 2023-01-20     18       calls 15662   2  2.80 2.58      18.23 1.29589041             2.87
8: 2021-10-04   GOLD 2023-01-20     30       calls 37274   4  0.51 0.48      18.23 1.29589041             0.36
9: 2021-10-04   GOLD 2023-01-20     40       calls 13215   5  0.21 0.20      18.23 1.29589041             0.06

As it can be seen in column calculated_price, the OTM (out of the money) calls are hugely underpriced compared to bid or ask price. I have used the below formulas to calculate the expected price of an option.

r = 0.0148 # Risk free rate
v = 0.3188 # Historic volatility of 252 trading days
b = 0.02 # TTM yeild
dt[, d1 := ((log(StockPrice/Strike)) + (r - b + (v^2)/2) * days2exp)/(v * (sqrt(days2exp)))]
dt[, d2 := d1 - v * (sqrt(days2exp))]
dt[, calculated_price := round(StockPrice * pnorm(d1) - Strike*exp(-r * days2exp)*pnorm(d2), 2)]

Can someone point me out what is wrong with these formulas and how to correct the mispricing?

The expected result is - The values in column calculated_price should be between the market price in bid and ask columns.

Thanks!

$\endgroup$
8
  • $\begingroup$ Why do you use historical vol? You need implied vol. $\endgroup$
    – AKdemy
    Oct 5 '21 at 20:30
  • $\begingroup$ The results in calculated_price are close to bid/ask price when I use Implied volatility. However, since implied volatility is calculated using the bid/ask price, it becomes a circular problem. $\endgroup$
    – Saurabh
    Oct 5 '21 at 20:36
  • 2
    $\begingroup$ Well, you cannot use historical vol and suspect to get the market price. Ivol has a skew. Moreover, seems you use the same interest and dividend throughout? That will be quite unrealistic, your longer dated options expire in 2023. Also, you need to convert to continuous rates. $\endgroup$
    – AKdemy
    Oct 5 '21 at 20:40
  • $\begingroup$ Thanks!, I will try the continuous intrest rates. However, I am not sure how I will use the continuous dividend in the future when the dividends are vastly unpredictable in most cases. $\endgroup$
    – Saurabh
    Oct 5 '21 at 20:44
  • 1
    $\begingroup$ Dividends can be implied from the options as well. May I ask what the end goal is? Neither fed funds nor libor has such a tenor. Treasury is not used usually. If you want a theoretical value, you would use a stripped risk free rate curve (usually SOFR now, used to be frequently based on 3m libor). $\endgroup$
    – AKdemy
    Oct 5 '21 at 20:51
2
$\begingroup$

Your end goal of obtaining "fair" theoretical option prices will unfortunately require a lot of effort if you want to get this done properly on your own.

Here are a few reasons why:

  • All Nasdaq marketplace stock options are American-style
  • IVOL exhibits a skew
  • You need to have reliable interest rates
  • Dividend assumptions will influence your pricing for longer tenors a fair bit

The forward price is not directly quoted for listed options markets. Futures may be quoted but maturities frequently do not coincide with (all) option maturities. Interpolation is not trivial because future dividends (even times of payments) are usually unknown. Therefore, most practitioners use vanilla equity options to back out (implied) dividends.

The problem hereby is that put-call parity for American-Style options does not hold. Even for European-Style options, there are frequently issues with different trading times and erratic option prices etc. Since dividend payments are discrete in nature, you require a dividend schedule with dates and amounts to derive an implied dividend curve. This curve is usually noisier than one would hope for and commonly smoothed (via Kalman filter of the like).

For American options, one needs to first compute the European equivalent via a process called de-Americanization. For tenors that are not liquid, extrapolation may also be needed.

For interest rates, it is customary to use stripped interest rate curves. These used to be Libor 3m based but are now mainly SOFR curves, which are fundamentally built in a similar way.

Lastly, your main task will be building a reliable vol surface. SVI is frequently used. Voladynamics provides some interesting ideas and examples.

Your formula seems to exclude $e^{-q}$. As Wikipedia correctly states, it should be $${\displaystyle Se^{-q\tau }\Phi (d_{1})-e^{-r\tau }K\Phi (d_{2})\,}$$ This formula also requires rates and dividends to be continuous.

This link shows data sources (also IVOL). I am not familiar with any of these to be honest, but potentially they will help (be reliable). Many vendors like Bloomberg also offer, at a cost, Vol surfaces as part of their standard product offering.

$\endgroup$
2
  • $\begingroup$ Thank you so much for pointing out the discount factor problem in the formula! The results are not much closer to market prices. I still have to implement the SOFR curve, but having a hard time finding a free data source for this data. Do you have any pointers? $\endgroup$
    – Saurabh
    Oct 6 '21 at 8:12
  • $\begingroup$ I don't think there is free (public) OIS swaps data available. There are some futures listed on the CME. $\endgroup$
    – AKdemy
    Oct 6 '21 at 8:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.