rh-console 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
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,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/robinhood_console'
4
+
5
+ console = RobinhoodConsole.new
6
+ console.initialize_client
7
+ console.print_help_text
8
+ console.menu_loop
@@ -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