cex 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 907cbeed0b941fc1e414efc87b6da5aea844dac625804780cba57fafc3e2770b
4
+ data.tar.gz: 46895875166c9e6e3beb4200a26fc83f946da4a9a3a4876bada58dd113d68083
5
+ SHA512:
6
+ metadata.gz: 5b0e3ad0f513df95f5d4e73dbaaf52916330b1574ed0c435a71709505653b9096e5d8c9196596e9fc3f515f7bae125d4dda992a7e0c443a62966223b9aa9d03e
7
+ data.tar.gz: 6d773a42262afb48402a990cfbe98fc188e9f6573896de8413802ddd14c8edf3910f309a5a52f8c1b9af4ae9ca1c252fcfc09c0f2a8b13c9248901cc11a2b446
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,12 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.7
3
+ EnabledByDefault: true
4
+
5
+ Style/Copyright:
6
+ Enabled: false
7
+
8
+ Lint/ConstantResolution:
9
+ Enabled: false
10
+
11
+ Style/ConstantVisibility:
12
+ Enabled: false
@@ -0,0 +1,5 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ rvm:
5
+ - 2.7.0
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at hernanirvaz@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in cex.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
@@ -0,0 +1,80 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ cex (0.1.3)
5
+ curb
6
+ google-cloud-bigquery
7
+ thor
8
+ yard
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ addressable (2.7.0)
14
+ public_suffix (>= 2.0.2, < 5.0)
15
+ concurrent-ruby (1.1.7)
16
+ curb (0.9.10)
17
+ declarative (0.0.20)
18
+ declarative-option (0.1.0)
19
+ faraday (1.0.1)
20
+ multipart-post (>= 1.2, < 3)
21
+ google-api-client (0.44.0)
22
+ addressable (~> 2.5, >= 2.5.1)
23
+ googleauth (~> 0.9)
24
+ httpclient (>= 2.8.1, < 3.0)
25
+ mini_mime (~> 1.0)
26
+ representable (~> 3.0)
27
+ retriable (>= 2.0, < 4.0)
28
+ signet (~> 0.12)
29
+ google-cloud-bigquery (1.21.2)
30
+ concurrent-ruby (~> 1.0)
31
+ google-api-client (~> 0.33)
32
+ google-cloud-core (~> 1.2)
33
+ googleauth (~> 0.9)
34
+ mini_mime (~> 1.0)
35
+ google-cloud-core (1.5.0)
36
+ google-cloud-env (~> 1.0)
37
+ google-cloud-errors (~> 1.0)
38
+ google-cloud-env (1.3.3)
39
+ faraday (>= 0.17.3, < 2.0)
40
+ google-cloud-errors (1.0.1)
41
+ googleauth (0.13.1)
42
+ faraday (>= 0.17.3, < 2.0)
43
+ jwt (>= 1.4, < 3.0)
44
+ memoist (~> 0.16)
45
+ multi_json (~> 1.11)
46
+ os (>= 0.9, < 2.0)
47
+ signet (~> 0.14)
48
+ httpclient (2.8.3)
49
+ jwt (2.2.2)
50
+ memoist (0.16.2)
51
+ mini_mime (1.0.2)
52
+ multi_json (1.15.0)
53
+ multipart-post (2.1.1)
54
+ os (1.1.1)
55
+ public_suffix (4.0.6)
56
+ rake (12.3.3)
57
+ representable (3.0.4)
58
+ declarative (< 0.1.0)
59
+ declarative-option (< 0.2.0)
60
+ uber (< 0.2.0)
61
+ retriable (3.1.2)
62
+ signet (0.14.0)
63
+ addressable (~> 2.3)
64
+ faraday (>= 0.17.3, < 2.0)
65
+ jwt (>= 1.5, < 3.0)
66
+ multi_json (~> 1.10)
67
+ thor (1.0.1)
68
+ uber (0.1.0)
69
+ yard (0.9.25)
70
+
71
+ PLATFORMS
72
+ ruby
73
+
74
+ DEPENDENCIES
75
+ bundler
76
+ cex!
77
+ rake (~> 12.0)
78
+
79
+ BUNDLED WITH
80
+ 2.1.4
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Hernâni Rodrigues Vaz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,47 @@
1
+ # Cex [![Build Status](https://travis-ci.com/hernanirvaz/cex.svg?branch=master)](https://travis-ci.com/hernanirvaz/cex)
2
+
3
+ Arquiva transactions kraken & bitcoinde no bigquery. Pode ajustar dias para reposicionamento temporal.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'cex'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install cex
20
+
21
+ ## Usage
22
+
23
+ $ cex help [COMMAND] # Describe available commands or one specific command
24
+ $ cex show # mostra resumo saldos & transacoes
25
+ ops [-v], [--no-v] # mostra transacoes
26
+ [-t], [--no-t] # mostra transacoes todas ou somente novas
27
+ $ cex work # carrega transacoes novas no bigquery
28
+ ops [-h=key:value] # configuracao ajuste reposicionamento temporal
29
+
30
+ ## Development
31
+
32
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
33
+
34
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
35
+
36
+ ## Contributing
37
+
38
+ Bug reports and pull requests are welcome on GitHub at https://github.com/hernanrvaz/cex. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/hernanrvaz/cex/blob/master/CODE_OF_CONDUCT.md).
39
+
40
+
41
+ ## License
42
+
43
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
44
+
45
+ ## Code of Conduct
46
+
47
+ Everyone interacting in the Cex project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/hernanrvaz/cex/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "cex"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative('lib/cex/version')
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'cex'
7
+ spec.version = Cex::VERSION
8
+ spec.authors = ['Hernâni Rodrigues Vaz']
9
+ spec.email = ['hernanirvaz@gmail.com']
10
+
11
+ spec.summary = 'Arquiva transactions kraken & bitcoinde no bigquery.'
12
+ spec.description = "#{spec.summary} Pode ajustar dias para reposicionamento temporal."
13
+ spec.homepage = 'https://github.com/hernanirvaz/cex'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
16
+
17
+ spec.metadata['yard.run'] = 'yard'
18
+ spec.metadata['homepage_uri'] = spec.homepage
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files =
23
+ Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ end
26
+ spec.bindir = 'exe'
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ['lib']
29
+
30
+ spec.add_development_dependency('bundler')
31
+ spec.add_development_dependency('rake')
32
+
33
+ spec.add_dependency('curb')
34
+ spec.add_dependency('google-cloud-bigquery')
35
+ spec.add_dependency('thor')
36
+ spec.add_dependency('yard')
37
+ end
data/exe/cex ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require('cex')
5
+
6
+ Cex::CLI.start(ARGV)
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('thor')
4
+ require('cex/bigquery')
5
+ require('cex/client')
6
+ require('cex/kraken')
7
+ require('cex/version')
8
+
9
+ module Cex
10
+ class Error < StandardError; end
11
+
12
+ # classe para carregar/mostrar dados transacoes kraken no bigquery
13
+ class CLI < Thor
14
+ desc 'work', 'carrega transacoes novas no bigquery'
15
+ option :h, type: :hash, default: {}, desc: 'configuracao ajuste reposicionamento temporal'
16
+ # carrega transacoes novas no bigquery
17
+ def work
18
+ Bigquery.new(options).processa
19
+ end
20
+
21
+ desc 'show', 'mostra resumo saldos & transacoes'
22
+ option :v, type: :boolean, default: false, desc: 'mostra transacoes'
23
+ option :t, type: :boolean, default: false, desc: 'mostra transacoes todas ou somente novas'
24
+ # mostra resumo saldos & transacoes
25
+ def show
26
+ Bigquery.new(options).transacoes.mostra_resumo
27
+ end
28
+
29
+ default_task :show
30
+ end
31
+ end
@@ -0,0 +1,126 @@
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 [Bitcoinde] API kraken - obter saldos & transacoes trades e ledger
34
+ def transacoes
35
+ @transacoes ||= Bitcoinde.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
@@ -0,0 +1,154 @@
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
@@ -0,0 +1,131 @@
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 trades e ledger
8
+ class Kraken
9
+ # @return [Client] API kraken
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 [Kraken] API kraken - obter saldos & transacoes trades e ledger
22
+ def initialize(dad, pop)
23
+ # API kraken base
24
+ @api = Client.new
25
+ @dbq = dad
26
+ @ops = pop
27
+ end
28
+
29
+ # @return [Hash] dados kraken - saldos & transacoes trades e ledger
30
+ def dkr
31
+ @dkr ||= {
32
+ sl: api.balance,
33
+ kt: api.trades_history,
34
+ kl: api.ledger
35
+ }
36
+ end
37
+
38
+ # @return [Array<String>] lista txid de transacoes trades
39
+ def kyt
40
+ @kyt ||= dkr[:kt]['trades'].keys - (ops[:t] ? [] : dbq[:nt].map { |e| e[:txid] })
41
+ end
42
+
43
+ # @return [Array<String>] lista txid de transacoes ledger
44
+ def kyl
45
+ @kyl ||= dkr[:kl]['ledger'].keys - (ops[:t] ? [] : dbq[:nl].map { |e| e[:txid] })
46
+ end
47
+
48
+ # @return [Hash] transacoes trades
49
+ def trades
50
+ @trades ||= dkr[:kt]['trades'].select { |k, _| kyt.include?(k) }
51
+ end
52
+
53
+ # @return [Hash] transacoes ledger
54
+ def ledger
55
+ @ledger ||= dkr[:kl]['ledger'].select { |k, _| kyl.include?(k) }
56
+ end
57
+
58
+ # @parm [String] moe codigo kraken da moeda
59
+ # @parm [String] moe saldo kraken da moeda
60
+ # @return [String] texto formatado saldos (kraken/bigquery) & iguais/ok/nok?
61
+ def formata_saldos(moe, sal)
62
+ t = dbq[:sl][moe.downcase.to_sym].to_d
63
+ format(
64
+ '%<mo>-5.5s %<kr>21.9f %<bq>21.9f %<ok>3.3s',
65
+ mo: moe,
66
+ kr: sal,
67
+ bq: t,
68
+ ok: t == sal ? 'OK' : 'NOK'
69
+ )
70
+ end
71
+
72
+ # @parm [String] idx codigo transacao
73
+ # @parm [Hash] htx transacao trade
74
+ # @return [String] texto formatado transacao trade
75
+ def formata_transacao_trades(idx, htx)
76
+ format(
77
+ '%<ky>-6.6s %<dt>19.19s %<ty>-10.10s %<mo>-8.8s %<pr>8.2f %<vl>15.7f %<co>8.2f',
78
+ ky: idx,
79
+ dt: Time.at(htx['time']),
80
+ ty: "#{htx['type']}/#{htx['ordertype']}",
81
+ mo: htx['pair'],
82
+ pr: htx['price'].to_d,
83
+ vl: htx['vol'].to_d,
84
+ co: htx['cost'].to_d
85
+ )
86
+ end
87
+
88
+ # @parm idx (see formata_transacao_trades)
89
+ # @parm [Hash] hlx transacao ledger
90
+ # @return [String] texto formatado transacao ledger
91
+ def formata_transacao_ledger(idx, hlx)
92
+ format(
93
+ '%<ky>-6.6s %<dt>19.19s %<ty>-10.10s %<mo>-4.4s %<pr>18.7f %<vl>18.7f',
94
+ ky: idx,
95
+ dt: Time.at(hlx['time']),
96
+ ty: hlx['type'],
97
+ mo: hlx['asset'],
98
+ pr: hlx['amount'].to_d,
99
+ vl: hlx['fee'].to_d
100
+ )
101
+ end
102
+
103
+ # @return [String] texto saldos & transacoes & ajuste dias
104
+ def mostra_resumo
105
+ puts("\nmoeda saldo kraken saldo bigquery")
106
+ dkr[:sl].each { |k, v| puts(formata_saldos(k, v.to_d)) }
107
+
108
+ mostra_trades
109
+ mostra_ledger
110
+ return unless trades.count.positive?
111
+
112
+ puts("\nstring ajuste dias dos trades\n-h=#{kyt.map { |e| "#{e}:0" }.join(' ')}")
113
+ end
114
+
115
+ # @return [String] texto transacoes trades
116
+ def mostra_trades
117
+ return unless ops[:v] && trades.count.positive?
118
+
119
+ puts("\ntrade data hora tipo par ---preco ---------volume ---custo")
120
+ trades.each { |k, v| puts(formata_transacao_trades(k, v)) }
121
+ end
122
+
123
+ # @return [String] texto transacoes ledger
124
+ def mostra_ledger
125
+ return unless ops[:v] && ledger.count.positive?
126
+
127
+ puts("\nledger data hora tipo moeda -------quantidade -------------custo")
128
+ ledger.each { |k, v| puts(formata_transacao_ledger(k, v)) }
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cex
4
+ VERSION = '0.1.3'
5
+ end
metadata ADDED
@@ -0,0 +1,149 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cex
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Hernâni Rodrigues Vaz
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-09-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: curb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: google-cloud-bigquery
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: thor
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Arquiva transactions kraken & bitcoinde no bigquery. Pode ajustar dias
98
+ para reposicionamento temporal.
99
+ email:
100
+ - hernanirvaz@gmail.com
101
+ executables:
102
+ - cex
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - ".gitignore"
107
+ - ".rubocop.yml"
108
+ - ".travis.yml"
109
+ - CODE_OF_CONDUCT.md
110
+ - Gemfile
111
+ - Gemfile.lock
112
+ - LICENSE.txt
113
+ - README.md
114
+ - Rakefile
115
+ - bin/console
116
+ - bin/setup
117
+ - cex.gemspec
118
+ - exe/cex
119
+ - lib/cex.rb
120
+ - lib/cex/bigquery.rb
121
+ - lib/cex/client.rb
122
+ - lib/cex/kraken.rb
123
+ - lib/cex/version.rb
124
+ homepage: https://github.com/hernanirvaz/cex
125
+ licenses:
126
+ - MIT
127
+ metadata:
128
+ yard.run: yard
129
+ homepage_uri: https://github.com/hernanirvaz/cex
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 2.3.0
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubygems_version: 3.1.2
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: Arquiva transactions kraken & bitcoinde no bigquery.
149
+ test_files: []