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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 42772c157960f755fbc0dd3dedc3dc41dcee05d7caf3d78107a9884ebed2ec08
4
+ data.tar.gz: 1063a3be2be3fae5ce37ede1c6ca702c7934d55738a4601af5e69d9feee736e2
5
+ SHA512:
6
+ metadata.gz: 7b528868a81353a9cd39e0190d1cc31e02d3abc20b2ed912dd372722da26b2c33fc9cf33da0f7a90819b16ed92f39c8f3cabdfebd4442b9427c7dc2a569b3e08
7
+ data.tar.gz: 5dbe0d912bc99a367c0c987e702aa896c0e3ce5201d0c598517d62235fa8013a260b5d7effb137f17b34dca96a5d500fea4b6f4fe993389e0654d94e63ff1d50
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --format documentation
3
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,139 @@
1
+ inherit_gem:
2
+ rubocop-shopify: rubocop.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 3.3
6
+ NewCops: enable
7
+ Exclude:
8
+ - 'vendor/**/*'
9
+ - 'bin/**/*'
10
+ - 'spec/spec_helper.rb'
11
+ - 'tmp/**/*'
12
+
13
+ # General style settings
14
+ Style/StringLiterals:
15
+ EnforcedStyle: single_quotes
16
+ Enabled: true
17
+
18
+ Style/StringLiteralsInInterpolation:
19
+ EnforcedStyle: single_quotes
20
+ Enabled: true
21
+
22
+ # Documentation is important for a library
23
+ Style/Documentation:
24
+ Enabled: true
25
+
26
+ # Use modern Ruby features
27
+ Style/FrozenStringLiteralComment:
28
+ Enabled: true
29
+ EnforcedStyle: always
30
+
31
+ # Method length and complexity
32
+ Metrics/MethodLength:
33
+ Max: 30
34
+
35
+ Metrics/AbcSize:
36
+ Max: 30
37
+
38
+ Metrics/CyclomaticComplexity:
39
+ Max: 15
40
+
41
+ Metrics/PerceivedComplexity:
42
+ Max: 15
43
+
44
+ Metrics/ParameterLists:
45
+ Max: 8
46
+
47
+ # Class and module length
48
+ Metrics/ClassLength:
49
+ Max: 300
50
+
51
+ Metrics/ModuleLength:
52
+ Max: 300
53
+
54
+ # Line length
55
+ Layout/LineLength:
56
+ Max: 100
57
+ Exclude:
58
+ - 'spec/**/*'
59
+
60
+ # Block length exception for specs
61
+ Metrics/BlockLength:
62
+ Max: 30
63
+ Exclude:
64
+ - 'spec/**/*'
65
+
66
+ # Naming conventions
67
+ Naming/MethodParameterName:
68
+ MinNameLength: 1 # Allow single letter variables for mathematical formulas
69
+
70
+ # Prefer compact module/class definitions
71
+ Style/ClassAndModuleChildren:
72
+ Enabled: true
73
+ EnforcedStyle: nested
74
+
75
+ # Discourage usage of globals
76
+ Style/GlobalVars:
77
+ Enabled: true
78
+
79
+ # Allow more descriptive module/class variable names
80
+ Naming/ClassAndModuleCamelCase:
81
+ Enabled: true
82
+
83
+ # Use snake_case for variables and methods
84
+ Naming/VariableName:
85
+ EnforcedStyle: snake_case
86
+
87
+ Naming/MethodName:
88
+ EnforcedStyle: snake_case
89
+
90
+ # Parentheses for method definitions
91
+ Style/DefWithParentheses:
92
+ Enabled: true
93
+
94
+ # Method call with or without parentheses
95
+ Style/MethodCallWithArgsParentheses:
96
+ Enabled: false
97
+
98
+ # Raise exceptions with explicit new
99
+ Style/RaiseArgs:
100
+ EnforcedStyle: exploded
101
+
102
+ # Prefer the newer safe navigation operator
103
+ Style/SafeNavigation:
104
+ Enabled: true
105
+
106
+ # Trailing commas
107
+ Style/TrailingCommaInArrayLiteral:
108
+ EnforcedStyleForMultiline: consistent_comma
109
+
110
+ Style/TrailingCommaInHashLiteral:
111
+ EnforcedStyleForMultiline: consistent_comma
112
+
113
+ # Prefer %i for symbol arrays
114
+ Style/SymbolArray:
115
+ EnforcedStyle: percent
116
+ MinSize: 3
117
+
118
+ # Prefer %w for word arrays
119
+ Style/WordArray:
120
+ EnforcedStyle: percent
121
+ MinSize: 3
122
+
123
+ # Prefer &&/|| over and/or
124
+ Style/AndOr:
125
+ EnforcedStyle: always
126
+
127
+ # Accessibility modifiers should be indented consistently
128
+ Layout/AccessModifierIndentation:
129
+ EnforcedStyle: indent
130
+
131
+ # Consistent empty lines
132
+ Layout/EmptyLinesAroundClassBody:
133
+ EnforcedStyle: empty_lines
134
+
135
+ Layout/EmptyLinesAroundModuleBody:
136
+ EnforcedStyle: empty_lines
137
+
138
+ Layout/EmptyLinesAroundMethodBody:
139
+ EnforcedStyle: empty_lines
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ YARD::Hooks.register_hook(:before_generate) do
4
+ # Ensure the images directory exists
5
+ FileUtils.mkdir_p('docs/images')
6
+ puts "✅ Created docs/images directory"
7
+ end
data/.yardopts ADDED
@@ -0,0 +1,11 @@
1
+ --markup markdown
2
+ --markup-provider redcarpet
3
+ --title 'OptionLab Documentation'
4
+ --readme README.md
5
+ --protected
6
+ --private
7
+ --embed-mixins
8
+ --asset docs/images:.
9
+ --output-dir docs
10
+ -
11
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in option_lab.gemspec
6
+ gemspec
7
+
8
+ # Runtime dependencies - these are always installed
9
+ gem "numo-narray", "~> 0.9.2"
10
+ gem "numo-linalg", "~> 0.1.7"
11
+ gem "distribution", "~> 0.8.0"
12
+ gem "unicode_plot", "~> 0.0.5"
13
+ gem "holidays", "~> 8.6.0"
14
+ gem "prime"
15
+ gem "bigdecimal"
16
+ gem "matrix"
17
+
18
+ # Development dependencies - only installed with `bundle install --with development`
19
+ group :development do
20
+ gem "rake", "~> 13.0"
21
+ gem "rspec", "~> 3.12"
22
+ gem "rubocop-shopify", require: false
23
+ gem "solargraph", "~> 0.49.0"
24
+ gem "yard", "~> 0.9.34"
25
+ gem "redcarpet", "~> 3.6.1" # Markdown processor for YARD
26
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,180 @@
1
+ # OptionLab
2
+
3
+ OptionLab is a lightweight Ruby library designed to provide quick evaluation of options trading strategies.
4
+ It aims to be a direct port of the popular Python library - [OptionLab](https://github.com/rgaveiga/optionlab)
5
+
6
+ ***docs page coming soon***
7
+ [![Documentation](https://img.shields.io/badge/docs-YARD-blue.svg)](https://xjackk.github.io/option_lab/)
8
+
9
+ ## Features
10
+
11
+ - Calculate profit/loss profiles for options strategies
12
+ - Estimate probability of profit using Black-Scholes or custom models
13
+ - Calculate option Greeks (Delta, Gamma, Theta, Vega, Rho)
14
+ - Generate profit/loss diagrams
15
+ - Support for complex multi-leg strategies
16
+ - Handle stock positions and previously closed trades
17
+ - Support for different dividend yield and interest rate scenarios
18
+ - Business day calculations across different countries
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ ```ruby
25
+ gem 'option_lab'
26
+ ```
27
+
28
+ And then execute:
29
+
30
+ ```
31
+ $ bundle install
32
+ ```
33
+
34
+ Or install it yourself as:
35
+
36
+ ```
37
+ $ gem install option_lab
38
+ ```
39
+
40
+ ## Requirements
41
+
42
+ OptionLab requires:
43
+
44
+ - Ruby 3.3.0 or higher
45
+ - numo-narray gem for numerical computations
46
+ - distribution gem for statistical calculations
47
+
48
+ ## Basic Usage
49
+
50
+ The evaluation of a strategy is done by calling the `run_strategy` method provided by the library. This method receives the input data as a Ruby hash or an `Inputs` object.
51
+
52
+ Here's an example of evaluating a naked call strategy:
53
+
54
+ ```ruby
55
+ require 'option_lab'
56
+
57
+ # Define the strategy
58
+ input_data = {
59
+ stock_price: 164.04,
60
+ start_date: Date.new(2023, 11, 22),
61
+ target_date: Date.new(2023, 12, 17),
62
+ volatility: 0.272,
63
+ interest_rate: 0.0002,
64
+ min_stock: 120,
65
+ max_stock: 200,
66
+ strategy: [
67
+ {
68
+ type: "call",
69
+ strike: 175.0,
70
+ premium: 1.15,
71
+ n: 100,
72
+ action: "sell"
73
+ }
74
+ ]
75
+ }
76
+
77
+ # Run the strategy calculation
78
+ outputs = OptionLab.run_strategy(input_data)
79
+
80
+ # Export P/L data to CSV
81
+ OptionLab.pl_to_csv(outputs, filename: "covered_call_pl.csv")
82
+ ```
83
+
84
+ ## Analyzing Results
85
+
86
+ The `Outputs` object returned by `run_strategy` contains a wealth of information:
87
+
88
+ ```ruby
89
+ # Key probability metrics
90
+ probability_of_profit = outputs.probability_of_profit
91
+ profit_ranges = outputs.profit_ranges
92
+ expected_profit = outputs.expected_profit
93
+ expected_loss = outputs.expected_loss
94
+
95
+ # Strategy costs
96
+ strategy_cost = outputs.strategy_cost
97
+ per_leg_cost = outputs.per_leg_cost
98
+
99
+ # Returns
100
+ min_return = outputs.minimum_return_in_the_domain
101
+ max_return = outputs.maximum_return_in_the_domain
102
+
103
+ # Option Greeks
104
+ delta = outputs.delta
105
+ gamma = outputs.gamma
106
+ theta = outputs.theta
107
+ vega = outputs.vega
108
+ rho = outputs.rho
109
+
110
+ # Print all metrics
111
+ puts outputs
112
+ ```
113
+
114
+ ## Contributing
115
+
116
+ 1. Fork it
117
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
118
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
119
+ 4. Push to the branch (`git push origin my-new-feature`)
120
+ 5. Create a new Pull Request
121
+
122
+ ## License
123
+
124
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
125
+
126
+ # Plot the profit/loss diagram
127
+ OptionLab.plot_pl(outputs)
128
+ ```
129
+
130
+ ## Common Strategies
131
+
132
+ OptionLab supports all standard options strategies, including:
133
+
134
+ - Covered calls
135
+ - Naked puts
136
+ - Bull/bear spreads
137
+ - Straddles/strangles
138
+ - Iron condors
139
+ - Butterflies
140
+ - Calendar spreads
141
+ - And more...
142
+
143
+ ## Advanced Usage
144
+
145
+ The library also allows for more advanced use cases, such as:
146
+
147
+ ```ruby
148
+ # Create a custom distribution model
149
+ bs_inputs = OptionLab::Models::BlackScholesModelInputs.new(
150
+ stock_price: 168.99,
151
+ volatility: 0.483,
152
+ interest_rate: 0.045,
153
+ years_to_target_date: 24.0 / 365
154
+ )
155
+
156
+ # Generate price array with 10,000 samples
157
+ prices = OptionLab.create_price_array(bs_inputs, n: 10_000, seed: 42)
158
+
159
+ # Run a strategy with the custom price array
160
+ input_data = {
161
+ stock_price: 168.99,
162
+ volatility: 0.483,
163
+ interest_rate: 0.045,
164
+ min_stock: 120,
165
+ max_stock: 200,
166
+ model: "array",
167
+ array: prices,
168
+ strategy: [
169
+ { type: "stock", n: 100, action: "buy" },
170
+ {
171
+ type: "call",
172
+ strike: 185.0,
173
+ premium: 4.1,
174
+ n: 100,
175
+ action: "sell"
176
+ }
177
+ ]
178
+ }
179
+
180
+ outputs = OptionLab.run_strategy(input_data)
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
13
+
14
+ desc 'Run example script'
15
+ task :example do
16
+ ruby 'examples/covered_call.rb'
17
+ end
18
+
19
+ desc 'Run benchmarks'
20
+ task :benchmark do
21
+ ruby 'spec/benchmarks/benchmark.rb'
22
+ end
23
+
24
+ desc 'Generate documentation using YARD'
25
+ task :doc do
26
+ sh 'mkdir -p docs/images'
27
+ sh 'yard doc lib/**/*.rb --output-dir docs'
28
+ end
29
+
30
+ desc 'Clean temporary files and build artifacts'
31
+ task :clean do
32
+ sh 'rm -rf *.gem *.rbc coverage .rspec docs doc'
33
+ sh 'rm -rf .bundle vendor Gemfile.lock'
34
+ sh 'rm -rf .yardoc log pkg tmp'
35
+ end
36
+
37
+ desc 'Open a console with the gem loaded'
38
+ task :console do
39
+ require 'irb'
40
+ require 'irb/completion'
41
+ require 'option_lab'
42
+ ARGV.clear
43
+ IRB.start
44
+ end