tradier 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 (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