Definition
A Covered Call is an options strategy that involves both the underlying stock and an options contract. The trader buys (or already owns) a stock, then sells call options for the same amount of stock. The aim of the Covered Call is to profits from the option premium by selling calls written on the stock you already owned. At any time for US options or at expiration for European options, if the stock moves below the strike price, you can keep the premium and still maintain the stock position. If the price moves above the strike, the options contract will be exercised and you will have to sell the stock at the strike price but you will still keep the premium. The risk of a Covered Call also comes from the long stock position whose price could drop.
The payoff is as follows:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
price = np.arange(110,230,1) # the stock price at expiration date
strike = 160 # the strike price
premium = 7.5 # the option premium
# the payoff of short call position
payoff_short_call = [min(premium, -(i - strike-premium)) for i in price]
# the payoff of long stock postion
payoff_long_stock = [i-strike for i in price]
# the payoff of covered call
payoff_covered_call = np.sum([payoff_short_call, payoff_long_stock], axis=0)
plt.figure(figsize=(20,11))
plt.plot(price, payoff_short_call, label = 'short call')
plt.plot(price, payoff_long_stock, label = 'underlying stock')
plt.plot(price, payoff_covered_call, label = 'covered call')
plt.legend(fontsize = 20)
plt.xlabel('Stock Price at Expiry',fontsize = 15)
plt.ylabel('payoff',fontsize = 15)
plt.title('Covered Call Strategy Payoff at Expiration',fontsize = 20)
plt.grid(True)
Implementation
Step 1: Initialize the Algorithm: At the beginning of your algorithm, you need to set the start date, the end date and the cash required for the algorithm. For options algorithm, you need to add the equity and the options written on this equity.
def Initialize(self):
self.SetStartDate(2016, 1, 1)
self.SetEndDate(2016, 3, 1)
self.SetCash(100000)
equity = self.AddEquity("IBM")
option = self.AddOption("IBM")
self.symbol = option.Symbol
# set our strike/expiry filter for this option chain
option.SetFilter(-3, +3, 0, 30)
# use the underlying equity as the benchmark
self.SetBenchmark(equity.Symbol)
self.call = None # Initialize the call contract
In the initialization process, you need to add a coarse selection for the options contracts. Here we use option.SetFilter(-3, +3, 0, 60)
to implement the coarse selection process. If today's market price of underlying stock is $159, the strike prices of IBM options are spaced $5. Then SetFilter will look up the most at the money contract with the strike being K=$160 (Here K might not be $159 since rarely will option be ATM exactly). The filter will look for options with strikes between and including (160 - 5 * 3, 160 + 5 * 3). The time to expiration of these options is restricted within 60 days from now on.
Step 2: Choose the Call Options Contract: Purchasing the underlying stock for 100 shares or an integer multiple of 100 shares. For options contract, one contract represents 100 shares of stock.
if not self.Portfolio[self.symbol.Underlying].Invested:
# buy 100 shares of underlying stocks
self.MarketOrder(self.symbol.Underlying, 100)
# do not open new option positions
if any([x for x in self.Portfolio.Values if x.Invested and x.Type == SecurityType.Option]):
return
Step 3: Filter out the call options from candidate contracts.
chain = slice.OptionChains.get(self.symbol)
calls = [x for x in chain if x.Right == OptionRight.Call]
Step 4: Select the most ATM contract with the furthest expiration date from call options contracts. Sell this call contract for each 100 shares of stock you own. Here you can also choose ITM or OTM contract based on your expected level of profit and the level of risk you can take.
# sorted the contracts according to their expiration dates and choose the ATM options
contracts = sorted(sorted(calls, key=lambda x: abs(chain.Underlying.Price - x.Strike)),
key=lambda x: x.Expiry, reverse=True)
# short the call options
self.Sell(calls[0].Symbol, 1)
Summary
From the above strategy we can see that the share price of IBM had been increasing during the backtesting period from January 2016 to June 2016. The drawdown is small -- the Covered Call strategy performs better than a simple buy-and-hold strategy of underlying stock in a bearish market. The benefit of Covered Call is that you keep the premium, any gains from the underlying price increase up to the strike price, and accrued dividends during the stock holding period. In a bullish market, however, you miss out on any gains if the underlying stock price breaches the strike price.