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.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +2 -17
- data/bin/cryptum +3 -3
- data/bin/cryptum-forecast +4 -4
- data/lib/cryptum/api/exchange_rates.rb +42 -0
- data/lib/cryptum/api/fees.rb +36 -0
- data/lib/cryptum/api/order_history.rb +56 -0
- data/lib/cryptum/api/orders.rb +253 -0
- data/lib/cryptum/api/portfolio.rb +79 -0
- data/lib/cryptum/api/products.rb +65 -0
- data/lib/cryptum/api/rest.rb +177 -0
- data/lib/cryptum/api/signature.rb +79 -0
- data/lib/cryptum/api.rb +10 -640
- data/lib/cryptum/event/buy.rb +1 -1
- data/lib/cryptum/event/cancel.rb +1 -1
- data/lib/cryptum/event/gtfo.rb +1 -1
- data/lib/cryptum/event/sell.rb +1 -1
- data/lib/cryptum/option/choice.rb +2 -2
- data/lib/cryptum/option/environment.rb +45 -0
- data/lib/cryptum/option/input_validation.rb +85 -0
- data/lib/cryptum/option/parser.rb +85 -0
- data/lib/cryptum/option.rb +3 -192
- data/lib/cryptum/order_book/generate.rb +1 -1
- data/lib/cryptum/portfolio/balance.rb +3 -5
- data/lib/cryptum/ui/order_execution.rb +2 -2
- data/lib/cryptum/version.rb +1 -1
- data/lib/cryptum/web_sock/coinbase.rb +1 -1
- data/spec/lib/cryptum/api/exchange_rates_spec.rb +10 -0
- data/spec/lib/cryptum/api/fees_spec.rb +10 -0
- data/spec/lib/cryptum/api/order_history_spec.rb +10 -0
- data/spec/lib/cryptum/api/orders_spec.rb +10 -0
- data/spec/lib/cryptum/api/portfolio_spec.rb +10 -0
- data/spec/lib/cryptum/api/products_spec.rb +10 -0
- data/spec/lib/cryptum/api/rest_spec.rb +10 -0
- data/spec/lib/cryptum/api/signature_spec.rb +10 -0
- data/spec/lib/cryptum/option/environment_spec.rb +10 -0
- data/spec/lib/cryptum/option/input_validation_spec.rb +10 -0
- data/spec/lib/cryptum/option/parser_spec.rb +10 -0
- 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
|