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/lib/cryptum/log.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Cryptum
|
6
|
+
# This plugin is used to instantiate a Cryptum logger with a custom message format
|
7
|
+
module Log
|
8
|
+
# Supported Method Parameters::
|
9
|
+
# Cryptum::Log.create(
|
10
|
+
# )
|
11
|
+
public_class_method def self.create
|
12
|
+
logger = Logger.new($stdout)
|
13
|
+
logger.level = Logger::INFO
|
14
|
+
logger.datetime_format = '%Y-%m-%d %H:%M:%S'
|
15
|
+
|
16
|
+
logger.formatter = proc do |severity, _datetime, _progname, msg|
|
17
|
+
# TODO: Include datetime & progname vars
|
18
|
+
"[#{severity}] #{msg}\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
logger
|
22
|
+
rescue StandardError => e
|
23
|
+
raise e
|
24
|
+
end
|
25
|
+
|
26
|
+
# Display Usage for this Module
|
27
|
+
|
28
|
+
public_class_method def self.help
|
29
|
+
puts "USAGE:
|
30
|
+
logger = #{self}.create()
|
31
|
+
"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module Cryptum
|
6
|
+
# This plugin is used for my own entertainment
|
7
|
+
module Matrix
|
8
|
+
# Supported Method Parameters::
|
9
|
+
# Cryptum::Matrix.generate(
|
10
|
+
# cols: cols
|
11
|
+
# )
|
12
|
+
|
13
|
+
public_class_method def self.generate(opts = {})
|
14
|
+
# Need to divide by two for wide characters
|
15
|
+
cols = opts[:cols].to_i
|
16
|
+
|
17
|
+
matrix_arr = [
|
18
|
+
0x30a0.chr('UTF-8'),
|
19
|
+
0x30a1.chr('UTF-8'),
|
20
|
+
0x30a2.chr('UTF-8'),
|
21
|
+
0x30a3.chr('UTF-8'),
|
22
|
+
0x30a4.chr('UTF-8'),
|
23
|
+
0x30a5.chr('UTF-8'),
|
24
|
+
0x30a6.chr('UTF-8'),
|
25
|
+
0x30a7.chr('UTF-8'),
|
26
|
+
0x30a8.chr('UTF-8'),
|
27
|
+
0x30a9.chr('UTF-8'),
|
28
|
+
0x30aa.chr('UTF-8'),
|
29
|
+
0x30ab.chr('UTF-8'),
|
30
|
+
0x30ac.chr('UTF-8'),
|
31
|
+
0x30ad.chr('UTF-8'),
|
32
|
+
0x30ae.chr('UTF-8'),
|
33
|
+
0x30af.chr('UTF-8'),
|
34
|
+
0x30b0.chr('UTF-8'),
|
35
|
+
0x30b1.chr('UTF-8'),
|
36
|
+
0x30b2.chr('UTF-8'),
|
37
|
+
0x30b3.chr('UTF-8'),
|
38
|
+
0x30b4.chr('UTF-8'),
|
39
|
+
0x30b5.chr('UTF-8'),
|
40
|
+
0x30b6.chr('UTF-8'),
|
41
|
+
0x30b7.chr('UTF-8'),
|
42
|
+
0x30b8.chr('UTF-8'),
|
43
|
+
0x30b9.chr('UTF-8'),
|
44
|
+
0x30ba.chr('UTF-8'),
|
45
|
+
0x30bb.chr('UTF-8'),
|
46
|
+
0x30bc.chr('UTF-8'),
|
47
|
+
0x30bd.chr('UTF-8'),
|
48
|
+
0x30be.chr('UTF-8'),
|
49
|
+
0x30bf.chr('UTF-8'),
|
50
|
+
0x30c0.chr('UTF-8'),
|
51
|
+
0x30c1.chr('UTF-8'),
|
52
|
+
0x30c2.chr('UTF-8'),
|
53
|
+
0x30c3.chr('UTF-8'),
|
54
|
+
0x30c4.chr('UTF-8'),
|
55
|
+
0x30c5.chr('UTF-8'),
|
56
|
+
0x30c6.chr('UTF-8'),
|
57
|
+
0x30c7.chr('UTF-8'),
|
58
|
+
0x30c8.chr('UTF-8'),
|
59
|
+
0x30c9.chr('UTF-8'),
|
60
|
+
0x30ca.chr('UTF-8'),
|
61
|
+
0x30cb.chr('UTF-8'),
|
62
|
+
0x30cc.chr('UTF-8'),
|
63
|
+
0x30cd.chr('UTF-8'),
|
64
|
+
0x30ce.chr('UTF-8'),
|
65
|
+
0x30cf.chr('UTF-8'),
|
66
|
+
0x30d0.chr('UTF-8'),
|
67
|
+
0x30d1.chr('UTF-8'),
|
68
|
+
0x30d2.chr('UTF-8'),
|
69
|
+
0x30d3.chr('UTF-8'),
|
70
|
+
0x30d4.chr('UTF-8'),
|
71
|
+
0x30d5.chr('UTF-8'),
|
72
|
+
0x30d6.chr('UTF-8'),
|
73
|
+
0x30d7.chr('UTF-8'),
|
74
|
+
0x30d8.chr('UTF-8'),
|
75
|
+
0x30d9.chr('UTF-8'),
|
76
|
+
0x30da.chr('UTF-8'),
|
77
|
+
0x30db.chr('UTF-8'),
|
78
|
+
0x30dc.chr('UTF-8'),
|
79
|
+
0x30dd.chr('UTF-8'),
|
80
|
+
0x30de.chr('UTF-8'),
|
81
|
+
0x30df.chr('UTF-8'),
|
82
|
+
0x30e0.chr('UTF-8'),
|
83
|
+
0x30e1.chr('UTF-8'),
|
84
|
+
0x30e2.chr('UTF-8'),
|
85
|
+
0x30e3.chr('UTF-8'),
|
86
|
+
0x30e4.chr('UTF-8'),
|
87
|
+
0x30e5.chr('UTF-8'),
|
88
|
+
0x30e6.chr('UTF-8'),
|
89
|
+
0x30e7.chr('UTF-8'),
|
90
|
+
0x30e8.chr('UTF-8'),
|
91
|
+
0x30e9.chr('UTF-8'),
|
92
|
+
0x30ea.chr('UTF-8'),
|
93
|
+
0x30eb.chr('UTF-8'),
|
94
|
+
0x30ec.chr('UTF-8'),
|
95
|
+
0x30ed.chr('UTF-8'),
|
96
|
+
0x30ee.chr('UTF-8'),
|
97
|
+
0x30ef.chr('UTF-8'),
|
98
|
+
0x30f0.chr('UTF-8'),
|
99
|
+
0x30f1.chr('UTF-8'),
|
100
|
+
0x30f2.chr('UTF-8'),
|
101
|
+
0x30f3.chr('UTF-8'),
|
102
|
+
0x30f4.chr('UTF-8'),
|
103
|
+
0x30f5.chr('UTF-8'),
|
104
|
+
0x30f6.chr('UTF-8'),
|
105
|
+
0x30f7.chr('UTF-8'),
|
106
|
+
0x30f8.chr('UTF-8'),
|
107
|
+
0x30f9.chr('UTF-8'),
|
108
|
+
0x30fa.chr('UTF-8'),
|
109
|
+
0x30fb.chr('UTF-8'),
|
110
|
+
0x30fc.chr('UTF-8'),
|
111
|
+
0x30fd.chr('UTF-8'),
|
112
|
+
0x30fe.chr('UTF-8'),
|
113
|
+
'0 ',
|
114
|
+
'1 ',
|
115
|
+
'2 ',
|
116
|
+
'3 ',
|
117
|
+
'4 ',
|
118
|
+
'5 ',
|
119
|
+
'6 ',
|
120
|
+
'7 ',
|
121
|
+
'8 ',
|
122
|
+
'9 ',
|
123
|
+
'A ',
|
124
|
+
'c ',
|
125
|
+
'R ',
|
126
|
+
'y ',
|
127
|
+
'P ',
|
128
|
+
't ',
|
129
|
+
'U ',
|
130
|
+
'm ',
|
131
|
+
'x ',
|
132
|
+
'Z ',
|
133
|
+
': ',
|
134
|
+
'{ ',
|
135
|
+
'[ ',
|
136
|
+
'} ',
|
137
|
+
'] ',
|
138
|
+
'| ',
|
139
|
+
'` ',
|
140
|
+
'~ ',
|
141
|
+
'! ',
|
142
|
+
'@ ',
|
143
|
+
'# ',
|
144
|
+
'$ ',
|
145
|
+
'% ',
|
146
|
+
'^ ',
|
147
|
+
'& ',
|
148
|
+
'* ',
|
149
|
+
'( ',
|
150
|
+
') ',
|
151
|
+
'_ ',
|
152
|
+
'- ',
|
153
|
+
'= ',
|
154
|
+
'+ ',
|
155
|
+
'> ',
|
156
|
+
'< ',
|
157
|
+
'. ',
|
158
|
+
', ',
|
159
|
+
]
|
160
|
+
|
161
|
+
last_index = matrix_arr.length - 1
|
162
|
+
|
163
|
+
matrix_row = ''
|
164
|
+
most_cols = cols - 1
|
165
|
+
most_cols.times.each do
|
166
|
+
matrix_row += "#{matrix_arr[Random.rand(0..last_index)]} "
|
167
|
+
end
|
168
|
+
matrix_row += matrix_arr[Random.rand(0..last_index)]
|
169
|
+
rescue StandardError => e
|
170
|
+
raise e
|
171
|
+
end
|
172
|
+
|
173
|
+
# Display Usage for this Module
|
174
|
+
|
175
|
+
public_class_method def self.help
|
176
|
+
puts "USAGE:
|
177
|
+
logger = #{self}.create()
|
178
|
+
"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cryptum
|
4
|
+
# This plugin is used to Cancel Open Limit Orders
|
5
|
+
module Option
|
6
|
+
# Keep Last Event History When Terminal Resize Occuers
|
7
|
+
class Choice
|
8
|
+
attr_accessor :autotrade,
|
9
|
+
:driver_name,
|
10
|
+
:list_products,
|
11
|
+
:proxy,
|
12
|
+
:repo_root,
|
13
|
+
:sandbox,
|
14
|
+
:symbol,
|
15
|
+
:market_trend_reset
|
16
|
+
|
17
|
+
rescue Interrupt
|
18
|
+
# Exit Gracefully if CTRL+C is Pressed During Session
|
19
|
+
Cryptum.exit_gracefully(which_self: self)
|
20
|
+
rescue StandardError => e
|
21
|
+
# Produce a Stacktrace for anything else
|
22
|
+
Curses.close_screen
|
23
|
+
raise e
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
module Cryptum
|
7
|
+
# Cryptum::UI Module used for Presenting the
|
8
|
+
# Cryptum Curses Interface
|
9
|
+
module Option
|
10
|
+
autoload :Choice, 'cryptum/option/choice'
|
11
|
+
|
12
|
+
# Options for cryptum Driver
|
13
|
+
public_class_method def self.parser(opts = {})
|
14
|
+
option_choice = Option::Choice.new
|
15
|
+
option_choice.driver_name = opts[:driver_name]
|
16
|
+
|
17
|
+
OptionParser.new do |options|
|
18
|
+
options.banner = "USAGE: #{option_choice.driver_name} [opts]"
|
19
|
+
|
20
|
+
options.on(
|
21
|
+
'-sSYMBOL',
|
22
|
+
'--symbol=SYMBOL',
|
23
|
+
'<Required - Crypto Symbol.(e.g. btc-usd, eth-usd, etc.)'
|
24
|
+
) { |s| option_choice.symbol = s.to_s.gsub('-', '_').downcase.to_sym }
|
25
|
+
|
26
|
+
options.on(
|
27
|
+
'-A',
|
28
|
+
'--[no-]autotrade',
|
29
|
+
'<Optional - Automatically Buy and Sell Crypto>'
|
30
|
+
) { |a| option_choice.autotrade = a }
|
31
|
+
|
32
|
+
options.on(
|
33
|
+
'-l',
|
34
|
+
'--[no-]list-products',
|
35
|
+
'<Optional - List Supported Crypto Currency Products and Exit>'
|
36
|
+
) { |l| option_choice.list_products = l }
|
37
|
+
|
38
|
+
options.on(
|
39
|
+
'-pPROXY',
|
40
|
+
'--proxy=PROXY',
|
41
|
+
'<Optional - HTTP Proxy e.g. "http://127.0.0.1:8080">'
|
42
|
+
) { |p| option_choice.proxy = p }
|
43
|
+
|
44
|
+
options.on(
|
45
|
+
'-rPATH',
|
46
|
+
'--repo-root=PATH',
|
47
|
+
'<Optional - Directory of Cloned Repo (Defaults to ~/cryptum)>'
|
48
|
+
) { |r| option_choice.repo_root = r }
|
49
|
+
|
50
|
+
options.on(
|
51
|
+
'-S',
|
52
|
+
'--[no-]sandbox',
|
53
|
+
'<Optional - Use Coinbase Sandbox Environment for Testing Ideas>'
|
54
|
+
) { |n| option_choice.sandbox = n }
|
55
|
+
|
56
|
+
options.on(
|
57
|
+
'-tSECONDS',
|
58
|
+
'--time-between-orders=SECONDS',
|
59
|
+
'<Optional - Seconds Between Market Trend Reset (Default 60)>'
|
60
|
+
) { |t| option_choice.market_trend_reset = t }
|
61
|
+
end.parse!
|
62
|
+
|
63
|
+
input_validation(option_choice: option_choice)
|
64
|
+
|
65
|
+
option_choice
|
66
|
+
rescue OptionParser::InvalidOption => e
|
67
|
+
# Print Usage if unsupported flags are passed
|
68
|
+
puts "ERROR: #{e.message}\n\n"
|
69
|
+
puts `#{option_choice.driver_name} --help`
|
70
|
+
exit 1
|
71
|
+
rescue StandardError => e
|
72
|
+
raise e
|
73
|
+
end
|
74
|
+
|
75
|
+
# Validate Options for cryptum Driver
|
76
|
+
public_class_method def self.input_validation(opts = {})
|
77
|
+
option_choice = opts[:option_choice]
|
78
|
+
|
79
|
+
# Conditions to display cryptum usage
|
80
|
+
if option_choice.symbol.nil? && option_choice.list_products.nil?
|
81
|
+
usage = true
|
82
|
+
reason = :symbol
|
83
|
+
end
|
84
|
+
|
85
|
+
option_choice.repo_root = "#{Dir.home}/cryptum" if option_choice.repo_root.nil?
|
86
|
+
|
87
|
+
unless Dir.exist?(option_choice.repo_root)
|
88
|
+
usage = true
|
89
|
+
reason = :repo_root
|
90
|
+
end
|
91
|
+
|
92
|
+
option_choice.market_trend_reset = 60 if option_choice.market_trend_reset.to_i.zero?
|
93
|
+
unless option_choice.market_trend_reset.to_f.positive?
|
94
|
+
usage = true
|
95
|
+
reason = :market_trend_reset
|
96
|
+
end
|
97
|
+
|
98
|
+
if usage
|
99
|
+
case reason
|
100
|
+
when :symbol
|
101
|
+
puts "ERROR: --symbol Flag is Required.\n\n"
|
102
|
+
when :repo_root
|
103
|
+
puts "ERROR: #{option_choice.repo_root} does not exist.\n\n"
|
104
|
+
when :market_trend_reset
|
105
|
+
puts "ERROR: #{option_choice.market_trend_reset} Must be a positive floating point number.\n\n"
|
106
|
+
end
|
107
|
+
|
108
|
+
puts `#{option_choice.driver_name} --help`
|
109
|
+
exit 1
|
110
|
+
end
|
111
|
+
rescue StandardError => e
|
112
|
+
raise e
|
113
|
+
end
|
114
|
+
|
115
|
+
# List Supported Cryptum Products and Exit
|
116
|
+
public_class_method def self.list_products_and_exit(opts = {})
|
117
|
+
option_choice = opts[:option_choice]
|
118
|
+
env = opts[:env]
|
119
|
+
|
120
|
+
puts `#{option_choice.driver_name} --help`
|
121
|
+
puts "\n#{option_choice.driver_name} Supports the Following Products:"
|
122
|
+
products = Cryptum::API.get_products(
|
123
|
+
option_choice: option_choice,
|
124
|
+
env: env
|
125
|
+
)
|
126
|
+
|
127
|
+
products.map do |product|
|
128
|
+
puts product[:id].downcase
|
129
|
+
end
|
130
|
+
|
131
|
+
exit 0
|
132
|
+
rescue StandardError => e
|
133
|
+
raise e
|
134
|
+
end
|
135
|
+
|
136
|
+
# Initialize Cryptum Session Environment
|
137
|
+
public_class_method def self.get_env(opts = {})
|
138
|
+
option_choice = opts[:option_choice]
|
139
|
+
|
140
|
+
yaml_conf_file = "#{option_choice.repo_root}/etc/coinbase_pro.yaml"
|
141
|
+
yaml_conf = YAML.load_file(
|
142
|
+
yaml_conf_file,
|
143
|
+
symbolize_names: true
|
144
|
+
)
|
145
|
+
|
146
|
+
env = yaml_conf[:prod]
|
147
|
+
env[:env] = :prod
|
148
|
+
env = yaml_conf[:sandbox] if option_choice.sandbox
|
149
|
+
env[:env] = :sandbox if option_choice.sandbox
|
150
|
+
|
151
|
+
env
|
152
|
+
rescue StandardError => e
|
153
|
+
raise e
|
154
|
+
end
|
155
|
+
|
156
|
+
# Display a List of Every UI Module
|
157
|
+
public_class_method def self.help
|
158
|
+
constants.sort
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'io/console'
|
4
|
+
require 'json'
|
5
|
+
require 'logger'
|
6
|
+
require 'tty-spinner'
|
7
|
+
|
8
|
+
module Cryptum
|
9
|
+
# This module is used to define the Order Book Data Structure
|
10
|
+
module OrderBook
|
11
|
+
module Generate
|
12
|
+
# Supported Method Parameters::
|
13
|
+
# Cryptum::OrderBook.generate(
|
14
|
+
# symbol: 'required - target symbol (e.g. btc-usd)',
|
15
|
+
# this_product: 'required - this_product',
|
16
|
+
# )
|
17
|
+
|
18
|
+
public_class_method def self.new_order_book(opts = {})
|
19
|
+
start_time = opts[:start_time]
|
20
|
+
option_choice = opts[:option_choice]
|
21
|
+
env = opts[:env]
|
22
|
+
bot_conf = opts[:bot_conf]
|
23
|
+
|
24
|
+
order_book_file = "#{option_choice.repo_root}/order_books/#{option_choice.symbol}.ORDER_BOOK.json"
|
25
|
+
|
26
|
+
order_history_meta = []
|
27
|
+
if File.exist?(order_book_file)
|
28
|
+
last_order_book = Cryptum::OrderBook.analyze(
|
29
|
+
order_book_file: order_book_file,
|
30
|
+
option_choice: option_choice
|
31
|
+
)
|
32
|
+
order_history_meta = last_order_book[:order_history_meta] unless last_order_book[:order_history_meta].empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
# Only need to retrieve a product list once / session.
|
36
|
+
products = Cryptum::API.get_products(
|
37
|
+
option_choice: option_choice,
|
38
|
+
env: env
|
39
|
+
)
|
40
|
+
this_product_arr = products.select do |product|
|
41
|
+
product if product[:id] == option_choice.symbol.to_s.gsub('_', '-').upcase
|
42
|
+
end
|
43
|
+
this_product = this_product_arr.first
|
44
|
+
|
45
|
+
order_book = {
|
46
|
+
path: order_book_file,
|
47
|
+
symbol: option_choice.symbol,
|
48
|
+
open_24h: 0.00,
|
49
|
+
high_24h: 0.00,
|
50
|
+
low_24h: 0.00,
|
51
|
+
volume_24h: 0.00,
|
52
|
+
ticker_price: 0.00,
|
53
|
+
ticker_price_second_to_last: 0.00,
|
54
|
+
ticker_price_third_to_last: 0.00,
|
55
|
+
highest_pie_in_sky_buy_percent: 0.00,
|
56
|
+
highest_pie_in_sky_sell_percent: 0.00,
|
57
|
+
sequence: -1,
|
58
|
+
this_product: this_product,
|
59
|
+
portfolio: [],
|
60
|
+
fiat_portfolio: [],
|
61
|
+
fees: [],
|
62
|
+
order_plan: [],
|
63
|
+
last_trend_reset: Time.now.strftime('%Y-%m-%d %H:%M:%S.%N%z'),
|
64
|
+
last_order_exec: Time.now.strftime('%Y-%m-%d %H:%M:%S.%N%z'),
|
65
|
+
market_trend: {
|
66
|
+
buy: 0,
|
67
|
+
buy_start: '--',
|
68
|
+
buy_end: '--',
|
69
|
+
sell: 0,
|
70
|
+
sell_start: '--',
|
71
|
+
sell_end: '--'
|
72
|
+
},
|
73
|
+
order_history: [],
|
74
|
+
order_history_meta: order_history_meta
|
75
|
+
}
|
76
|
+
|
77
|
+
# Order History Retention ---------------------------------------#
|
78
|
+
# Instantiate Event History attr_accessible
|
79
|
+
# Object to Keep Track of Everything as Events
|
80
|
+
# are Parsed.
|
81
|
+
event_history = Cryptum::Event::History.new(
|
82
|
+
option_choice: option_choice,
|
83
|
+
start_time: start_time,
|
84
|
+
order_book: order_book
|
85
|
+
)
|
86
|
+
|
87
|
+
# Write order_book to file at session initiation
|
88
|
+
File.open(order_book_file, 'w') do |f|
|
89
|
+
f.puts order_book.to_json
|
90
|
+
end
|
91
|
+
|
92
|
+
event_history.order_book = order_book
|
93
|
+
|
94
|
+
event_history
|
95
|
+
rescue StandardError => e
|
96
|
+
raise e
|
97
|
+
end
|
98
|
+
|
99
|
+
# Display Usage for this Module
|
100
|
+
|
101
|
+
public_class_method def self.help
|
102
|
+
puts "USAGE:
|
103
|
+
order_book = #{self}.new_order_book(
|
104
|
+
symbol: 'required - target symbol (e.g. btc-usd)',
|
105
|
+
this_product: 'required - this_product'
|
106
|
+
)
|
107
|
+
"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cryptum
|
4
|
+
# This plugin is used to calculate Exponential Moving Average
|
5
|
+
# Price of a Symbol over time.
|
6
|
+
|
7
|
+
module OrderBook
|
8
|
+
class Indicator
|
9
|
+
attr_accessor :market_trend,
|
10
|
+
:profit_margin,
|
11
|
+
:weighted_avg,
|
12
|
+
:action_signal,
|
13
|
+
:last_action_signal
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cryptum
|
4
|
+
# This plugin is used to indicate if the order trend
|
5
|
+
|
6
|
+
module OrderBook
|
7
|
+
module MarketTrend
|
8
|
+
# Supported Method Parameters::
|
9
|
+
# Cryptum::OrderBook::OrderTrend.status(
|
10
|
+
# )
|
11
|
+
|
12
|
+
public_class_method def self.status(opts = {})
|
13
|
+
event_history = opts[:event_history]
|
14
|
+
event = opts[:event]
|
15
|
+
indicator_status = opts[:indicator_status]
|
16
|
+
|
17
|
+
# Decent for debugging.
|
18
|
+
# puts event.inspect
|
19
|
+
|
20
|
+
if event_history.reset_market_trend
|
21
|
+
event_history.order_book[:market_trend][:buy] = 0
|
22
|
+
event_history.order_book[:market_trend][:sell] = 0
|
23
|
+
event_history.reset_market_trend = false
|
24
|
+
end
|
25
|
+
|
26
|
+
buy_or_sell = event[:changes].first[0].to_s.to_sym
|
27
|
+
case buy_or_sell
|
28
|
+
when :buy
|
29
|
+
event_history.order_book[:market_trend][:buy] += 1
|
30
|
+
when :sell
|
31
|
+
event_history.order_book[:market_trend][:sell] += 1
|
32
|
+
else
|
33
|
+
raise "UNKNOWN Value in event[:changes] => #{buy_or_sell}"
|
34
|
+
end
|
35
|
+
|
36
|
+
indicator_hash = {}
|
37
|
+
buy_total = event_history.order_book[:market_trend][:buy].to_i
|
38
|
+
indicator_hash[:buy] = buy_total
|
39
|
+
|
40
|
+
sell_total = event_history.order_book[:market_trend][:sell].to_i
|
41
|
+
indicator_hash[:sell] = sell_total
|
42
|
+
|
43
|
+
# order_difference = 0
|
44
|
+
if buy_total > sell_total
|
45
|
+
order_difference = buy_total - sell_total
|
46
|
+
indicator_hash[:color] = :green
|
47
|
+
indicator_hash[:ui] = "BUYS UP BY #{order_difference}"
|
48
|
+
indicator_hash[:status] = "B#{Cryptum.up_arrow}"
|
49
|
+
elsif buy_total < sell_total
|
50
|
+
order_difference = sell_total - buy_total
|
51
|
+
indicator_hash[:color] = :red
|
52
|
+
indicator_hash[:ui] = "SELLS UP BY #{order_difference}"
|
53
|
+
indicator_hash[:status] = "S#{Cryptum.up_arrow}"
|
54
|
+
else
|
55
|
+
# This Condition is Met When candle_buy_tot == candle_sell_tot
|
56
|
+
indicator_hash[:color] = :yellow
|
57
|
+
indicator_hash[:ui] = 'BUYS == SELLS'
|
58
|
+
indicator_hash[:status] = "F#{Cryptum.up_arrow}"
|
59
|
+
end
|
60
|
+
|
61
|
+
indicator_status.market_trend = indicator_hash
|
62
|
+
rescue StandardError => e
|
63
|
+
raise e
|
64
|
+
end
|
65
|
+
|
66
|
+
public_class_method def self.reset(opts = {})
|
67
|
+
# IT IS ABSOLUTELY CRITICAL THIS METHOD IS AS FAST AS POSSIBLE
|
68
|
+
# TO AVOID TICKER PRICE SYNCING ISSUES.
|
69
|
+
option_choice = opts[:option_choice]
|
70
|
+
terminal_win = opts[:terminal_win]
|
71
|
+
event_history = opts[:event_history]
|
72
|
+
bot_conf = opts[:bot_conf]
|
73
|
+
|
74
|
+
ai_enabled = bot_conf[:artifical_intelligence]
|
75
|
+
gross_tpm = bot_conf[:target_profit_margin_percent].to_f
|
76
|
+
|
77
|
+
# Only retain past 24 hours of
|
78
|
+
# order history meta for expired and sold
|
79
|
+
# keep open limit sell orders indefintely
|
80
|
+
before_twenty_four_hrs_ago = Time.now - 86400
|
81
|
+
order_history = event_history.order_book[:order_history]
|
82
|
+
order_history_meta = event_history.order_book[:order_history_meta]
|
83
|
+
order_history_meta.delete_if do |ohm|
|
84
|
+
next unless ohm[:done_at]
|
85
|
+
Time.parse(ohm[:done_at]) < before_twenty_four_hrs_ago &&
|
86
|
+
(
|
87
|
+
ohm[:color].to_sym == :black ||
|
88
|
+
ohm[:color].to_sym == :green ||
|
89
|
+
ohm[:color].to_sym == :cyan ||
|
90
|
+
ohm[:color].to_sym == :red
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Only keep order history meta for those
|
95
|
+
# hashes that exist in the last order history
|
96
|
+
# response
|
97
|
+
order_history_meta.keep_if do |ohm|
|
98
|
+
order_history.find do |oh|
|
99
|
+
oh[:id] == ohm[:buy_order_id] ||
|
100
|
+
oh[:id] == ohm[:sell_order_id] ||
|
101
|
+
ohm[:color].to_sym == :black ||
|
102
|
+
ohm[:color].to_sym == :green
|
103
|
+
end
|
104
|
+
end
|
105
|
+
event_history.order_book[:order_history_meta] = order_history_meta
|
106
|
+
|
107
|
+
# Refactor TPM to be 0.01 > than fee tier,
|
108
|
+
# particularly as fee tier goes up or down
|
109
|
+
fees = event_history.order_book[:fees]
|
110
|
+
taker_rate = 0.5
|
111
|
+
taker_rate = fees[:taker_fee_rate].to_f unless fees.empty?
|
112
|
+
taker_fee = format('%0.2f', taker_rate * 100)
|
113
|
+
default_net_tpm = 3
|
114
|
+
|
115
|
+
if ai_enabled
|
116
|
+
low_24h = event_history.order_book[:low_24h].to_f
|
117
|
+
high_24h = event_history.order_book[:high_24h].to_f
|
118
|
+
ai_net_tpm = (1 - (low_24h / high_24h)) * 100
|
119
|
+
default_net_tpm = ai_net_tpm if ai_net_tpm > default_net_tpm
|
120
|
+
end
|
121
|
+
|
122
|
+
min_gross_tpm = format(
|
123
|
+
'%0.2f',
|
124
|
+
(taker_fee.to_f * 2) + default_net_tpm
|
125
|
+
)
|
126
|
+
|
127
|
+
if ai_enabled && min_gross_tpm != gross_tpm.to_s
|
128
|
+
bot_conf[:target_profit_margin_percent] = min_gross_tpm.to_f
|
129
|
+
Cryptum::BotConf.update(
|
130
|
+
option_choice: option_choice,
|
131
|
+
bot_conf: bot_conf,
|
132
|
+
key: :target_profit_margin_percent,
|
133
|
+
value: min_gross_tpm.to_f
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Reload Bot Conf (i.e. Risk Allocation)
|
138
|
+
terminal_win.key_press_event.key_r = true
|
139
|
+
|
140
|
+
# Reset Market Trend Counter
|
141
|
+
event_history.reset_market_trend = true
|
142
|
+
event_history.order_book[:last_trend_reset] = Time.now.strftime(
|
143
|
+
'%Y-%m-%d %H:%M:%S.%N%z'
|
144
|
+
)
|
145
|
+
|
146
|
+
# Write Order Book to Disk
|
147
|
+
terminal_win.key_press_event.key_w = true
|
148
|
+
rescue StandardError => e
|
149
|
+
raise e
|
150
|
+
end
|
151
|
+
|
152
|
+
# Display Usage for this Module
|
153
|
+
|
154
|
+
public_class_method def self.help
|
155
|
+
puts "USAGE:
|
156
|
+
order_trend_indicator_hash = #{self}.status
|
157
|
+
"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|