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!
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$