What are perpetual options?
Everyone familiar with crypto trading will have heard of perpetual futures. These products are defined by regular settlements, say once per day at times \(t_1, t_2, t_3,…\), where the holder pays the amount \(V(t,S(t)) – P(S(t))\). Here, \(P\) is the payoff of the future, given by \(P(S) = S\). The function \(V\) is the current price at which the perpetual is trading on the market.
Perpetual options come about by simply replacing the payoff P in the above construct with the payoff off an option. That is, \(Max(S-K, 0)\) for a call option and \(Max(K-S, 0)\) for a put option.
For each daily settlement, you can view \(P\) as the cashflow you receive, and \(V\) as the cashflow you have to pay. The function \(V\), known as the funding fee, is often viewed as a penalty which forces the value of the perpetual to converge towards the payoff as the time approaches each daily expiry. Otherwise, the holders of the perpetuals are penalized by having to pay more than what they receive. As we’ll see, another way to view it in the case of a perpetual option, is as the premium of a portfolio of options.
One of the arguments used to motivate perpetuals is that they prevent the available liquidity from being divided among options of many different expiries. Another is that they avoid the inconvenience and spread fees of having to manually roll contracts as each option expires.
Perpetual options were originally discussed in this short paper.
Perpetual options as a portfolio of options
Let’s just consider for a moment the second part of the settlement only. Since at each time \(t_i\) we receive the payoff \(P_i = P(S(t_i))\), we can view this collection of cashflows as exactly that from a portfolio of options with expiries \(t_1, t_2, t_3,…\).
It makes sense therefore that the payments \(V_i = V(t_i,S_i)\) can be conceived of as the premium payments corresponding to the option portfolio. Now pay attention to the following fact: since at each time \(t_i\) the holder of the perpetual pays the current value of the option portfolio, this means that the notionals of all remaining options must double.
about the payment as the option premium payment, since the investor pays the current value of the portfolio, it’s clear that the notional of the options must double at each payment time (excluding the one that’s expiring at the same time, of course). Since the kth option notional will be doubled one more time than the (k-1)th option, each successive option in the portfolio will have half the notional than the last one. In other words, the notionals must follow a geometric series with ratio ½.
Continuous funding
The notional halfing each time you move to the option with an expiry one day longer means that the notionals obey an exponential relationship. Instead of using a base of one half, we can use a base of \(e\) as long as we introduce a constant out the front. Thus, assuming our perpetual is a call, we could write the price of our perpetual (option portfolio) as
\[V = A\sum_{i=1}^{\infty} e^{-t_i/T} C_{t_i},\]
for some constant \(A\), where \(C_{t_i}\) is the price of a call option with expiry \(t_i\), and \(T\) is the interval between option expiries (assumed to be one day in our discussion above). If we now imagine decreasing the spacing of the options so that the sum becomes an integral (while leaving \(T\) unchanged), we get what’s known as the continuous funding case:
\[V = A\int_{0}^{\infty} e^{-t/T} C_{t}dt\]
Pricing models for perpetual options
Since the product can be conceived of as a (discrete or continuous) collection of options, the problem of pricing reduces to the problem of pricing options of different maturities. Assuming a Black-Scholes framework, this reduces to the problem of fitting an arbitrage free volatility surface to whatever implied volatilities exist in the market for vanilla options. Algorithms exist that can find the closest (least squares) fit subject to no arbitrage conditions. If there is limited data, a parametric approach could be considered, as these have far fewer degrees of freedom than a surface obtained by interpolating between options which exist in the market. At the more complex end of the scale, local and stochastic vol models are both parametric approaches but could be overkill.
As usual, volatilities for options whose strikes or expiries fall in between those in the market are generated by interpolating the volatility surface. For example, interpolating between time 0 and the first option can be done by assuming the volatility surface is linear in variance (\(V^2T\) interpolation).
Continuously funded everlasting options would need to be priced as a numerical integral, with options of different expiries being assigned different volatilities from the surface.
Variants where the strike is a moving average of recent prices can also be handled using the corresponding option pricing formulae for these products.
In other words, as long as you have the volatility data and model required to price regular options, perpetual prices follow without too much difficulty.
In terms of evaluating the integral above, the exponential weighting term means that we should only need to consider about 10 funding intervals (each of length \(T\)) before the contribution of additional terms becomes negligible. The integral can then be carried out by approximating it by a finite number of steps as usual.
How do the price and greeks of perpetual options compare to vanilla options?
The price/greeks of an everlasting are going to be a weighted sum of the prices/greeks of options of increasing expiries. It should be noted that the price of an everlasting will depend on how the volatility of an option depends on expiry according to the chosen vol surface. For simplicity, I’ve assumed the volatility surface is flat. If the funding period is short such as a single day, assuming volatility has no term structure may be reasonable.
To see how the price and greeks of a perpetual option relates to that of a single vanilla option with a single expiry, I’ve used python code to produce some graphs.
Focusing on calls, I’ve plotted the prices of an 8 hour, strike 100 call. I’ve set the volatility to 80% to accentuate the difference between the two prices which is otherwise hard to see.
The two prices are surprisingly close. The vanilla is slightly more valuable near at the money, and slightly less valuable in the wings. This is seen more clearly when plotting the difference between the two prices:
Since the price graphs are very similar, the Greeks will be very similar as well. We plot the delta difference:
The gamma difference:
And the vega difference:
The patterns are interesting, but their small magnitude wouldn’t have much impact on a standard market risk or margin amount (VaR) calculation, for which approximate values of greeks would be sufficient. Thus the risk profile is very similar to that of a dated option with maturity equal to the length of the funding period.
Hedging perpetual options
Viewing it as a portfolio of regular options, you can hedge it using a portfolio of whatever instruments you would normally use for the regular options. However, unless you only wish to hedge the nearest few expiries, this might require purchasing many instruments. Conceptually, purchasing spot in order to delta hedge could be accomplished by either combining the spot amounts required for each of the deltas of the individual options, or purchasing an amount of spot based on the delta of the everlasting option.
Alternatively, depending on the hedge, it might be possible to hedge all expiries simultaneously using another perpetual product, if it exists.
Arbitrage with vanilla options
In the standard options market one can look for various kinds of arbitrage, including violations of put call parity and inconsistencies with the volatility surface. This includes calendar arbitrage, where an option with closer maturity is assigned an implied volatility that leads it to be more valuable than an option with further maturity, and butterfly arbitrage, where the option price as a function of strike is not convex.
If the everlasting option is viewed as a finite portfolio of options, and one of those options is mispriced compared to an equivalent dated option with the same expiry, then one simply buys one and sells the other. In someone believes that the perpetual is mispriced at many expiries, they can buy/sell a portfolio of dated options alongside buying or selling the everlasting option.
Python code
Below is the python code used for this article.
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt
T = 1/365/3
K = 100
r = 0
V = 0.8
def Call(V, S, K, T, r):
if T > 0:
d1 = (np.log(S/K) + (r + 0.5*V**2)*T)/(V*np.sqrt(T))
d2 = (np.log(S/K) + (r - 0.5*V**2)*T)/(V*np.sqrt(T))
call = S*norm.cdf(d1,0.0,1.0) - K*np.exp(-r*T)*norm.cdf(d2,0.0,1.0)
return call
else:
return S - K
def ECall(V, S, K, T, r):
u = np.sqrt(1 + 8/(V*V*T))
intrinsic = max(S-K,0)
if S >= K:
timevalue = (K/u)*(S/K)**(-(u-1)/2)
else:
timevalue = (K/u)*(S/K)**((u+1)/2)
return intrinsic + timevalue
def Delta(V, S, K, T, r, Pricefunction):
step = 0.0001*S
return(Pricefunction(V,S+step,K,T,r) - Pricefunction(V,S-step,K,T,r)) / (2*step)
def Gamma(V, S, K, T, r, Pricefunction):
step = 0.0001*S
return (Pricefunction(V,S+step,K,T,r) -2*Pricefunction(V,S,K,T,r) + Pricefunction(V,S-step,K,T,r))/(step**2)
def Vega(V, S, K, T, r, Pricefunction):
step = 0.0001*V
return (Pricefunction(V+step,S,K,T,r) - Pricefunction(V,S,K,T,r))/step
# Price plot
plt.figure(1)
plt.xlabel('Spot', fontsize=12)
plt.ylabel('Call Price', fontsize=12)
xlist = np.linspace(90,110,300)
ylistvan = [Call(V, S, K, T, r) for S in xlist]
plt.plot(xlist,ylistvan,label='Vanilla', linewidth=1)
ylistever = [ECall(V, S, K, T, r) for S in xlist]
plt.plot(xlist,ylistever,label='Everlasting', linewidth=1)
#plt.plot(xlist[:-1],ylist,label='Everlasting')
plt.legend(loc='upper right')
# Price difference plot
plt.figure(2)
plt.xlabel('Spot', fontsize=12)
plt.ylabel('Everlasting - vanilla price', fontsize=12)
ylistdiff = [ylistever[i] - ylistvan[i] for i in range(len(ylistever))]
plt.plot(xlist,ylistdiff,label='Everlasting - vanilla', linewidth=1)
# Delta difference plot
plt.figure(3)
plt.xlabel('Spot', fontsize=12)
plt.ylabel('Everlasting - vanilla delta', fontsize=12)
ylistdeltavan = [Delta(V, S, K, T, r, Call) for S in xlist]
ylistdeltaever = [Delta(V, S, K, T, r, ECall) for S in xlist]
ylistdeltadiff = [ylistdeltaever[i] - ylistdeltavan[i] for i in range(len(ylistever))]
plt.plot(xlist,ylistdeltadiff,label='Everlasting - vanilla', linewidth=1)
# Gamma difference plot
plt.figure(4)
plt.xlabel('Spot', fontsize=12)
plt.ylabel('Everlasting - vanilla gamma', fontsize=12)
ylistgammavan = [Gamma(V, S, K, T, r, Call) for S in xlist]
ylistgammaever = [Gamma(V, S, K, T, r, ECall) for S in xlist]
ylistdeltadiff = [ylistgammaever[i] - ylistgammavan[i] for i in range(len(ylistever))]
plt.plot(xlist,ylistdeltadiff,label='Everlasting - vanilla', linewidth=1)
# Vega difference plot
plt.figure(5)
plt.xlabel('Spot', fontsize=12)
plt.ylabel('Everlasting - vanilla vega', fontsize=12)
ylistvegavan = [Vega(V, S, K, T, r, Call) for S in xlist]
ylistvegaever = [Vega(V, S, K, T, r, ECall) for S in xlist]
ylistdeltadiff = [ylistvegaever[i] - ylistvegavan[i] for i in range(len(ylistever))]
plt.plot(xlist,ylistdeltadiff,label='Everlasting - vanilla', linewidth=1)