rh-console 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +78 -0
- data/bin/rh-console +8 -0
- data/initializers/string.rb +10 -0
- data/lib/helpers/format_helpers.rb +18 -0
- data/lib/helpers/http_helpers.rb +43 -0
- data/lib/helpers/table.rb +83 -0
- data/lib/robinhood_client.rb +785 -0
- data/lib/robinhood_console.rb +686 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b4caf5635220e379b72b6100e9c63e59d0846b2cc81895869a288a62379beb2c
|
4
|
+
data.tar.gz: 58a8a8cbd5c98a1cc41ceef48fdf93946fa1397c6210b5001ff128de9cc6620d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 656bd2edfe7f38ed3dd3ad4db3686ef20616e6cea0dd150494aac358042cb490596216729ae7c65c58b7ec1c3bd46b34b16c20ee966c4ef7177c818c1da8544e
|
7
|
+
data.tar.gz: 9c4dde382ed6500caaf3dd0931b060aad2946a2664000d4ab00efcce83645aae1bc84f715b6eebb97750a741de0ec44170baba22df69c44b9c61fa7b2b6dbc84
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
## Robinhood console
|
2
|
+
|
3
|
+
A Ruby command line interface to the Robinhood API:
|
4
|
+
|
5
|
+
<img height="440" alt="rh-console" src="https://user-images.githubusercontent.com/6415223/78421025-6afd7480-7609-11ea-852a-39280b3ef671.png">
|
6
|
+
|
7
|
+
### Installation
|
8
|
+
|
9
|
+
:warning: WARNING: This is no longer maintained and has not been thoroughly used in years. It is **not** recommended to use this to place trades or perform any sensitive actions, as this is **not** an official product of Robinhood and the APIs it's making use of may change at any time :warning:
|
10
|
+
|
11
|
+
Rh-console is hosted on RubyGems and can be installed via:
|
12
|
+
|
13
|
+
`gem install rh-console`
|
14
|
+
|
15
|
+
And you'll have access to a `rh-console` executable in your terminal.
|
16
|
+
|
17
|
+
Alternatively, clone the repository and run it:
|
18
|
+
```
|
19
|
+
git clone https://github.com/brentjo/rh-console
|
20
|
+
cd rh-console
|
21
|
+
bin/rh-console
|
22
|
+
```
|
23
|
+
|
24
|
+
Or run with Docker:
|
25
|
+
|
26
|
+
```
|
27
|
+
docker build -f Dockerfile -t rh-console .
|
28
|
+
docker run -it --rm rh-console
|
29
|
+
```
|
30
|
+
|
31
|
+
### Features
|
32
|
+
|
33
|
+
- Stream live equity and option quotes
|
34
|
+
- Place orders for equities and options
|
35
|
+
- View order history and cancel open orders
|
36
|
+
- Print a summary of your portfolio
|
37
|
+
- View information about your account
|
38
|
+
- Backup weekly historical data for your watchlist
|
39
|
+
- Manually make authenticated requests to the API using the `get` command
|
40
|
+
- The JWT authentication token auto-refreshes in the background.
|
41
|
+
- Supports accounts with multi-factor authentication enabled
|
42
|
+
|
43
|
+
### Development
|
44
|
+
|
45
|
+
There are no dependencies -- only the ruby standard library is used, so simply clone, start making edits, and run with `bin/rh-console`.
|
46
|
+
|
47
|
+
The few gems listed in the Gemfile are needed to run and record new tests, and can be installed with `bundle install`. Tests use [vcr](https://github.com/vcr/vcr) to record interactions with the Robinhood API. The initial recording hits the live API and your test cases make assertions based off it, but subsequent runs match against requests in the VCR recording.
|
48
|
+
|
49
|
+
After making changes, update the YARD documentation with `bundle exec rake yard`.
|
50
|
+
|
51
|
+
### Testing
|
52
|
+
|
53
|
+
Install the dependencies and run tests via rake:
|
54
|
+
```
|
55
|
+
bundle install
|
56
|
+
bundle exec rake test
|
57
|
+
```
|
58
|
+
|
59
|
+
Alternatively, build and run a Dockerfile:
|
60
|
+
|
61
|
+
```
|
62
|
+
docker build -f Dockerfile.ci -t rh-console-ci .
|
63
|
+
docker run --rm rh-console-ci
|
64
|
+
```
|
65
|
+
|
66
|
+
**Command line interactions**
|
67
|
+
Tests that assert that certain command line input should lead to certain library calls are within `test/test_robinhood_console.rb`.
|
68
|
+
|
69
|
+
**Robinhood client**
|
70
|
+
The actual client that interacts with the API to place orders, get quotes, etc, is tested within `test/test_unauthenticated_robinhood_client.rb` and `test/test_authenticated_robinhood_client.rb`. Unfortunately, because these VCR recordings are real API interactions, the cassettes for most tests are not checked into source control.
|
71
|
+
|
72
|
+
### Documentation
|
73
|
+
Full YARD documentation can be found at: https://brentjo.github.io/rh-console/top-level-namespace.html
|
74
|
+
- [RobinhoodClient](./lib/robinhood_client.rb) - Contains the bulk of the code that handles making requests to the Robinhood API.
|
75
|
+
- [RobinhoodConsole](./lib/robinhood_console.rb) - Contains all the code to handle taking in user input, parsing it, and sending it to the RobinhoodClient.
|
76
|
+
- [Table](./lib/helpers/table.rb) - A method that takes an array of headers, and an array or rows, and formats it into a pretty table in the style of [`tj/terminal-table`](https://github.com/tj/terminal-table).
|
77
|
+
- [HttpHelpers](./lib/helpers/http_helpers.rb) - Contains wrappers around `Net:HTTP`'s GET and POST methods to help craft the requests to the API.
|
78
|
+
- [String](./initializers/string.rb) - String is monkey-patched to add some color helper methods so you're able to do `"text".red` and the text will be output red in the terminal.
|
data/bin/rh-console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
class String
|
2
|
+
def black; "\e[30m#{self}\e[0m" end
|
3
|
+
def red; "\e[31m#{self}\e[0m" end
|
4
|
+
def green; "\e[32m#{self}\e[0m" end
|
5
|
+
def brown; "\e[33m#{self}\e[0m" end
|
6
|
+
def blue; "\e[34m#{self}\e[0m" end
|
7
|
+
def magenta; "\e[35m#{self}\e[0m" end
|
8
|
+
def cyan; "\e[36m#{self}\e[0m" end
|
9
|
+
def gray; "\e[37m#{self}\e[0m" end
|
10
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module FormatHelpers
|
2
|
+
|
3
|
+
# Formats a float to 2 decimal places and the color specified
|
4
|
+
#
|
5
|
+
# @param price [Float] The float to format
|
6
|
+
# @param color [Symbol] The color
|
7
|
+
# @return [String] The colored string rounded to 2 decimal places
|
8
|
+
# @example
|
9
|
+
# FormatHelpers.format_float(123.4567, color: :green)
|
10
|
+
def self.format_float(price, color: nil)
|
11
|
+
rounded = '%.2f' % price
|
12
|
+
if color
|
13
|
+
rounded.send(color)
|
14
|
+
else
|
15
|
+
rounded
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module HttpHelpers
|
5
|
+
|
6
|
+
# Make a GET request
|
7
|
+
#
|
8
|
+
# @param url [String] URL to make the request to
|
9
|
+
# @param headers [Hash] Headers to add to the request
|
10
|
+
# @param params [Hash] Parameters to add to the request
|
11
|
+
# @return [Net::HTTP] The response of the request
|
12
|
+
def self.get(url, headers: {}, params: {})
|
13
|
+
uri = URI.parse(url)
|
14
|
+
uri.query = URI.encode_www_form(params) unless params.empty?
|
15
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
16
|
+
http.use_ssl = true
|
17
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
18
|
+
headers.each do |key, value|
|
19
|
+
request[key] = value
|
20
|
+
end
|
21
|
+
response = http.request(request)
|
22
|
+
response
|
23
|
+
end
|
24
|
+
|
25
|
+
# Make a POST request
|
26
|
+
#
|
27
|
+
# @param url [String] URL to make the request to
|
28
|
+
# @param headers [Hash] Headers to add to the request
|
29
|
+
# @param body [Hash] Parameters to add to the request
|
30
|
+
# @return [Net::HTTP] The response of the request
|
31
|
+
def self.post(url, headers, body)
|
32
|
+
uri = URI.parse(url)
|
33
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
34
|
+
http.use_ssl = true
|
35
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
36
|
+
headers.each do |key, value|
|
37
|
+
request[key] = value
|
38
|
+
end
|
39
|
+
request.body = body.to_json
|
40
|
+
response = http.request(request)
|
41
|
+
response
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Table
|
2
|
+
|
3
|
+
def self.new(headers, rows)
|
4
|
+
|
5
|
+
# Add 1 space padding to all values
|
6
|
+
headers.map! do |header|
|
7
|
+
header.prepend(" ")
|
8
|
+
header += " "
|
9
|
+
header
|
10
|
+
end
|
11
|
+
|
12
|
+
rows.map! do |row|
|
13
|
+
row.map! do |value|
|
14
|
+
# We don't want change the values of any variables passed in
|
15
|
+
# We only prepend spaces for visual purposes, so let's modify a dup instead
|
16
|
+
dupped_value = "" unless value
|
17
|
+
dupped_value = value.dup if value
|
18
|
+
dupped_value.prepend(" ")
|
19
|
+
dupped_value += " "
|
20
|
+
dupped_value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
column_length = {}
|
25
|
+
headers.each_with_index do |value, index|
|
26
|
+
column_length[index] = value.length unless column_length.key?(index)
|
27
|
+
column_length[index] = value.length if value.length > column_length[index]
|
28
|
+
end
|
29
|
+
|
30
|
+
rows.each do |row|
|
31
|
+
row.each_with_index do |value, index|
|
32
|
+
column_length[index] = value.length unless column_length.key?(index)
|
33
|
+
column_length[index] = value.length if value.length > column_length[index]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
table = "+"
|
38
|
+
headers.each_with_index do |value, index|
|
39
|
+
table += ("-" * column_length[index])
|
40
|
+
table += "+"
|
41
|
+
end
|
42
|
+
table += "\n"
|
43
|
+
|
44
|
+
table += "|"
|
45
|
+
headers.each_with_index do |value, index|
|
46
|
+
table += value + (" " * (column_length[index] - value.length))
|
47
|
+
table += "|"
|
48
|
+
end
|
49
|
+
table += "\n"
|
50
|
+
|
51
|
+
table += "+"
|
52
|
+
headers.each_with_index do |value, index|
|
53
|
+
table += "-" * column_length[index]
|
54
|
+
table += "+"
|
55
|
+
end
|
56
|
+
table += "\n"
|
57
|
+
|
58
|
+
rows.each do |row|
|
59
|
+
table += "|"
|
60
|
+
row.each_with_index do |value, index|
|
61
|
+
# Remove color characters so they don't count towards string length
|
62
|
+
value_for_length = value.gsub(/\e\[(\d+)m/, "")
|
63
|
+
value_for_length = value_for_length.gsub(/\e\[(\d+);(\d+);(\d+)m/, "")
|
64
|
+
num_spaces = (column_length[index] - value_for_length.length)
|
65
|
+
table += value
|
66
|
+
table += " " * num_spaces
|
67
|
+
table += "|"
|
68
|
+
end
|
69
|
+
table += "\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
table += "+"
|
73
|
+
headers.each_with_index do |value, index|
|
74
|
+
table += ("-" * column_length[index])
|
75
|
+
table += "+"
|
76
|
+
end
|
77
|
+
table += "\n"
|
78
|
+
|
79
|
+
table
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|