Python for Options Trading (2): Mixing Options and Stocks

Roberto Gomes, PhD
6 min readSep 7, 2023

--

Photo by rajat sarki on Unsplash

EDIT: OptionLab is undergoing extensive modifications to its source code, which impliest that the example showcased in this article does not work with the latest version. You can access the source code of the old library here. It is also possible to install the old version using pip, as shown below.

Options trading is a highly risky activity and should be approached with due diligence, as it can lead to significant losses. The content of this article is not a recommendation and is purely for educational purposes.

First of all, welcome to my blog on Medium.com. In this article, I provide examples of how to analyze a simple and very popular options trading strategy known as covered call, using the OptionLab library and Python. To install OptionLab, it is enough to run pip install optionlab==0.2.0in a terminal. The source code for OptionLab is freely available at the link below.

The covered call is a two-legged strategy in which a stock is purchased (or already owned) by the trader, while s/he sells call options, typically out-of-the-money (OTM). To evaluate this strategy in terms of, for example, its profitability, we need to consider three distinct scenarios:

  1. Covered call where you buy the stock and sell the calls simultaneously.
  2. Covered call where you sell the calls but already own the underlying stock and the stock price increased since you acquired the shares.
  3. Covered call where you sell the calls but already own the underlying stock and the stock price declined since you acquired the shares.

As an example of the first scenario, let’s say you purchased 100 shares of Nvidia (ticker: NVDA) for $168.99 each on January 16, 2023. Immediately, you sold 100 OTM calls with a strike price of $185.00, which is approximately 10% above the current stock price, expiring on February 17, 2023. For the calls, you received a premium of $4.10 per option. The implementation of this simple strategy can be seen in the Python code snippet below.

# Import the required library
from optionlab.strategy import Strategy

# Input data (Nvidia, NVDA)
stockprice=168.99
volatility=0.483
startdate="2023-01-16"
targetdate="2023-02-17"
interestrate=0.045
minstock=stockprice-100.0
maxstock=stockprice+100.0

# Strategy object is created
st=Strategy()

# The covered call strategy is defined
strategy=[{"type":"stock","n":100,"action":"buy"},
{"type":"call","strike":185.0,"premium":4.1,"n":100,"action":"sell"}]

# Input data is provided and the calculations are performed
st.getdata(stockprice=stockprice,startdate=startdate,
targetdate=targetdate,volatility=volatility,
interestrate=interestrate,minstock=minstock,
maxstock=maxstock,strategy=strategy)

out=st.run()

# Print useful information on screen
print("Strategy cost: %.2f" % out["StrategyCost"])
print("Stock price profitable range at maturity: %.2f -> %.2f" %
(out["ProfitRanges"][0][0],out["ProfitRanges"][0][1]))
print("Maximum profit: %.2f" % out["MaximumReturnInTheDomain"])
print("Probability of profit: %.1f%%" % (out["ProbabilityOfProfit"]*100.0))

# Display the profit/loss diagram
st.plotPL()

After running this Python script, you will see the following output:

Strategy cost: -16489.00
Stock price profitable range at maturity: 164.90 -> inf
Maximum profit: 2011.00
Probability of profit: 54.9%

In other words, you will need to spend $16,489.00, which is the cost of acquiring 100 shares of Nvidia minus the total premium received from the sold calls. In order to profit from this trade, it is necessary for the stock price to be at least $164.90 at expiration.

The maximum profit of $2,011.00 is achieved when the stock price is at or above the strike price at maturity. It is calculated as the difference between the strike price and the stock price, plus the premium received, multiplied by the number of calls sold.

The probability of profit (PoP) of this covered call strategy is about 55%. The profit/loss (P/L) diagram follows:

Profit/loss diagram of the covered call.

In the P/L diagram, the position of the sold calls is indicated by the red right arrow, while the green dashed line represents the position of the stock spot price.

Let’s now analyze the second scenario. Suppose you already owned those 100 shares of Nvidia, which you bought some time ago (the exact date doesn’t matter) for $10.00 less than the price at which the stock was trading on January 16, 2023. And on January 16, 2023, you sold 100 calls with the same strike price of $185.00.

Is it possible to evaluate this strategy using OptionLab?

The anwer is yes. All you need to do is make this small change in the Python code above by adding an extra key to the Python dictionary where the stock leg of the strategy is defined:

strategy=[{"type":"stock","n":100,"action":"buy","prevpos":158.99},
{"type":"call","strike":185.0,"premium":4.1,"n":100,"action":"sell"}]

If you make this change and run the script again, the result will be:

Strategy cost: -15489.00
Stock price profitable range at maturity: 154.90 -> inf
Maximum profit: 3011.00
Probability of profit: 70.9%

It’s not surprising that the cost to construct this strategy ($15,489.00) is significantly lower. After all, you purchased the shares at a lower price of $158.99 per share, as indicated by the value of the “prevpos” key in the strategy definition. Also, the strategy is profitable even if the stock price at expiration drops to as low as $154.90 and the maximum profit is also much higher in this case ($3,011.00).

Finally, since the range of stock prices for which the strategy would be profitable has widened, the Probability of Profit (PoP) has also increased to almost 71%!

I leave it to you, the reader, as an exercise to determine what will happen to these numbers if you implement the third scenario, assuming that you purchased the stock when Nvidia was trading at $178.99.

As a bonus: what if we reversed the logic of the covered call? Let’s say — after careful market analysis — you have a feeling that Nvidia’s stock price will fall instead of rise. So, on January 16, 2023, you borrowed 100 shares of Nvidia and sold them at the current price of $168.99, hoping to repurchase these shares at a lower price and profit from the difference.

Quite often, predicitions about the market direction fail. This is to say that Nvidia’s stock price can skyrocket against your forecasts, resulting in a substantial loss for your position. One way to limit the loss in this scenario would be to buy calls that give you the right to repurchase Nvidia’s shares at a predefined price you would be willing to pay.

For this purpose, you decided to buy those same calls with a strike price of $185.00 expiring on February 17, 2023. Using the same Python code snippet, all that is needed is to define this strategy as follows:

strategy=[{"type":"stock","n":100,"action":"sell"},
{"type":"call","strike":185.0,"premium":4.1,"n":100,"action":"buy"}]

You may also want to change one of the print commands in the script to display not the maximum profit, but the maximul loss.

print("Maximum loss: %.2f" % (abs(out["MinimumReturnInTheDomain"])))

Then, you run the Python script and get the following output:

Strategy cost: 16489.00
Stock price profitable range at maturity: 0.00 -> 164.88
Maximum loss: 2011.00
Probability of profit: 45.1%

Obviously, in order to make a profit, the stock price has to decline, being at or less than $164.88 at the expiration of the call options. The fact that the strategy cost is positive means that you will receive that amount of money.

The P/L diagram of this “reversed” covered call strategy can be seen below. The blue right arrow indicates the position of the bought calls.

Profit/loss diagram of the “reversed” covered call.

OptionLab is provided as is, with no guarantee that its results are accurate. As such, I am not responsible for any losses caused by the use of the code. Bugs can be reported as issues on the project’s GitHub page. I am open to hearing any questions, corrections, comments or suggestions about the code. You can also reach me on Linkedin.

--

--

Roberto Gomes, PhD

I am a Professor of Materials Engineering specialized in computational research in materials science, physics, and engineering. Also interested in finance.