robinhood-api 0.4.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +5 -5
  2. data/lib/robinhood/api.rb +232 -0
  3. metadata +4 -4
  4. data/lib/robinhood.rb +0 -249
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: eb1a905cad6bb6ae3fb150ff653b2e82f14652f1
4
- data.tar.gz: 34f062042df628a04bac595cc4ce8a1ce26186e6
2
+ SHA256:
3
+ metadata.gz: 81ac293079b6363a879823566ebb18d622c40882f5a9a66ed1d62569ae12b288
4
+ data.tar.gz: ab0fe7c48885d4a2489629b37edec1f31b25679b0b5289be3c559c1e01f28e8d
5
5
  SHA512:
6
- metadata.gz: 2398720f646d2326ae3fe356a9fa1ae24c0014ea6540132ca827a6a96be22aa6851bad03ae20c27f55d74b76e785bd851a9716c88a2d81aa33ed0716f4dfb76a
7
- data.tar.gz: 529e73b047f8d64cfaf1cabdfa061e56e66d3b2e556f76af875c996cb8d9fd72c45e2fa1ded5865db008f533fa1c5d564458d5e40a64a106dd756add25e62b3f
6
+ metadata.gz: c99809c83fc0abcaac0e36625db1b8f7e7f5c8d0ba75016136b2c828d481fb0c3b66c2b35cc8c454eee16c349820c44d26ae9e574f3ed105e49b67f4d7ce779a
7
+ data.tar.gz: 053762a01c049948191ad17bc61baf903fb4d16b59d2f20057f603af7608510a2795feb6754ba26498fa8756881ccfac29c6f0982b7b808f26603195285b914e
@@ -0,0 +1,232 @@
1
+ require 'date'
2
+
3
+ module Robinhood
4
+ # The API module check for methods that require login.
5
+ module ApiModule
6
+ # Your code goes here...
7
+ def self.before(*names)
8
+ names.each do |name|
9
+ m = instance_method(name)
10
+ define_method(name) do |*args, &block|
11
+ if token_compliant?(name)
12
+ m.bind(self).call(*args, &block)
13
+ else
14
+ puts 'You have to run the login(<username>, <password>) method ' \
15
+ "or a Robinhood.new instance before running the #{name} method"
16
+ exit 1
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ # The API module instance methods
24
+ module ApiModule
25
+ require 'httparty'
26
+ require 'json'
27
+
28
+ require_relative './api/orders'
29
+
30
+ include HTTParty
31
+
32
+ attr_accessor :errors
33
+
34
+ def initialize; end
35
+
36
+ def login(username, password)
37
+ raw_response = HTTParty.post(
38
+ endpoints[:login],
39
+ body: {
40
+ 'password' => password,
41
+ 'username' => username
42
+ },
43
+ headers: headers
44
+ )
45
+ response = JSON.parse(raw_response.body)
46
+ if response['token']
47
+ response = response['token']
48
+ @headers['Authorization'] = "Token #{response}"
49
+ end
50
+ response
51
+ end
52
+
53
+ def investment_profile
54
+ raw_response = HTTParty.get(
55
+ endpoints[:investment_profile], headers: headers
56
+ )
57
+ JSON.parse(raw_response.body)
58
+ end
59
+
60
+ def accounts
61
+ raw_response = HTTParty.get(endpoints[:accounts], headers: headers)
62
+ JSON.parse(raw_response.body)
63
+ end
64
+
65
+ def portfolio(account_number)
66
+ raw_response = HTTParty.get(
67
+ "https://api.robinhood.com/accounts/#{account_number}/portfolio/",
68
+ headers: headers
69
+ )
70
+ JSON.parse(raw_response.body)
71
+ end
72
+
73
+ def instruments(symbol)
74
+ if symbol.include?('-')
75
+ raw_response = HTTParty.get(
76
+ "#{endpoints[:instruments]}#{symbol}/", headers: headers
77
+ )
78
+ else
79
+ raw_response = HTTParty.get(
80
+ endpoints[:instruments],
81
+ query: { 'query' => symbol.upcase },
82
+ headers: headers
83
+ )
84
+ end
85
+
86
+ JSON.parse(raw_response.body)
87
+ end
88
+
89
+ def quote(symbol)
90
+ raw_response = HTTParty.get(
91
+ "https://api.robinhood.com/quotes/#{symbol}/",
92
+ headers: headers
93
+ )
94
+ JSON.parse(raw_response.body)
95
+ end
96
+
97
+ def positions(account_number, instrument_id = nil)
98
+ url = "https://api.robinhood.com/accounts/#{account_number}/positions"
99
+ url = "#{url}/#{instrument_id}/" if instrument_id
100
+ raw_response = HTTParty.get(url, headers: headers)
101
+ JSON.parse(raw_response.body)
102
+ end
103
+
104
+ private
105
+
106
+ def endpoints
107
+ {
108
+ login: 'https://api.robinhood.com/api-token-auth/',
109
+ investment_profile: 'https://api.robinhood.com/user/investment_profile/',
110
+ accounts: 'https://api.robinhood.com/accounts/',
111
+ ach_iav_auth: 'https://api.robinhood.com/ach/iav/auth/',
112
+ ach_relationships: 'https://api.robinhood.com/ach/relationships/',
113
+ ach_transfers: 'https://api.robinhood.com/ach/transfers/',
114
+ applications: 'https://api.robinhood.com/applications/',
115
+ dividends: 'https://api.robinhood.com/dividends/',
116
+ edocuments: 'https://api.robinhood.com/documents/',
117
+ instruments: 'https://api.robinhood.com/instruments/',
118
+ margin_upgrade: 'https://api.robinhood.com/margin/upgrades/',
119
+ markets: 'https://api.robinhood.com/markets/',
120
+ notifications: 'https://api.robinhood.com/notifications/',
121
+ orders: 'https://api.robinhood.com/orders/',
122
+ password_reset: 'https://api.robinhood.com/password_reset/request/',
123
+ quotes: 'https://api.robinhood.com/quotes/',
124
+ document_requests: 'https://api.robinhood.com/upload/document_requests/',
125
+ user: 'https://api.robinhood.com/user/',
126
+ watchlists: 'https://api.robinhood.com/watchlists/'
127
+ }
128
+ end
129
+
130
+ def methodlist
131
+ %i[investment_profile accounts ach_iav_auth ach_relationships
132
+ ach_transfers applications dividends edocuments margin_upgrade
133
+ notifications orders password_reset document_requests user watchlists]
134
+ end
135
+
136
+ def headers
137
+ @headers ||= {
138
+ 'Accept' => 'application/json'
139
+ }
140
+ end
141
+
142
+ def token_compliant?(method)
143
+ if methodlist.include?(method)
144
+ if headers.key?('Authorization')
145
+ true
146
+ else
147
+ false
148
+ end
149
+ else
150
+ true
151
+ end
152
+ end
153
+
154
+ # before(*instance_methods) { puts 'start' }
155
+ end
156
+
157
+ # Robinhood API's class methods
158
+ class Api
159
+ include ApiModule
160
+
161
+ def self.flatten(var)
162
+ new_var = {}
163
+ var.each do |k, v|
164
+ if v.class == Hash
165
+ v.each do |l, w|
166
+ new_var[l] = w
167
+ end
168
+ else
169
+ new_var[k] = v
170
+ end
171
+ end
172
+ new_var
173
+ end
174
+
175
+ def self.sanitize(var)
176
+ var.delete('updated_at') if var.keys.include?('updated_at')
177
+
178
+ var.delete('created_at') if var.keys.include?('created_at')
179
+
180
+ new_var = {}
181
+ var.each do |k, v|
182
+ key = k
183
+ key = 'object_type' if key == 'type'
184
+ key = 'third_party_id' if key == 'id'
185
+ if v.class == String
186
+ if v.include?('T') && v.include?('Z')
187
+ begin
188
+ new_var[key] = Time.parse(v)
189
+ rescue StandardError
190
+ new_var[key] = v
191
+ end
192
+ else
193
+ begin
194
+ new_var[key] = Float(v)
195
+ rescue StandardError
196
+ new_var[key] = v
197
+ end
198
+ end
199
+ end
200
+ end
201
+ new_var
202
+ end
203
+
204
+ def self.strip(str)
205
+ str.split('/').last
206
+ end
207
+
208
+ def self.fix(var)
209
+ if var.class == Hash
210
+ fix_hash(var)
211
+ elsif var.class == Array
212
+ arr = []
213
+ var.each do |ha|
214
+ arr << fix_hash(ha)
215
+ end
216
+ arr
217
+ end
218
+ end
219
+
220
+ def self.fix_hash(var)
221
+ instance = var.clone
222
+ instance = flatten(instance)
223
+ instance = sanitize(instance)
224
+ keys = %w[account instrument position quote market fundamentals]
225
+ keys.each do |key|
226
+ instance[key] = strip(instance[key]) if instance.key?(key)
227
+ end
228
+
229
+ instance
230
+ end
231
+ end
232
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: robinhood-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Alcala
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-28 00:00:00.000000000 Z
11
+ date: 2018-04-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Get the most of Robinhood: accounts, positions, portfolio, buy and sell
14
14
  securities, etc.'
@@ -17,7 +17,7 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - lib/robinhood.rb
20
+ - lib/robinhood/api.rb
21
21
  homepage: https://github.com/ThomasMarcel/robinhood-api
22
22
  licenses:
23
23
  - MIT
@@ -38,7 +38,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
38
  version: '0'
39
39
  requirements: []
40
40
  rubyforge_project:
41
- rubygems_version: 2.6.11
41
+ rubygems_version: 2.7.6
42
42
  signing_key:
43
43
  specification_version: 4
44
44
  summary: Calling the Robinhood API
@@ -1,249 +0,0 @@
1
- module RobinhoodModule
2
- def self.before(*names)
3
- names.each do |name|
4
- m = instance_method(name)
5
- define_method(name) do |*args, &block|
6
- if token_compliant?(name)
7
- m.bind(self).(*args, &block)
8
- else
9
- puts "You have to run the login(<username>, <password>) method or a Robinhood.new instance before running the #{name} method"
10
- exit 1
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- module RobinhoodModule
18
- require 'httparty'
19
- require 'json'
20
-
21
- include HTTParty
22
-
23
- attr_accessor :errors
24
-
25
- def initialize
26
- end
27
-
28
- def login(username, password)
29
- raw_response = HTTParty.post(
30
- endpoints[:login],
31
- body: {
32
- 'password' => password,
33
- 'username'=> username
34
- },
35
- headers: headers
36
- )
37
- response = JSON.parse(raw_response.body)
38
- if response['token']
39
- response = response['token']
40
- @headers['Authorization'] = "Token #{response}"
41
- end
42
- return response
43
- end
44
-
45
- def investment_profile
46
- raw_response = HTTParty.get(endpoints[:investment_profile], headers: headers)
47
- JSON.parse(raw_response.body)
48
- end
49
-
50
- def orders(order_id=nil)
51
- url = order_id ? "#{endpoints[:orders]}#{order_id}" : endpoints[:orders]
52
- raw_response = HTTParty.get(url, headers: headers)
53
- JSON.parse(raw_response.body)
54
- end
55
-
56
- def accounts
57
- raw_response = HTTParty.get(endpoints[:accounts], headers: headers)
58
- JSON.parse(raw_response.body)
59
- end
60
-
61
- def portfolio(account_number)
62
- raw_response = HTTParty.get("https://api.robinhood.com/accounts/#{account_number}/portfolio/", headers: headers)
63
- JSON.parse(raw_response.body)
64
- end
65
-
66
- def instruments(symbol)
67
- if symbol.include?('-')
68
- raw_response = HTTParty.get("#{endpoints[:instruments]}#{symbol}/", headers: headers)
69
- else
70
- raw_response = HTTParty.get(endpoints[:instruments], query: {'query' => symbol.upcase}, headers: headers)
71
- end
72
-
73
- JSON.parse(raw_response.body)
74
- end
75
-
76
- def quote(symbol)
77
- raw_response = HTTParty.get("https://api.robinhood.com/quotes/#{symbol}/", headers: headers)
78
- JSON.parse(raw_response.body)
79
- end
80
-
81
- def buy(account_number, symbol, instrument_id, price, quantity)
82
- raw_response = HTTParty.post(
83
- endpoints[:orders],
84
- body: {
85
- 'account' => "https://api.robinhood.com/accounts/#{account_number}/",
86
- 'instrument' => "https://api.robinhood.com/instruments/#{instrument_id}/",
87
- 'price' => price,
88
- 'quantity' => quantity,
89
- 'side' => "buy",
90
- 'symbol' => symbol,
91
- 'time_in_force' => 'gfd',
92
- 'trigger' => 'immediate',
93
- 'type' => 'market'
94
- },
95
- headers: headers
96
- )
97
-
98
- JSON.parse(raw_response.body)
99
- end
100
-
101
- def limit_buy(account_number, symbol, instrument_id, price, quantity)
102
- raw_response = HTTParty.post(
103
- endpoints[:orders],
104
- body: {
105
- 'account' => "https://api.robinhood.com/accounts/#{account_number}/",
106
- 'instrument' => "https://api.robinhood.com/instruments/#{instrument_id}/",
107
- 'price' => price,
108
- 'quantity' => quantity,
109
- 'side' => "buy",
110
- 'symbol' => symbol,
111
- 'time_in_force' => 'gfd',
112
- 'trigger' => 'immediate',
113
- 'type' => 'limit'
114
- }.to_json,
115
- headers: headers
116
- )
117
-
118
- JSON.parse(raw_response.body)
119
- end
120
-
121
- def sell(account_number, symbol, instrument_id, price, quantity)
122
- raw_response = HTTParty.post(
123
- endpoints[:orders],
124
- body: {
125
- 'account' => "https://api.robinhood.com/accounts/#{account_number}/",
126
- 'instrument' => "https://api.robinhood.com/instruments/#{instrument_id}/",
127
- 'price' => price,
128
- 'quantity' => quantity,
129
- 'side' => "sell",
130
- 'symbol' => symbol,
131
- 'time_in_force' => 'gfd',
132
- 'trigger' => 'immediate',
133
- 'type' => 'market'
134
- },
135
- headers: headers
136
- )
137
-
138
- JSON.parse(raw_response.body)
139
- end
140
-
141
- def limit_sell(account_number, symbol, instrument_id, price, quantity)
142
- raw_response = HTTParty.post(
143
- endpoints[:orders],
144
- body: {
145
- 'account' => "https://api.robinhood.com/accounts/#{account_number}/",
146
- 'instrument' => "https://api.robinhood.com/instruments/#{instrument_id}/",
147
- 'price' => price,
148
- 'quantity' => quantity,
149
- 'side' => "sell",
150
- 'symbol' => symbol,
151
- 'time_in_force' => 'gfd',
152
- 'trigger' => 'immediate',
153
- 'type' => 'limit'
154
- }.to_json,
155
- headers: headers
156
- )
157
-
158
- JSON.parse(raw_response.body)
159
- end
160
-
161
- def stop_loss_sell(account_number, symbol, instrument_id, price, quantity)
162
- raw_response = HTTParty.post(
163
- endpoints[:orders],
164
- body: {
165
- 'account' => "https://api.robinhood.com/accounts/#{account_number}/",
166
- 'instrument' => "https://api.robinhood.com/instruments/#{instrument_id}/",
167
- 'stop_price' => price,
168
- 'quantity' => quantity,
169
- 'side' => "sell",
170
- 'symbol' => symbol,
171
- 'time_in_force' => 'gtc',
172
- 'trigger' => 'stop',
173
- 'type' => 'market'
174
- }.to_json,
175
- headers: headers
176
- )
177
-
178
- JSON.parse(raw_response.body)
179
- end
180
-
181
- def cancel_order(order_id)
182
- raw_response = HTTParty.post("https://api.robinhood.com/orders/#{order_id}/cancel/", headers: headers)
183
- raw_response.code == 200
184
- end
185
-
186
- def positions(account_number, instrument_id = nil)
187
- url = "https://api.robinhood.com/accounts/#{account_number}/positions"
188
- if instrument_id
189
- url = "#{url}/#{instrument_id}/"
190
- end
191
- raw_response = HTTParty.get(url, headers: headers)
192
- JSON.parse(raw_response.body)
193
- end
194
-
195
- private
196
-
197
- def endpoints
198
- {
199
- login: 'https://api.robinhood.com/api-token-auth/',
200
- investment_profile: 'https://api.robinhood.com/user/investment_profile/',
201
- accounts: 'https://api.robinhood.com/accounts/',
202
- ach_iav_auth: 'https://api.robinhood.com/ach/iav/auth/',
203
- ach_relationships: 'https://api.robinhood.com/ach/relationships/',
204
- ach_transfers: 'https://api.robinhood.com/ach/transfers/',
205
- applications: 'https://api.robinhood.com/applications/',
206
- dividends: 'https://api.robinhood.com/dividends/',
207
- edocuments: 'https://api.robinhood.com/documents/',
208
- instruments: 'https://api.robinhood.com/instruments/',
209
- margin_upgrade: 'https://api.robinhood.com/margin/upgrades/',
210
- markets: 'https://api.robinhood.com/markets/',
211
- notifications: 'https://api.robinhood.com/notifications/',
212
- orders: 'https://api.robinhood.com/orders/',
213
- password_reset: 'https://api.robinhood.com/password_reset/request/',
214
- quotes: 'https://api.robinhood.com/quotes/',
215
- document_requests: 'https://api.robinhood.com/upload/document_requests/',
216
- user: 'https://api.robinhood.com/user/',
217
- watchlists: 'https://api.robinhood.com/watchlists/'
218
- }
219
- end
220
-
221
- def methodlist
222
- [:investment_profile, :accounts, :ach_iav_auth, :ach_relationships, :ach_transfers, :applications, :dividends, :edocuments, :margin_upgrade, :notifications, :orders, :password_reset, :document_requests, :user, :watchlists]
223
- end
224
-
225
- def headers
226
- @headers ||= {
227
- 'Accept' => 'application/json',
228
- }
229
- end
230
-
231
- def token_compliant?(method)
232
-
233
- if methodlist.include?(method)
234
- if headers.key?('Authorization')
235
- return true
236
- else
237
- return false
238
- end
239
- else
240
- return true
241
- end
242
- end
243
-
244
- before(*instance_methods) { puts "start" }
245
- end
246
-
247
- class Robinhood
248
- include RobinhoodModule
249
- end