rupee 0.2.1 → 0.2.2

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.
@@ -0,0 +1,54 @@
1
+ module Rupee
2
+ class Calendar
3
+ # The national Japanese calendar
4
+ Japan = Calendar.new("The national Japanese calendar")
5
+
6
+ # Weekends
7
+ Japan.has_weekends_off
8
+
9
+ # Fixed and solar holidays
10
+ Japan.has_day_off_when do |date|
11
+ case date.month
12
+ when JANUARY
13
+ # New Year's Day
14
+ date.day == 1
15
+ when FEBRUARY
16
+ # National Foundation Day
17
+ date.day == 11
18
+ when MARCH
19
+ # Vernal Equinox Day
20
+ date.day == 20
21
+ when APRIL
22
+ # Showa Day
23
+ date.day == 29
24
+ when MAY
25
+ # Golden Week: Constitution Memorial Day, Greenery Day and Children's
26
+ # Day, respectively
27
+ date.day.between?(3, 5)
28
+ when SEPTEMBER
29
+ # Autumnal Equinox Day
30
+ date.day == 23
31
+ when NOVEMBER
32
+ # Culture Day and Labour Thanksgiving Day
33
+ date.day == 3 || date.day == 23
34
+ when DECEMBER
35
+ # Emperor's Birthday
36
+ date.day == 23
37
+ end
38
+ end
39
+
40
+ # Mondays
41
+ Japan.has_day_off_when do |date|
42
+ if date.monday?
43
+ case date.month
44
+ when JANUARY, OCTOBER
45
+ # Coming of Age Day, Health and Sports Day
46
+ week_of(date) == 2
47
+ when JULY, SEPTEMBER
48
+ # Marine Day, Respect-for-the-Aged Day
49
+ week_of(date) == 3
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,59 @@
1
+ module Rupee
2
+ class Calendar
3
+ # The US Federal Reserve calendar
4
+ US = Calendar.new("The Federal Reserve Calendar")
5
+
6
+ # Weekends
7
+ US.has_weekends_off
8
+
9
+ # New Year's Day (January 1)
10
+ US.has_day_off_on :new_years do |date|
11
+ date.month == JANUARY && next_weekday(date, 1)
12
+ end
13
+
14
+ # Martin Luther King, Jr.'s Birthday (third Monday of January)
15
+ US.has_day_off_on :mlk_day do |date|
16
+ date.month == JANUARY && date.monday? && week_of(date) == 3
17
+ end
18
+
19
+ # Washington's Birthday (third Monday of February)
20
+ US.has_day_off_on :washingtons_day do |date|
21
+ date.month == FEBRUARY && date.monday? && week_of(date) == 3
22
+ end
23
+
24
+ # Memorial Day (last Monday of May)
25
+ US.has_day_off_on :memorial_day do |date|
26
+ date.month == MAY && date.monday? && last_week?(date)
27
+ end
28
+
29
+ # Independence Day (July 4)
30
+ US.has_day_off_on :independence_day do |date|
31
+ date.month == JULY && nearest_weekday(date, 4)
32
+ end
33
+
34
+ # Labor Day (first Monday of September)
35
+ US.has_day_off_on :labor_day do |date|
36
+ date.month == SEPTEMBER && date.monday? && week_of(date) == 1
37
+ end
38
+
39
+ # Columbus Day (second Monday of October)
40
+ US.has_day_off_on :columbus_day do |date|
41
+ date.month == OCTOBER && date.monday? && week_of(date) == 2
42
+ end
43
+
44
+ # Veterans Day (November 11)
45
+ US.has_day_off_on :veterans_day do |date|
46
+ date.month == NOVEMBER && nearest_weekday(date, 11)
47
+ end
48
+
49
+ # Thanksgiving Day (fourth Thursday of November)
50
+ US.has_day_off_on :thanksgiving do |date|
51
+ date.month == NOVEMBER && date.thursday? && week_of(date) == 4
52
+ end
53
+
54
+ # Christmas Day (December 25)
55
+ US.has_day_off_on :christmas do |date|
56
+ date.month == DECEMBER && nearest_weekday(date, 25)
57
+ end
58
+ end
59
+ end
data/lib/rupee/option.rb CHANGED
@@ -27,6 +27,14 @@ module Rupee
27
27
  @value = self.class.black_scholes @type.to_s, @underlying, @strike,
28
28
  @time, @rate, @div_yield, @volatility
29
29
  end
30
+
31
+ [:charm, :color, :delta, :dual_delta, :dual_gamma, :dvega_dtime, :gamma,
32
+ :rho, :speed, :theta, :vanna, :vega, :vomma, :zomma].each do |method_name|
33
+ define_method method_name do
34
+ self.class.send method_name, @type, @underlying, @strike, @time,
35
+ @rate, @div_yield, @volatility
36
+ end
37
+ end
30
38
  end
31
39
 
32
40
  # The same thing as Rupee::Option, but with the <tt>:type</tt> flag set to
data/lib/rupee/quote.rb CHANGED
@@ -44,6 +44,9 @@ module Rupee
44
44
  # Configuration options
45
45
  #
46
46
  # * <tt>:source</tt> - The name of the source (default is +:bloomberg+).
47
+ # * <tt>:bloomberg</tt> - The Bloomberg quote service
48
+ # * <tt>:google</tt> - The Google Finance quote service
49
+ # * <tt>:yahoo</tt> - The Yahoo! quote service
47
50
  # * <tt>:frequency</tt> - How often the quote will seek new values from the
48
51
  # quote source, in seconds (default is +15+).
49
52
  def initialize(ticker, opts = {})
@@ -54,7 +57,10 @@ module Rupee
54
57
  @next_pull = Time.now
55
58
  end
56
59
 
57
- # Retrieves the current price of a security
60
+ # Retrieves the current information for a security
61
+ #
62
+ # Rupee::Quote.new("WFC").get :price, :change, :pct_chg
63
+ # #=> {:price=>24.96, :change=>0.17, :pct_chg =>0.686}
58
64
  def get(*params)
59
65
  now = Time.now
60
66
  params = [:price] if params.empty?
@@ -83,6 +89,12 @@ module Rupee
83
89
  end
84
90
  end
85
91
 
92
+ # Retrieves the current information for a security
93
+ #
94
+ # Rupee::Quote.new("WFC")[:price, :change, :pct_chg]
95
+ # #=> {:price=>24.96, :change=>0.17, :pct_chg =>0.686}
96
+ alias :[] :get
97
+
86
98
  # call-seq: #price
87
99
  #
88
100
  # Test
@@ -95,22 +107,39 @@ module Rupee
95
107
 
96
108
  # The bid-ask spread
97
109
  def bid_ask
98
- b, a = bid, ask
110
+ diff bid, ask
111
+ end
99
112
 
100
- if b.nil? || a.nil?
101
- nil
102
- else
103
- (a - b).round precision(a, b)
104
- end
113
+ # The daily trading range
114
+ def range
115
+ diff low, high
105
116
  end
106
117
 
107
- def frequency=(x) # :nodoc:
118
+ # The daily trading range
119
+ alias :trading_range :range
120
+
121
+ # The setter method for <tt>frequency</tt> also adjusts <tt>next_pull</tt>,
122
+ # such that if you change <tt>frequency</tt> from <tt>15</tt> to
123
+ # <tt>5</tt>, <tt>next_pull</tt> will move 10 seconds earlier.
124
+ def frequency=(x)
108
125
  @next_pull += (x - @frequency)
109
126
  @frequency = x
110
127
  end
111
128
 
112
129
  private
113
130
 
131
+ # Calculates the difference between <tt>x</tt> and <tt>y</tt>. This is
132
+ # different from merely subtracting <tt>x</tt> from <tt>y</tt> because of
133
+ # it forces the result to have the same number of significant digits as
134
+ # <tt>x</tt> or <tt>y</tt>, adjusted for whichever has more.
135
+ def diff(x, y)
136
+ if x.nil? || y.nil?
137
+ nil
138
+ else
139
+ (y - x).round precision(x, y)
140
+ end
141
+ end
142
+
114
143
  # Parses an object that might be a number
115
144
  #
116
145
  # parse "15" #=> 15
data/lib/rupee/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Rupee
2
2
  # The current version
3
- VERSION = "0.2.1"
3
+ VERSION = "0.2.2"
4
4
  end
@@ -4,53 +4,140 @@ describe Option do
4
4
  describe "European option valuation" do
5
5
  before :each do
6
6
  @tolerance = 0.0001
7
- @call = Option.new(
8
- :underlying => 60,
9
- :strike => 65,
10
- :time => 0.25,
11
- :rate => 0.08,
12
- :div_yield => 0,
13
- :volatility => 0.3
7
+ @underlying = 60
8
+ @strike = 65
9
+ @time = 0.25
10
+ @rate = 0.08
11
+ @div_yield = 0.0
12
+ @volatility = 0.3
13
+
14
+ @call = Call.new(
15
+ :underlying => @underlying,
16
+ :strike => @strike,
17
+ :time => @time,
18
+ :rate => @rate,
19
+ :div_yield => @div_yield,
20
+ :volatility => @volatility
21
+ )
22
+
23
+ @put = Put.new(
24
+ :underlying => @underlying,
25
+ :strike => @strike,
26
+ :time => @time,
27
+ :rate => @rate,
28
+ :div_yield => @div_yield,
29
+ :volatility => @volatility
14
30
  )
15
31
  end
16
32
 
17
33
  describe "using the Black-76 model" do
18
- describe "on a call option of price $60, strike $65, time to expiry 0.25, risk-free rate 8%, and volatility 30%" do
19
- it "should return $1.7202 for a call" do
20
- Option.black76("c", 60, 65, 0.25, 0.08, 0.3).should be_within(@tolerance).of 1.7202
21
- end
34
+ it "should return an accurate valuation for a call" do
35
+ Option.black76("c", @underlying, @strike, @time, @rate, @volatility).should be_within(@tolerance).of 1.7202
36
+ end
22
37
 
23
- it "should return $6.6212 for a put" do
24
- Option.black76("p", 60, 65, 0.25, 0.08, 0.3).should be_within(@tolerance).of 6.6212
25
- end
38
+ it "should return an accurate valuation for a put" do
39
+ Option.black76("p", @underlying, @strike, @time, @rate, @volatility).should be_within(@tolerance).of 6.6212
26
40
  end
27
41
  end
28
42
 
29
43
  describe "using the generalized Black-Scholes model" do
30
- describe "on a call option of price $60, strike $65, time to expiry 0.25, risk-free rate 8%, and volatility 30%" do
31
- it "should return $1.7202 for a call" do
32
- Option.generalized_black_scholes("c", 60, 65, 0.25, 0.08, 0, 0.3).should be_within(@tolerance).of 1.7202
33
- Option.gbs("c", 60, 65, 0.25, 0.08, 0, 0.3).should be_within(@tolerance).of 1.7202
34
- end
44
+ it "should return an accurate valuation for a call" do
45
+ Option.generalized_black_scholes("c", @underlying, @strike, @time, @rate, @div_yield, @volatility).should be_within(@tolerance).of 1.7202
46
+ Option.gbs("c", @underlying, @strike, @time, @rate, @div_yield, @volatility).should be_within(@tolerance).of 1.7202
47
+ end
35
48
 
36
- it "should return $6.6212 for a put" do
37
- Option.generalized_black_scholes("p", 60, 65, 0.25, 0.08, 0, 0.3).should be_within(@tolerance).of 6.6212
38
- Option.gbs("p", 60, 65, 0.25, 0.08, 0, 0.3).should be_within(@tolerance).of 6.6212
39
- end
49
+ it "should return an accurate valuation for a put" do
50
+ Option.generalized_black_scholes("p", @underlying, @strike, @time, @rate, @div_yield, @volatility).should be_within(@tolerance).of 6.6212
51
+ Option.gbs("p", @underlying, @strike, @time, @rate, @div_yield, @volatility).should be_within(@tolerance).of 6.6212
40
52
  end
41
53
  end
42
54
 
43
55
  describe "using the Black-Scholes model" do
44
- describe "on a call option of price $60, strike $65, time to expiry 0.25, risk-free rate 8%, and volatility 30%" do
45
- it "should return $1.7202 for a call" do
46
- Option.black_scholes("c", 60, 65, 0.25, 0.08, 0, 0.3).should be_within(@tolerance).of 2.1334
47
- Option.bs("c", 60, 65, 0.25, 0.08, 0, 0.3).should be_within(@tolerance).of 2.1334
48
- @call.black_scholes.should be_within(@tolerance).of 2.1334
56
+ describe "on a call option" do
57
+ it "should return an accurate valuation" do
58
+ value = @call.black_scholes
59
+ value.should be_within(@tolerance).of 2.1334
60
+ Option.black_scholes("c", @underlying, @strike, @time, @rate, @div_yield, @volatility).should == value
61
+ Option.bs("c", @underlying, @strike, @time, @rate, @div_yield, @volatility).should == value
62
+ end
63
+
64
+ it "should return an accurate charm" do
65
+ value = @call.charm
66
+ value.should be_a_kind_of Float
67
+ end
68
+
69
+ it "should return an accurate color" do
70
+ value = @call.color
71
+ value.should be_a_kind_of Float
72
+ end
73
+
74
+ it "should return an accurate delta" do
75
+ value = @call.delta
76
+ value.should be_a_kind_of Float
77
+ end
78
+
79
+ it "should return an accurate dual_delta" do
80
+ value = @call.dual_delta
81
+ value.should be_a_kind_of Float
82
+ end
83
+
84
+ it "should return an accurate dual_gamma" do
85
+ value = @call.dual_gamma
86
+ value.should be_a_kind_of Float
49
87
  end
50
88
 
51
- it "should return $6.6212 for a put" do
52
- Option.black_scholes("p", 60, 65, 0.25, 0.08, 0, 0.3).should be_within(@tolerance).of 5.8463
53
- Option.bs("p", 60, 65, 0.25, 0.08, 0, 0.3).should be_within(@tolerance).of 5.8463
89
+ it "should return an accurate dvega_dtime" do
90
+ value = @call.dvega_dtime
91
+ value.should be_a_kind_of Float
92
+ end
93
+
94
+ it "should return an accurate gamma" do
95
+ value = @call.gamma
96
+ value.should be_a_kind_of Float
97
+ end
98
+
99
+ it "should return an accurate rho" do
100
+ value = @call.rho
101
+ value.should be_a_kind_of Float
102
+ end
103
+
104
+ it "should return an accurate speed" do
105
+ value = @call.speed
106
+ value.should be_a_kind_of Float
107
+ end
108
+
109
+ it "should return an accurate theta" do
110
+ value = @call.theta
111
+ value.should be_a_kind_of Float
112
+ end
113
+
114
+ it "should return an accurate vanna" do
115
+ value = @call.vanna
116
+ value.should be_a_kind_of Float
117
+ end
118
+
119
+ it "should return an accurate vega" do
120
+ value = @call.vega
121
+ value.should be_a_kind_of Float
122
+ end
123
+
124
+ it "should return an accurate vomma" do
125
+ value = @call.vomma
126
+ value.should be_a_kind_of Float
127
+ end
128
+
129
+ it "should return an accurate zomma" do
130
+ value = @call.zomma
131
+ value.should be_a_kind_of Float
132
+ end
133
+ end
134
+
135
+ describe "on a put option" do
136
+ it "should return an accurate valuation" do
137
+ value = @put.black_scholes
138
+ value.should be_within(@tolerance).of 5.8463
139
+ Option.black_scholes("p", @underlying, @strike, @time, @rate, @div_yield, @volatility).should == value
140
+ Option.bs("p", @underlying, @strike, @time, @rate, @div_yield, @volatility).should == value
54
141
  end
55
142
  end
56
143
  end
@@ -0,0 +1,85 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ describe Calendar do
4
+ describe "for Federal Reserve holidays" do
5
+ it "should be accurate for New Year's Day" do
6
+ Calendar::US.day_off?(Time.new(2011, 1, 1)).should_not be false
7
+ Calendar::US.day_off?(Time.new(2012, 1, 2)).should_not be false
8
+ Calendar::US.day_off?(Time.new(2013, 1, 1)).should_not be false
9
+ Calendar::US.day_off?(Time.new(2014, 1, 1)).should_not be false
10
+ Calendar::US.day_off?(Time.new(2015, 1, 1)).should_not be false
11
+ end
12
+
13
+ it "should be accurate for Martin Luther King's Birthday" do
14
+ Calendar::US.day_off?(Time.new(2011, 1, 17)).should_not be false
15
+ Calendar::US.day_off?(Time.new(2012, 1, 16)).should_not be false
16
+ Calendar::US.day_off?(Time.new(2013, 1, 21)).should_not be false
17
+ Calendar::US.day_off?(Time.new(2014, 1, 20)).should_not be false
18
+ Calendar::US.day_off?(Time.new(2015, 1, 19)).should_not be false
19
+ end
20
+
21
+ it "should be accurate for Washington's Birthday" do
22
+ Calendar::US.day_off?(Time.new(2011, 2, 21)).should_not be false
23
+ Calendar::US.day_off?(Time.new(2012, 2, 20)).should_not be false
24
+ Calendar::US.day_off?(Time.new(2013, 2, 18)).should_not be false
25
+ Calendar::US.day_off?(Time.new(2014, 2, 17)).should_not be false
26
+ Calendar::US.day_off?(Time.new(2015, 2, 16)).should_not be false
27
+ end
28
+
29
+ it "should be accurate for Memorial Day" do
30
+ Calendar::US.day_off?(Time.new(2011, 5, 30)).should_not be false
31
+ Calendar::US.day_off?(Time.new(2012, 5, 28)).should_not be false
32
+ Calendar::US.day_off?(Time.new(2013, 5, 27)).should_not be false
33
+ Calendar::US.day_off?(Time.new(2014, 5, 26)).should_not be false
34
+ Calendar::US.day_off?(Time.new(2015, 5, 25)).should_not be false
35
+ end
36
+
37
+ it "should be accurate for Independence Day" do
38
+ Calendar::US.day_off?(Time.new(2011, 7, 4)).should_not be false
39
+ Calendar::US.day_off?(Time.new(2012, 7, 4)).should_not be false
40
+ Calendar::US.day_off?(Time.new(2013, 7, 4)).should_not be false
41
+ Calendar::US.day_off?(Time.new(2014, 7, 4)).should_not be false
42
+ Calendar::US.day_off?(Time.new(2015, 7, 4)).should_not be false
43
+ end
44
+
45
+ it "should be accurate for Labor Day" do
46
+ Calendar::US.day_off?(Time.new(2011, 9, 5)).should_not be false
47
+ Calendar::US.day_off?(Time.new(2012, 9, 3)).should_not be false
48
+ Calendar::US.day_off?(Time.new(2013, 9, 2)).should_not be false
49
+ Calendar::US.day_off?(Time.new(2014, 9, 1)).should_not be false
50
+ Calendar::US.day_off?(Time.new(2015, 9, 7)).should_not be false
51
+ end
52
+
53
+ it "should be accurate for Columbus Day" do
54
+ Calendar::US.day_off?(Time.new(2011, 10, 10)).should_not be false
55
+ Calendar::US.day_off?(Time.new(2012, 10, 8)).should_not be false
56
+ Calendar::US.day_off?(Time.new(2013, 10, 14)).should_not be false
57
+ Calendar::US.day_off?(Time.new(2014, 10, 13)).should_not be false
58
+ Calendar::US.day_off?(Time.new(2015, 10, 12)).should_not be false
59
+ end
60
+
61
+ it "should be accurate for Veterans Day" do
62
+ Calendar::US.day_off?(Time.new(2011, 11, 11)).should_not be false
63
+ Calendar::US.day_off?(Time.new(2012, 11, 12)).should_not be false
64
+ Calendar::US.day_off?(Time.new(2013, 11, 11)).should_not be false
65
+ Calendar::US.day_off?(Time.new(2014, 11, 11)).should_not be false
66
+ Calendar::US.day_off?(Time.new(2015, 11, 11)).should_not be false
67
+ end
68
+
69
+ it "should be accurate for Thanksgiving Day" do
70
+ Calendar::US.day_off?(Time.new(2011, 11, 24)).should_not be false
71
+ Calendar::US.day_off?(Time.new(2012, 11, 22)).should_not be false
72
+ Calendar::US.day_off?(Time.new(2013, 11, 28)).should_not be false
73
+ Calendar::US.day_off?(Time.new(2014, 11, 27)).should_not be false
74
+ Calendar::US.day_off?(Time.new(2015, 11, 26)).should_not be false
75
+ end
76
+
77
+ it "should be accurate for Christmas Day" do
78
+ Calendar::US.day_off?(Time.new(2011, 12, 26)).should_not be false
79
+ Calendar::US.day_off?(Time.new(2012, 12, 25)).should_not be false
80
+ Calendar::US.day_off?(Time.new(2013, 12, 25)).should_not be false
81
+ Calendar::US.day_off?(Time.new(2014, 12, 25)).should_not be false
82
+ Calendar::US.day_off?(Time.new(2015, 12, 25)).should_not be false
83
+ end
84
+ end
85
+ end