option_lab 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +139 -0
  4. data/.yard/hooks/before_generate.rb +7 -0
  5. data/.yardopts +11 -0
  6. data/Gemfile +26 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +180 -0
  9. data/Rakefile +44 -0
  10. data/docs/OptionLab/BinomialTree.html +1271 -0
  11. data/docs/OptionLab/BjerksundStensland.html +2022 -0
  12. data/docs/OptionLab/BlackScholes.html +2388 -0
  13. data/docs/OptionLab/Engine.html +1716 -0
  14. data/docs/OptionLab/Models/AmericanModelInputs.html +937 -0
  15. data/docs/OptionLab/Models/ArrayInputs.html +463 -0
  16. data/docs/OptionLab/Models/BaseModel.html +223 -0
  17. data/docs/OptionLab/Models/BinomialModelInputs.html +1161 -0
  18. data/docs/OptionLab/Models/BlackScholesInfo.html +967 -0
  19. data/docs/OptionLab/Models/BlackScholesModelInputs.html +851 -0
  20. data/docs/OptionLab/Models/ClosedPosition.html +445 -0
  21. data/docs/OptionLab/Models/EngineData.html +2523 -0
  22. data/docs/OptionLab/Models/EngineDataResults.html +435 -0
  23. data/docs/OptionLab/Models/Inputs.html +2241 -0
  24. data/docs/OptionLab/Models/LaplaceInputs.html +777 -0
  25. data/docs/OptionLab/Models/Option.html +736 -0
  26. data/docs/OptionLab/Models/Outputs.html +1753 -0
  27. data/docs/OptionLab/Models/PoPOutputs.html +645 -0
  28. data/docs/OptionLab/Models/PricingResult.html +848 -0
  29. data/docs/OptionLab/Models/Stock.html +583 -0
  30. data/docs/OptionLab/Models/TreeVisualization.html +688 -0
  31. data/docs/OptionLab/Models.html +251 -0
  32. data/docs/OptionLab/Plotting.html +548 -0
  33. data/docs/OptionLab/Support.html +2884 -0
  34. data/docs/OptionLab/Utils.html +619 -0
  35. data/docs/OptionLab.html +133 -0
  36. data/docs/_index.html +376 -0
  37. data/docs/class_list.html +54 -0
  38. data/docs/css/common.css +1 -0
  39. data/docs/css/full_list.css +58 -0
  40. data/docs/css/style.css +503 -0
  41. data/docs/file.LICENSE.html +70 -0
  42. data/docs/file.README.html +263 -0
  43. data/docs/file_list.html +64 -0
  44. data/docs/frames.html +22 -0
  45. data/docs/index.html +263 -0
  46. data/docs/js/app.js +344 -0
  47. data/docs/js/full_list.js +242 -0
  48. data/docs/js/jquery.js +4 -0
  49. data/docs/method_list.html +1974 -0
  50. data/docs/top-level-namespace.html +110 -0
  51. data/examples/american_options.rb +163 -0
  52. data/examples/covered_call.rb +76 -0
  53. data/lib/option_lab/binomial_tree.rb +238 -0
  54. data/lib/option_lab/bjerksund_stensland.rb +276 -0
  55. data/lib/option_lab/black_scholes.rb +323 -0
  56. data/lib/option_lab/engine.rb +492 -0
  57. data/lib/option_lab/models.rb +768 -0
  58. data/lib/option_lab/plotting.rb +182 -0
  59. data/lib/option_lab/support.rb +471 -0
  60. data/lib/option_lab/utils.rb +107 -0
  61. data/lib/option_lab/version.rb +5 -0
  62. data/lib/option_lab.rb +134 -0
  63. data/option_lab.gemspec +43 -0
  64. metadata +207 -0
@@ -0,0 +1,263 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; OptionLab Documentation
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" />
16
+
17
+ <script type="text/javascript">
18
+ pathId = "README";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="file_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: README</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'><h1 id="optionlab">OptionLab</h1>
61
+
62
+ <p>OptionLab is a lightweight Ruby library designed to provide quick evaluation of options trading strategies.
63
+ It aims to be a direct port of the popular Python library - <a href="https://github.com/rgaveiga/optionlab">OptionLab</a></p>
64
+
65
+ <p><a href="https://xjackk.github.io/option_lab/"><img src="https://img.shields.io/badge/docs-YARD-blue.svg" alt="Documentation"></a></p>
66
+
67
+ <h2 id="features">Features</h2>
68
+
69
+ <ul>
70
+ <li>Calculate profit/loss profiles for options strategies</li>
71
+ <li>Estimate probability of profit using Black-Scholes or custom models</li>
72
+ <li>Calculate option Greeks (Delta, Gamma, Theta, Vega, Rho)</li>
73
+ <li>Generate profit/loss diagrams</li>
74
+ <li>Support for complex multi-leg strategies</li>
75
+ <li>Handle stock positions and previously closed trades</li>
76
+ <li>Support for different dividend yield and interest rate scenarios</li>
77
+ <li>Business day calculations across different countries</li>
78
+ </ul>
79
+
80
+ <h2 id="installation">Installation</h2>
81
+
82
+ <p>Add this line to your application&#39;s Gemfile:</p>
83
+
84
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>option_lab</span><span class='tstring_end'>&#39;</span></span>
85
+ </code></pre>
86
+
87
+ <p>And then execute:</p>
88
+
89
+ <pre class="code ruby"><code class="ruby">$ bundle install
90
+ </code></pre>
91
+
92
+ <p>Or install it yourself as:</p>
93
+
94
+ <pre class="code ruby"><code class="ruby">$ gem install option_lab
95
+ </code></pre>
96
+
97
+ <h2 id="requirements">Requirements</h2>
98
+
99
+ <p>OptionLab requires:</p>
100
+
101
+ <ul>
102
+ <li>Ruby 3.3.0 or higher</li>
103
+ <li>numo-narray gem for numerical computations</li>
104
+ <li>distribution gem for statistical calculations</li>
105
+ <li>gnuplot gem for visualization</li>
106
+ </ul>
107
+
108
+ <h2 id="basic-usage">Basic Usage</h2>
109
+
110
+ <p>The evaluation of a strategy is done by calling the <code>run_strategy</code> method provided by the library. This method receives the input data as a Ruby hash or an <code>Inputs</code> object.</p>
111
+
112
+ <p>Here&#39;s an example of evaluating a naked call strategy:</p>
113
+
114
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>option_lab</span><span class='tstring_end'>&#39;</span></span>
115
+
116
+ <span class='comment'># Define the strategy
117
+ </span><span class='id identifier rubyid_input_data'>input_data</span> <span class='op'>=</span> <span class='lbrace'>{</span>
118
+ <span class='label'>stock_price:</span> <span class='float'>164.04</span><span class='comma'>,</span>
119
+ <span class='label'>start_date:</span> <span class='const'>Date</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='int'>2023</span><span class='comma'>,</span> <span class='int'>11</span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span><span class='comma'>,</span>
120
+ <span class='label'>target_date:</span> <span class='const'>Date</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='int'>2023</span><span class='comma'>,</span> <span class='int'>12</span><span class='comma'>,</span> <span class='int'>17</span><span class='rparen'>)</span><span class='comma'>,</span>
121
+ <span class='label'>volatility:</span> <span class='float'>0.272</span><span class='comma'>,</span>
122
+ <span class='label'>interest_rate:</span> <span class='float'>0.0002</span><span class='comma'>,</span>
123
+ <span class='label'>min_stock:</span> <span class='int'>120</span><span class='comma'>,</span>
124
+ <span class='label'>max_stock:</span> <span class='int'>200</span><span class='comma'>,</span>
125
+ <span class='label'>strategy:</span> <span class='lbracket'>[</span>
126
+ <span class='lbrace'>{</span>
127
+ <span class='label'>type:</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>call</span><span class='tstring_end'>&quot;</span></span><span class='comma'>,</span>
128
+ <span class='label'>strike:</span> <span class='float'>175.0</span><span class='comma'>,</span>
129
+ <span class='label'>premium:</span> <span class='float'>1.15</span><span class='comma'>,</span>
130
+ <span class='label'>n:</span> <span class='int'>100</span><span class='comma'>,</span>
131
+ <span class='label'>action:</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>sell</span><span class='tstring_end'>&quot;</span></span>
132
+ <span class='rbrace'>}</span>
133
+ <span class='rbracket'>]</span>
134
+ <span class='rbrace'>}</span>
135
+
136
+ <span class='comment'># Run the strategy calculation
137
+ </span><span class='id identifier rubyid_outputs'>outputs</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="OptionLab.html" title="OptionLab (module)">OptionLab</a></span></span><span class='period'>.</span><span class='id identifier rubyid_run_strategy'>run_strategy</span><span class='lparen'>(</span><span class='id identifier rubyid_input_data'>input_data</span><span class='rparen'>)</span>
138
+
139
+ <span class='comment'># Export P/L data to CSV
140
+ </span><span class='const'><span class='object_link'><a href="OptionLab.html" title="OptionLab (module)">OptionLab</a></span></span><span class='period'>.</span><span class='id identifier rubyid_pl_to_csv'>pl_to_csv</span><span class='lparen'>(</span><span class='id identifier rubyid_outputs'>outputs</span><span class='comma'>,</span> <span class='label'>filename:</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>covered_call_pl.csv</span><span class='tstring_end'>&quot;</span></span><span class='rparen'>)</span>
141
+ </code></pre>
142
+
143
+ <h2 id="analyzing-results">Analyzing Results</h2>
144
+
145
+ <p>The <code>Outputs</code> object returned by <code>run_strategy</code> contains a wealth of information:</p>
146
+
147
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Key probability metrics
148
+ </span><span class='id identifier rubyid_probability_of_profit'>probability_of_profit</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_probability_of_profit'>probability_of_profit</span>
149
+ <span class='id identifier rubyid_profit_ranges'>profit_ranges</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_profit_ranges'>profit_ranges</span>
150
+ <span class='id identifier rubyid_expected_profit'>expected_profit</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_expected_profit'>expected_profit</span>
151
+ <span class='id identifier rubyid_expected_loss'>expected_loss</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_expected_loss'>expected_loss</span>
152
+
153
+ <span class='comment'># Strategy costs
154
+ </span><span class='id identifier rubyid_strategy_cost'>strategy_cost</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_strategy_cost'>strategy_cost</span>
155
+ <span class='id identifier rubyid_per_leg_cost'>per_leg_cost</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_per_leg_cost'>per_leg_cost</span>
156
+
157
+ <span class='comment'># Returns
158
+ </span><span class='id identifier rubyid_min_return'>min_return</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_minimum_return_in_the_domain'>minimum_return_in_the_domain</span>
159
+ <span class='id identifier rubyid_max_return'>max_return</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_maximum_return_in_the_domain'>maximum_return_in_the_domain</span>
160
+
161
+ <span class='comment'># Option Greeks
162
+ </span><span class='id identifier rubyid_delta'>delta</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_delta'>delta</span>
163
+ <span class='id identifier rubyid_gamma'>gamma</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_gamma'>gamma</span>
164
+ <span class='id identifier rubyid_theta'>theta</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_theta'>theta</span>
165
+ <span class='id identifier rubyid_vega'>vega</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_vega'>vega</span>
166
+ <span class='id identifier rubyid_rho'>rho</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_rho'>rho</span>
167
+
168
+ <span class='comment'># Print all metrics
169
+ </span><span class='id identifier rubyid_puts'>puts</span> <span class='id identifier rubyid_outputs'>outputs</span>
170
+ </code></pre>
171
+
172
+ <h2 id="contributing">Contributing</h2>
173
+
174
+ <ol>
175
+ <li>Fork it</li>
176
+ <li>Create your feature branch (<code>git checkout -b my-new-feature</code>)</li>
177
+ <li>Commit your changes (<code>git commit -am &#39;Add some feature&#39;</code>)</li>
178
+ <li>Push to the branch (<code>git push origin my-new-feature</code>)</li>
179
+ <li>Create a new Pull Request</li>
180
+ </ol>
181
+
182
+ <h2 id="license">License</h2>
183
+
184
+ <p>The gem is available as open source under the terms of the <a href="https://opensource.org/licenses/MIT">MIT License</a>.</p>
185
+
186
+ <h2 id="disclaimer">Disclaimer</h2>
187
+
188
+ <p>This is free software and is provided as is. The author makes no guarantee that its results are accurate and is not responsible for any losses caused by the use of the code.</p>
189
+
190
+ <p>Options are 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.</p>
191
+
192
+ <h1 id="print-the-results">Print the results</h1>
193
+
194
+ <p>puts outputs</p>
195
+
196
+ <h1 id="plot-the-profit-loss-diagram">Plot the profit/loss diagram</h1>
197
+
198
+ <p>OptionLab.plot_pl(outputs)</p>
199
+
200
+ <pre class="code ruby"><code class="ruby">
201
+ ## Common Strategies
202
+
203
+ OptionLab supports all standard options strategies, including:
204
+
205
+ - Covered calls
206
+ - Naked puts
207
+ - Bull/bear spreads
208
+ - Straddles/strangles
209
+ - Iron condors
210
+ - Butterflies
211
+ - Calendar spreads
212
+ - And more...
213
+
214
+ ## Advanced Usage
215
+
216
+ The library also allows for more advanced use cases, such as:
217
+
218
+ ```ruby
219
+ # Create a custom distribution model
220
+ bs_inputs = OptionLab::Models::BlackScholesModelInputs.new(
221
+ stock_price: 168.99,
222
+ volatility: 0.483,
223
+ interest_rate: 0.045,
224
+ years_to_target_date: 24.0 / 365
225
+ )
226
+
227
+ # Generate price array with 10,000 samples
228
+ prices = OptionLab.create_price_array(bs_inputs, n: 10_000, seed: 42)
229
+
230
+ # Run a strategy with the custom price array
231
+ input_data = {
232
+ stock_price: 168.99,
233
+ volatility: 0.483,
234
+ interest_rate: 0.045,
235
+ min_stock: 120,
236
+ max_stock: 200,
237
+ model: &quot;array&quot;,
238
+ array: prices,
239
+ strategy: [
240
+ { type: &quot;stock&quot;, n: 100, action: &quot;buy&quot; },
241
+ {
242
+ type: &quot;call&quot;,
243
+ strike: 185.0,
244
+ premium: 4.1,
245
+ n: 100,
246
+ action: &quot;sell&quot;
247
+ }
248
+ ]
249
+ }
250
+
251
+ outputs = OptionLab.run_strategy(input_data)
252
+ </code></pre>
253
+ </div></div>
254
+
255
+ <div id="footer">
256
+ Generated on Sun Apr 27 16:09:33 2025 by
257
+ <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
258
+ 0.9.37 (ruby-3.3.3).
259
+ </div>
260
+
261
+ </div>
262
+ </body>
263
+ </html>
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html>
2
+ <html >
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+ <meta charset="utf-8" />
6
+
7
+ <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" />
8
+
9
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" />
10
+
11
+
12
+
13
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
16
+
17
+
18
+ <title>File List</title>
19
+ <base id="base_target" target="_parent" />
20
+ </head>
21
+ <body>
22
+ <div id="content">
23
+ <div class="fixed_header">
24
+ <h1 id="full_list_header">File List</h1>
25
+ <div id="full_list_nav">
26
+
27
+ <span><a target="_self" href="class_list.html">
28
+ Classes
29
+ </a></span>
30
+
31
+ <span><a target="_self" href="method_list.html">
32
+ Methods
33
+ </a></span>
34
+
35
+ <span><a target="_self" href="file_list.html">
36
+ Files
37
+ </a></span>
38
+
39
+ </div>
40
+
41
+ <div id="search">
42
+ <label for="search-class">Search:</label>
43
+ <input id="search-class" type="text" />
44
+ </div>
45
+ </div>
46
+
47
+ <ul id="full_list" class="file">
48
+
49
+
50
+ <li id="object_README" class="odd">
51
+ <div class="item"><span class="object_link"><a href="index.html" title="README">README</a></span></div>
52
+ </li>
53
+
54
+
55
+ <li id="object_LICENSE" class="even">
56
+ <div class="item"><span class="object_link"><a href="file.LICENSE.html" title="LICENSE">LICENSE</a></span></div>
57
+ </li>
58
+
59
+
60
+
61
+ </ul>
62
+ </div>
63
+ </body>
64
+ </html>
data/docs/frames.html ADDED
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>OptionLab Documentation</title>
6
+ </head>
7
+ <script type="text/javascript">
8
+ var mainUrl = 'index.html';
9
+ try {
10
+ var match = decodeURIComponent(window.location.hash).match(/^#!(.+)/);
11
+ var name = match ? match[1] : mainUrl;
12
+ var url = new URL(name, location.href);
13
+ window.top.location.replace(url.origin === location.origin ? name : mainUrl);
14
+ } catch (e) {
15
+ window.top.location.replace(mainUrl);
16
+ }
17
+ </script>
18
+ <noscript>
19
+ <h1>Oops!</h1>
20
+ <h2>YARD requires JavaScript!</h2>
21
+ </noscript>
22
+ </html>
data/docs/index.html ADDED
@@ -0,0 +1,263 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; OptionLab Documentation
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" />
16
+
17
+ <script type="text/javascript">
18
+ pathId = "README";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="class_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: README</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'><h1 id="optionlab">OptionLab</h1>
61
+
62
+ <p>OptionLab is a lightweight Ruby library designed to provide quick evaluation of options trading strategies.
63
+ It aims to be a direct port of the popular Python library - <a href="https://github.com/rgaveiga/optionlab">OptionLab</a></p>
64
+
65
+ <p><a href="https://xjackk.github.io/option_lab/"><img src="https://img.shields.io/badge/docs-YARD-blue.svg" alt="Documentation"></a></p>
66
+
67
+ <h2 id="features">Features</h2>
68
+
69
+ <ul>
70
+ <li>Calculate profit/loss profiles for options strategies</li>
71
+ <li>Estimate probability of profit using Black-Scholes or custom models</li>
72
+ <li>Calculate option Greeks (Delta, Gamma, Theta, Vega, Rho)</li>
73
+ <li>Generate profit/loss diagrams</li>
74
+ <li>Support for complex multi-leg strategies</li>
75
+ <li>Handle stock positions and previously closed trades</li>
76
+ <li>Support for different dividend yield and interest rate scenarios</li>
77
+ <li>Business day calculations across different countries</li>
78
+ </ul>
79
+
80
+ <h2 id="installation">Installation</h2>
81
+
82
+ <p>Add this line to your application&#39;s Gemfile:</p>
83
+
84
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>option_lab</span><span class='tstring_end'>&#39;</span></span>
85
+ </code></pre>
86
+
87
+ <p>And then execute:</p>
88
+
89
+ <pre class="code ruby"><code class="ruby">$ bundle install
90
+ </code></pre>
91
+
92
+ <p>Or install it yourself as:</p>
93
+
94
+ <pre class="code ruby"><code class="ruby">$ gem install option_lab
95
+ </code></pre>
96
+
97
+ <h2 id="requirements">Requirements</h2>
98
+
99
+ <p>OptionLab requires:</p>
100
+
101
+ <ul>
102
+ <li>Ruby 3.3.0 or higher</li>
103
+ <li>numo-narray gem for numerical computations</li>
104
+ <li>distribution gem for statistical calculations</li>
105
+ <li>gnuplot gem for visualization</li>
106
+ </ul>
107
+
108
+ <h2 id="basic-usage">Basic Usage</h2>
109
+
110
+ <p>The evaluation of a strategy is done by calling the <code>run_strategy</code> method provided by the library. This method receives the input data as a Ruby hash or an <code>Inputs</code> object.</p>
111
+
112
+ <p>Here&#39;s an example of evaluating a naked call strategy:</p>
113
+
114
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_require'>require</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>option_lab</span><span class='tstring_end'>&#39;</span></span>
115
+
116
+ <span class='comment'># Define the strategy
117
+ </span><span class='id identifier rubyid_input_data'>input_data</span> <span class='op'>=</span> <span class='lbrace'>{</span>
118
+ <span class='label'>stock_price:</span> <span class='float'>164.04</span><span class='comma'>,</span>
119
+ <span class='label'>start_date:</span> <span class='const'>Date</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='int'>2023</span><span class='comma'>,</span> <span class='int'>11</span><span class='comma'>,</span> <span class='int'>22</span><span class='rparen'>)</span><span class='comma'>,</span>
120
+ <span class='label'>target_date:</span> <span class='const'>Date</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='int'>2023</span><span class='comma'>,</span> <span class='int'>12</span><span class='comma'>,</span> <span class='int'>17</span><span class='rparen'>)</span><span class='comma'>,</span>
121
+ <span class='label'>volatility:</span> <span class='float'>0.272</span><span class='comma'>,</span>
122
+ <span class='label'>interest_rate:</span> <span class='float'>0.0002</span><span class='comma'>,</span>
123
+ <span class='label'>min_stock:</span> <span class='int'>120</span><span class='comma'>,</span>
124
+ <span class='label'>max_stock:</span> <span class='int'>200</span><span class='comma'>,</span>
125
+ <span class='label'>strategy:</span> <span class='lbracket'>[</span>
126
+ <span class='lbrace'>{</span>
127
+ <span class='label'>type:</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>call</span><span class='tstring_end'>&quot;</span></span><span class='comma'>,</span>
128
+ <span class='label'>strike:</span> <span class='float'>175.0</span><span class='comma'>,</span>
129
+ <span class='label'>premium:</span> <span class='float'>1.15</span><span class='comma'>,</span>
130
+ <span class='label'>n:</span> <span class='int'>100</span><span class='comma'>,</span>
131
+ <span class='label'>action:</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>sell</span><span class='tstring_end'>&quot;</span></span>
132
+ <span class='rbrace'>}</span>
133
+ <span class='rbracket'>]</span>
134
+ <span class='rbrace'>}</span>
135
+
136
+ <span class='comment'># Run the strategy calculation
137
+ </span><span class='id identifier rubyid_outputs'>outputs</span> <span class='op'>=</span> <span class='const'><span class='object_link'><a href="OptionLab.html" title="OptionLab (module)">OptionLab</a></span></span><span class='period'>.</span><span class='id identifier rubyid_run_strategy'>run_strategy</span><span class='lparen'>(</span><span class='id identifier rubyid_input_data'>input_data</span><span class='rparen'>)</span>
138
+
139
+ <span class='comment'># Export P/L data to CSV
140
+ </span><span class='const'><span class='object_link'><a href="OptionLab.html" title="OptionLab (module)">OptionLab</a></span></span><span class='period'>.</span><span class='id identifier rubyid_pl_to_csv'>pl_to_csv</span><span class='lparen'>(</span><span class='id identifier rubyid_outputs'>outputs</span><span class='comma'>,</span> <span class='label'>filename:</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>covered_call_pl.csv</span><span class='tstring_end'>&quot;</span></span><span class='rparen'>)</span>
141
+ </code></pre>
142
+
143
+ <h2 id="analyzing-results">Analyzing Results</h2>
144
+
145
+ <p>The <code>Outputs</code> object returned by <code>run_strategy</code> contains a wealth of information:</p>
146
+
147
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Key probability metrics
148
+ </span><span class='id identifier rubyid_probability_of_profit'>probability_of_profit</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_probability_of_profit'>probability_of_profit</span>
149
+ <span class='id identifier rubyid_profit_ranges'>profit_ranges</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_profit_ranges'>profit_ranges</span>
150
+ <span class='id identifier rubyid_expected_profit'>expected_profit</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_expected_profit'>expected_profit</span>
151
+ <span class='id identifier rubyid_expected_loss'>expected_loss</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_expected_loss'>expected_loss</span>
152
+
153
+ <span class='comment'># Strategy costs
154
+ </span><span class='id identifier rubyid_strategy_cost'>strategy_cost</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_strategy_cost'>strategy_cost</span>
155
+ <span class='id identifier rubyid_per_leg_cost'>per_leg_cost</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_per_leg_cost'>per_leg_cost</span>
156
+
157
+ <span class='comment'># Returns
158
+ </span><span class='id identifier rubyid_min_return'>min_return</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_minimum_return_in_the_domain'>minimum_return_in_the_domain</span>
159
+ <span class='id identifier rubyid_max_return'>max_return</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_maximum_return_in_the_domain'>maximum_return_in_the_domain</span>
160
+
161
+ <span class='comment'># Option Greeks
162
+ </span><span class='id identifier rubyid_delta'>delta</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_delta'>delta</span>
163
+ <span class='id identifier rubyid_gamma'>gamma</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_gamma'>gamma</span>
164
+ <span class='id identifier rubyid_theta'>theta</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_theta'>theta</span>
165
+ <span class='id identifier rubyid_vega'>vega</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_vega'>vega</span>
166
+ <span class='id identifier rubyid_rho'>rho</span> <span class='op'>=</span> <span class='id identifier rubyid_outputs'>outputs</span><span class='period'>.</span><span class='id identifier rubyid_rho'>rho</span>
167
+
168
+ <span class='comment'># Print all metrics
169
+ </span><span class='id identifier rubyid_puts'>puts</span> <span class='id identifier rubyid_outputs'>outputs</span>
170
+ </code></pre>
171
+
172
+ <h2 id="contributing">Contributing</h2>
173
+
174
+ <ol>
175
+ <li>Fork it</li>
176
+ <li>Create your feature branch (<code>git checkout -b my-new-feature</code>)</li>
177
+ <li>Commit your changes (<code>git commit -am &#39;Add some feature&#39;</code>)</li>
178
+ <li>Push to the branch (<code>git push origin my-new-feature</code>)</li>
179
+ <li>Create a new Pull Request</li>
180
+ </ol>
181
+
182
+ <h2 id="license">License</h2>
183
+
184
+ <p>The gem is available as open source under the terms of the <a href="https://opensource.org/licenses/MIT">MIT License</a>.</p>
185
+
186
+ <h2 id="disclaimer">Disclaimer</h2>
187
+
188
+ <p>This is free software and is provided as is. The author makes no guarantee that its results are accurate and is not responsible for any losses caused by the use of the code.</p>
189
+
190
+ <p>Options are 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.</p>
191
+
192
+ <h1 id="print-the-results">Print the results</h1>
193
+
194
+ <p>puts outputs</p>
195
+
196
+ <h1 id="plot-the-profit-loss-diagram">Plot the profit/loss diagram</h1>
197
+
198
+ <p>OptionLab.plot_pl(outputs)</p>
199
+
200
+ <pre class="code ruby"><code class="ruby">
201
+ ## Common Strategies
202
+
203
+ OptionLab supports all standard options strategies, including:
204
+
205
+ - Covered calls
206
+ - Naked puts
207
+ - Bull/bear spreads
208
+ - Straddles/strangles
209
+ - Iron condors
210
+ - Butterflies
211
+ - Calendar spreads
212
+ - And more...
213
+
214
+ ## Advanced Usage
215
+
216
+ The library also allows for more advanced use cases, such as:
217
+
218
+ ```ruby
219
+ # Create a custom distribution model
220
+ bs_inputs = OptionLab::Models::BlackScholesModelInputs.new(
221
+ stock_price: 168.99,
222
+ volatility: 0.483,
223
+ interest_rate: 0.045,
224
+ years_to_target_date: 24.0 / 365
225
+ )
226
+
227
+ # Generate price array with 10,000 samples
228
+ prices = OptionLab.create_price_array(bs_inputs, n: 10_000, seed: 42)
229
+
230
+ # Run a strategy with the custom price array
231
+ input_data = {
232
+ stock_price: 168.99,
233
+ volatility: 0.483,
234
+ interest_rate: 0.045,
235
+ min_stock: 120,
236
+ max_stock: 200,
237
+ model: &quot;array&quot;,
238
+ array: prices,
239
+ strategy: [
240
+ { type: &quot;stock&quot;, n: 100, action: &quot;buy&quot; },
241
+ {
242
+ type: &quot;call&quot;,
243
+ strike: 185.0,
244
+ premium: 4.1,
245
+ n: 100,
246
+ action: &quot;sell&quot;
247
+ }
248
+ ]
249
+ }
250
+
251
+ outputs = OptionLab.run_strategy(input_data)
252
+ </code></pre>
253
+ </div></div>
254
+
255
+ <div id="footer">
256
+ Generated on Sun Apr 27 16:09:33 2025 by
257
+ <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
258
+ 0.9.37 (ruby-3.3.3).
259
+ </div>
260
+
261
+ </div>
262
+ </body>
263
+ </html>