robinhood-api 0.4.4 → 0.6.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 (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