rupee 0.1.3 → 0.1.5

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.
data/README.rdoc ADDED
@@ -0,0 +1,103 @@
1
+ = Rupee - financial tools for Ruby
2
+
3
+ Homepage:: http://www.brymck.com
4
+ Author:: Bryan McKelvey
5
+ Copyright:: (c) 2011 Bryan McKelvey
6
+ License:: MIT
7
+
8
+ /|\
9
+ / | \
10
+ / | \
11
+ /_ / \ _\ RU PE E
12
+ | | | | _ _ _
13
+ | | | | | | | | |__o ____
14
+ | | | | | | | _ | __| |____|
15
+ | _| |_ | | | |/ / | |___
16
+ \ \ / / /_/|___/ \____|
17
+ \ | /
18
+ \ | /
19
+ \|/
20
+
21
+ == Installing
22
+
23
+ Note that you must have Ruby 1.8.7+ installed and the ability to compile native
24
+ extensions (standard on most platforms and available on Windows via
25
+ {DevKit}[http://rubyinstaller.org/downloads/]).
26
+
27
+ gem install rupee
28
+
29
+ You can also do things the hard way if you want to keep track of the repo:
30
+
31
+ git clone git://github.com/brymck/rupee.git
32
+ cd rupee
33
+ bundle update
34
+ rake install
35
+
36
+ After all that hard work, you can take a test drive by running something like
37
+ this in the Ruby console (i.e. <tt>irb</tt> in a command prompt):
38
+
39
+ require "rupee"
40
+ Rupee::Option.black_scholes "c", 60, 65, 0.25, 0.08, 0, 0.3
41
+ Rupee::Call.new(
42
+ :underlying => 60,
43
+ :strike => 65,
44
+ :time => 0.25,
45
+ :rate => 0.08,
46
+ :div_yield => 0.00,
47
+ :volatility => 0.3
48
+ ).black_scholes
49
+
50
+ both of which should return <tt>2.1334</tt>.
51
+
52
+ You should also be able to get the latest stock info for, for example, Wells
53
+ Fargo using the following (note that you only need to <tt>require</tt> the
54
+ <tt>quote</tt> module):
55
+
56
+ require "rupee/quote"
57
+ wfc = Rupee::Quote.new("WFC")
58
+
59
+ wfc.get :price, :change, :pct_change
60
+ #=> {:price=>24.96, :change=>0.17, :pct_change =>0.686}
61
+
62
+ wfc.price
63
+ #=> 24.96
64
+
65
+ wfc.change
66
+ #=> 0.17
67
+
68
+ <tt>wfc.get</tt> will return a hash of the requested information for the security.
69
+ Each valid parameter will also have its own utility method. The results will
70
+ update every <tt>wfc.frequency</tt> seconds (defaults to 15).
71
+
72
+ Got it? Good. This will surely help you collect some rupees in real life.
73
+
74
+ == Performance
75
+
76
+ This is just a simple benchmark I ran on my own laptop, where I value a simple
77
+ call option with Black-Scholes 100,000 times. You can test the same on yours
78
+ with rake, but in any case it makes the point that for the mathematical side
79
+ of finance a native extension has substantial benefits:
80
+
81
+ rake benchmark:black_scholes
82
+
83
+ Results:
84
+
85
+ user system total real
86
+ Rupee (class): 0.190000 0.000000 0.190000 ( 0.194001)
87
+ Rupee (one object): 0.180000 0.000000 0.180000 ( 0.183091)
88
+ Rupee (new object): 2.210000 0.000000 2.210000 ( 2.213351)
89
+ Pure Ruby: 2.320000 0.000000 2.320000 ( 2.324259)
90
+
91
+ In words, for math-intensive operations, using a C implementation is clearly
92
+ faster than the same thing in Ruby.
93
+
94
+ Also, if you're doing a valuation on a one-off set of examples (e.g. in a Monte
95
+ Carlo simulation), you probably don't want to create an object every time.
96
+ Something like <tt>Rupee::Option.black_scholes ...</tt> should work just fine.
97
+ Creating a <tt>Rupee::Option</tt> object takes roughly the same amount of time as
98
+ running <tt>Rupee::Option.black_scholes</tt> a dozen times.
99
+
100
+ However, if you're creating and reusing an object, I strongly recommend
101
+ preserving the object orientation of Ruby: the penalty for using a new instance
102
+ rather than calling the class method directly is almost entirely in the object
103
+ initialization itself.
data/ext/rupee/bond.c CHANGED
@@ -295,7 +295,7 @@ init_bond()
295
295
  rb_define_singleton_method(klass, "duration", duration_discrete, 3);
296
296
  rb_define_alias(singleton, "dur", "duration");
297
297
  rb_define_singleton_method(klass, "macaulay", macaulay_discrete, 3);
298
- rb_define_alias(singleton, "macaulary_duration", "macaulay");
298
+ rb_define_alias(singleton, "macaulay_duration", "macaulay");
299
299
  rb_define_singleton_method(klass, "price", price_discrete, 3);
300
300
  rb_define_alias(singleton, "value", "price");
301
301
  rb_define_singleton_method(klass, "yield_to_maturity", yield_to_maturity_discrete, 3);
@@ -53,7 +53,7 @@ init_distribution()
53
53
  VALUE klass, singleton;
54
54
 
55
55
  #if 0
56
- value module = rb_define_module("rupee");
56
+ VALUE module = rb_define_module("Rupee");
57
57
  #endif
58
58
 
59
59
  klass = rb_define_class_under(module, "Distribution", rb_cObject);
@@ -3,7 +3,9 @@ module Rupee
3
3
  class Benchmark
4
4
  class << self
5
5
  # Black-Scholes option price valuation
6
+ #
6
7
  # by Michael Neumann (with some revisions)
8
+ #
7
9
  # http://www.espenhaug.com/black_scholes.html
8
10
  def black_scholes(callPutFlag, s, x, t, r, v)
9
11
  d1 = (Math.log(s / x) + (r + v * v / 2.0) * t) / (v * Math.sqrt(t))
@@ -17,14 +19,16 @@ module Rupee
17
19
 
18
20
  private
19
21
 
20
- A1 = 0.31938153
21
- A2 = -0.356563782
22
- A3 = 1.781477937
23
- A4 = -1.821255978
24
- A5 = 1.330274429
22
+ A1 = 0.31938153 # :nodoc:
23
+ A2 = -0.356563782 # :nodoc:
24
+ A3 = 1.781477937 # :nodoc:
25
+ A4 = -1.821255978 # :nodoc:
26
+ A5 = 1.330274429 # :nodoc:
25
27
 
26
28
  # Cumulative normal distribution
29
+ #
27
30
  # by Michael Neumann (with some revisions)
31
+ #
28
32
  # http://www.espenhaug.com/black_scholes.html
29
33
  def cnd(x)
30
34
  l = x.abs
data/lib/rupee/option.rb CHANGED
@@ -2,28 +2,45 @@ require "rupee/security"
2
2
 
3
3
  module Rupee
4
4
  class Option < Security
5
- attr_accessor :type, :underlying, :strike, :time, :rate, :div_yield, :volatility, :price
6
- alias :rfr :rate
7
- alias :rfr= :rate=
8
- alias :risk_free_rate :rate
9
- alias :risk_free_rate= :rate=
10
- alias :value :price
11
- alias :value= :price=
5
+ # The type of the option. Accepts <tt>"call"</tt> and <tt>"put"</tt>.
6
+ attr_accessor :type
7
+ # The price of the underlying security
8
+ attr_accessor :underlying
9
+ # The strike price of the underlying security
10
+ attr_accessor :strike
11
+ # The remaining time to maturity
12
+ attr_accessor :time
13
+ # The risk-free rate
14
+ attr_accessor :rate
15
+ # The dividend yield
16
+ attr_accessor :div_yield
17
+ # The annualized price volatility
18
+ attr_accessor :volatility
19
+ # The price of the option
20
+ attr_accessor :price
21
+
22
+ attr_alias :rfr, :rate
23
+ attr_alias :risk_free_rate, :rate
24
+ attr_alias :value, :price
12
25
 
13
26
  def black_scholes
14
27
  @value = self.class.black_scholes @type.to_s, @underlying, @strike, @time, @rate, @div_yield, @volatility
15
28
  end
16
29
  end
17
30
 
31
+ # The same thing as Rupee::Option, but with the <tt>:type</tt> flag set to
32
+ # <tt>"call"</tt>
18
33
  class Call < Option
19
- def initialize(opts = {})
34
+ def initialize(opts = {}) # :nodoc:
20
35
  @type = "call"
21
36
  super
22
37
  end
23
38
  end
24
39
 
40
+ # The same thing as Rupee::Option, but with the <tt>:type</tt> flag set to
41
+ # <tt>"put"</tt>
25
42
  class Put < Option
26
- def initialize(opts = {})
43
+ def initialize(opts = {}) # :nodoc:
27
44
  @type = :put
28
45
  super
29
46
  end
data/lib/rupee/quote.rb CHANGED
@@ -3,7 +3,23 @@ autoload :Net, "net/http"
3
3
  autoload :URI, "uri"
4
4
 
5
5
  module Rupee
6
- # The quote and data import functionality in Rupee
6
+ # An object representing a security quote from an online source. With a
7
+ # Rupee::Quote object, you can retrieve the most recent information on a
8
+ # particular security using either the <tt>get</tt> method or the helper
9
+ # methods for each parameter (e.g. <tt>price</tt>, <tt>change</tt>):
10
+ #
11
+ # require "rupee/quote"
12
+ #
13
+ # wfc = Rupee::Quote.new("WFC")
14
+ #
15
+ # wfc.get :price, :change, :pct_change
16
+ # #=> {:price=>24.96, :change=>0.17, :pct_change =>0.686}
17
+ #
18
+ # wfc.price
19
+ # #=> 24.96
20
+ #
21
+ # wfc.change
22
+ # #=> 0.17
7
23
  class Quote
8
24
  # A ticker symbol
9
25
  attr_accessor :ticker
@@ -11,19 +27,29 @@ module Rupee
11
27
  # The name of the quote source
12
28
  attr_accessor :source
13
29
 
14
- # The cached HTML
15
- attr :html
16
-
17
30
  # The frequency in seconds that a quote's information should be updated
18
31
  attr_accessor :frequency
19
32
 
20
33
  # The time at which the next pull from the online quote source will occur
21
34
  attr :next_pull
22
35
 
36
+ # Creates a new Rupee::Quote object.
37
+ #
38
+ # wfc = Rupee::Quote.new("WFC")
39
+ #
40
+ # is equivalent to
41
+ #
42
+ # wfc = Rupee::Quote.new("WFC", :source => :bloomberg, :frequency => 15)
43
+ #
44
+ # Configuration options
45
+ #
46
+ # * <tt>:source</tt> - The name of the source (default is +:bloomberg+).
47
+ # * <tt>:frequency</tt> - How often the quote will seek new values from the
48
+ # quote source, in seconds (default is +15+).
23
49
  def initialize(ticker, opts = {})
24
50
  opts = { :source => :bloomberg, :frequency => 15 }.merge opts
25
51
  @ticker = ticker
26
- @source = Quote.sources[opts[:source]]
52
+ @source = shorten_source(Quote.sources[opts[:source]])
27
53
  @frequency = opts[:frequency]
28
54
  @next_pull = Time.now
29
55
  end
@@ -58,6 +84,9 @@ module Rupee
58
84
  end
59
85
  end
60
86
 
87
+ # call-seq: Rupee#price
88
+ #
89
+ # Blah
61
90
  [:price, :change, :pct_change, :date, :time, :bid, :ask, :open, :high,
62
91
  :low, :volume, :mkt_cap, :p_e].each do |method_name|
63
92
  define_method method_name do
@@ -65,7 +94,7 @@ module Rupee
65
94
  end
66
95
  end
67
96
 
68
- def frequency=(x)
97
+ def frequency=(x) # :nodoc:
69
98
  @next_pull += (x - @frequency)
70
99
  @frequency = x
71
100
  end
@@ -87,6 +116,10 @@ module Rupee
87
116
  end
88
117
  end
89
118
 
119
+ # Parses an object that might be a number
120
+ #
121
+ # parse "15" #=> 15
122
+ # parse "abc" #=> "abc"
90
123
  def parse(result)
91
124
  begin
92
125
  Float(result)
@@ -4,26 +4,26 @@ module Rupee
4
4
  # Automatically sets all arguments passed to <tt>initialize</tt> to
5
5
  # instance variables if they exist (think Rails mass assignment).
6
6
  #
7
- # require "rupee"
7
+ # require "rupee"
8
8
  #
9
- # call = Rupee::Call.new(
10
- # :underlying => 60,
11
- # :strike => 65,
12
- # :time => 0.25,
13
- # :rate => 0.08,
14
- # :div_yield => 0.00,
15
- # :volatility => 0.3
16
- # )
17
- # puts call.black_scholes
18
- # #=> 2.1333718619275794
9
+ # call = Rupee::Call.new(
10
+ # :underlying => 60,
11
+ # :strike => 65,
12
+ # :time => 0.25,
13
+ # :rate => 0.08,
14
+ # :div_yield => 0.00,
15
+ # :volatility => 0.3
16
+ # )
17
+ # puts call.black_scholes
18
+ # #=> 2.1333718619275794
19
19
  #
20
20
  # You still have the option of avoiding the creation of an object (and the
21
21
  # overhead it entails) by using the class methods directly:
22
22
  #
23
- # require "rupee"
23
+ # require "rupee"
24
24
  #
25
- # puts Rupee::Option.black_scholes "c", 60, 65, 0.25, 0.08, 0, 0.3
26
- # #=> 2.1333718619275794
25
+ # puts Rupee::Option.black_scholes "c", 60, 65, 0.25, 0.08, 0, 0.3
26
+ # #=> 2.1333718619275794
27
27
  def initialize(opts = {})
28
28
  opts.each do |key, value|
29
29
  writer = key.to_s.+("=").to_sym
@@ -32,5 +32,22 @@ module Rupee
32
32
  end
33
33
  end
34
34
  end
35
+
36
+ class << self
37
+ # Aliases an attribute, taking into account both its getter and setter
38
+ # methods. For example,
39
+ #
40
+ # attr_accessor :price
41
+ # attr_alias :value, :price
42
+ #
43
+ # would add both a <tt>value</tt> and a <tt>value=</tt> that are equivalent
44
+ # to their <tt>price</tt> counterparts.
45
+ def attr_alias(new_read, old_read)
46
+ alias_method(new_read, old_read) if method_defined?(old_read)
47
+ new_write = "#{new_read}="
48
+ old_write = "#{old_read}="
49
+ alias_method(new_write, old_write) if method_defined?(old_write)
50
+ end
51
+ end
35
52
  end
36
53
  end
data/lib/rupee/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Rupee
2
2
  # The current version
3
- VERSION = "0.1.3"
3
+ VERSION = "0.1.5"
4
4
  end
data/spec/c/bond_spec.rb CHANGED
@@ -7,10 +7,9 @@ require File.dirname(__FILE__) + "/../spec_helper"
7
7
  # bond yield to maturity = 0.09
8
8
  # new bond price = 104.282
9
9
 
10
- TOLERANCE = 0.001
11
-
12
10
  describe Rupee::Bond do
13
11
  before :each do
12
+ @tolerance = 0.001
14
13
  @times = [1, 2, 3]
15
14
  @cflows = [10, 10, 110]
16
15
  @r = 0.09
@@ -18,39 +17,39 @@ describe Rupee::Bond do
18
17
 
19
18
  describe "with discrete discounting" do
20
19
  it "should produce an accurate price" do
21
- Rupee::Bond.price(@times, @cflows, @r).should be_within(TOLERANCE).of 102.531
20
+ Rupee::Bond.price(@times, @cflows, @r).should be_within(@tolerance).of 102.531
22
21
  end
23
22
 
24
23
  it "should produce an accurate duration" do
25
- Rupee::Bond.duration(@times, @cflows, @r).should be_within(TOLERANCE).of 2.73895
24
+ Rupee::Bond.duration(@times, @cflows, @r).should be_within(@tolerance).of 2.73895
26
25
  end
27
26
 
28
27
  it "should produce an accurate convexity" do
29
- Rupee::Bond.convexity(@times, @cflows, @r).should be_within(TOLERANCE).of 8.93248
28
+ Rupee::Bond.convexity(@times, @cflows, @r).should be_within(@tolerance).of 8.93248
30
29
  end
31
30
 
32
31
  it "should produce an accurate yield to maturity" do
33
32
  @price = Rupee::Bond.price(@times, @cflows, @r)
34
- Rupee::Bond.yield_to_maturity(@times, @cflows, @price).should be_within(TOLERANCE).of @r
33
+ Rupee::Bond.yield_to_maturity(@times, @cflows, @price).should be_within(@tolerance).of @r
35
34
  end
36
35
  end
37
36
 
38
37
  describe "with continuous discounting" do
39
38
  it "should produce an accurate price" do
40
- Rupee::Bond.continuous_price(@times, @cflows, @r).should be_within(TOLERANCE).of 101.464
39
+ Rupee::Bond.continuous_price(@times, @cflows, @r).should be_within(@tolerance).of 101.464
41
40
  end
42
41
 
43
42
  it "should produce an accurate duration" do
44
- Rupee::Bond.continuous_duration(@times, @cflows, @r).should be_within(TOLERANCE).of 2.73753
43
+ Rupee::Bond.continuous_duration(@times, @cflows, @r).should be_within(@tolerance).of 2.73753
45
44
  end
46
45
 
47
46
  it "should produce an accurate convexity" do
48
- Rupee::Bond.continuous_convexity(@times, @cflows, @r).should be_within(TOLERANCE).of 7.86779
47
+ Rupee::Bond.continuous_convexity(@times, @cflows, @r).should be_within(@tolerance).of 7.86779
49
48
  end
50
49
 
51
50
  it "should produce an accurate yield to maturity" do
52
51
  @price = Rupee::Bond.continuous_price(@times, @cflows, @r)
53
- Rupee::Bond.continuous_yield_to_maturity(@times, @cflows, @price).should be_within(TOLERANCE).of @r
52
+ Rupee::Bond.continuous_yield_to_maturity(@times, @cflows, @price).should be_within(@tolerance).of @r
54
53
  end
55
54
  end
56
55
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rupee
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2011-09-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
16
- requirement: &79757030 !ruby/object:Gem::Requirement
16
+ requirement: &84129210 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '1.0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *79757030
24
+ version_requirements: *84129210
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &79755150 !ruby/object:Gem::Requirement
27
+ requirement: &84128900 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '2.0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *79755150
35
+ version_requirements: *84128900
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: autotest
38
- requirement: &79754560 !ruby/object:Gem::Requirement
38
+ requirement: &84127610 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '4.0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *79754560
46
+ version_requirements: *84127610
47
47
  description: rupee aims to provide user-friendly tools for use in financial gems and
48
48
  applications.
49
49
  email:
@@ -58,7 +58,7 @@ files:
58
58
  - .rspec
59
59
  - COPYING
60
60
  - Gemfile
61
- - README.md
61
+ - README.rdoc
62
62
  - Rakefile
63
63
  - ext/rupee/bond.c
64
64
  - ext/rupee/distribution.c
data/README.md DELETED
@@ -1,122 +0,0 @@
1
- Rupee - financial tools for Ruby
2
- ================================
3
-
4
- <table>
5
- <tr>
6
- <td>Homepage</td>
7
- <td><a href="http://www.brymck.com">www.brymck.com</a></td>
8
- </tr>
9
- <tr>
10
- <td>Author</td>
11
- <td>Bryan McKelvey</td>
12
- </tr>
13
- <tr>
14
- <td>Copyright</td>
15
- <td>(c) 2011 Bryan McKelvey</td>
16
- </tr>
17
- <tr>
18
- <td>License</td>
19
- <td>MIT</td>
20
- </tr>
21
- </table>
22
-
23
- [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=brymck&url=https://github.com/brymck/rupee&title=rupee&language=en_GB&tags=github&category=software)
24
-
25
- /|\
26
- / | \
27
- / | \
28
- /_ / \ _\ RU PE E
29
- | | | | _ _ _
30
- | | | | | | | | |__o ____
31
- | | | | | | | _ | __| |____|
32
- | _| |_ | | | |/ / | |___
33
- \ \ / / /_/|___/ \____|
34
- \ | /
35
- \ | /
36
- \|/ brymck
37
-
38
- Installing
39
- ----------
40
-
41
- Note that you must have Ruby 1.8.7+ installed and the ability to compile native
42
- extensions (standard on most platforms and available on Windows via
43
- [DevKit](http://rubyinstaller.org/downloads/)).
44
-
45
- gem install rupee
46
-
47
- You can also do things the hard way if you want to keep track of the repo:
48
-
49
- git clone git://github.com/brymck/rupee.git
50
- cd rupee
51
- bundle update
52
- rake install
53
-
54
- After all that hard work, you can take a test drive by running something like
55
- this in the Ruby console (i.e. `irb` in a command prompt):
56
-
57
- require "rupee"
58
- Rupee::Option.black_scholes "c", 60, 65, 0.25, 0.08, 0, 0.3
59
- Rupee::Call.new(
60
- :underlying => 60,
61
- :strike => 65,
62
- :time => 0.25,
63
- :rate => 0.08,
64
- :div_yield => 0.00,
65
- :volatility => 0.3
66
- ).black_scholes
67
-
68
- both of which should return `2.1334`.
69
-
70
- You should also be able to get the latest stock info for, for example, Wells
71
- Fargo using the following (note that you only need to `require` the `quote`
72
- module):
73
-
74
- require "rupee/quote"
75
- wfc = Rupee::Quote.new("WFC")
76
-
77
- wfc.get :price, :change, :pct_change
78
- #=> {:price=>24.96, :change=>0.17, :pct_change =>0.686}
79
-
80
- wfc.price
81
- #=> 24.96
82
-
83
- wfc.change
84
- #=> 0.17
85
-
86
- `wfc.get` will return a hash of the requested information for the security.
87
- Each valid parameter will also have its own utility method. The results will
88
- update every `wfc.frequency` seconds (defaults to 15).
89
-
90
- Got it? Good. This will surely help you collect some rupees in real life.
91
-
92
- Performance
93
- -----------
94
-
95
- This is just a simple benchmark I ran on my own laptop, where I value a simple
96
- call option with Black-Scholes 100,000 times. You can test the same on yours
97
- with rake, but in any case it makes the point that for the mathematical side
98
- of finance a native extension has substantial benefits:
99
-
100
- rake benchmark:black_scholes
101
-
102
- Results:
103
-
104
- user system total real
105
- Rupee (class): 0.190000 0.000000 0.190000 ( 0.194001)
106
- Rupee (one object): 0.180000 0.000000 0.180000 ( 0.183091)
107
- Rupee (new object): 2.210000 0.000000 2.210000 ( 2.213351)
108
- Pure Ruby: 2.320000 0.000000 2.320000 ( 2.324259)
109
-
110
- In words, for math-intensive operations, using a C implementation is clearly
111
- faster than the same thing in Ruby.
112
-
113
- Also, if you're doing a valuation on a one-off set of examples (e.g. in a Monte
114
- Carlo simulation), you probably don't want to create an object every time.
115
- Something like `Rupee::Option.black_scholes ...` should work just fine.
116
- Creating a `Rupee::Option` object takes roughly the same amount of time as
117
- running `Rupee::Option.black_scholes` a dozen times.
118
-
119
- However, if you're creating and reusing an object, I strongly recommend
120
- preserving the object orientation of Ruby: the penalty for using a new instance
121
- rather than calling the class method directly is almost entirely in the object
122
- initialization itself.