rupee 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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