robinhood-ruby 0.3.5 → 0.4.3
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.
- 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
|