robinhood-ruby 0.3.5 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/example/robinhood-sample/Gemfile.lock +5 -1
- data/example/robinhood-sample/config/initializers/robinhood.rb +1 -1
- data/lib/robinhood-ruby.rb +19 -17
- data/lib/robinhood-ruby/rest/api.rb +141 -123
- data/lib/robinhood-ruby/rest/client.rb +39 -57
- data/lib/robinhood-ruby/rest/endpoints.rb +49 -0
- data/lib/robinhood-ruby/util/request.rb +0 -42
- data/lib/robinhood-ruby/version.rb +1 -1
- data/robinhood-ruby.gemspec +11 -10
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed4e4fe2c505118eb5b522956d1c86ac52ce7451
|
4
|
+
data.tar.gz: 3441713ad67a76c1efc7f0f7bdbf0fa691cfc54b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3bf890bcff3fb275fe401d5fbee547b85e0ef13277a02a611aa4c41e154b1af8eeaf33b7483e36e366727efe3475c0f5f87294ac0f3c0c9dd588e9e845a8004
|
7
|
+
data.tar.gz: 6e26ec7a0142ac4f75fa3febc39bbe6d948401aecc797e277b6d08ff974bfdfdeee9fd73c1143ee0a392d1db802e4124cd92d7151f8b065a7a8247617bf966d2
|
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../..
|
3
3
|
specs:
|
4
|
-
robinhood-ruby (0.3
|
4
|
+
robinhood-ruby (0.4.3)
|
5
5
|
builder (>= 2.1.2)
|
6
|
+
httparty
|
6
7
|
jwt (~> 1.0)
|
7
8
|
multi_json (>= 1.3.0)
|
8
9
|
rack
|
@@ -65,6 +66,8 @@ GEM
|
|
65
66
|
execjs (2.7.0)
|
66
67
|
globalid (0.3.7)
|
67
68
|
activesupport (>= 4.1.0)
|
69
|
+
httparty (0.14.0)
|
70
|
+
multi_xml (>= 0.5.2)
|
68
71
|
i18n (0.7.0)
|
69
72
|
jquery-rails (4.2.1)
|
70
73
|
rails-dom-testing (>= 1, < 3)
|
@@ -83,6 +86,7 @@ GEM
|
|
83
86
|
mini_portile2 (2.1.0)
|
84
87
|
minitest (5.10.1)
|
85
88
|
multi_json (1.12.1)
|
89
|
+
multi_xml (0.6.0)
|
86
90
|
nokogiri (1.6.8.1)
|
87
91
|
mini_portile2 (~> 2.1.0)
|
88
92
|
pry (0.10.4)
|
@@ -1 +1 @@
|
|
1
|
-
@robinhood = Robinhood::REST::Client.new(ENV['robinhood_username'], ENV['robinhood_password'])
|
1
|
+
# @robinhood = Robinhood::REST::Client.new(ENV['robinhood_username'], ENV['robinhood_password'])
|
data/lib/robinhood-ruby.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
1
|
+
require "net/http"
|
2
|
+
require "net/https"
|
3
|
+
require "builder"
|
4
|
+
require "multi_json"
|
5
|
+
require "cgi"
|
6
|
+
require "openssl"
|
7
|
+
require "base64"
|
8
|
+
require "forwardable"
|
9
|
+
require "singleton"
|
10
|
+
require "httparty"
|
10
11
|
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
12
|
+
require "robinhood-ruby/version" unless defined?(Robinhood::VERSION)
|
13
|
+
require "robinhood-ruby"
|
14
|
+
require "robinhood-ruby/util"
|
15
|
+
require "robinhood-ruby/util/configuration"
|
16
|
+
require "robinhood-ruby/util/request"
|
17
|
+
require "robinhood-ruby/rest/endpoints"
|
18
|
+
require "robinhood-ruby/rest/api"
|
19
|
+
require "robinhood-ruby/rest/client"
|
18
20
|
|
19
21
|
module Robinhood
|
20
22
|
extend SingleForwardable
|
@@ -22,7 +24,7 @@ module Robinhood
|
|
22
24
|
def_delegators :configuration, :username, :password
|
23
25
|
|
24
26
|
##
|
25
|
-
# Pre-configure with account SID and auth token so that you don
|
27
|
+
# Pre-configure with account SID and auth token so that you don"t need to
|
26
28
|
# pass them to various initializers each time.
|
27
29
|
def self.configure(&block)
|
28
30
|
yield configuration
|
@@ -2,151 +2,168 @@ module Robinhood
|
|
2
2
|
module REST
|
3
3
|
class API
|
4
4
|
def account
|
5
|
-
|
6
|
-
|
7
|
-
puts response.read_body
|
8
|
-
JSON.parse(response.read_body)
|
5
|
+
raw_response = HTTParty.get(endpoints[:accounts], headers: headers)
|
6
|
+
JSON.parse(raw_response.body)
|
9
7
|
end
|
10
8
|
|
11
9
|
def investment_profile
|
12
|
-
|
13
|
-
|
14
|
-
puts response.read_body
|
15
|
-
JSON.parse(response.read_body)
|
10
|
+
raw_response = HTTParty.get(endpoints[:investment_profile], headers: headers)
|
11
|
+
JSON.parse(raw_response.body)
|
16
12
|
end
|
17
13
|
|
18
14
|
def fundamentals(ticker)
|
19
|
-
|
20
|
-
|
21
|
-
puts response.read_body
|
22
|
-
JSON.parse(response.read_body)
|
15
|
+
raw_response = HTTParty.get(endpoints[:fundamentals], query: {"symbols" => ticker.upcase}, headers: headers)
|
16
|
+
JSON.parse(raw_response.body)
|
23
17
|
end
|
24
18
|
|
25
19
|
def instruments(symbol)
|
26
|
-
|
27
|
-
|
28
|
-
puts response.read_body
|
29
|
-
JSON.parse(response.read_body)
|
20
|
+
raw_response = HTTParty.get(endpoints[:instruments], query: {"query" => symbol.upcase}, headers: headers)
|
21
|
+
JSON.parse(raw_response.body)
|
30
22
|
end
|
31
23
|
|
32
24
|
def quote_data(symbol)
|
33
|
-
|
34
|
-
|
35
|
-
response = http_request(url)
|
36
|
-
puts response.read_body
|
37
|
-
JSON.parse(response.read_body)
|
25
|
+
raw_response = HTTParty.post(@api_url + "quotes/#{symbol}/", headers: headers)
|
26
|
+
JSON.parse(raw_response.body)
|
38
27
|
end
|
39
28
|
|
40
29
|
def user
|
41
|
-
|
42
|
-
|
43
|
-
puts response.read_body
|
44
|
-
JSON.parse(response.read_body)
|
30
|
+
raw_response = HTTParty.get(endpoints[:user], headers: headers)
|
31
|
+
JSON.parse(raw_response.body)
|
45
32
|
end
|
46
33
|
|
47
34
|
def dividends
|
48
|
-
|
49
|
-
|
50
|
-
puts response.read_body
|
51
|
-
JSON.parse(response.read_body)
|
35
|
+
raw_response = HTTParty.get(endpoints[:dividends], headers: headers)
|
36
|
+
JSON.parse(raw_response.body)
|
52
37
|
end
|
53
38
|
|
54
39
|
def orders
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
40
|
+
raw_response = HTTParty.get(endpoints[:orders], headers: headers)
|
41
|
+
JSON.parse(raw_response.body)
|
42
|
+
end
|
43
|
+
|
44
|
+
def buy(symbol, instrument_id, price, quantity)
|
45
|
+
raw_response = HTTParty.post(
|
46
|
+
endpoints[:orders],
|
47
|
+
body: {
|
48
|
+
"account" => @private.account,
|
49
|
+
"instrument" => @api_url + "instruments/#{instrument_id}/",
|
50
|
+
"price" => price,
|
51
|
+
"quantity" => quantity,
|
52
|
+
"side" => "buy",
|
53
|
+
"symbol" => symbol,
|
54
|
+
"time_in_force" => "gfd",
|
55
|
+
"trigger" => "immediate",
|
56
|
+
"type" => "market"
|
57
|
+
}.as_json,
|
58
|
+
headers: headers
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
def limit_buy(symbol, instrument_id, price, quantity)
|
63
|
+
raw_response = HTTParty.post(
|
64
|
+
endpoints[:orders],
|
65
|
+
body: {
|
66
|
+
"account" => @private.account,
|
67
|
+
"instrument" => @api_url + "instruments/#{instrument_id}/",
|
68
|
+
"price" => price,
|
69
|
+
"quantity" => quantity,
|
70
|
+
"side" => "buy",
|
71
|
+
"symbol" => symbol,
|
72
|
+
"time_in_force" => "gfd",
|
73
|
+
"trigger" => "immediate",
|
74
|
+
"type" => "limit"
|
75
|
+
}.as_json,
|
76
|
+
headers: headers
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
def sell(symbol, instrument_id, price, quantity)
|
81
|
+
raw_response = HTTParty.post(
|
82
|
+
endpoints[:orders],
|
83
|
+
body: {
|
84
|
+
"account" => @private.account,
|
85
|
+
"instrument" => @api_url + "instruments/#{instrument_id}/",
|
86
|
+
"price" => price,
|
87
|
+
"quantity" => quantity,
|
88
|
+
"side" => "sell",
|
89
|
+
"symbol" => symbol,
|
90
|
+
"time_in_force" => "gfd",
|
91
|
+
"trigger" => "immediate",
|
92
|
+
"type" => "market"
|
93
|
+
}.as_json,
|
94
|
+
headers: headers
|
95
|
+
)
|
96
|
+
end
|
97
|
+
|
98
|
+
def limit_sell(symbol, instrument_id, price, quantity)
|
99
|
+
raw_response = HTTParty.post(
|
100
|
+
endpoints[:orders],
|
101
|
+
body: {
|
102
|
+
"account" => @private.account,
|
103
|
+
"instrument" => @api_url + "instruments/#{instrument_id}/",
|
104
|
+
"price" => price,
|
105
|
+
"quantity" => quantity,
|
106
|
+
"side" => "sell",
|
107
|
+
"symbol" => symbol,
|
108
|
+
"time_in_force" => "gfd",
|
109
|
+
"trigger" => "immediate",
|
110
|
+
"type" => "limit"
|
111
|
+
}.as_json,
|
112
|
+
headers: headers
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
def stop_loss_sell(symbol, instrument_id, price, quantity)
|
117
|
+
raw_response = HTTParty.post(
|
118
|
+
endpoints[:orders],
|
119
|
+
body: {
|
120
|
+
"account" => @private.account,
|
121
|
+
"instrument" => @api_url + "instruments/#{instrument_id}/",
|
122
|
+
"stop_price" => price,
|
123
|
+
"quantity" => quantity,
|
124
|
+
"side" => "sell",
|
125
|
+
"symbol" => symbol,
|
126
|
+
"time_in_force" => "gtc",
|
127
|
+
"trigger" => "stop",
|
128
|
+
"type" => "market"
|
129
|
+
}.as_json,
|
130
|
+
headers: headers
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
def cancel_order(order_id)
|
135
|
+
raw_response = HTTParty.post(@api_url + "orders/#{order_id}/cancel/", headers: headers)
|
136
|
+
raw_response.code == 200
|
137
|
+
end
|
138
|
+
|
139
|
+
def positions(instrument_id)
|
140
|
+
raw_response = HTTParty.get(@private.account + "/positions/#{instrument_id}/", headers: headers)
|
141
|
+
JSON.parse(raw_response.body)
|
142
|
+
end
|
116
143
|
|
117
144
|
def positions
|
118
|
-
|
119
|
-
|
120
|
-
puts response.read_body
|
121
|
-
JSON.parse(response.read_body)
|
145
|
+
raw_response = HTTParty.get(endpoints[:positions], headers: headers)
|
146
|
+
JSON.parse(raw_response.body)
|
122
147
|
end
|
123
148
|
|
124
149
|
def news(symbol)
|
125
|
-
|
126
|
-
|
127
|
-
puts response.read_body
|
128
|
-
JSON.parse(response.read_body)
|
150
|
+
raw_response = HTTParty.get(endpoints[:news] + symbol.to_s + "/", headers: headers)
|
151
|
+
JSON.parse(raw_response.body)
|
129
152
|
end
|
130
153
|
|
131
154
|
def markets
|
132
|
-
|
133
|
-
|
134
|
-
puts response.read_body
|
135
|
-
JSON.parse(response.read_body)
|
155
|
+
raw_response = HTTParty.get(endpoints[:markets], headers: headers)
|
156
|
+
JSON.parse(raw_response.body)
|
136
157
|
end
|
137
158
|
|
138
159
|
def sp500_up
|
139
|
-
|
140
|
-
|
141
|
-
puts response.read_body
|
142
|
-
JSON.parse(response.read_body)
|
160
|
+
raw_response = HTTParty.get(endpoints[:sp500_up], headers: headers)
|
161
|
+
JSON.parse(raw_response.body)
|
143
162
|
end
|
144
163
|
|
145
164
|
def sp500_down
|
146
|
-
|
147
|
-
|
148
|
-
puts response.read_body
|
149
|
-
JSON.parse(response.read_body)
|
165
|
+
raw_response = HTTParty.get(endpoints[:sp500_down], headers: headers)
|
166
|
+
JSON.parse(raw_response.body)
|
150
167
|
end
|
151
168
|
|
152
169
|
# def create_watch_list(name, callback)
|
@@ -159,26 +176,27 @@ module Robinhood
|
|
159
176
|
# end
|
160
177
|
|
161
178
|
def watchlists
|
162
|
-
|
163
|
-
|
164
|
-
puts response.read_body
|
165
|
-
JSON.parse(response.read_body)
|
179
|
+
raw_response = HTTParty.get(endpoints[:watchlists], headers: headers)
|
180
|
+
JSON.parse(raw_response.body)
|
166
181
|
end
|
167
182
|
|
168
183
|
def splits(instrument)
|
169
|
-
|
170
|
-
|
171
|
-
puts response.read_body
|
172
|
-
JSON.parse(response.read_body)
|
184
|
+
raw_response = HTTParty.get(endpoints[:instruments] + "/splits/" + instrument.to_s, headers: headers)
|
185
|
+
JSON.parse(raw_response.body)
|
173
186
|
end
|
174
187
|
|
175
188
|
def historicals(symbol, intv, span)
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
189
|
+
raw_response = HTTParty.get(endpoints[:quotes] + "historicals/" + symbol, query: {"interval" => intv.to_s, "span" => span}, headers: headers)
|
190
|
+
JSON.parse(raw_response.body)
|
191
|
+
end
|
192
|
+
|
193
|
+
def headers
|
194
|
+
Client.headers
|
180
195
|
end
|
181
|
-
end
|
182
196
|
|
197
|
+
def endpoints
|
198
|
+
Endpoints.endpoints
|
199
|
+
end
|
200
|
+
end
|
183
201
|
end
|
184
202
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Robinhood
|
2
2
|
module REST
|
3
3
|
class Client < API
|
4
|
-
attr_accessor :token, :
|
4
|
+
attr_accessor :token, :options, :private, :headers
|
5
5
|
|
6
6
|
def initialize(*args)
|
7
7
|
@options = args.last.is_a?(Hash) ? args.pop : {}
|
@@ -11,11 +11,12 @@ module Robinhood
|
|
11
11
|
@options[:username] = (args.size > 2 && args[2].is_a?(String) ? args[2] : args[0]) || Robinhood.username
|
12
12
|
|
13
13
|
if @options[:username].nil? || @options[:password].nil?
|
14
|
-
raise ArgumentError,
|
14
|
+
raise ArgumentError, "Account username and password are required"
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
|
+
setup_headers
|
17
18
|
configuration
|
18
|
-
|
19
|
+
login
|
19
20
|
end
|
20
21
|
|
21
22
|
def inspect # :nodoc:
|
@@ -43,43 +44,7 @@ module Robinhood
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def configuration()
|
46
|
-
@api_url =
|
47
|
-
|
48
|
-
@endpoints = {
|
49
|
-
"login": 'api-token-auth/',
|
50
|
-
"investment_profile": 'user/investment_profile/',
|
51
|
-
"accounts": 'accounts/',
|
52
|
-
"ach_iav_auth": 'ach/iav/auth/',
|
53
|
-
"ach_relationships": 'ach/relationships/',
|
54
|
-
"ach_transfers": 'ach/transfers/',
|
55
|
-
"ach_deposit_schedules": "ach/deposit_schedules/",
|
56
|
-
"applications": 'applications/',
|
57
|
-
"dividends": 'dividends/',
|
58
|
-
"edocuments": 'documents/',
|
59
|
-
"instruments": 'instruments/',
|
60
|
-
"margin_upgrade": 'margin/upgrades/',
|
61
|
-
"markets": 'markets/',
|
62
|
-
"notifications": 'notifications/',
|
63
|
-
"notifications_devices": "notifications/devices/",
|
64
|
-
"orders": 'orders/',
|
65
|
-
"cancel_order": 'orders/', #API expects https://api.robinhood.com/orders/{{orderId}}/cancel/
|
66
|
-
"password_reset": 'password_reset/request/',
|
67
|
-
"quotes": 'quotes/',
|
68
|
-
"document_requests": 'upload/document_requests/',
|
69
|
-
"user": 'user/',
|
70
|
-
|
71
|
-
"user_additional_info": "user/additional_info/",
|
72
|
-
"user_basic_info": "user/basic_info/",
|
73
|
-
"user_employment": "user/employment/",
|
74
|
-
"user_investment_profile": "user/investment_profile/",
|
75
|
-
|
76
|
-
"watchlists": 'watchlists/',
|
77
|
-
"positions": 'positions/',
|
78
|
-
"fundamentals": 'fundamentals/',
|
79
|
-
"sp500_up": 'midlands/movers/sp500/?direction=up',
|
80
|
-
"sp500_down": 'midlands/movers/sp500/?direction=down',
|
81
|
-
"news": 'midlands/news/'
|
82
|
-
}
|
47
|
+
@api_url = "https://api.robinhood.com/"
|
83
48
|
|
84
49
|
@is_init = false
|
85
50
|
|
@@ -94,27 +59,44 @@ module Robinhood
|
|
94
59
|
|
95
60
|
@api = {}
|
96
61
|
end
|
62
|
+
|
63
|
+
def setup_headers
|
64
|
+
@headers ||= {
|
65
|
+
"Accept" => "*/*",
|
66
|
+
"Accept-Encoding" => "gzip, deflate",
|
67
|
+
"Accept-Language" => "en;q=1, fr;q=0.9, de;q=0.8, ja;q=0.7, nl;q=0.6, it;q=0.5",
|
68
|
+
"Content-Type" => "application/x-www-form-urlencoded; charset=utf-8",
|
69
|
+
"X-Robinhood-API-Version" => "1.0.0",
|
70
|
+
"Connection" => "keep-alive",
|
71
|
+
"User-Agent" => "Robinhood/823 (iPhone; iOS 7.1.2; Scale/2.00)",
|
72
|
+
}
|
73
|
+
end
|
97
74
|
|
98
|
-
def
|
99
|
-
@private[:username] = @options[:username]
|
100
|
-
@private[:password] = @options[:password]
|
75
|
+
def login
|
76
|
+
@private[:username] = @options[:username]
|
77
|
+
@private[:password] = @options[:password]
|
101
78
|
|
102
79
|
if @private[:auth_token].nil?
|
103
|
-
|
80
|
+
raw_response = HTTParty.post(
|
81
|
+
@api_url + "api-token-auth/",
|
82
|
+
body: {
|
83
|
+
"password" => @private[:password],
|
84
|
+
"username" => @private[:username]
|
85
|
+
}.as_json,
|
86
|
+
headers: @headers
|
87
|
+
)
|
88
|
+
response = JSON.parse(raw_response.body)
|
89
|
+
|
90
|
+
if response["non_field_errors"]
|
91
|
+
puts response["non_field_errors"]
|
92
|
+
false
|
93
|
+
elsif response["token"]
|
94
|
+
@private[:auth_token] = response["token"]
|
95
|
+
@headers["Authorization"] = "Token " + @private[:auth_token].to_s
|
96
|
+
@private[:account] = account["results"][0]["url"]
|
97
|
+
end
|
104
98
|
end
|
105
99
|
end
|
106
|
-
|
107
|
-
def http_request(url)
|
108
|
-
request = Util::Request.new(@private)
|
109
|
-
request.http_request(url)
|
110
|
-
end
|
111
|
-
|
112
|
-
def login
|
113
|
-
url = URI(@api_url + "api-token-auth/")
|
114
|
-
response = http_request(url)
|
115
|
-
@private[:auth_token] = JSON.parse(response.read_body)["token"]
|
116
|
-
@private[:account] = account["results"][0]["url"]
|
117
|
-
end
|
118
100
|
end
|
119
101
|
end
|
120
102
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Robinhood
|
2
|
+
module REST
|
3
|
+
class Endpoints
|
4
|
+
attr_accessor :endpoints
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.endpoints
|
10
|
+
api_url = "https://api.robinhood.com/"
|
11
|
+
{
|
12
|
+
login: api_url + "api-token-auth/",
|
13
|
+
investment_profile: api_url + "user/investment_profile/",
|
14
|
+
accounts: api_url + "accounts/",
|
15
|
+
ach_iav_auth: api_url + "ach/iav/auth/",
|
16
|
+
ach_relationships: api_url + "ach/relationships/",
|
17
|
+
ach_transfers: api_url + "ach/transfers/",
|
18
|
+
ach_deposit_schedules: api_url + "ach/deposit_schedules/",
|
19
|
+
applications: api_url + "applications/",
|
20
|
+
dividends: api_url + "dividends/",
|
21
|
+
edocuments: api_url + "documents/",
|
22
|
+
instruments: api_url + "instruments/",
|
23
|
+
margin_upgrade: api_url + "margin/upgrades/",
|
24
|
+
markets: api_url + "markets/",
|
25
|
+
notifications: api_url + "notifications/",
|
26
|
+
notifications_devices: api_url + "notifications/devices/",
|
27
|
+
orders: api_url + "orders/",
|
28
|
+
cancel_order: api_url + "orders/",
|
29
|
+
password_reset: api_url + "password_reset/request/",
|
30
|
+
quotes: api_url + "quotes/",
|
31
|
+
document_requests: api_url + "upload/document_requests/",
|
32
|
+
user: api_url + "user/",
|
33
|
+
|
34
|
+
user_additional_info: api_url + "user/additional_info/",
|
35
|
+
user_basic_info: api_url + "user/basic_info/",
|
36
|
+
user_employment: api_url + "user/employment/",
|
37
|
+
user_investment_profile: api_url + "user/investment_profile/",
|
38
|
+
|
39
|
+
watchlists: api_url + "watchlists/",
|
40
|
+
positions: api_url + "positions/",
|
41
|
+
fundamentals: api_url + "fundamentals/",
|
42
|
+
sp500_up: api_url + "midlands/movers/sp500/?direction=up",
|
43
|
+
sp500_down: api_url + "midlands/movers/sp500/?direction=down",
|
44
|
+
news: api_url + "midlands/news/"
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -4,48 +4,6 @@ module Robinhood
|
|
4
4
|
def initialize(private_params)
|
5
5
|
@private = private_params
|
6
6
|
end
|
7
|
-
|
8
|
-
def http_request(url)
|
9
|
-
http = Net::HTTP.new(url.host, url.port)
|
10
|
-
http.use_ssl = true
|
11
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
12
|
-
|
13
|
-
request = prepare_request(url)
|
14
|
-
|
15
|
-
response = http.request(request)
|
16
|
-
end
|
17
|
-
|
18
|
-
def setup_headers(request)
|
19
|
-
request["accept"] = '*/*'
|
20
|
-
request["accept-encoding"] = 'gzip, deflate'
|
21
|
-
request["accept-language"] = 'en;q=1, fr;q=0.9, de;q=0.8, ja;q=0.7, nl;q=0.6, it;q=0.5'
|
22
|
-
request["content-type"] = 'multipart/form-data; boundary=---011000010111000001101001'
|
23
|
-
request["x-robinhood-api-version"] = '1.0.0'
|
24
|
-
request["connection"] = 'keep-alive'
|
25
|
-
request["user-agent"] = 'Robinhood/823 (iPhone; iOS 7.1.2; Scale/2.00)'
|
26
|
-
request["cache-control"] = 'no-cache'
|
27
|
-
request
|
28
|
-
end
|
29
|
-
|
30
|
-
def prepare_request(url)
|
31
|
-
if @private[:auth_token].nil?
|
32
|
-
request = Net::HTTP::Post.new(url)
|
33
|
-
else
|
34
|
-
request = Net::HTTP::Get.new(url)
|
35
|
-
end
|
36
|
-
|
37
|
-
request = setup_headers(request)
|
38
|
-
|
39
|
-
if @private[:auth_token].nil?
|
40
|
-
request["authorization"] = 'Basic cmVtZW1iZXJsZW5ueTpPbmx5RGVzdGlueTgh'
|
41
|
-
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"username\"\r\n\r\n" + @private[:username] + "\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"password\"\r\n\r\n" + @private[:password] + "\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"\"\r\n\r\n\r\n-----011000010111000001101001--"
|
42
|
-
else
|
43
|
-
request["authorization"] = 'Token ' + @private[:auth_token].to_s
|
44
|
-
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"username\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"password\"\r\n\r\n\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"\"\r\n\r\n\r\n-----011000010111000001101001--"
|
45
|
-
end
|
46
|
-
|
47
|
-
request
|
48
|
-
end
|
49
7
|
end
|
50
8
|
end
|
51
9
|
end
|
data/robinhood-ruby.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "robinhood-ruby/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "robinhood-ruby"
|
@@ -14,10 +14,10 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.homepage = "https://github.com/rememberlenny/robinhood-ruby"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host"
|
18
18
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
19
|
if spec.respond_to?(:metadata)
|
20
|
-
spec.metadata[
|
20
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
21
21
|
else
|
22
22
|
raise "RubyGems 2.0 or newer is required to protect against " \
|
23
23
|
"public gem pushes."
|
@@ -30,13 +30,14 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
31
|
spec.require_paths = ["lib"]
|
32
32
|
|
33
|
-
spec.add_dependency(
|
34
|
-
spec.add_dependency(
|
35
|
-
spec.add_dependency(
|
36
|
-
spec.add_dependency(
|
37
|
-
spec.add_dependency(
|
33
|
+
spec.add_dependency("multi_json", ">= 1.3.0")
|
34
|
+
spec.add_dependency("builder", ">= 2.1.2")
|
35
|
+
spec.add_dependency("jwt", "~> 1.0")
|
36
|
+
spec.add_dependency("rack")
|
37
|
+
spec.add_dependency("httparty")
|
38
|
+
spec.add_dependency("jruby-openssl") if RUBY_PLATFORM == "java"
|
38
39
|
# Workaround for RBX <= 2.2.1, should be fixed in next version
|
39
|
-
spec.add_dependency(
|
40
|
+
spec.add_dependency("rubysl") if defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
|
40
41
|
|
41
42
|
spec.add_development_dependency "bundler", "~> 1.13"
|
42
43
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: robinhood-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leonard Bogdonoff
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: httparty
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -312,6 +326,7 @@ files:
|
|
312
326
|
- lib/robinhood-ruby/rest/.DS_Store
|
313
327
|
- lib/robinhood-ruby/rest/api.rb
|
314
328
|
- lib/robinhood-ruby/rest/client.rb
|
329
|
+
- lib/robinhood-ruby/rest/endpoints.rb
|
315
330
|
- lib/robinhood-ruby/util.rb
|
316
331
|
- lib/robinhood-ruby/util/.DS_Store
|
317
332
|
- lib/robinhood-ruby/util/configuration.rb
|