tradier 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/.yardopts +8 -0
  2. data/LICENSE.md +20 -0
  3. data/README.md +114 -0
  4. data/Rakefile +19 -0
  5. data/lib/tradier.rb +31 -0
  6. data/lib/tradier/account.rb +30 -0
  7. data/lib/tradier/api/accounts.rb +122 -0
  8. data/lib/tradier/api/markets.rb +113 -0
  9. data/lib/tradier/api/orders.rb +84 -0
  10. data/lib/tradier/api/utils.rb +47 -0
  11. data/lib/tradier/api/utils/account.rb +15 -0
  12. data/lib/tradier/api/utils/balance.rb +15 -0
  13. data/lib/tradier/api/utils/base.rb +46 -0
  14. data/lib/tradier/api/utils/event.rb +15 -0
  15. data/lib/tradier/api/utils/expiration.rb +19 -0
  16. data/lib/tradier/api/utils/gainloss.rb +15 -0
  17. data/lib/tradier/api/utils/history.rb +15 -0
  18. data/lib/tradier/api/utils/option_quote.rb +15 -0
  19. data/lib/tradier/api/utils/order.rb +15 -0
  20. data/lib/tradier/api/utils/position.rb +15 -0
  21. data/lib/tradier/api/utils/quote.rb +15 -0
  22. data/lib/tradier/api/utils/strike.rb +15 -0
  23. data/lib/tradier/api/utils/timesales.rb +15 -0
  24. data/lib/tradier/api/utils/watchlist.rb +15 -0
  25. data/lib/tradier/api/watchlists.rb +139 -0
  26. data/lib/tradier/balance.rb +17 -0
  27. data/lib/tradier/base.rb +76 -0
  28. data/lib/tradier/calendar.rb +23 -0
  29. data/lib/tradier/client.rb +89 -0
  30. data/lib/tradier/clock.rb +21 -0
  31. data/lib/tradier/configurable.rb +76 -0
  32. data/lib/tradier/core_ext/enumerable.rb +9 -0
  33. data/lib/tradier/default.rb +75 -0
  34. data/lib/tradier/error.rb +34 -0
  35. data/lib/tradier/error/bad_gateway.rb +11 -0
  36. data/lib/tradier/error/bad_request.rb +10 -0
  37. data/lib/tradier/error/client_error.rb +28 -0
  38. data/lib/tradier/error/configuration_error.rb +6 -0
  39. data/lib/tradier/error/decode_error.rb +9 -0
  40. data/lib/tradier/error/forbidden.rb +10 -0
  41. data/lib/tradier/error/gateway_timeout.rb +11 -0
  42. data/lib/tradier/error/internal_server_error.rb +11 -0
  43. data/lib/tradier/error/not_acceptable.rb +10 -0
  44. data/lib/tradier/error/not_found.rb +10 -0
  45. data/lib/tradier/error/raise_error.rb +31 -0
  46. data/lib/tradier/error/server_error.rb +28 -0
  47. data/lib/tradier/error/service_unavailable.rb +11 -0
  48. data/lib/tradier/error/too_many_requests.rb +12 -0
  49. data/lib/tradier/error/unauthorized.rb +10 -0
  50. data/lib/tradier/error/unprocessable_entity.rb +10 -0
  51. data/lib/tradier/event.rb +8 -0
  52. data/lib/tradier/history.rb +20 -0
  53. data/lib/tradier/option_quote.rb +37 -0
  54. data/lib/tradier/order.rb +14 -0
  55. data/lib/tradier/position.rb +7 -0
  56. data/lib/tradier/profile.rb +14 -0
  57. data/lib/tradier/quote.rb +12 -0
  58. data/lib/tradier/response/parse_json.rb +25 -0
  59. data/lib/tradier/response/raise_error.rb +31 -0
  60. data/lib/tradier/symbol.rb +147 -0
  61. data/lib/tradier/timesales.rb +11 -0
  62. data/lib/tradier/version.rb +3 -0
  63. data/lib/tradier/watchlist.rb +16 -0
  64. data/lib/tradier/watchlist_item.rb +17 -0
  65. data/spec/fixtures/account_balances.json +28 -0
  66. data/spec/fixtures/account_gainloss.json +18 -0
  67. data/spec/fixtures/account_history.json +96 -0
  68. data/spec/fixtures/account_orders.json +833 -0
  69. data/spec/fixtures/account_positions.json +22 -0
  70. data/spec/fixtures/calendar.json +400 -0
  71. data/spec/fixtures/chain.json +2972 -0
  72. data/spec/fixtures/clock.json +10 -0
  73. data/spec/fixtures/expirations.json +18 -0
  74. data/spec/fixtures/history.json +2086 -0
  75. data/spec/fixtures/option_quote.json +14 -0
  76. data/spec/fixtures/option_quotes.json +26 -0
  77. data/spec/fixtures/order.json +1 -0
  78. data/spec/fixtures/order_with_warnings.json +17 -0
  79. data/spec/fixtures/placed_order.json +6 -0
  80. data/spec/fixtures/quote.json +45 -0
  81. data/spec/fixtures/quotes.json +88 -0
  82. data/spec/fixtures/session.json +6 -0
  83. data/spec/fixtures/strikes.json +173 -0
  84. data/spec/fixtures/timesales.json +2956 -0
  85. data/spec/fixtures/user_balances.json +118 -0
  86. data/spec/fixtures/user_gainloss.json +6775 -0
  87. data/spec/fixtures/user_history.json +101 -0
  88. data/spec/fixtures/user_orders.json +57 -0
  89. data/spec/fixtures/user_positions.json +50 -0
  90. data/spec/fixtures/user_profile.json +103 -0
  91. data/spec/fixtures/watchlist.json +30 -0
  92. data/spec/fixtures/watchlist_item.json +6 -0
  93. data/spec/fixtures/watchlists.json +18 -0
  94. data/spec/spec_helper.rb +64 -0
  95. data/spec/tradier/account_spec.rb +76 -0
  96. data/spec/tradier/api/accounts_spec.rb +195 -0
  97. data/spec/tradier/api/markets_spec.rb +219 -0
  98. data/spec/tradier/api/orders_spec.rb +94 -0
  99. data/spec/tradier/api/utils/expiration_spec.rb +8 -0
  100. data/spec/tradier/api/watchlists_spec.rb +164 -0
  101. data/spec/tradier/balance_spec.rb +4 -0
  102. data/spec/tradier/base_spec.rb +11 -0
  103. data/spec/tradier/calendar_spec.rb +27 -0
  104. data/spec/tradier/client_spec.rb +125 -0
  105. data/spec/tradier/clock_spec.rb +73 -0
  106. data/spec/tradier/error/client_error_spec.rb +22 -0
  107. data/spec/tradier/error/server_error_spec.rb +22 -0
  108. data/spec/tradier/error_spec.rb +26 -0
  109. data/spec/tradier/option_quote_spec.rb +61 -0
  110. data/spec/tradier/order_spec.rb +43 -0
  111. data/spec/tradier/position_spec.rb +4 -0
  112. data/spec/tradier/profile_spec.rb +28 -0
  113. data/spec/tradier/quote_spec.rb +29 -0
  114. data/spec/tradier/symbol_spec.rb +54 -0
  115. data/spec/tradier/watchlist_item_spec.rb +48 -0
  116. data/spec/tradier/watchlist_spec.rb +35 -0
  117. data/spec/tradier_spec.rb +105 -0
  118. data/tradier.gemspec +30 -0
  119. metadata +302 -0
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::API::Utils::Expiration do
4
+ it 'returns an empty array when response is null' do
5
+ expirations = Tradier::API::Utils::Expiration.new(:expirations => 'null')
6
+ expect(expirations.body).to be_empty
7
+ end
8
+ end
@@ -0,0 +1,164 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::API::Watchlists do
4
+
5
+ before do
6
+ @client = Tradier::Client.new
7
+ end
8
+
9
+ describe "#watchlists" do
10
+ before do
11
+ stub_get("/v1/watchlists").
12
+ to_return(:body => fixture("watchlists.json"), :headers => {:content_type => "application/json; charset=utf-8"})
13
+ end
14
+
15
+ it "requests the correct resource" do
16
+ @client.watchlists
17
+ expect(a_get("/v1/watchlists")).to have_been_made
18
+ end
19
+
20
+ it "returns an array of 'Tradier::Watchlist' objects" do
21
+ watchlists = @client.watchlists
22
+ expect(watchlists).to be_an Array
23
+ expect(watchlists.size).to eq(3)
24
+ expect(watchlists.first).to be_a Tradier::Watchlist
25
+ end
26
+ end
27
+
28
+ describe "#watchlist" do
29
+ before do
30
+ stub_get("/v1/watchlists/default").
31
+ to_return(:body => fixture("watchlist.json"), :headers => {:content_type => "application/json; charset=utf-8"})
32
+ end
33
+
34
+ it "requests the correct resource" do
35
+ @client.watchlist('default')
36
+ expect(a_get("/v1/watchlists/default")).to have_been_made
37
+ end
38
+
39
+ it "returns a 'Tradier::Watchlist' object" do
40
+ watchlist = @client.watchlist('default')
41
+ expect(watchlist).to be_a Tradier::Watchlist
42
+ end
43
+ end
44
+
45
+ describe "#delete_watchlist" do
46
+ before do
47
+ stub_delete("/v1/watchlists/default").
48
+ to_return(:body => '', :headers => {:content_type => "application/json; charset=utf-8"})
49
+ end
50
+
51
+ it "requests the correct resource" do
52
+ @client.delete_watchlist('default')
53
+ expect(a_delete("/v1/watchlists/default")).to have_been_made
54
+ end
55
+
56
+ it "returns a 'Tradier::Watchlist' object" do
57
+ status = @client.delete_watchlist('default')
58
+ expect(status).to be_true
59
+ end
60
+ end
61
+
62
+ describe "#create_watchlist" do
63
+ before do
64
+ stub_post("/v1/watchlists").
65
+ to_return(:body => fixture('watchlist.json'), :headers => {:content_type => "application/json; charset=utf-8"})
66
+ end
67
+
68
+ it "requests the correct resource" do
69
+ @client.create_watchlist(:name => 'default')
70
+ expect(a_post("/v1/watchlists")).to have_been_made
71
+ end
72
+
73
+ it "returns a 'Tradier::Watchlist' object" do
74
+ status = @client.create_watchlist(:name => 'default')
75
+ expect(status).to be_a Tradier::Watchlist
76
+ end
77
+ end
78
+
79
+ describe "#update_watchlist" do
80
+ before do
81
+ stub_put("/v1/watchlists/default").
82
+ to_return(:body => fixture('watchlist.json'), :headers => {:content_type => "application/json; charset=utf-8"})
83
+ end
84
+
85
+ it "requests the correct resource" do
86
+ @client.update_watchlist('default', :symbols => 'AAPL,GOOG')
87
+ expect(a_put("/v1/watchlists/default")).to have_been_made
88
+ end
89
+
90
+ it "returns a 'Tradier::Watchlist' object" do
91
+ status = @client.update_watchlist('default', :symbols => 'AAPL,GOOG')
92
+ expect(status).to be_a Tradier::Watchlist
93
+ end
94
+ end
95
+
96
+ describe '#watchlist_item' do
97
+ before do
98
+ stub_get("/v1/watchlists/default/symbols/aapl").
99
+ to_return(:body => fixture('watchlist_item.json'), :headers => {:content_type => "application/json; charset=utf-8"})
100
+ end
101
+
102
+ it "requests the correct resource" do
103
+ @client.watchlist_item('default', 'aapl')
104
+ expect(a_get("/v1/watchlists/default/symbols/aapl")).to have_been_made
105
+ end
106
+
107
+ it "returns a 'Tradier::WatchlistItem' object" do
108
+ status = @client.watchlist_item('default', 'aapl')
109
+ expect(status).to be_a Tradier::WatchlistItem
110
+ end
111
+ end
112
+
113
+ describe '#add_watchlist_item' do
114
+ before do
115
+ stub_post("/v1/watchlists/default/symbols").
116
+ to_return(:body => fixture('watchlist_item.json'), :headers => {:content_type => "application/json; charset=utf-8"})
117
+ end
118
+
119
+ it "requests the correct resource" do
120
+ @client.add_watchlist_item('default', :symbols => 'aapl')
121
+ expect(a_post("/v1/watchlists/default/symbols")).to have_been_made
122
+ end
123
+
124
+ it "returns a 'Tradier::Watchlist' object" do
125
+ status = @client.add_watchlist_item('default', :symbols => 'aapl')
126
+ expect(status).to be_a Tradier::WatchlistItem
127
+ end
128
+ end
129
+
130
+ describe '#remove_watchlist_item' do
131
+ before do
132
+ stub_delete("/v1/watchlists/default/symbols/aapl").
133
+ to_return(:headers => {:content_type => "application/json; charset=utf-8"})
134
+ end
135
+
136
+ it "requests the correct resource" do
137
+ @client.remove_watchlist_item('default', 'aapl')
138
+ expect(a_delete("/v1/watchlists/default/symbols/aapl")).to have_been_made
139
+ end
140
+
141
+ it "returns a 'Tradier::WatchlistItem' object" do
142
+ status = @client.remove_watchlist_item('default', 'aapl')
143
+ expect(status).to be_true
144
+ end
145
+ end
146
+
147
+ describe '#update_watchlist_item' do
148
+ before do
149
+ stub_put("/v1/watchlists/default/symbols/aapl").
150
+ to_return(:body => fixture('watchlist_item.json'), :headers => {:content_type => "application/json; charset=utf-8"})
151
+ end
152
+
153
+ it "requests the correct resource" do
154
+ @client.update_watchlist_item('default', 'aapl', :shares => 100)
155
+ expect(a_put("/v1/watchlists/default/symbols/aapl")).to have_been_made
156
+ end
157
+
158
+ it "returns a 'Tradier::Watchlist' object" do
159
+ status = @client.update_watchlist_item('default', 'aapl', :shares => 100)
160
+ expect(status).to be_a Tradier::WatchlistItem
161
+ end
162
+ end
163
+
164
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::Balance do
4
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::Base do
4
+
5
+ describe '#attrs' do
6
+ it 'returns a hash of attributes' do
7
+ expect(Tradier::Base.new(:id => 1).attrs).to eq({:id => 1})
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::Calendar do
4
+
5
+ describe "#month" do
6
+ it "returns the month when set" do
7
+ calendar = Tradier::Calendar.new({ :calendar => { :days => { :month => 6 }}})
8
+ expect(calendar.month).to eq(6)
9
+ end
10
+ it "returns nil when month is not set" do
11
+ calendar = Tradier::Calendar.new({ :calendar => { :days => {}}})
12
+ expect(calendar.month).to be_nil
13
+ end
14
+ end
15
+
16
+ describe "#year" do
17
+ it "returns the year when set" do
18
+ calendar = Tradier::Calendar.new({ :calendar => { :days => { :year => 2013 }}})
19
+ expect(calendar.year).to eq(2013)
20
+ end
21
+ it "returns nil when year is not set" do
22
+ calendar = Tradier::Calendar.new({ :calendar => { :days => {}}})
23
+ expect(calendar.year).to be_nil
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::Client do
4
+
5
+ subject do
6
+ Tradier::Client.new(:access_token => "AT")
7
+ end
8
+
9
+ context "with module configuration" do
10
+
11
+ before do
12
+ Tradier.configure do |config|
13
+ Tradier::Configurable.keys.each do |key|
14
+ config.send("#{key}=", key)
15
+ end
16
+ end
17
+ end
18
+
19
+ after do
20
+ Tradier.reset!
21
+ end
22
+
23
+ it "inherits the module configuration" do
24
+ client = Tradier::Client.new
25
+ Tradier::Configurable.keys.each do |key|
26
+ expect(client.instance_variable_get(:"@#{key}")).to eq key
27
+ end
28
+ end
29
+
30
+ context "with class configuration" do
31
+
32
+ before do
33
+ @configuration = {
34
+ :connection_options => {:timeout => 10},
35
+ :access_token => "AT",
36
+ :endpoint => 'https://api.tradierbrokerage.com/',
37
+ :middleware => Proc.new{},
38
+ :version => 'v2'
39
+ }
40
+ end
41
+
42
+ context "during initialization" do
43
+ it "overrides the module configuration" do
44
+ client = Tradier::Client.new(@configuration)
45
+ Tradier::Configurable.keys.each do |key|
46
+ expect(client.instance_variable_get(:"@#{key}")).to eq @configuration[key]
47
+ end
48
+ end
49
+ end
50
+
51
+ context "after initialization" do
52
+ it "overrides the module configuration after initialization" do
53
+ client = Tradier::Client.new
54
+ client.configure do |config|
55
+ @configuration.each do |key, value|
56
+ config.send("#{key}=", value)
57
+ end
58
+ end
59
+ Tradier::Configurable.keys.each do |key|
60
+ expect(client.instance_variable_get(:"@#{key}")).to eq @configuration[key]
61
+ end
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+
68
+ describe "#delete" do
69
+ before do
70
+ stub_delete("/v1/custom/delete").with(:query => {:deleted => "object"})
71
+ end
72
+ it "allows custom delete requests" do
73
+ subject.delete("/custom/delete", {:deleted => "object"})
74
+ expect(a_delete("/v1/custom/delete").with(:query => {:deleted => "object"})).to have_been_made
75
+ end
76
+ end
77
+
78
+ describe "#put" do
79
+ before do
80
+ stub_put("/v1/custom/put").with(:body => {:updated => "object"})
81
+ end
82
+ it "allows custom put requests" do
83
+ subject.put("/custom/put", {:updated => "object"})
84
+ expect(a_put("/v1/custom/put").with(:body => {:updated => "object"})).to have_been_made
85
+ end
86
+ end
87
+
88
+ describe "#credentials?" do
89
+ it "returns true if all credentials are present" do
90
+ client = Tradier::Client.new(:access_token => "AT")
91
+ expect(client.credentials?).to be_true
92
+ end
93
+ it "returns false if any credentials are missing" do
94
+ client = Tradier::Client.new
95
+ expect(client.credentials?).to be_false
96
+ end
97
+ end
98
+
99
+ describe "#connection" do
100
+ it "looks like Faraday connection" do
101
+ expect(subject.send(:connection)).to respond_to(:run_request)
102
+ end
103
+ it "memoizes the connection" do
104
+ c1, c2 = subject.send(:connection), subject.send(:connection)
105
+ expect(c1.object_id).to eq c2.object_id
106
+ end
107
+ end
108
+
109
+ describe "#request" do
110
+ it "encodes the entire body when no uploaded media is present" do
111
+ stub_get("/v1/markets/quotes").with(:query => {:symbols => "AAPL"}).to_return(:body => fixture("quote.json"), :headers => {:content_type => "application/json; charset=utf-8"})
112
+ subject.quotes("AAPL")
113
+ expect(a_get("/v1/markets/quotes").with(:query => {:symbols => "AAPL"})).to have_been_made
114
+ end
115
+ it "catches Faraday errors" do
116
+ subject.stub(:connection).and_raise(Faraday::Error::ClientError.new("Oops"))
117
+ expect{subject.send(:request, :get, "/path")}.to raise_error Tradier::Error::ClientError
118
+ end
119
+ it "catches MultiJson::DecodeError errors" do
120
+ subject.stub(:connection).and_raise(MultiJson::DecodeError.new("unexpected token", [], "<!DOCTYPE html>"))
121
+ expect{subject.send(:request, :get, "/path")}.to raise_error Tradier::Error::DecodeError
122
+ end
123
+ end
124
+
125
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::Clock do
4
+
5
+ describe "#date" do
6
+ it "returns the date when set" do
7
+ clock = Tradier::Clock.new({ :date => '2013-07-04' })
8
+ expect(clock.date).to be_a Date
9
+ expect(clock.date.to_s).to eq('2013-07-04')
10
+ end
11
+ it "returns nil when date is not set" do
12
+ clock = Tradier::Clock.new('clock' => {})
13
+ expect(clock.date).to be_nil
14
+ end
15
+ end
16
+
17
+ describe "#time" do
18
+ it "returns the timestamp when set" do
19
+ clock = Tradier::Clock.new({ :timestamp => 1372103978 })
20
+ expect(clock.time).to be_a Time
21
+ expect(clock.time.utc.to_s).to eq('2013-06-24 19:59:38 UTC')
22
+ end
23
+ it "returns nil when time is not set" do
24
+ clock = Tradier::Clock.new('clock' => {})
25
+ expect(clock.time).to be_nil
26
+ end
27
+ end
28
+
29
+ describe "#description" do
30
+ it "returns the date when set" do
31
+ clock = Tradier::Clock.new({ :description => 'Market is closed.' })
32
+ expect(clock.description).to eq('Market is closed.')
33
+ end
34
+ it "returns nil when description is not set" do
35
+ clock = Tradier::Clock.new('clock' => {})
36
+ expect(clock.description).to be_nil
37
+ end
38
+ end
39
+
40
+ describe "#next_change" do
41
+ it "returns the date when set" do
42
+ clock = Tradier::Clock.new({ :next_change => '08:00' })
43
+ expect(clock.next_change).to eq('08:00')
44
+ end
45
+ it "returns nil when next_change is not set" do
46
+ clock = Tradier::Clock.new('clock' => {})
47
+ expect(clock.next_change).to be_nil
48
+ end
49
+ end
50
+
51
+ describe "#next_state" do
52
+ it "returns the date when set" do
53
+ clock = Tradier::Clock.new({ :next_state => 'premarket' })
54
+ expect(clock.next_state).to eq('premarket')
55
+ end
56
+ it "returns nil when next_state is not set" do
57
+ clock = Tradier::Clock.new('clock' => {})
58
+ expect(clock.next_state).to be_nil
59
+ end
60
+ end
61
+
62
+ describe "#state" do
63
+ it "returns the date when set" do
64
+ clock = Tradier::Clock.new({ :state => 'closed' })
65
+ expect(clock.state).to eq('closed')
66
+ end
67
+ it "returns nil when state is not set" do
68
+ clock = Tradier::Clock.new('clock' => {})
69
+ expect(clock.state).to be_nil
70
+ end
71
+ end
72
+
73
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::Error::ClientError do
4
+
5
+ before do
6
+ @client = Tradier::Client.new
7
+ end
8
+
9
+ Tradier::Error::ClientError.errors.each do |status, exception|
10
+ context "when HTTP status is #{status}" do
11
+ before do
12
+ stub_get("/v1/markets/quotes").
13
+ with(:query => {:symbols => 'AAPL'}).
14
+ to_return(:status => status, :body => "Oops! We got a #{exception}")
15
+ end
16
+ it "raises #{exception.name}" do
17
+ expect{@client.quotes('AAPL')}.to raise_error exception
18
+ end
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tradier::Error::ServerError do
4
+
5
+ before do
6
+ @client = Tradier::Client.new
7
+ end
8
+
9
+ Tradier::Error::ServerError.errors.each do |status, exception|
10
+ context "when HTTP status is #{status}" do
11
+ before do
12
+ stub_get("/v1/markets/quotes").
13
+ with(:query => {:symbols => 'AAPL'}).
14
+ to_return(:status => status)
15
+ end
16
+ it "raises #{exception.name}" do
17
+ expect{@client.quotes('AAPL')}.to raise_error exception
18
+ end
19
+ end
20
+ end
21
+
22
+ end