cex 0.1.5 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cex
4
- VERSION = '0.1.5'
4
+ VERSION = '0.1.7'
5
5
  end
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.5
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-02 00:00:00.000000000 Z
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 & bitcoinde no bigquery. Pode ajustar dias
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/bigquery.rb
121
- - lib/cex/client.rb
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 & bitcoinde no bigquery.
155
+ summary: Arquiva transactions bitcoinde/kraken/paymium/therock no bigquery.
149
156
  test_files: []
@@ -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
@@ -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