cex 0.1.5 → 0.1.7
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/Gemfile.lock +2 -2
- data/README.md +1 -1
- data/cex.gemspec +1 -1
- data/lib/cex.rb +11 -4
- data/lib/cex/apide.rb +240 -0
- data/lib/cex/apifr.rb +139 -0
- data/lib/cex/apimt.rb +138 -0
- data/lib/cex/apius.rb +167 -0
- data/lib/cex/bigquery1.rb +145 -0
- data/lib/cex/bigquery2.rb +151 -0
- data/lib/cex/bitcoinde.rb +135 -0
- data/lib/cex/kraken.rb +36 -35
- data/lib/cex/paymium.rb +106 -0
- data/lib/cex/therock.rb +95 -0
- data/lib/cex/version.rb +1 -1
- metadata +14 -7
- data/lib/cex/bigquery.rb +0 -126
- data/lib/cex/client.rb +0 -154
data/lib/cex/therock.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require('bigdecimal/util')
|
4
|
+
|
5
|
+
# @author Hernani Rodrigues Vaz
|
6
|
+
module Cex
|
7
|
+
# classe para processar saldos & transacoes ledger
|
8
|
+
class TheRock
|
9
|
+
# @return [Apius] API therock
|
10
|
+
attr_reader :api
|
11
|
+
# @return [Array<Hash>] todos os dados bigquery
|
12
|
+
attr_reader :dbq
|
13
|
+
# @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
|
14
|
+
attr_reader :ops
|
15
|
+
|
16
|
+
# @param [Hash] dad todos os dados bigquery
|
17
|
+
# @param [Thor::CoreExt::HashWithIndifferentAccess] pop opcoes trabalho
|
18
|
+
# @option pop [Hash] :h ({}) configuracao dias ajuste reposicionamento temporal
|
19
|
+
# @option pop [Boolean] :v (false) mostra dados transacoes trades & ledger?
|
20
|
+
# @option pop [Boolean] :t (false) mostra transacoes todas ou somente novas?
|
21
|
+
# @return [TheRock] API therock - obter saldos & transacoes ledger
|
22
|
+
def initialize(dad, pop)
|
23
|
+
# API therock base
|
24
|
+
@api = Apimt.new
|
25
|
+
@dbq = dad
|
26
|
+
@ops = pop
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Hash] dados exchange therock - saldos & transacoes ledger
|
30
|
+
def exd
|
31
|
+
@exd ||= {
|
32
|
+
sl: api.account,
|
33
|
+
kl: api.ledger
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Array<String>] lista txid de transacoes ledger
|
38
|
+
def kyl
|
39
|
+
@kyl ||= exd[:kl].map { |h| h[:id] } - (ops[:t] ? [] : dbq[:nl].map { |e| e[:txid] })
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Hash] transacoes ledger
|
43
|
+
def ledger
|
44
|
+
@ledger ||= exd[:kl].select { |o| kyl.include?(o[:id]) }
|
45
|
+
end
|
46
|
+
|
47
|
+
# @example (see Apimt#account)
|
48
|
+
# @param [Hash] hsl saldo therock da moeda
|
49
|
+
# @return [String] texto formatado saldos (therock/bigquery) & iguais/ok/nok?
|
50
|
+
def formata_saldos(hsl)
|
51
|
+
b = dbq[:sl][hsl[:currency].downcase.to_sym].to_d
|
52
|
+
k = hsl[:balance].to_d
|
53
|
+
format(
|
54
|
+
'%<mo>-5.5s %<kr>21.9f %<bq>21.9f %<ok>3.3s',
|
55
|
+
mo: hsl[:currency].upcase,
|
56
|
+
kr: k,
|
57
|
+
bq: b,
|
58
|
+
ok: k == b ? 'OK' : 'NOK'
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
# @example (see Apimt#ledger)
|
63
|
+
# @param (see Bigquery#mtl_val1)
|
64
|
+
# @return [String] texto formatado transacao ledger
|
65
|
+
def formata_ledger(hlx)
|
66
|
+
format(
|
67
|
+
'%<ky>6i %<dt>19.19s %<ty>-27.27s %<mo>-4.4s %<vl>20.7f',
|
68
|
+
ky: hlx[:id],
|
69
|
+
dt: Time.parse(hlx[:date]),
|
70
|
+
ty: hlx[:type],
|
71
|
+
mo: hlx[:currency].upcase,
|
72
|
+
vl: hlx[:price].to_d
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [String] texto saldos & transacoes & ajuste dias
|
77
|
+
def mostra_resumo
|
78
|
+
puts("\nTHEROCK\nmoeda saldo therock saldo bigquery")
|
79
|
+
exd[:sl].each { |h| puts(formata_saldos(h)) }
|
80
|
+
|
81
|
+
mostra_ledger
|
82
|
+
return unless ledger.count.positive?
|
83
|
+
|
84
|
+
puts("\nstring ajuste dias da ledger\n-h=#{kyl.map { |e| "#{e}:0" }.join(' ')}")
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [String] texto transacoes ledger
|
88
|
+
def mostra_ledger
|
89
|
+
return unless ops[:v] && ledger.count.positive?
|
90
|
+
|
91
|
+
puts("\nledger data hora tipo moeda ---------quantidade")
|
92
|
+
ledger.sort { |a, b| b[:id] <=> a[:id] }.each { |o| puts(formata_ledger(o)) }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/cex/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hernâni Rodrigues Vaz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,8 +94,8 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
description: Arquiva transactions kraken
|
98
|
-
para reposicionamento temporal.
|
97
|
+
description: Arquiva transactions bitcoinde/kraken/paymium/therock no bigquery. Pode
|
98
|
+
ajustar dias para reposicionamento temporal.
|
99
99
|
email:
|
100
100
|
- hernanirvaz@gmail.com
|
101
101
|
executables:
|
@@ -117,9 +117,16 @@ files:
|
|
117
117
|
- cex.gemspec
|
118
118
|
- exe/cex
|
119
119
|
- lib/cex.rb
|
120
|
-
- lib/cex/
|
121
|
-
- lib/cex/
|
120
|
+
- lib/cex/apide.rb
|
121
|
+
- lib/cex/apifr.rb
|
122
|
+
- lib/cex/apimt.rb
|
123
|
+
- lib/cex/apius.rb
|
124
|
+
- lib/cex/bigquery1.rb
|
125
|
+
- lib/cex/bigquery2.rb
|
126
|
+
- lib/cex/bitcoinde.rb
|
122
127
|
- lib/cex/kraken.rb
|
128
|
+
- lib/cex/paymium.rb
|
129
|
+
- lib/cex/therock.rb
|
123
130
|
- lib/cex/version.rb
|
124
131
|
homepage: https://github.com/hernanirvaz/cex
|
125
132
|
licenses:
|
@@ -145,5 +152,5 @@ requirements: []
|
|
145
152
|
rubygems_version: 3.1.2
|
146
153
|
signing_key:
|
147
154
|
specification_version: 4
|
148
|
-
summary: Arquiva transactions kraken
|
155
|
+
summary: Arquiva transactions bitcoinde/kraken/paymium/therock no bigquery.
|
149
156
|
test_files: []
|
data/lib/cex/bigquery.rb
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require('google/cloud/bigquery')
|
4
|
-
require('bigdecimal/util')
|
5
|
-
|
6
|
-
# @author Hernani Rodrigues Vaz
|
7
|
-
module Cex
|
8
|
-
BD = 'hernanirvaz.coins'
|
9
|
-
|
10
|
-
# classe para processar bigquery & kraken
|
11
|
-
class Bigquery
|
12
|
-
# @return [Google::Cloud::Bigquery] API bigquery
|
13
|
-
attr_reader :api
|
14
|
-
# @return [Google::Cloud::Bigquery::QueryJob] job bigquery
|
15
|
-
attr_reader :job
|
16
|
-
# @return [Thor::CoreExt::HashWithIndifferentAccess] opcoes trabalho
|
17
|
-
attr_reader :ops
|
18
|
-
# @return (see sql)
|
19
|
-
attr_reader :sqr
|
20
|
-
|
21
|
-
# @param [Thor::CoreExt::HashWithIndifferentAccess] pop opcoes trabalho
|
22
|
-
# @option pop [Hash] :h ({}) configuracao ajuste reposicionamento temporal
|
23
|
-
# @option pop [Boolean] :v (false) mostra transacoes trades & ledger?
|
24
|
-
# @option pop [Boolean] :t (false) mostra transacoes todas ou somente novas?
|
25
|
-
# @return [Bigquery] API bigquery & kraken
|
26
|
-
def initialize(pop)
|
27
|
-
# usa env GOOGLE_APPLICATION_CREDENTIALS para obter credentials
|
28
|
-
# @see https://cloud.google.com/bigquery/docs/authentication/getting-started
|
29
|
-
@api = Google::Cloud::Bigquery.new
|
30
|
-
@ops = pop
|
31
|
-
end
|
32
|
-
|
33
|
-
# @return [Kraken] API kraken - obter saldos & transacoes trades e ledger
|
34
|
-
def transacoes
|
35
|
-
@transacoes ||= Kraken.new(
|
36
|
-
{
|
37
|
-
sl: sql("select * from #{BD}.ussl")[0],
|
38
|
-
nt: sql("select * from #{BD}.ustx order by time,txid"),
|
39
|
-
nl: sql("select * from #{BD}.uslx order by time,txid")
|
40
|
-
},
|
41
|
-
ops
|
42
|
-
)
|
43
|
-
end
|
44
|
-
|
45
|
-
# insere transacoes novas nas tabelas ust (trades), usl (ledger)
|
46
|
-
def processa
|
47
|
-
puts(format("%<n>2i TRADES INSERIDAS #{BD}.ust", n: transacoes.trades.count.positive? ? dml(ust_ins) : 0))
|
48
|
-
puts(format("%<n>2i LEDGER INSERIDAS #{BD}.usl", n: transacoes.ledger.count.positive? ? dml(usl_ins) : 0))
|
49
|
-
end
|
50
|
-
|
51
|
-
# @return [String] comando insert SQL formatado ust (trades)
|
52
|
-
def ust_ins
|
53
|
-
"insert #{BD}.ust(txid,ordertxid,pair,time,type,ordertype,price,cost,fee,vol,margin,misc,ledgers,dias" \
|
54
|
-
") VALUES#{transacoes.trades.map { |k, v| ust_val1(k, v) }.join(',')}"
|
55
|
-
end
|
56
|
-
|
57
|
-
# @return [String] valores formatados ust (trades parte1)
|
58
|
-
def ust_val1(idx, hes)
|
59
|
-
"('#{idx}'," \
|
60
|
-
"'#{hes['ordertxid']}'," \
|
61
|
-
"'#{hes['pair']}'," \
|
62
|
-
"PARSE_DATETIME('%s', '#{String(hes['time'].round)}')," \
|
63
|
-
"'#{hes['type']}'," \
|
64
|
-
"'#{hes['ordertype']}'," \
|
65
|
-
"cast(#{hes['price']} as numeric)," \
|
66
|
-
"cast(#{hes['cost']} as numeric)," \
|
67
|
-
"cast(#{hes['fee']} as numeric)," \
|
68
|
-
"#{ust_val2(idx, hes)}"
|
69
|
-
end
|
70
|
-
|
71
|
-
# @return [String] valores formatados ust (trades parte2)
|
72
|
-
def ust_val2(idx, hes)
|
73
|
-
"cast(#{hes['vol']} as numeric)," \
|
74
|
-
"cast(#{hes['margin']} as numeric)," \
|
75
|
-
"#{hes['misc'].length.zero? ? 'null' : "'#{hes['misc']}'"}," \
|
76
|
-
"'#{transacoes.ledger.select { |_, v| v['refid'] == idx }.keys.join(',') || ''}'," \
|
77
|
-
"#{Integer(ops[:h][idx] || 0)})"
|
78
|
-
end
|
79
|
-
|
80
|
-
# @return [String] comando insert SQL formatado usl (ledger)
|
81
|
-
def usl_ins
|
82
|
-
"insert #{BD}.usl(txid,refid,time,type,aclass,asset,amount,fee" \
|
83
|
-
") VALUES#{transacoes.ledger.map { |k, v| usl_val(k, v) }.join(',')}"
|
84
|
-
end
|
85
|
-
|
86
|
-
# @return [String] valores formatados usl (ledger)
|
87
|
-
def usl_val(idx, hes)
|
88
|
-
"('#{idx}'," \
|
89
|
-
"'#{hes['refid']}'," \
|
90
|
-
"PARSE_DATETIME('%s', '#{String(hes['time'].round)}')," \
|
91
|
-
"'#{hes['type']}'," \
|
92
|
-
"#{hes['aclass'].length.zero? ? 'null' : "'#{hes['aclass']}'"}," \
|
93
|
-
"'#{hes['asset']}'," \
|
94
|
-
"cast(#{hes['amount']} as numeric)," \
|
95
|
-
"cast(#{hes['fee']} as numeric))"
|
96
|
-
end
|
97
|
-
|
98
|
-
# cria job bigquery & verifica execucao
|
99
|
-
#
|
100
|
-
# @param cmd (see sql)
|
101
|
-
# @return [Boolean] job ok?
|
102
|
-
def job?(cmd)
|
103
|
-
@job = api.query_job(cmd)
|
104
|
-
@job.wait_until_done!
|
105
|
-
puts(@job.error['message']) if @job.failed?
|
106
|
-
@job.failed?
|
107
|
-
end
|
108
|
-
|
109
|
-
# cria Structured Query Language (SQL) job bigquery
|
110
|
-
#
|
111
|
-
# @param [String] cmd comando SQL a executar
|
112
|
-
# @param [String] red resultado quando SQL tem erro
|
113
|
-
# @return [Google::Cloud::Bigquery::Data] resultado do SQL
|
114
|
-
def sql(cmd, red = [])
|
115
|
-
@sqr = job?(cmd) ? red : job.data
|
116
|
-
end
|
117
|
-
|
118
|
-
# cria Data Manipulation Language (DML) job bigquery
|
119
|
-
#
|
120
|
-
# @param cmd (see sql)
|
121
|
-
# @return [Integer] numero linhas afetadas
|
122
|
-
def dml(cmd)
|
123
|
-
job?(cmd) ? 0 : job.num_dml_affected_rows
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
data/lib/cex/client.rb
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require('openssl')
|
4
|
-
require('base64')
|
5
|
-
require('curb')
|
6
|
-
require('json')
|
7
|
-
|
8
|
-
# @author Hernani Rodrigues Vaz
|
9
|
-
module Cex
|
10
|
-
# classe para processar dados no kraken
|
11
|
-
class Client
|
12
|
-
# @return [String] API key
|
13
|
-
attr_reader :aky
|
14
|
-
# @return [String] API secret
|
15
|
-
attr_reader :asc
|
16
|
-
# @return [String] API public url
|
17
|
-
attr_reader :puu
|
18
|
-
# @return [String] API private url
|
19
|
-
attr_reader :pru
|
20
|
-
# @return [String] API private path
|
21
|
-
attr_reader :pth
|
22
|
-
|
23
|
-
# @param [String] pky API key
|
24
|
-
# @param [String] psc API secret
|
25
|
-
# @return [Client] API kraken base
|
26
|
-
def initialize(pky: ENV['KRAKEN_API_KEY'], psc: ENV['KRAKEN_API_SECRET'], options: {})
|
27
|
-
b = options.fetch(:base_uri, 'https://api.kraken.com')
|
28
|
-
v = options.fetch(:version, 0)
|
29
|
-
@aky = pky
|
30
|
-
@asc = psc
|
31
|
-
@puu = "#{b}/#{v}/public/"
|
32
|
-
@pru = "#{b}/#{v}/private/"
|
33
|
-
@pth = "/#{v}/private/"
|
34
|
-
end
|
35
|
-
|
36
|
-
# @return [Hash] resultados ultimas transacoes trades no kraken
|
37
|
-
# @example
|
38
|
-
# {
|
39
|
-
# 'trades' => {
|
40
|
-
# 'TLADFV-QIUTN-QDNCBR' => {
|
41
|
-
# 'ordertxid' => 'O2CRFG-5PCJA-EMX7VC',
|
42
|
-
# 'pair' => 'XETHXXBT',
|
43
|
-
# 'time' => 1_463_422_494.7069,
|
44
|
-
# 'type' => 'buy',
|
45
|
-
# 'ordertype' => 'market',
|
46
|
-
# 'price' => '0.024400',
|
47
|
-
# 'cost' => '1.358424',
|
48
|
-
# 'fee' => '0.003532',
|
49
|
-
# 'vol' => '55.67311475',
|
50
|
-
# 'margin' => '0.000000',
|
51
|
-
# 'misc' => ''
|
52
|
-
# },
|
53
|
-
# ...
|
54
|
-
# },
|
55
|
-
# 'count' => 156
|
56
|
-
# }
|
57
|
-
def trades_history
|
58
|
-
post_private('TradesHistory')['result']
|
59
|
-
end
|
60
|
-
|
61
|
-
# @return [Hash] resultados ultimas transacoes ledger no kraken
|
62
|
-
# @example
|
63
|
-
# {
|
64
|
-
# 'ledger' => {
|
65
|
-
# 'LUK3QC-QW6TA-27B7NI' => {
|
66
|
-
# 'refid' => 'A2BNCQS-CHCETZ-JYCER6',
|
67
|
-
# 'time' => 1_584_349_306.9479,
|
68
|
-
# 'type' => 'withdrawal',
|
69
|
-
# 'subtype' => '',
|
70
|
-
# 'aclass' => 'currency',
|
71
|
-
# 'asset' => 'XETH',
|
72
|
-
# 'amount' => '-29.2659039100',
|
73
|
-
# 'fee' => '0.0050000000',
|
74
|
-
# 'balance' => '1.1806988100'
|
75
|
-
# }
|
76
|
-
# ,
|
77
|
-
# ...
|
78
|
-
# },
|
79
|
-
# 'count' => 373
|
80
|
-
# }
|
81
|
-
def ledger
|
82
|
-
post_private('Ledgers')['result']
|
83
|
-
end
|
84
|
-
|
85
|
-
# @return [Hash] saldos no kraken
|
86
|
-
# @example
|
87
|
-
# {
|
88
|
-
# 'ZEUR' => '0.0000',
|
89
|
-
# 'XXBT' => '0.0000000000',
|
90
|
-
# 'XETH' => '1.1806988100',
|
91
|
-
# 'XETC' => '0.0000000000',
|
92
|
-
# 'EOS' => '0.0000001700',
|
93
|
-
# 'BCH' => '0.0000000000'
|
94
|
-
# }
|
95
|
-
def balance
|
96
|
-
post_private('Balance')['result']
|
97
|
-
end
|
98
|
-
|
99
|
-
# @return [Hash] data hora kraken
|
100
|
-
# @example
|
101
|
-
# {
|
102
|
-
# 'unixtime' => 1_598_956_727,
|
103
|
-
# 'rfc1123' => 'Tue, 1 Sep 20 10:38:47 +0000'
|
104
|
-
# }
|
105
|
-
def server_time
|
106
|
-
get_public('Time')['result']
|
107
|
-
end
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
# HTTP GET request for public API queries.
|
112
|
-
def get_public(method, **opts)
|
113
|
-
parse_response(Curl.get("#{puu}#{method}", opts))
|
114
|
-
end
|
115
|
-
|
116
|
-
# HTTP POST request for private API queries involving user credentials.
|
117
|
-
def post_private(method, **opts)
|
118
|
-
# Generate a continually-increasing unsigned 51-bit integer nonce from the current Unix Time.
|
119
|
-
opts.merge!({ nonce: Integer(Time.now) * 1_000_000 })
|
120
|
-
|
121
|
-
parse_response(Curl.post("#{pru}#{method}", opts) do |r|
|
122
|
-
r.headers = {
|
123
|
-
'api-key': aky,
|
124
|
-
'api-sign': authenticate(method, opts[:nonce], opts.map { |p| p.join('=') }.join('&'))
|
125
|
-
}
|
126
|
-
end)
|
127
|
-
end
|
128
|
-
|
129
|
-
def authenticate(method, nonce, params)
|
130
|
-
raise(ArgumentError, 'API Key is not set') unless aky
|
131
|
-
raise(ArgumentError, 'API Secret is not set') unless asc
|
132
|
-
|
133
|
-
Base64.strict_encode64(OpenSSL::HMAC.digest(
|
134
|
-
'sha512',
|
135
|
-
Base64.decode64(asc),
|
136
|
-
"#{pth}#{method}#{Digest::SHA256.digest("#{nonce}#{params}")}"
|
137
|
-
))
|
138
|
-
end
|
139
|
-
|
140
|
-
def parse_response(http)
|
141
|
-
# HTTP_SUCCESS = 200
|
142
|
-
http.response_code == 200 ? JSON.parse(http.body) : http.status
|
143
|
-
rescue JSON::ParserError,
|
144
|
-
EOFError,
|
145
|
-
Errno::ECONNRESET,
|
146
|
-
Errno::EINVAL,
|
147
|
-
Net::HTTPBadResponse,
|
148
|
-
Net::HTTPHeaderSyntaxError,
|
149
|
-
Net::ProtocolError,
|
150
|
-
Timeout::Error => e
|
151
|
-
"Erro da API #{e.inspect}"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|