If you take Quantuple's stuff a little further, you can really see whether you're long skew. You can pretty easily see the dependence on convexity too (though it should be obvious that you're long convexity).
So first off, we need some smile parametrisation that lets us easily control convexity and skew. I just went with a made up one;
$$\mathrm{convexity} = \mathrm{C} = \left. \frac{\partial^2 \sigma}{\partial K^2} \right|_{K=F} \\
\mathrm{skew} = \mathrm{S} = \left. \frac{\partial \sigma}{\partial K} \right|_{K=F} \\
\sigma_{\mathrm{atm}} = \sigma(F)
$$
which gives:
$$
\frac{1}{2} C (K-F)^2 + S(K-F) + \sigma_\mathrm{atm}
$$
*Note that i understand this is not a proper smile, i'm just using it as a simple example.
Then if you look a pretty extreme range of smiles;
$$
-0.001 \leqslant \mathrm{S} \leqslant 0.001\\
0 \leqslant \mathrm{C} \leqslant 0.0001\\
\sigma_\mathrm{atm} = 20\%
$$
you get a bunch of images like Quantuple's in the other answer:
But, we can do better:
So yes, you are long skew. But only a really tiny amount - you're much longer convexity.
Here's python code for this if you want to mess around with it.
import numpy as np
def CND(X):
a1,a2,a3,a4,a5 = 0.31938153, -0.356563782, 1.781477937, -1.821255978, 1.330274429
L = np.abs(X)
K = 1.0 / (1.0 + 0.2316419 * L)
w = 1.0 - 1.0 / np.sqrt(2*np.pi)*np.exp(-L*L/2.) * (a1*K + a2*K*K + a3*np.power(K,3) + a4*np.power(K,4) + a5*np.power(K,5))
if X<0:
w = 1.0-w
return w
def BlackSholes(cp,S,X,T,r,v):
d1 = (np.log(S/X)+(r+v*v/2.)*T)/(v*np.sqrt(T))
d2 = d1-v*np.sqrt(T)
if cp=='c':
return S*CND(d1)-X*np.exp(-r*T)*CND(d2)
else:
return X*np.exp(-r*T)*CND(-d2)-S*CND(-d1)
def C(S,X,T,r,v):
return BlackSholes("c", S, X, T, r, v)
def P(S,X,T,r,v):
return BlackSholes("p", S, X, T, r, v)
def B(r,t):
return np.exp(-r*t)
def vol(k, vol_atm, convexity, skew, atm=100, max_vol=1):
v = 0.5*convexity*k**2 + (skew - convexity*atm)*k + vol_atm + 0.5*convexity*atm**2 - skew*atm
return max(1e-5,min(v, max_vol))
import scipy.integrate as integrate
import scipy.special as special
def var_swap(S,T,r,atm_vol, convexity, skew):
F = S/B(r,T)
return np.sqrt((2 / (T*B(r,T))) * (integrate.quad(lambda k: P(S, k, T, r, vol(k, atm_vol, convexity, skew, atm=F)) * k**-2, 0, F)[0] + integrate.quad(lambda k: C(S, k, T, r, vol(k, atm_vol, convexity, skew, atm=F)) * k**-2, F, F*5)[0]))
r = 0.0
T = 1.0
S = 100.0
F = S/B(r,T)
print F
atm_vol = 0.2
convexity = 0.0001
skew = 0.001
ks = [k for k in range(1, int(F*2))]
n_scenarios = 20
skews = np.linspace(-skew, skew, n_scenarios)
convexities = np.linspace(0, convexity, n_scenarios)
plot_smiles = False
if plot_smiles:
import colorsys
blues = [colorsys.hsv_to_rgb(h, 1, 1) for h in np.linspace(0.5, 0.65, n_scenarios)]
reds = [colorsys.hsv_to_rgb(h, 1, 1) for h in np.linspace(0.0, 0.15, n_scenarios)]
from matplotlib import pyplot
fig = pyplot.figure()
ax_smiles = fig.add_subplot(1,1,1)
ax_opts = ax_smiles.twinx()
for i, (convexity, skew) in enumerate(zip(convexities, skews)):
vols = [vol(k, atm_vol, convexity, skew, atm=F) for k in ks]
opts = [BlackSholes("p" if k < F else "c", S, k, T, r, vol(k, atm_vol, convexity, skew, atm=F)) * k**-2 for k in ks]
ax_smiles.plot(ks, vols, color=blues[i])
ax_opts.plot(ks, opts, color=reds[i])
pyplot.show()
else:
CC = np.linspace(0, convexity,n_scenarios)
SS = np.linspace(-skew, skew,n_scenarios)
CC, SS = np.meshgrid(CC, SS)
VV = np.empty(CC.shape)
for i in range(CC.shape[0]):
for j in range(CC.shape[1]):
VV[i,j] = var_swap(S, T, r, atm_vol, CC[i,j], SS[i,j])
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(CC, SS, VV, rstride=1, cstride=1, cmap=cm.jet, linewidth=0, antialiased=True)
ax.set_xlabel("Convexity")
ax.set_ylabel("Skew")
ax.set_zlabel("Var. Swap par rate")
ax.set_ylim(ax.get_ylim()[::-1])
plt.show()
There is a caveat here though - this is the theoretical value of a variance swap. The market does not trade these according to the theoretical value, there is a difference which I have not seen a way of accounting for yet. The solution to this is that you store a table of varswap par rate spreads which can be interpolated and applied to varswaps at the corresponding start and end dates.
This spread does not come from stochastic vol, it seems to me to be some sort of insurance against unpleasantly large costs when something happens. The alternative is trading corridor variance swaps (i.e. variance only accrues when the index is inside a corridor), to limit the likelihood of this downside.
You can easily get skew exposure with trades like the above though, if variance is only accruing when the underlying is above/below a certain level, then you will be long/short skew when the underlying is near the barrier - because when you're only looking at one side of a point, skew and convexity have similar effects.