Introduction to Options

Historical Volatility and Implied Volatility


The change of volatility can have a significant impact on the performance of options trading. In addition to the Vega we explained in Greeks letter chapter, this part of the volatility tutorial will discuss the concept of volatility, specifically, we discuss realized and implied volatility, their meanings, measurements, uses, and limitations.

Historical Volatility

1. Definition

It is a measurement of how much the price of the asset has changed on average during the certain period of time. In common, volatility is said to be the standard deviation of the return of assets price.

2. Calculation

Next we discuss how to estimate the historical volatility of the option empirically.

\[r_i=ln(\frac{S_i}{S_{i-1}})\quad for\ i=0,1,2,3,...,n\]

Where (n+1) is the number of observations, \(S_i\) is the stock price at end of it time interval

The  standard deviation of the \(r_i\) is given by


where \(\overline{r}\) is the mean of \(r_i\)

If we assume there are n trading days per year. Then the estimate of historical volatility per annum is

import pandas as pd
from numpy import sqrt,mean,log,diff
import quandl
quandl.ApiConfig.api_key = 'NxTUTAQswbKs5ybBbwfK'
goog_table = quandl.get('WIKI/GOOG')
# use the daily data of Google(NASDAQ: GOOG) from 01/2016 to 08/2016
close = goog_table['2016-01':'2016-08']['Adj. Close']
r = diff(log(close))
r_mean = mean(r)
diff_square = [(r[i]-r_mean)**2 for i in range(0,len(r))]
std = sqrt(sum(diff_square)*(1.0/(len(r)-1)))
vol = std*sqrt(252)

An asset has a historical volatility based on its past performance as described above, investors can gain insight on the fluctuations of the underlying price during the past period of time. But it does not tell us anything about the volatility in the market now and in the future. So here we introduce the implied volatility.

Implied Volatility

In contrast to historical volatility, the implied volatility looks ahead. It is often interpreted as the market’s expectation for the future volatility of a stock and is implied by the price of the stock’s options. Here implied volatility means it is not observable in the market but can be derived from the price of an option.

1. Definition

We use volatility as an input parameter in option pricing model. If we take a look at the BSM pricing, the theoretical price or the fair value of an option is P, where P is a function of historical volatility σ, stock  price S, strike price K, risk-free rate r and the time to expiration T.  That is \(P=f(\sigma,S,K,r,T)\). But the market price of options is not always the same with the theoretical price. Now in contrast, if we are given the market’s prices of calls and puts written on some asset and also the value of S, K, r, T. For each asset we can solve a new volatility that corresponds to the price of each option – the implied volatility. Then the implied volatility is \(\IV=f^{-1}(P,S,K,r,T)\).

2. Calculation

Here we use the bisection method to solve the BSM pricing equation and find the root which is the implied volatility. We use Yahoo Finance Python API to get the real time option data.

def bsm_price(option_type, sigma, s, k, r, T, q):
    # calculate the bsm price of European call and put options
    sigma = float(sigma)
    d1 = (np.log(s / k) + (r - q + sigma ** 2 * 0.5) * T) / (sigma * np.sqrt(T))
    d2 = d1 - sigma * np.sqrt(T)
    if option_type == 'c':
        price = np.exp(-r*T) * (s * np.exp((r - q)*T) * stats.norm.cdf(d1) - k *  stats.norm.cdf(d2))
        return price
    elif option_type == 'p':
        price = np.exp(-r*T) * (k * stats.norm.cdf(-d2) - s * np.exp((r - q)*T) *  stats.norm.cdf(-d1))
        return price
        print('No such option type %s') %option_type
def implied_vol(option_type, option_price, s, k, r, T, q):
    # apply bisection method to get the implied volatility by solving the BSM function
    precision = 0.00001
    upper_vol = 500.0
    max_vol = 500.0
    min_vol = 0.0001
    lower_vol = 0.0001
    iteration = 0

    while 1:
        iteration +=1
        mid_vol = (upper_vol + lower_vol)/2.0
        price = bsm_price(option_type, mid_vol, s, k, r, T, q)
        if option_type == 'c':

            lower_price = bsm_price(option_type, lower_vol, s, k, r, T, q)
            if (lower_price - option_price) * (price - option_price) > 0:
                lower_vol = mid_vol
                upper_vol = mid_vol
            if abs(price - option_price) < precision: break if mid_vol > max_vol - 5 :
                mid_vol = 0.000001

        elif option_type == 'p':
            upper_price = bsm_price(option_type, upper_vol, s, k, r, T, q)

            if (upper_price - option_price) * (price - option_price) > 0:
                upper_vol = mid_vol
                lower_vol = mid_vol
            if abs(price - option_price) < precision: break if iteration > 50: break

    return mid_vol
implied_vol('c', 0.3, 3, 3, 0.032, 30.0/365, 0.01)

From the result above, the implied volatility of European call option (with premium c=0.3, S=3, K=3, r=0.032, T =30 days, d=0.01) is 0.87.

3. Factors Affecting Implied Volatility

According to the time value description in the first tutorial, in general, the more time to expiration, the greater the time value of the option. Investors are willing to pay extra money for zero intrinsic value options which have more time to expiration because more time increases the likelihood of price movement and fluctuations, it is the options will become profitable. Implied volatility tends to be an increasing function of maturity. A short-dated option often has a low implied volatility, whereas a long-dated option tends to have a high implied volatility.

Volatility Skew

For European options of the same maturity and the same underlying assets, the implied volatilities vary with the strikes. For a series of put options or call options, if we plot these implied volatilities for a series of options which have the same expiration date and the same underlying with the x-axis being the different strikes, we would get a convex curve. The shape of this curve is like people's smiling, it is being called the volatility. The shape of volatility smile depends on the assets and the market conditions.

Here we give an example how to plot the volatility smile by using the real time options data of SPDR S&P 500 ETF(NYSEARCA: SPY).

# download option data for all expiry months from Yahoo Finance
# provide a formatted DataFrame with a hierarchical index
opt = Options('spy', 'yahoo')
opt.expiry_dates  # list all the available expiration dates
def IV_plot(opt,option_type,expiry_index):
    expiry = opt.expiry_dates[expiry_index]
    if option_type == 'c':
        data = opt.get_call_data(expiry=expiry)
    elif option_type == 'p':
        data = opt.get_put_data(expiry=expiry)
    r = 0.01 # risk free rate
    d = 0.01 # continuous devidend yield
    s = opt.underlying_price # data_call['Underlying_Price']  undelying price
    expiry = data.index.get_level_values('Expiry')[0] # get the expiry
    current_date = opt.quote_time # current_date = # get the current date
    time_to_expire = float((expiry - current_date).days)/365 # compute time to expiration
    premium = (data['Ask'] + data['Bid'])/2 # option premium
    strike = list(data.index.get_level_values('Strike')) # get the strike price
    IV = []
    for i in range(len(data)):
        IV.append(implied_vol(option_type, premium.values[i], s, strike[i], r, time_to_expire, d))

    plt.figure(figsize=(16, 7))
    a = plt.scatter(strike,IV, c='r', label="IV by solving BSM")
    b = plt.scatter(strike,data['IV'],c = 'b', label="IV from Yahoo Finance")
    if option_type == 'c':
        plt.ylabel('Implied Volatility for call option')
        plt.legend((a,b), ("IV(call) by solving BSM", "IV(call) from Yahoo Finance"))
    elif option_type == 'p':
        plt.ylabel('Implied Volatility for put options')
        plt.legend((a,b), ("IV(put) by solving BSM", "IV(put) from Yahoo Finance"))

    return strike,IV
k_call, IV_call = IV_plot(opt,'c',23)
k_put, IV_put = IV_plot(opt,'p',23)
plt.figure(figsize=(16, 7))
e = plt.scatter(k_call,IV_call, c ='red', label="IV(call options)")
f = plt.scatter(k_put,IV_put, c = 'black', label="IV(put options)")
plt.ylabel('Implied Volatility')
plt.legend((e,f), ("IV (call options)", "IV (put options)"))

The current date is 08/14/2017. We plot the implied volatilities for SPY options which expire on 12/21/2018.

implied volatility of call options implied volatility of put options

Plotting these implied volatilities across strikes gives us the implied volatility skew. For the shape of volatility smile, it should be a symmetry convex curve. But from the above chart, the implied volatility curve slopes downward to the right. This is referred to the skew, which means that options with low strikes have higher implied volatilities than those with higher strikes. The smile is not symmetry. The skew of a distribution is a measure of its asymmetry. Although the volatility skew is dynamic, in equity markets it is almost always a decreasing function of the strike. Other asset classes such as FX and commodities have differently shaped skews.

If we plot the call and put options implied volatility smile in the same chart for the same expiration date:

implied volatility of call and put options

From the above chart, we can see the implied volatility for put options is higher than call options. Usually, put options trade for a higher price than call options, because traders place more risk in the short put positions, which raises the amount of reward they require to sell the position. Higher option prices signify an increase in risk and are represented by higher implied volatility levels derived from the option pricing model. Then we scattered all the implied volatilities of contracts across all the strikes.

opt = Options('spy', 'yahoo')
r = 0.01 # risk free rate
d = 0.01 # continuous devidend yield
expiry_dates = [i for i in opt.expiry_dates if i >]
current_date =  ## get the current date
s = opt.underlying_price # undelying price
num_expiry = len(expiry_dates)
IV = [] # (num_expiry * 3)-dimension list with each row being [time_to_expire, strike, implied_vol]

for expiry_index in range(num_expiry):
    data = opt.get_put_data(expiry=expiry_dates[expiry_index])
    expiry = expiry_dates[expiry_index] # get the expiry
    time_to_expire = float((expiry - current_date).days)/365 # compute time to expiration
    premium = (data['Ask'] + data['Bid'])/2.0 # option premium
    strike = data.index.get_level_values('Strike') # get the strike price
    num_strike = len(data)
    for j in range(num_strike):
        IV.append([time_to_expire, strike[j], implied_vol('c', premium.values[j], s, strike[j], r, time_to_expire, d)])
x= [IV[i][0] for i in range(len(IV))]
y= [IV[i][1] for i in range(len(IV))]
z= [IV[i][2] for i in range(len(IV))]
fig = plt.figure(figsize=(20,11))
ax = fig.add_subplot(111, projection='3d')
implied volatility surface

Volatility Surface

By fixing the maturity and looking at the implied volatilities of European options on the same underlying but different strikes, we obtain the implied volatility skew or smile. The volatility surface is the three-dimensional surface when we plots the market implied volatilities of European options with different strikes and different maturities.

Through the interpolation method, we can generate the implied volatility surface of SPY options for both put and call options as follows:

implied volatility surface for call options implied volatility surface for put options

The Reason for Volatility Skew

The volatility skew reveals that for put options, implied volatility is higher for deep OTM options and is decreasing as it moves toward ITM options. For call options, the implied volatility is higher for deep ITM options and is decreasing as it moves toward OTM options. From the demand and supply degree, the skew reflects that investors are more willing to buy deep OTM puts and ITM calls. Why there is volatility skew in the market? First, the majority of the equity positions are long. Investors usually have two ways to hedge those long positions risks: Buying downside puts or selling upside calls. The increase in demand create increases in the price of downside puts and decreases in the price of upside calls. The volatility is a reflection of options price. Therefore the volatility of in-the-money put is higher and the volatility of in-the-money call is lower. The second reason for volatility skew is that the market moves down faster than it moves up. The downside market move is riskier than the upside move. Thus the price of OTM puts is higher than OTM calls.


In this chapter, we discussed the historical volatility and the implied volatility. The historical volatility of an asset is the statistical measure we know as the standard deviation of the stock return series. The implied volatility of the same asset, on the other hand, is the volatility parameter that we can infer from the prices of traded options written on this asset. In contrast to historical volatility, which looks at fluctuations of asset prices in the past, implied volatility looks ahead. The two volatilities do not necessarily coincide, and although they may be close, they are typically not equal. Now we know the constant volatility assumption in Black-Sholes-Merton model is not applicable in the real market because there is volatility skew for most options. In next chapter, we will introduce some volatility models to capture the volatility skew in options pricing.


  1. Options Pricing: Intrinsic Value And Time Value, Jean Folger, Online Copy

You can also see our Documentation and Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the tutorials: