cryptum 0.0.379 → 0.0.381

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/.rubocop_todo.yml +2 -17
  4. data/bin/cryptum +3 -3
  5. data/bin/cryptum-forecast +4 -4
  6. data/lib/cryptum/api/exchange_rates.rb +42 -0
  7. data/lib/cryptum/api/fees.rb +36 -0
  8. data/lib/cryptum/api/order_history.rb +56 -0
  9. data/lib/cryptum/api/orders.rb +253 -0
  10. data/lib/cryptum/api/portfolio.rb +79 -0
  11. data/lib/cryptum/api/products.rb +65 -0
  12. data/lib/cryptum/api/rest.rb +177 -0
  13. data/lib/cryptum/api/signature.rb +79 -0
  14. data/lib/cryptum/api.rb +10 -640
  15. data/lib/cryptum/event/buy.rb +1 -1
  16. data/lib/cryptum/event/cancel.rb +1 -1
  17. data/lib/cryptum/event/gtfo.rb +1 -1
  18. data/lib/cryptum/event/sell.rb +1 -1
  19. data/lib/cryptum/option/choice.rb +2 -2
  20. data/lib/cryptum/option/environment.rb +45 -0
  21. data/lib/cryptum/option/input_validation.rb +85 -0
  22. data/lib/cryptum/option/parser.rb +85 -0
  23. data/lib/cryptum/option.rb +3 -192
  24. data/lib/cryptum/order_book/generate.rb +1 -1
  25. data/lib/cryptum/portfolio/balance.rb +3 -5
  26. data/lib/cryptum/ui/order_execution.rb +2 -2
  27. data/lib/cryptum/version.rb +1 -1
  28. data/lib/cryptum/web_sock/coinbase.rb +1 -1
  29. data/spec/lib/cryptum/api/exchange_rates_spec.rb +10 -0
  30. data/spec/lib/cryptum/api/fees_spec.rb +10 -0
  31. data/spec/lib/cryptum/api/order_history_spec.rb +10 -0
  32. data/spec/lib/cryptum/api/orders_spec.rb +10 -0
  33. data/spec/lib/cryptum/api/portfolio_spec.rb +10 -0
  34. data/spec/lib/cryptum/api/products_spec.rb +10 -0
  35. data/spec/lib/cryptum/api/rest_spec.rb +10 -0
  36. data/spec/lib/cryptum/api/signature_spec.rb +10 -0
  37. data/spec/lib/cryptum/option/environment_spec.rb +10 -0
  38. data/spec/lib/cryptum/option/input_validation_spec.rb +10 -0
  39. data/spec/lib/cryptum/option/parser_spec.rb +10 -0
  40. metadata +24 -2
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rest-client'
4
+ require 'json'
5
+
6
+ module Cryptum
7
+ # This module is used to Interact with the APIs
8
+ module API
9
+ # Module specifically related to orders history retrieval.
10
+ module Rest
11
+ # Actually Make a REST API call
12
+ public_class_method def self.call(opts = {})
13
+ env = opts[:env]
14
+ option_choice = opts[:option_choice]
15
+ order_type = opts[:order_type]
16
+ event_notes = opts[:event_notes]
17
+ api_endpoint = opts[:api_endpoint]
18
+ base_increment = opts[:base_increment].to_f
19
+
20
+ api_key = env[:api_key]
21
+ api_secret = env[:api_secret]
22
+ api_passphrase = env[:api_passphrase]
23
+ api_endpoint = 'https://api.exchange.coinbase.com'
24
+ api_endpoint = 'https://api-public.sandbox.exchange.coinbase.com' if env[:env] == :sandbox
25
+ api_endpoint = opts[:api_endpoint] if opts[:api_endpoint]
26
+
27
+ http_method = if opts[:http_method].nil?
28
+ :GET
29
+ else
30
+ opts[:http_method].to_s.upcase.scrub.strip.chomp.to_sym
31
+ end
32
+ api_call = opts[:api_call].to_s.scrub
33
+ params = opts[:params]
34
+ http_body = opts[:http_body].to_s.scrub.strip.chomp
35
+
36
+ max_conn_attempts = 30
37
+ conn_attempt = 0
38
+
39
+ begin
40
+ conn_attempt += 1
41
+ if option_choice.proxy
42
+ rest_client = RestClient
43
+ rest_client.proxy = option_choice.proxy
44
+ rest_client_request = rest_client::Request
45
+ else
46
+ rest_client_request = RestClient::Request
47
+ end
48
+
49
+ api_signature_response = Cryptum::API::Signature.generate(
50
+ api_secret: api_secret,
51
+ http_method: http_method,
52
+ api_call: api_call,
53
+ params: params,
54
+ http_body: http_body
55
+ )
56
+ api_signature = api_signature_response[:api_signature]
57
+ api_timestamp = api_signature_response[:api_timestamp]
58
+
59
+ case http_method
60
+ when :GET
61
+ headers = {
62
+ content_type: 'application/json; charset=UTF-8',
63
+ CB_ACCESS_TIMESTAMP: api_timestamp,
64
+ CB_ACCESS_PASSPHRASE: api_passphrase,
65
+ CB_ACCESS_KEY: api_key,
66
+ CB_ACCESS_SIGN: api_signature
67
+ }
68
+
69
+ headers[:params] = params if params
70
+ headers[:ORDER_TYPE] = order_type if order_type
71
+ headers[:EVENT_NOTES] = event_notes if event_notes
72
+
73
+ response = rest_client_request.execute(
74
+ method: :GET,
75
+ url: "#{api_endpoint}#{api_call}",
76
+ headers: headers,
77
+ verify_ssl: false
78
+ )
79
+
80
+ when :DELETE
81
+ headers = {
82
+ content_type: 'application/json; charset=UTF-8',
83
+ CB_ACCESS_TIMESTAMP: api_timestamp,
84
+ CB_ACCESS_PASSPHRASE: api_passphrase,
85
+ CB_ACCESS_KEY: api_key,
86
+ CB_ACCESS_SIGN: api_signature
87
+ }
88
+
89
+ headers[:params] = params if params
90
+ headers[:ORDER_TYPE] = order_type if order_type
91
+ headers[:EVENT_NOTES] = event_notes if event_notes
92
+
93
+ response = rest_client_request.execute(
94
+ method: :DELETE,
95
+ url: "#{api_endpoint}#{api_call}",
96
+ headers: headers,
97
+ verify_ssl: false
98
+ )
99
+
100
+ when :POST
101
+ headers = {
102
+ content_type: 'application/json; charset=UTF-8',
103
+ CB_ACCESS_TIMESTAMP: api_timestamp,
104
+ CB_ACCESS_PASSPHRASE: api_passphrase,
105
+ CB_ACCESS_KEY: api_key,
106
+ CB_ACCESS_SIGN: api_signature
107
+ }
108
+
109
+ headers[:params] = params if params
110
+ headers[:ORDER_TYPE] = order_type if order_type
111
+ headers[:EVENT_NOTES] = event_notes if event_notes
112
+
113
+ response = rest_client_request.execute(
114
+ method: :POST,
115
+ url: "#{api_endpoint}#{api_call}",
116
+ headers: headers,
117
+ payload: http_body,
118
+ verify_ssl: false
119
+ )
120
+
121
+ else
122
+ raise @@logger.error("Unsupported HTTP Method #{http_method} for #{self} Plugin")
123
+ end
124
+
125
+ resp = JSON.parse(response, symbolize_names: true)
126
+ resp ||= []
127
+ rescue RestClient::Unauthorized => e
128
+ File.open('/tmp/cryptum-errors.txt', 'a') do |f|
129
+ f.puts Time.now.strftime('%Y-%m-%d %H:%M:%S.%N %z')
130
+ f.puts "#{self}\n#{e}\n\n\n"
131
+ end
132
+
133
+ raise e if conn_attempt > max_conn_attempts
134
+
135
+ sleep 60
136
+ retry
137
+ end
138
+ rescue RestClient::ExceptionWithResponse => e
139
+ File.open('/tmp/cryptum-errors.txt', 'a') do |f|
140
+ f.puts Time.now.strftime('%Y-%m-%d %H:%M:%S.%N %z')
141
+ f.puts "Module: #{self}"
142
+ f.puts "URL: #{api_endpoint}#{api_call}"
143
+ f.puts "PARAMS: #{params.inspect}"
144
+ f.puts "HTTP POST BODY: #{http_body.inspect}" if http_body != ''
145
+ f.puts "#{e}\n#{e.response}\n\n\n"
146
+ end
147
+
148
+ insufficient_funds = '{"message":"Insufficient funds"}'
149
+ size -= base_increment if e.response == insufficient_funds
150
+
151
+ sleep 0.3
152
+ retry
153
+ rescue RestClient::TooManyRequests => e
154
+ File.open('/tmp/cryptum-errors.txt', 'a') do |f|
155
+ f.puts Time.now.strftime('%Y-%m-%d %H:%M:%S.%N %z')
156
+ f.puts "Module: #{self}"
157
+ f.puts "URL: #{api_endpoint}#{api_call}"
158
+ f.puts "PARAMS: #{params.inspect}"
159
+ f.puts "HTTP POST BODY: #{http_body.inspect}" if http_body != ''
160
+ f.puts "#{e}\n#{e.response}\n\n\n"
161
+ end
162
+
163
+ sleep 1
164
+ retry
165
+ end
166
+
167
+ # Display Usage for this Module
168
+ public_class_method def self.help
169
+ puts "USAGE:
170
+ rest_response = #{self}.call(
171
+ env: 'required - Coinbase::Option::Environment.get Object'
172
+ )
173
+ "
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'addressable'
4
+ require 'base64'
5
+ require 'openssl'
6
+
7
+ module Cryptum
8
+ # This module is used to Interact with the APIs
9
+ module API
10
+ # Module specifically related to orders history retrieval.
11
+ module Signature
12
+ # Obtain latest order history
13
+ public_class_method def self.generate(opts = {})
14
+ api_secret = opts[:api_secret]
15
+
16
+ http_method = if opts[:http_method].nil?
17
+ :GET
18
+ else
19
+ opts[:http_method].to_s.upcase.scrub.strip.chomp.to_sym
20
+ end
21
+
22
+ api_call = opts[:api_call].to_s.scrub.strip.chomp
23
+ api_call = '/users/self/verify' if opts[:api_call].nil?
24
+
25
+ if opts[:params].nil?
26
+ path = api_call
27
+ else
28
+ uri = Addressable::URI.new
29
+ uri.query_values = opts[:params]
30
+ params = uri.query
31
+ path = "#{api_call}?#{params}"
32
+ end
33
+
34
+ http_body = opts[:http_body].to_s.scrub.strip.chomp
35
+
36
+ api_timestamp = Time.now.utc.to_i.to_s
37
+
38
+ api_signature = Base64.strict_encode64(
39
+ OpenSSL::HMAC.digest(
40
+ 'sha256',
41
+ Base64.strict_decode64(api_secret),
42
+ "#{api_timestamp}#{http_method}#{path}#{http_body}"
43
+ )
44
+ )
45
+
46
+ if http_body == ''
47
+ api_signature = Base64.strict_encode64(
48
+ OpenSSL::HMAC.digest(
49
+ 'sha256',
50
+ Base64.strict_decode64(api_secret),
51
+ "#{api_timestamp}#{http_method}#{path}"
52
+ )
53
+ )
54
+ end
55
+
56
+ api_signature_response = {}
57
+ api_signature_response[:api_timestamp] = api_timestamp
58
+ api_signature_response[:api_signature] = api_signature
59
+
60
+ api_signature_response
61
+ rescue StandardError => e
62
+ raise e
63
+ end
64
+
65
+ # Display Usage for this Module
66
+ public_class_method def self.help
67
+ puts "USAGE:
68
+ signature = #{self}.generate_signature(
69
+ api_secret: 'required - Coinbase Pro API Secret',
70
+ http_method: 'optional - Defaults to :GET',
71
+ api_call: 'optional - Defaults to /users/self/verify',
72
+ params: 'optional - HTTP GET Parameters',
73
+ http_body: 'optional HTTP POST Body'
74
+ )
75
+ "
76
+ end
77
+ end
78
+ end
79
+ end