cryptum 0.0.230
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 +7 -0
- data/.github/workflows/main.yml +16 -0
- data/.gitignore +30 -0
- data/.rspec +3 -0
- data/.rspec_status +0 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +250 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +36 -0
- data/LICENSE +674 -0
- data/README.md +72 -0
- data/Rakefile +19 -0
- data/bin/cryptum +72 -0
- data/bin/cryptum-forecast +199 -0
- data/bin/cryptum-repl +73 -0
- data/bin/cryptum_autoinc_version +38 -0
- data/build_cryptum_gem.sh +52 -0
- data/cryptum.gemspec +50 -0
- data/cryptum_container.sh +1 -0
- data/docker/cryptum.json +60 -0
- data/docker/cryptum_container.sh +59 -0
- data/docker/packer_secrets.json.EXAMPLE +7 -0
- data/docker/provisioners/cryptum.sh +11 -0
- data/docker/provisioners/docker_bashrc.sh +2 -0
- data/docker/provisioners/docker_rvm.sh +22 -0
- data/docker/provisioners/init_image.sh +28 -0
- data/docker/provisioners/post_install.sh +6 -0
- data/docker/provisioners/ruby.sh +16 -0
- data/docker/provisioners/upload_globals.sh +49 -0
- data/etc/bot_confs/.gitkeep +0 -0
- data/etc/bot_confs/BOT_CONF.TEMPLATE +10 -0
- data/etc/coinbase_pro.yaml.EXAMPLE +8 -0
- data/git_commit.sh +22 -0
- data/lib/cryptum/api.rb +693 -0
- data/lib/cryptum/bot_conf.rb +76 -0
- data/lib/cryptum/event/buy.rb +144 -0
- data/lib/cryptum/event/cancel.rb +49 -0
- data/lib/cryptum/event/history.rb +64 -0
- data/lib/cryptum/event/key_press.rb +64 -0
- data/lib/cryptum/event/sell.rb +120 -0
- data/lib/cryptum/event.rb +168 -0
- data/lib/cryptum/log.rb +34 -0
- data/lib/cryptum/matrix.rb +181 -0
- data/lib/cryptum/option/choice.rb +26 -0
- data/lib/cryptum/option.rb +161 -0
- data/lib/cryptum/order_book/generate.rb +111 -0
- data/lib/cryptum/order_book/indicator.rb +16 -0
- data/lib/cryptum/order_book/market_trend.rb +161 -0
- data/lib/cryptum/order_book/profit_margin.rb +55 -0
- data/lib/cryptum/order_book/weighted_avg.rb +157 -0
- data/lib/cryptum/order_book.rb +156 -0
- data/lib/cryptum/portfolio/balance.rb +123 -0
- data/lib/cryptum/portfolio.rb +15 -0
- data/lib/cryptum/ui/command.rb +274 -0
- data/lib/cryptum/ui/key_press_event.rb +22 -0
- data/lib/cryptum/ui/market_trend.rb +117 -0
- data/lib/cryptum/ui/order_execution.rb +478 -0
- data/lib/cryptum/ui/order_plan.rb +376 -0
- data/lib/cryptum/ui/order_timer.rb +119 -0
- data/lib/cryptum/ui/portfolio.rb +231 -0
- data/lib/cryptum/ui/signal_engine.rb +122 -0
- data/lib/cryptum/ui/terminal_window.rb +95 -0
- data/lib/cryptum/ui/ticker.rb +317 -0
- data/lib/cryptum/ui.rb +306 -0
- data/lib/cryptum/version.rb +5 -0
- data/lib/cryptum/web_sock/coinbase.rb +94 -0
- data/lib/cryptum/web_sock/event_machine.rb +182 -0
- data/lib/cryptum/web_sock.rb +16 -0
- data/lib/cryptum.rb +183 -0
- data/order_books/.gitkeep +0 -0
- data/reinstall_cryptum_gemset.sh +29 -0
- data/spec/lib/cryptum/api_spec.rb +10 -0
- data/spec/lib/cryptum/event_spec.rb +10 -0
- data/spec/lib/cryptum/log_spec.rb +10 -0
- data/spec/lib/cryptum/option_spec.rb +10 -0
- data/spec/lib/cryptum/order_book/generate_spec.rb +10 -0
- data/spec/lib/cryptum/order_book/market_trend_spec.rb +10 -0
- data/spec/lib/cryptum/order_book_spec.rb +10 -0
- data/spec/lib/cryptum/ui/command_spec.rb +10 -0
- data/spec/lib/cryptum/ui/ticker_spec.rb +10 -0
- data/spec/lib/cryptum/ui_spec.rb +10 -0
- data/spec/lib/cryptum/web_sock_spec.rb +10 -0
- data/spec/lib/cryptum_spec.rb +10 -0
- data/spec/spec_helper.rb +3 -0
- data/upgrade_Gemfile_gems.sh +20 -0
- data/upgrade_cryptum.sh +13 -0
- data/upgrade_gem.sh +4 -0
- data/upgrade_ruby.sh +46 -0
- metadata +472 -0
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
## **Welcome to Cryptum!** ###
|
2
|
+
#### What ####
|
3
|
+
Cryptum is an automated, momentum-trading crypto robot written in Ruby.
|
4
|
+
|
5
|
+
#### Why ####
|
6
|
+
The goal of cryptum is three-fold:
|
7
|
+
- Identify bugs that qualify for bounty on [H1](https://hackerone.com/coinbase)
|
8
|
+
- Take the emotion out of trading crypto currency.
|
9
|
+
- Grow asset portfolios.
|
10
|
+
|
11
|
+
#### How ####
|
12
|
+
By combining real-time market data in conjunction with personalized portfolio and order history, cryptum leverages a collection of status indicators to derive probabilities to buy, sell, hold, cancel orders, or skip a respective crytpo.
|
13
|
+
|
14
|
+
Once these probabilities are derived (which occurs at a high cadence), the respective transaction will be submitted for fulfillment.
|
15
|
+
|
16
|
+
### **Installation** ###
|
17
|
+
Tested on Linux, & OSX leveraging Ruby via RVM.
|
18
|
+
|
19
|
+
```
|
20
|
+
$ rvm gemset create cryptum
|
21
|
+
$ rvm list gemsets
|
22
|
+
$ rvm use ruby-<VERSION>@cryptum
|
23
|
+
$ gem install --verbose cryptum
|
24
|
+
$ cryptum --help
|
25
|
+
```
|
26
|
+
|
27
|
+
- Create a Local Coinbot Config Folder
|
28
|
+
```
|
29
|
+
$ mkdir -p ~/cryptum/order_books
|
30
|
+
```
|
31
|
+
|
32
|
+
- Copy the Gem etc to the Local Config Folder
|
33
|
+
```
|
34
|
+
$ cp -a $(ruby -r 'puts "#{Gem.path.first}/gems/cryptum-#{Coinbot::VERSION}/etc"') ~/cryptum
|
35
|
+
```
|
36
|
+
|
37
|
+
- Copy coinbase_pro.yaml.EXAMPLE to the Local Config Folder
|
38
|
+
```
|
39
|
+
$ cp ~/cryptum/etc/coinbase_pro.yaml.EXAMPLE \
|
40
|
+
~/cryptum/etc/coinbase_pro.yaml
|
41
|
+
```
|
42
|
+
|
43
|
+
- Add Your API Details to ~/cryptum/etc/coinbase_pro.yaml:
|
44
|
+
```
|
45
|
+
$ vi ~/cryptum/etc/coinbase_pro.yaml
|
46
|
+
```
|
47
|
+
|
48
|
+
|
49
|
+
### **Usage** ###
|
50
|
+
|
51
|
+
```
|
52
|
+
$ rvm use ruby-<VERSION>@cryptum
|
53
|
+
$ cryptum --help
|
54
|
+
$ cryptum --symbol btc-usd \
|
55
|
+
--autotrade \
|
56
|
+
--repo-root ~/cryptum
|
57
|
+
```
|
58
|
+
|
59
|
+
### **Contributing** ###
|
60
|
+
|
61
|
+
For details around contributing to this project, please refer to the [Cryptum Development Guide](https://github.com/0dayinc/cryptum/blob/master/web/app/public/wiki/dev_getting_started.md).
|
62
|
+
|
63
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/0dayinc/cryptum. 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/0dayinc/cryptum/blob/master/CODE_OF_CONDUCT.md).
|
64
|
+
|
65
|
+
### **Code of Conduct** ###
|
66
|
+
|
67
|
+
Everyone interacting in the Cryptum project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/0dayinc/cryptum/blob/master/CODE_OF_CONDUCT.md).
|
68
|
+
|
69
|
+
### **DISCLAIMER** ###
|
70
|
+
Cryptum is for educational purposes only. No information, forward looking statements, or estimations presented herein represent any final determination on investment performance. While the capabilities implemented in this project have been researched and thought to be reasonably accurate, any investment is speculative in nature.
|
71
|
+
|
72
|
+
0day Inc. and/or its agents cannot and do not guarantee any rate of return or investment timeline based on the capabilities provided herein. Feel free to use cryptum at your own risk.
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rdoc/task'
|
6
|
+
require 'rubocop/rake_task'
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
|
+
RuboCop::RakeTask.new do |rubocop|
|
10
|
+
config_file = '.rubocop.yml'
|
11
|
+
rubocop.options = ['-E', '-S', '-c', config_file]
|
12
|
+
end
|
13
|
+
|
14
|
+
RDoc::Task.new do |rdoc|
|
15
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
end
|
18
|
+
|
19
|
+
task default: %i[spec rubocop rdoc]
|
data/bin/cryptum
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require 'cryptum'
|
6
|
+
|
7
|
+
begin
|
8
|
+
start_time = Time.now.strftime('%Y-%m-%d %H:%M:%S%z')
|
9
|
+
# Initialize Driver Name & Parse cryptum Flags
|
10
|
+
driver_name = File.basename($PROGRAM_NAME)
|
11
|
+
option_choice = Cryptum::Option.parser(driver_name: driver_name)
|
12
|
+
|
13
|
+
# Initialize the Respective Environment / API Authentication Artifacts
|
14
|
+
env = Cryptum::Option.get_env(option_choice: option_choice)
|
15
|
+
|
16
|
+
# Dump out supported products if --list-products flag is passed and exit
|
17
|
+
if option_choice.list_products
|
18
|
+
Cryptum::Option.list_products_and_exit(
|
19
|
+
option_choice: option_choice,
|
20
|
+
env: env
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Instantiate Our Status Indicators & History Objects
|
25
|
+
indicator_status = Cryptum::OrderBook::Indicator.new
|
26
|
+
|
27
|
+
# Automatically Create Bot Confs if they don't
|
28
|
+
# Exist and Initialize Automated Trading Parameters
|
29
|
+
bot_conf = Cryptum::BotConf.read(option_choice: option_choice)
|
30
|
+
|
31
|
+
# Generate an Order Book for Session Tracking
|
32
|
+
# Load previous order_book_justification from
|
33
|
+
# Order Book File (if it exists) to preserve
|
34
|
+
# Order Tags and load last 180 candles from
|
35
|
+
# Coinbase
|
36
|
+
event_history = Cryptum::OrderBook::Generate.new_order_book(
|
37
|
+
start_time: start_time,
|
38
|
+
option_choice: option_choice,
|
39
|
+
env: env,
|
40
|
+
bot_conf: bot_conf
|
41
|
+
)
|
42
|
+
|
43
|
+
# Initialize Curses UI
|
44
|
+
terminal_win = Cryptum::UI.init
|
45
|
+
|
46
|
+
# Connect to WebSocket
|
47
|
+
# Trigger Events as Event Data
|
48
|
+
# is Generated via Coinbase Pro
|
49
|
+
# Web Socket HTTP Responses
|
50
|
+
# Refresh UI with Event Data
|
51
|
+
# Update "Status Indicators"
|
52
|
+
# Leverage "Status Indicators" to Initiate Actions
|
53
|
+
Cryptum::WebSock::EventMachine.run(
|
54
|
+
option_choice: option_choice,
|
55
|
+
env: env,
|
56
|
+
terminal_win: terminal_win,
|
57
|
+
event_history: event_history,
|
58
|
+
indicator_status: indicator_status,
|
59
|
+
bot_conf: bot_conf
|
60
|
+
)
|
61
|
+
rescue Interrupt
|
62
|
+
# Exit Gracefully if CTRL+C is Pressed During Session
|
63
|
+
Cryptum.exit_gracefully(
|
64
|
+
which_self: self,
|
65
|
+
event_history: event_history,
|
66
|
+
option_choice: option_choice,
|
67
|
+
env: env
|
68
|
+
)
|
69
|
+
rescue StandardError => e
|
70
|
+
# Produce a Stacktrace for anything else
|
71
|
+
raise e
|
72
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'cryptum'
|
7
|
+
|
8
|
+
class Choice
|
9
|
+
attr_accessor :autotrade_percent,
|
10
|
+
:cycles_complete,
|
11
|
+
:driver_name,
|
12
|
+
:proxy,
|
13
|
+
:repo_root,
|
14
|
+
:sandbox,
|
15
|
+
:symbol,
|
16
|
+
:tpm,
|
17
|
+
:total_holdings
|
18
|
+
|
19
|
+
rescue StandardError => e
|
20
|
+
# Produce a Stacktrace for anything else
|
21
|
+
raise e
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
option_choice = Choice.new
|
26
|
+
option_choice.driver_name = File.basename($PROGRAM_NAME)
|
27
|
+
|
28
|
+
OptionParser.new do |options|
|
29
|
+
options.banner = "USAGE: #{option_choice.driver_name} [opts]"
|
30
|
+
options.on(
|
31
|
+
'-sSYMBOL',
|
32
|
+
'--symbol=SYMBOL',
|
33
|
+
'<Required - Crypto Symbol.(e.g. btc-usd, eth-usd, etc.)'
|
34
|
+
) { |s| option_choice.symbol = s.to_s.gsub('-', '_').downcase.to_sym }
|
35
|
+
|
36
|
+
options.on(
|
37
|
+
'-aPERCENT',
|
38
|
+
'--autotrade=PERCENT',
|
39
|
+
'<Optional - Autotrade % (Defaults to Value in Respective Bot Conf)'
|
40
|
+
) { |a| option_choice.autotrade_percent = a.to_f }
|
41
|
+
|
42
|
+
options.on(
|
43
|
+
'-cNUMBER',
|
44
|
+
'--cycles-completed=NUMBER',
|
45
|
+
'<Optional - Total # of Autotrade Cycles to Evaluate (Defaults to 1)">'
|
46
|
+
) { |c| option_choice.cycles_complete = c.to_i }
|
47
|
+
|
48
|
+
options.on(
|
49
|
+
'-hHOLDINGS',
|
50
|
+
'--total-holdings=HOLDINGS',
|
51
|
+
'<Optional - Total Portfolio Holdings in USD (Defaults to Current Balance)'
|
52
|
+
) { |h| option_choice.total_holdings = h.to_f }
|
53
|
+
|
54
|
+
options.on(
|
55
|
+
'-pPROXY',
|
56
|
+
'--proxy=PROXY',
|
57
|
+
'<Optional - HTTP Proxy e.g. "http://127.0.0.1:8080">'
|
58
|
+
) { |p| option_choice.proxy = p }
|
59
|
+
|
60
|
+
options.on(
|
61
|
+
'-rPATH',
|
62
|
+
'--repo-root=PATH',
|
63
|
+
'<Optional - Directory of Cloned Repo (Defaults to Dir.pwd)">'
|
64
|
+
) { |r| option_choice.repo_root = r }
|
65
|
+
|
66
|
+
options.on(
|
67
|
+
'-tTPM',
|
68
|
+
'--target-profit-margin=TPM',
|
69
|
+
'<Optional - Target Profit Margin % (Defaults to Value in Respective Bot Conf)'
|
70
|
+
) { |t| option_choice.tpm = t.to_f }
|
71
|
+
|
72
|
+
options.on(
|
73
|
+
'-S',
|
74
|
+
'--[no-]sandbox',
|
75
|
+
'<Optional - Use Coinbase Sandbox Environment for Testing Ideas>'
|
76
|
+
) { |n| option_choice.sandbox = n }
|
77
|
+
end.parse!
|
78
|
+
|
79
|
+
# Conditions to display cryptum usage
|
80
|
+
if option_choice.symbol.nil?
|
81
|
+
usage = true
|
82
|
+
reason = :symbol
|
83
|
+
end
|
84
|
+
|
85
|
+
option_choice.repo_root = Dir.pwd if option_choice.repo_root.nil?
|
86
|
+
|
87
|
+
if option_choice.autotrade_percent.to_f > 100
|
88
|
+
usage = true
|
89
|
+
reason = :autotrade_percent
|
90
|
+
end
|
91
|
+
|
92
|
+
unless Dir.exist?(option_choice.repo_root)
|
93
|
+
usage = true
|
94
|
+
reason = :repo_root
|
95
|
+
end
|
96
|
+
|
97
|
+
if usage
|
98
|
+
case reason
|
99
|
+
when :autotrade_percent
|
100
|
+
puts 'ERROR: --autotrade PERCENT value cannot exceed 100'
|
101
|
+
when :symbol
|
102
|
+
puts "ERROR: --symbol Flag is Required.\n\n"
|
103
|
+
when :repo_root
|
104
|
+
puts "ERROR: #{option_choice.repo_root} does not exist.\n\n"
|
105
|
+
end
|
106
|
+
|
107
|
+
puts `#{option_choice.driver_name} --help`
|
108
|
+
exit 1
|
109
|
+
end
|
110
|
+
|
111
|
+
autotrade_cycle_tot = option_choice.cycles_complete
|
112
|
+
autotrade_cycle_tot = 1 unless option_choice.cycles_complete.to_i.positive?
|
113
|
+
|
114
|
+
# Initialize the Respective Environment / API Authentication Artifacts
|
115
|
+
env = Cryptum::Option.get_env(option_choice: option_choice)
|
116
|
+
|
117
|
+
# Read in Bot Conf Values
|
118
|
+
bot_conf = Cryptum::BotConf.read(option_choice: option_choice)
|
119
|
+
|
120
|
+
products = Cryptum::API.get_products(
|
121
|
+
option_choice: option_choice,
|
122
|
+
env: env
|
123
|
+
)
|
124
|
+
|
125
|
+
crypto = products.last[:base_currency]
|
126
|
+
fiat = products.last[:quote_currency]
|
127
|
+
fiat_portfolio_file = "#{option_choice.repo_root}/order_books/#{fiat}_PORTFOLIO.json"
|
128
|
+
|
129
|
+
portfolio = Cryptum::API.get_portfolio(
|
130
|
+
option_choice: option_choice,
|
131
|
+
env: env,
|
132
|
+
crypto: crypto,
|
133
|
+
fiat: fiat,
|
134
|
+
fiat_portfolio_file: fiat_portfolio_file
|
135
|
+
)
|
136
|
+
|
137
|
+
fiat_portfolio = JSON.parse(
|
138
|
+
File.read(fiat_portfolio_file),
|
139
|
+
symbolize_names: true
|
140
|
+
)
|
141
|
+
|
142
|
+
holdings = fiat_portfolio.last[:total_holdings].to_f
|
143
|
+
holdings = option_choice.total_holdings.to_f if option_choice.total_holdings.to_f.positive?
|
144
|
+
|
145
|
+
autotrade = bot_conf[:autotrade_portfolio_percent].to_f / 100
|
146
|
+
autotrade = option_choice.autotrade_percent.to_f / 100 if option_choice.autotrade_percent.to_f.positive?
|
147
|
+
|
148
|
+
gross_tpm = bot_conf[:target_profit_margin_percent].to_f / 100
|
149
|
+
gross_tpm = option_choice.tpm.to_f if option_choice.tpm.to_f.positive?
|
150
|
+
|
151
|
+
fees = Cryptum::API.get_fees(
|
152
|
+
option_choice: option_choice,
|
153
|
+
env: env
|
154
|
+
)
|
155
|
+
taker_fee = format('%0.4f', fees[:taker_fee_rate].to_f)
|
156
|
+
total_cycle_fees = taker_fee.to_f * 2
|
157
|
+
net_tpm = gross_tpm - total_cycle_fees
|
158
|
+
|
159
|
+
beautify_holdings = Cryptum.beautify_large_number(
|
160
|
+
value: format('%0.2f', holdings)
|
161
|
+
)
|
162
|
+
|
163
|
+
print "Initial Holdings: $#{beautify_holdings} | "
|
164
|
+
print "Autotrade: #{format('%0.2f', autotrade * 100)}% | "
|
165
|
+
print "Gross TPM: #{format('%0.2f', gross_tpm * 100)}% | "
|
166
|
+
print "Fee: #{format('%0.2f', total_cycle_fees * 100)}% | "
|
167
|
+
puts "Net TPM: #{format('%0.2f', net_tpm * 100)}%"
|
168
|
+
|
169
|
+
(1..autotrade_cycle_tot).each do |autotrade_cycle|
|
170
|
+
risk_alloc = holdings * autotrade
|
171
|
+
bal = risk_alloc
|
172
|
+
bal += bal * net_tpm
|
173
|
+
profit = bal - risk_alloc
|
174
|
+
holdings += profit
|
175
|
+
|
176
|
+
beautify_risk_alloc = Cryptum.beautify_large_number(
|
177
|
+
value: format('%0.2f', risk_alloc)
|
178
|
+
)
|
179
|
+
|
180
|
+
beautify_profit = Cryptum.beautify_large_number(
|
181
|
+
value: format('%0.2f', profit)
|
182
|
+
)
|
183
|
+
|
184
|
+
beautify_holdings = Cryptum.beautify_large_number(
|
185
|
+
value: format('%0.2f', holdings)
|
186
|
+
)
|
187
|
+
|
188
|
+
print "##{autotrade_cycle} | "
|
189
|
+
print "Risk Alloc: $#{beautify_risk_alloc} | "
|
190
|
+
print "Profit: $#{beautify_profit} | "
|
191
|
+
puts "Holdings: $#{beautify_holdings}"
|
192
|
+
end
|
193
|
+
rescue Interrupt
|
194
|
+
# Exit Gracefully if CTRL+C is Pressed During Session
|
195
|
+
puts "Interrupt detected in #{self}...goodbye."
|
196
|
+
rescue StandardError => e
|
197
|
+
# Produce a Stacktrace for anything else
|
198
|
+
raise e
|
199
|
+
end
|
data/bin/cryptum-repl
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'cryptum'
|
5
|
+
require 'pry'
|
6
|
+
require 'tty-prompt'
|
7
|
+
require 'tty-reader'
|
8
|
+
|
9
|
+
begin
|
10
|
+
# TODO: Remove once this feature is available in mainline
|
11
|
+
class Pry
|
12
|
+
# Overwrite Pry::History.push method in History class to get duplicate history entries
|
13
|
+
# in order to properly replay automation in this prototyping driver
|
14
|
+
class History
|
15
|
+
def push(line)
|
16
|
+
return line if line.empty? || invalid_readline_line?(line)
|
17
|
+
|
18
|
+
# begin
|
19
|
+
# last_line = @history.last
|
20
|
+
# rescue IndexError
|
21
|
+
# last_line = nil
|
22
|
+
# end
|
23
|
+
# return line if line == last_line
|
24
|
+
|
25
|
+
@history << line
|
26
|
+
@history_line_count += 1
|
27
|
+
@saver.call(line) if !should_ignore?(line) && Pry.config.history_save
|
28
|
+
|
29
|
+
line
|
30
|
+
end
|
31
|
+
alias << push
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
cli = Pry
|
36
|
+
|
37
|
+
cli.config.hooks.add_hook(:before_eval, :autocomplete) do
|
38
|
+
# prompt = TTY::Prompt.new
|
39
|
+
reader = TTY::Reader.new
|
40
|
+
reader.on(:keypress) { |key_event| prompt(key_event) }
|
41
|
+
end
|
42
|
+
|
43
|
+
cli::Commands.create_command 'toggle-pager' do
|
44
|
+
description 'Toggle less on returned objects surpassing the terminal.'
|
45
|
+
|
46
|
+
def process
|
47
|
+
# Toggle pager from true to false via XOR
|
48
|
+
pry_instance.config.pager ^= true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Custom Main & Wait (Multi-Line) Prompts
|
53
|
+
title = "\001\e[1m\002\001\e[31m\002cryptum\001\e[0m\002" # Bold Red
|
54
|
+
version = "\001\e[36m\002v#{Cryptum::VERSION}\001\e[0m\002" # Cyan
|
55
|
+
arrow = "\001\e[32m\002>>>\001\e[0m\002" # Green
|
56
|
+
splat = "\001\e[33m\002***\001\e[0m\002" # Yellow
|
57
|
+
|
58
|
+
prompt = [
|
59
|
+
proc do |_target_self, _nest_level, pry|
|
60
|
+
line_pad = format('%0.3d', pry.input_ring.size)
|
61
|
+
line_count = "\001\e[34m\002#{line_pad}\001\e[0m\002" # Blue
|
62
|
+
"#{title}[#{version}]:#{line_count} #{arrow} ".to_s.scrub
|
63
|
+
end,
|
64
|
+
proc do |_target_self, _nest_level, pry|
|
65
|
+
line_pad = format('%0.3d', pry.input_ring.size)
|
66
|
+
line_count = "\001\e[34m\002#{line_pad}\001\e[0m\002" # Blue
|
67
|
+
"#{title}[#{version}]:#{line_count} #{splat} ".to_s.scrub
|
68
|
+
end
|
69
|
+
]
|
70
|
+
cli.start(self, prompt: Pry::Prompt.new(:cryptum, 'CRYPTUM_PROTOTYPING_DRIVER', prompt))
|
71
|
+
rescue StandardError => e
|
72
|
+
raise e
|
73
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require 'cryptum'
|
6
|
+
|
7
|
+
old_rev = Cryptum::VERSION
|
8
|
+
placeholder_arr = old_rev.split('.')
|
9
|
+
major = placeholder_arr[0].to_i
|
10
|
+
minor = placeholder_arr[1].to_i
|
11
|
+
hotfix = placeholder_arr[2].to_i
|
12
|
+
|
13
|
+
if hotfix < 999
|
14
|
+
hotfix += 1
|
15
|
+
placeholder_arr[2] = hotfix.to_s
|
16
|
+
else
|
17
|
+
# TODO: Tag master branch once minor version is reached
|
18
|
+
placeholder_arr[2] = '0'
|
19
|
+
if minor < 9
|
20
|
+
minor += 1
|
21
|
+
placeholder_arr[1] = minor.to_s
|
22
|
+
else
|
23
|
+
placeholder_arr[1] = '0'
|
24
|
+
major += 1
|
25
|
+
placeholder_arr[0] = major.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
new_rev = placeholder_arr.join('.')
|
30
|
+
|
31
|
+
puts "Upgrading to #{new_rev}..."
|
32
|
+
File.open('./lib/cryptum/version.rb', 'w') do |f|
|
33
|
+
f.puts '# frozen_string_literal: true'
|
34
|
+
f.puts "\n"
|
35
|
+
f.puts 'module Cryptum'
|
36
|
+
f.puts " VERSION = '#{new_rev}'"
|
37
|
+
f.puts 'end'
|
38
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/bin/bash --login
|
2
|
+
if [[ $CRYPTUM_ROOT == '' ]]; then
|
3
|
+
if [[ ! -d '/opt/cryptum' ]]; then
|
4
|
+
cryptum_root=$(pwd)
|
5
|
+
else
|
6
|
+
cryptum_root='/opt/cryptum'
|
7
|
+
fi
|
8
|
+
else
|
9
|
+
cryptum_root="${CRYPTUM_ROOT}"
|
10
|
+
fi
|
11
|
+
|
12
|
+
ls pkg/*.gem 2> /dev/null | while read previous_gems; do
|
13
|
+
rvmsudo rm $previous_gems
|
14
|
+
done
|
15
|
+
old_ruby_version=`cat ${cryptum_root}/.ruby-version`
|
16
|
+
# Default Strategy is to merge codebase
|
17
|
+
# rvmsudo git config pull.rebase false
|
18
|
+
# rvmsudo git pull origin master
|
19
|
+
git config pull.rebase false
|
20
|
+
git pull origin master
|
21
|
+
new_ruby_version=`cat ${cryptum_root}/.ruby-version`
|
22
|
+
|
23
|
+
rvm list gemsets | grep `cat ${cryptum_root}/.ruby-gemset`
|
24
|
+
if [[ $? != 0 ]]; then
|
25
|
+
echo "Ruby v${new_ruby_version} is not installed. Installing..."
|
26
|
+
cd $cryptum_root && ./upgrade_ruby.sh $new_ruby_version
|
27
|
+
# Rely on RVM to creeate gemset
|
28
|
+
cd / && cd $cryptum_root
|
29
|
+
fi
|
30
|
+
|
31
|
+
if [[ $old_ruby_version == $new_ruby_version ]]; then
|
32
|
+
export rvmsudo_secure_path=1
|
33
|
+
rvmsudo /bin/bash --login -c "cd ${cryptum_root} && ./reinstall_cryptum_gemset.sh"
|
34
|
+
rvmsudo rake
|
35
|
+
rvmsudo rake install
|
36
|
+
rvmsudo rake rerdoc
|
37
|
+
rvmsudo gem update --system
|
38
|
+
rvmsudo gem rdoc --rdoc --ri --overwrite -V cryptum
|
39
|
+
echo "Invoking bundle-audit Gemfile Scanner..."
|
40
|
+
rvmsudo bundle-audit
|
41
|
+
else
|
42
|
+
cd $cryptum_root && ./upgrade_ruby.sh $new_ruby_version $old_ruby_version
|
43
|
+
fi
|
44
|
+
|
45
|
+
unpriv_user=`echo $USER`
|
46
|
+
if [[ $unpriv_user != 'root' ]]; then
|
47
|
+
if [[ $(uname -s) == 'Darwin' ]]; then
|
48
|
+
rvmsudo chown -R $unpriv_user $cryptum_root
|
49
|
+
else
|
50
|
+
rvmsudo chown -R $unpriv_user:$unpriv_user $cryptum_root
|
51
|
+
fi
|
52
|
+
fi
|
data/cryptum.gemspec
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'cryptum/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.required_ruby_version = ">= #{File.read('.ruby-version')}"
|
9
|
+
spec.name = 'cryptum'
|
10
|
+
spec.version = Cryptum::VERSION
|
11
|
+
spec.authors = ['0day Inc.']
|
12
|
+
spec.email = ['request.pentest@0dayinc.com']
|
13
|
+
spec.summary = 'Coinbase Pro High-Frequency Trading Bot'
|
14
|
+
spec.description = 'Personalized High-Frequency Trading Bot'
|
15
|
+
spec.homepage = 'https://github.com/0dayinc/cryptum'
|
16
|
+
spec.license = 'GPL'
|
17
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0")
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
dev_dependency_arr = %i[
|
25
|
+
bundler
|
26
|
+
rake
|
27
|
+
rdoc
|
28
|
+
rspec
|
29
|
+
]
|
30
|
+
|
31
|
+
File.readlines('./Gemfile').each do |line|
|
32
|
+
columns = line.chomp.split
|
33
|
+
next unless columns.first == 'gem'
|
34
|
+
|
35
|
+
gem_name = columns[1].delete("'").delete(',')
|
36
|
+
gem_version = columns.last.delete("'")
|
37
|
+
|
38
|
+
if dev_dependency_arr.include?(gem_name.to_sym)
|
39
|
+
spec.add_development_dependency(
|
40
|
+
gem_name,
|
41
|
+
gem_version
|
42
|
+
)
|
43
|
+
else
|
44
|
+
spec.add_runtime_dependency(
|
45
|
+
gem_name,
|
46
|
+
gem_version
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
docker/cryptum_container.sh
|
data/docker/cryptum.json
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
{
|
2
|
+
"variables": {
|
3
|
+
"ssh_auth_sock": "{{env `SSH_AUTH_SOCK`}}",
|
4
|
+
"repository": "{{env `REPOSITORY`}}",
|
5
|
+
"aws_access_key": "{{env `AWS_ACCESS_KEY`}}",
|
6
|
+
"aws_secret_key": "{{env `AWS_SECRET_KEY`}}",
|
7
|
+
"aws_token": "{{env `AWS_TOKEN`}}",
|
8
|
+
"aws_profile": "{{env `AWS_PROFILE`}}",
|
9
|
+
"login_server": "{{env `LOGIN_SERVER`}}"
|
10
|
+
},
|
11
|
+
"builders": [{
|
12
|
+
"type": "docker",
|
13
|
+
"image": "kalilinux/kali-rolling",
|
14
|
+
"commit": true,
|
15
|
+
"volumes": {
|
16
|
+
"{{user `ssh_auth_sock` }}": "/ssh-agent"
|
17
|
+
},
|
18
|
+
"changes": [
|
19
|
+
"EXPOSE 9999"
|
20
|
+
],
|
21
|
+
"run_command": [
|
22
|
+
"--detach",
|
23
|
+
"--interactive",
|
24
|
+
"--tty",
|
25
|
+
"--name=cryptum",
|
26
|
+
"--entrypoint=/bin/bash",
|
27
|
+
"{{.Image}}"
|
28
|
+
]
|
29
|
+
}],
|
30
|
+
"provisioners": [{
|
31
|
+
"type": "shell",
|
32
|
+
"scripts": [
|
33
|
+
"provisioners/upload_globals.sh",
|
34
|
+
"provisioners/init_image.sh",
|
35
|
+
"provisioners/docker_rvm.sh",
|
36
|
+
"provisioners/docker_bashrc.sh",
|
37
|
+
"provisioners/ruby.sh",
|
38
|
+
"provisioners/cryptum.sh",
|
39
|
+
"provisioners/post_install.sh"
|
40
|
+
],
|
41
|
+
"pause_before": "1s"
|
42
|
+
}],
|
43
|
+
"post-processors": [
|
44
|
+
[
|
45
|
+
{
|
46
|
+
"type": "docker-tag",
|
47
|
+
"repository": "{{user `repository`}}",
|
48
|
+
"tag": "latest"
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"type": "docker-push",
|
52
|
+
"ecr_login": true,
|
53
|
+
"aws_access_key": "{{user `aws_access_key`}}",
|
54
|
+
"aws_secret_key": "{{user `aws_secret_key`}}",
|
55
|
+
"login_server": "https://{{user `repository`}}",
|
56
|
+
"keep_input_artifact": false
|
57
|
+
}
|
58
|
+
]
|
59
|
+
]
|
60
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/bin/bash --login
|
2
|
+
debug=false
|
3
|
+
export PACKER_LOG=1
|
4
|
+
set -e
|
5
|
+
|
6
|
+
function usage() {
|
7
|
+
echo -e "USAGE: ${0} <build || debug>"
|
8
|
+
exit 1
|
9
|
+
}
|
10
|
+
|
11
|
+
function pack() {
|
12
|
+
packer_provider_template=$1
|
13
|
+
debug=$2
|
14
|
+
packer_secrets='./packer_secrets.json'
|
15
|
+
|
16
|
+
if [[ $CRYPTUM_ROOT == '' ]]; then
|
17
|
+
if [[ ! -d '/opt/cryptum' ]]; then
|
18
|
+
cryptum_root=$(pwd)
|
19
|
+
else
|
20
|
+
cryptum_root='/opt/cryptum'
|
21
|
+
fi
|
22
|
+
else
|
23
|
+
cryptum_root="${CRYPTUM_ROOT}"
|
24
|
+
fi
|
25
|
+
|
26
|
+
cd $cryptum_root/docker
|
27
|
+
|
28
|
+
if $debug; then
|
29
|
+
packer build \
|
30
|
+
-debug \
|
31
|
+
-only docker \
|
32
|
+
-var "box_version=latest" \
|
33
|
+
-var "ssh_auth_sock=${SSH_AUTH_SOCK}" \
|
34
|
+
-var-file=$packer_secrets \
|
35
|
+
$packer_provider_template
|
36
|
+
else
|
37
|
+
packer build \
|
38
|
+
-only docker \
|
39
|
+
-var "box_version=latest" \
|
40
|
+
-var "ssh_auth_sock=${SSH_AUTH_SOCK}" \
|
41
|
+
-var-file=$packer_secrets \
|
42
|
+
$packer_provider_template
|
43
|
+
fi
|
44
|
+
}
|
45
|
+
|
46
|
+
if [[ $# < 1 ]]; then
|
47
|
+
usage
|
48
|
+
fi
|
49
|
+
|
50
|
+
action="${1}"
|
51
|
+
|
52
|
+
case $action in
|
53
|
+
'build')
|
54
|
+
pack ./cryptum.json false;;
|
55
|
+
'debug')
|
56
|
+
pack ./cryptum.json true;;
|
57
|
+
'*')
|
58
|
+
usage;;
|
59
|
+
esac
|