Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## 1.5.1 (2025-12-24)

- Added the calculation of the probability of an option ever getting ITM before expiration (see function `get_probability_of_touch` in black_scholes.py and the corresponding fields in models.py).
- Updated documentation.

## 1.5.0 (2025-12-14)

- Changed `get_pop` to compute the expected profit and expected loss of a strategy with the Black-Scholes model by calling a new function, `_compute_expected_returns_bs`.
Expand Down
46 changes: 29 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,37 @@
![OptionLab](optionlab.png)
![OptionLab](https://raw.githubusercontent.com/rgaveiga/optionlab/refs/heads/main/optionlab.png)

# OptionLab

This package is a lightweight library written entirely in Python, designed to provide
quick evaluation of option strategy ideas.
This package is a lightweight library designed to provide quick evaluation of options trading
strategies. It produces various outputs:

The code produces various outputs, including the profit/loss profile of the strategy on
a user-defined target date, the range of stock prices for which the strategy is
profitable (i.e., generating a return greater than \$0.01), the Greeks associated with
each leg of the strategy using the Black-Sholes model, the resulting debit or credit on the
trading account, the maximum and minimum returns within a specified lower and higher price
range of the underlying asset, and an estimate of the strategy's probability of profit.
- the profit/loss profile of the strategy on a user-defined target date

- the range of stock prices for which the strategy is profitable (i.e., generating a return of
at least \$0.01)

- the Greeks (delta, theta, rho, vega and gamma) associated with each leg of the strategy

- the resulting debit or credit on the trading account

- the maximum and minimum returns within a specified lower and higher price
range of the underlying asset

- The expected profit when the strategy is profitable and the expected loss if it proves unprofitable

- the strategy's probability of profit.

## Contact

If you have any questions, corrections, comments or suggestions, just
[drop a message](mailto:roberto.veiga@ufabc.edu.br).

You can also reach me on [Linkedin](https://www.linkedin.com/in/roberto-gomes-phd-8a718317b/) or
follow me on [X](https://x.com/rgaveiga). When I have some free time, which is rare, I publish articles
on [Medium](https://medium.com/@rgaveiga).
follow me on [X](https://x.com/rgaveiga).

If you want to support this and other open source projects that I maintain, become a
[sponsor on Github](https://github.com/sponsors/rgaveiga).
> [!NOTE]
> If you want to support this and other open source projects that I maintain, become a
>[sponsor on Github](https://github.com/sponsors/rgaveiga).

## Installation

Expand Down Expand Up @@ -48,8 +59,9 @@ This is free software and is provided as is. The author makes no guarantee that
results are accurate and is not responsible for any losses caused by the use of the
code.

Options are very risky derivatives and, like any other type of financial vehicle,
trading options requires due diligence. This code is provided for educational and
research purposes only.

Bugs can be reported as issues.

> [!CAUTION]
> Options are very risky derivatives and, like any other type of financial vehicle,
> trading options requires due diligence. This code is provided for educational and
> research purposes only.
2 changes: 1 addition & 1 deletion docs/optionlab.html
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ <h2 id="examples">Examples</h2>
</span><span id="L-155"><a href="#L-155"><span class="linenos">155</span></a><span class="kn">from</span> <span class="nn">.utils</span> <span class="kn">import</span> <span class="n">get_pl</span><span class="p">,</span> <span class="n">pl_to_csv</span>
</span><span id="L-156"><a href="#L-156"><span class="linenos">156</span></a>
</span><span id="L-157"><a href="#L-157"><span class="linenos">157</span></a><span class="n">__docformat__</span> <span class="o">=</span> <span class="s2">&quot;markdown&quot;</span>
</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&quot;1.5.0&quot;</span>
</span><span id="L-158"><a href="#L-158"><span class="linenos">158</span></a><span class="n">__version__</span> <span class="o">=</span> <span class="s2">&quot;1.5.1&quot;</span>
</span></pre></div>


Expand Down
1,621 changes: 908 additions & 713 deletions docs/optionlab/black_scholes.html

Large diffs are not rendered by default.

450 changes: 228 additions & 222 deletions docs/optionlab/engine.html

Large diffs are not rendered by default.

871 changes: 471 additions & 400 deletions docs/optionlab/models.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/search.js

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions examples/black_scholes_calculator.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"output_type": "stream",
"text": [
"Python version: 3.11.9 | packaged by Anaconda, Inc. | (main, Apr 19 2024, 16:40:41) [MSC v.1916 64 bit (AMD64)]\n",
"OptionLab version: 1.5.0\n"
"OptionLab version: 1.5.1\n"
]
}
],
Expand Down Expand Up @@ -106,8 +106,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: total: 15.6 ms\n",
"Wall time: 7.02 ms\n"
"CPU times: total: 0 ns\n",
"Wall time: 0 ns\n"
]
}
],
Expand Down Expand Up @@ -152,6 +152,7 @@
" Theta: -8.78\n",
" Rho: 0.05\n",
" ITM probability: 26.70\n",
" Probability of touch: 54.04\n",
"\n",
"\n",
"PUT\n",
Expand All @@ -161,6 +162,7 @@
" Theta: -7.73\n",
" Rho: -0.13\n",
" ITM probability: 73.30\n",
" Probability of touch: 100.00\n",
"\n",
"\n",
"Gamma and Vega: 0.0425 \n",
Expand All @@ -176,6 +178,7 @@
"print(f\" Theta: {bs.call_theta:.2f}\")\n",
"print(f\" Rho: {bs.call_rho: .2f}\")\n",
"print(f\" ITM probability: {bs.call_itm_prob * 100.0:.2f}\")\n",
"print(f\" Probability of touch: {bs.call_prob_of_touch * 100.0:.2f}\")\n",
"print(\"\\n\")\n",
"print(\"PUT\")\n",
"print(\"===\")\n",
Expand All @@ -184,6 +187,7 @@
"print(f\" Theta: {bs.put_theta:.2f}\")\n",
"print(f\" Rho: {bs.put_rho: .2f}\")\n",
"print(f\" ITM probability: {bs.put_itm_prob * 100.0:.2f}\")\n",
"print(f\" Probability of touch: {bs.put_prob_of_touch * 100.0:.2f}\")\n",
"print(\"\\n\")\n",
"print(f\"Gamma and Vega: {bs.gamma:.4f} \\n {bs.vega:.2f}\")"
]
Expand Down
9 changes: 5 additions & 4 deletions examples/calendar_spread.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"output_type": "stream",
"text": [
"Python version: 3.11.9 | packaged by Anaconda, Inc. | (main, Apr 19 2024, 16:40:41) [MSC v.1916 64 bit (AMD64)]\n",
"OptionLab version: 1.5.0\n"
"OptionLab version: 1.5.1\n"
]
}
],
Expand Down Expand Up @@ -120,7 +120,7 @@
"output_type": "stream",
"text": [
"CPU times: total: 297 ms\n",
"Wall time: 367 ms\n"
"Wall time: 450 ms\n"
]
}
],
Expand Down Expand Up @@ -179,14 +179,15 @@
"text": [
"Probability of profit: 0.599111819020198\n",
"Profit ranges: [(118.87, 136.15)]\n",
"Expected profit: 1383.2\n",
"Expected loss: -691.09\n",
"Expected profit if profitable: 1383.2\n",
"Expected loss if unprofitable: -691.09\n",
"Per leg cost: [4600.0, -5900.0]\n",
"Strategy cost: -1300.0\n",
"Minimum return in the domain: -1300.0000000000146\n",
"Maximum return in the domain: 3009.999999999999\n",
"Implied volatility: [0.47300000000000003, 0.419]\n",
"In the money probability: [0.4895105709759477, 0.4805997906939539]\n",
"Probability of touch: [1.0, 1.0]\n",
"Delta: [-0.5216914758915705, 0.5273457614638198]\n",
"Gamma: [0.03882722919950356, 0.02669940508461828]\n",
"Theta: [0.22727438444823292, -0.15634971608107964]\n",
Expand Down
78 changes: 42 additions & 36 deletions examples/call_spread.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: total: 1min 25s\n",
"Wall time: 1min 29s\n"
"CPU times: total: 2min 41s\n",
"Wall time: 2min 51s\n"
]
}
],
Expand Down Expand Up @@ -243,25 +243,28 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Strategy cost: -15995.00\n",
"Maximum loss: 15995.00\n",
"Maximum profit: 5.00\n",
"Profitable stock price range:\n",
" 304.96 ---> inf\n",
"Probability of Profit (PoP): 99.1\n"
"Probability of profit: 0.9906981384518034\n",
"Profit ranges: [(304.96, inf)]\n",
"Expected profit if profitable: 5.0\n",
"Expected loss if unprofitable: -499.07\n",
"Per leg cost: [-19805.0, 3810.0]\n",
"Strategy cost: -15995.0\n",
"Minimum return in the domain: -15995.0\n",
"Maximum return in the domain: 5.0\n",
"Implied volatility: [0.999, 0.2]\n",
"In the money probability: [1.0, 0.9906315405574139]\n",
"Probability of touch: [1.0, 1.0]\n",
"Delta: [1.0, -0.9918058094935618]\n",
"Gamma: [1.951791997745016e-68, 0.00132062967266379]\n",
"Theta: [-0.0005753534439382797, 0.011185261446659761]\n",
"Vega: [3.1158128584143207e-67, 0.02108234340566703]\n",
"Rho: [0.10931715434827315, -0.22778876835532164]\n",
"\n"
]
}
],
"source": [
"print(f\"Strategy cost: {out.strategy_cost:.2f}\")\n",
"print(f\"Maximum loss: {abs(out.minimum_return_in_the_domain):.2f}\")\n",
"print(f\"Maximum profit: {out.maximum_return_in_the_domain:.2f}\")\n",
"print(\"Profitable stock price range:\")\n",
"\n",
"for low, high in out.profit_ranges:\n",
" print(f\" {low:.2f} ---> {high:.2f}\")\n",
"\n",
"print(f\"Probability of Profit (PoP): {out.probability_of_profit * 100.0:.1f}\")"
"print(out)"
]
},
{
Expand All @@ -277,7 +280,7 @@
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x21b4b9b8250>]"
"[<matplotlib.lines.Line2D at 0x222784d3890>]"
]
},
"execution_count": 12,
Expand Down Expand Up @@ -391,8 +394,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: total: 1min 26s\n",
"Wall time: 1min 31s\n"
"CPU times: total: 2min 34s\n",
"Wall time: 2min 46s\n"
]
}
],
Expand Down Expand Up @@ -462,25 +465,28 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Strategy cost: -8293.00\n",
"Maximum loss: 8293.00\n",
"Maximum profit: 8707.00\n",
"Profitable stock price range:\n",
" 342.94 ---> inf\n",
"Probability of Profit (PoP): 49.1\n"
"Probability of profit: 0.4914563792806722\n",
"Profit ranges: [(342.94, inf)]\n",
"Expected profit if profitable: 1381.92\n",
"Expected loss if unprofitable: -1323.79\n",
"Per leg cost: [-8300.0, 7.000000000000001]\n",
"Strategy cost: -8293.0\n",
"Minimum return in the domain: -8293.0\n",
"Maximum return in the domain: 8707.000000000002\n",
"Implied volatility: [0.319, 0.327]\n",
"In the money probability: [0.9999999880052545, 2.126445370979977e-06]\n",
"Probability of touch: [1.0, 4.272550589235243e-06]\n",
"Delta: [0.9999999909830838, -2.6925191836574867e-06]\n",
"Gamma: [3.083980302091833e-09, 7.547374646336367e-07]\n",
"Theta: [-0.0010316915524542186, 5.710822366452319e-06]\n",
"Vega: [4.923222091009698e-08, 1.2048521050139721e-05]\n",
"Rho: [0.1960169640664196, -6.893551133656091e-07]\n",
"\n"
]
}
],
"source": [
"print(f\"Strategy cost: {out.strategy_cost:.2f}\")\n",
"print(f\"Maximum loss: {abs(out.minimum_return_in_the_domain):.2f}\")\n",
"print(f\"Maximum profit: {out.maximum_return_in_the_domain:.2f}\")\n",
"print(\"Profitable stock price range:\")\n",
"\n",
"for low, high in out.profit_ranges:\n",
" print(f\" {low:.2f} ---> {high:.2f}\")\n",
"\n",
"print(f\"Probability of Profit (PoP): {out.probability_of_profit * 100.0:.1f}\")"
"print(out)"
]
},
{
Expand All @@ -496,7 +502,7 @@
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x21b4b9b1590>]"
"[<matplotlib.lines.Line2D at 0x2227fa87a10>]"
]
},
"execution_count": 15,
Expand Down
13 changes: 7 additions & 6 deletions examples/covered_call.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"output_type": "stream",
"text": [
"Python version: 3.11.9 | packaged by Anaconda, Inc. | (main, Apr 19 2024, 16:40:41) [MSC v.1916 64 bit (AMD64)]\n",
"OptionLab version: 1.5.0\n"
"OptionLab version: 1.5.1\n"
]
}
],
Expand Down Expand Up @@ -119,8 +119,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: total: 234 ms\n",
"Wall time: 293 ms\n"
"CPU times: total: 297 ms\n",
"Wall time: 341 ms\n"
]
}
],
Expand All @@ -142,7 +142,7 @@
{
"data": {
"text/plain": [
"<matplotlib.legend.Legend at 0x1909fae4910>"
"<matplotlib.legend.Legend at 0x21d8b7fc910>"
]
},
"execution_count": 5,
Expand Down Expand Up @@ -195,14 +195,15 @@
"text": [
"Probability of profit: 0.522421406650333\n",
"Profit ranges: [(162.9, inf)]\n",
"Expected profit: 787.24\n",
"Expected loss: -904.12\n",
"Expected profit if profitable: 787.24\n",
"Expected loss if unprofitable: -904.12\n",
"Per leg cost: [-16404.0, 114.99999999999999]\n",
"Strategy cost: -16289.0\n",
"Minimum return in the domain: -8087.0\n",
"Maximum return in the domain: 1211.0000000000018\n",
"Implied volatility: [0.0, 0.256]\n",
"In the money probability: [1.0, 0.1832371984432129]\n",
"Probability of touch: [1.0, 0.3741546603689868]\n",
"Delta: [1.0, -0.20371918274704337]\n",
"Gamma: [0.0, 0.023104402361599465]\n",
"Theta: [0.0, 0.091289876347897]\n",
Expand Down
15 changes: 8 additions & 7 deletions examples/naked_call.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@
"output_type": "stream",
"text": [
"Python version: 3.11.9 | packaged by Anaconda, Inc. | (main, Apr 19 2024, 16:40:41) [MSC v.1916 64 bit (AMD64)]\n",
"OptionLab version: 1.5.0\n"
"OptionLab version: 1.5.1\n"
]
}
],
"source": [
"print(\"Python version: %s\" % sys.version)\n",
"print(\"OptionLab version: %s\" % __version__)"
"print(f\"Python version: {sys.version}\")\n",
"print(f\"OptionLab version: {__version__}\")"
]
},
{
Expand Down Expand Up @@ -116,8 +116,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: total: 141 ms\n",
"Wall time: 262 ms\n"
"CPU times: total: 312 ms\n",
"Wall time: 442 ms\n"
]
}
],
Expand Down Expand Up @@ -176,14 +176,15 @@
"text": [
"Probability of profit: 0.8389215512144531\n",
"Profit ranges: [(0.0, 176.14)]\n",
"Expected profit: 113.49\n",
"Expected loss: -717.5\n",
"Expected profit if profitable: 113.49\n",
"Expected loss if unprofitable: -717.5\n",
"Per leg cost: [114.99999999999999]\n",
"Strategy cost: 114.99999999999999\n",
"Minimum return in the domain: -6991.999999999999\n",
"Maximum return in the domain: 114.99999999999999\n",
"Implied volatility: [0.256]\n",
"In the money probability: [0.1832371984432129]\n",
"Probability of touch: [0.3741546603689868]\n",
"Delta: [-0.20371918274704337]\n",
"Gamma: [0.023104402361599465]\n",
"Theta: [0.091289876347897]\n",
Expand Down
2 changes: 1 addition & 1 deletion optionlab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,4 @@
from .utils import get_pl, pl_to_csv

__docformat__ = "markdown"
__version__ = "1.5.0"
__version__ = "1.5.1"
Loading