cryptum 0.0.230

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +16 -0
  3. data/.gitignore +30 -0
  4. data/.rspec +3 -0
  5. data/.rspec_status +0 -0
  6. data/.rubocop.yml +5 -0
  7. data/.rubocop_todo.yml +250 -0
  8. data/.ruby-gemset +1 -0
  9. data/.ruby-version +1 -0
  10. data/CODE_OF_CONDUCT.md +84 -0
  11. data/Gemfile +36 -0
  12. data/LICENSE +674 -0
  13. data/README.md +72 -0
  14. data/Rakefile +19 -0
  15. data/bin/cryptum +72 -0
  16. data/bin/cryptum-forecast +199 -0
  17. data/bin/cryptum-repl +73 -0
  18. data/bin/cryptum_autoinc_version +38 -0
  19. data/build_cryptum_gem.sh +52 -0
  20. data/cryptum.gemspec +50 -0
  21. data/cryptum_container.sh +1 -0
  22. data/docker/cryptum.json +60 -0
  23. data/docker/cryptum_container.sh +59 -0
  24. data/docker/packer_secrets.json.EXAMPLE +7 -0
  25. data/docker/provisioners/cryptum.sh +11 -0
  26. data/docker/provisioners/docker_bashrc.sh +2 -0
  27. data/docker/provisioners/docker_rvm.sh +22 -0
  28. data/docker/provisioners/init_image.sh +28 -0
  29. data/docker/provisioners/post_install.sh +6 -0
  30. data/docker/provisioners/ruby.sh +16 -0
  31. data/docker/provisioners/upload_globals.sh +49 -0
  32. data/etc/bot_confs/.gitkeep +0 -0
  33. data/etc/bot_confs/BOT_CONF.TEMPLATE +10 -0
  34. data/etc/coinbase_pro.yaml.EXAMPLE +8 -0
  35. data/git_commit.sh +22 -0
  36. data/lib/cryptum/api.rb +693 -0
  37. data/lib/cryptum/bot_conf.rb +76 -0
  38. data/lib/cryptum/event/buy.rb +144 -0
  39. data/lib/cryptum/event/cancel.rb +49 -0
  40. data/lib/cryptum/event/history.rb +64 -0
  41. data/lib/cryptum/event/key_press.rb +64 -0
  42. data/lib/cryptum/event/sell.rb +120 -0
  43. data/lib/cryptum/event.rb +168 -0
  44. data/lib/cryptum/log.rb +34 -0
  45. data/lib/cryptum/matrix.rb +181 -0
  46. data/lib/cryptum/option/choice.rb +26 -0
  47. data/lib/cryptum/option.rb +161 -0
  48. data/lib/cryptum/order_book/generate.rb +111 -0
  49. data/lib/cryptum/order_book/indicator.rb +16 -0
  50. data/lib/cryptum/order_book/market_trend.rb +161 -0
  51. data/lib/cryptum/order_book/profit_margin.rb +55 -0
  52. data/lib/cryptum/order_book/weighted_avg.rb +157 -0
  53. data/lib/cryptum/order_book.rb +156 -0
  54. data/lib/cryptum/portfolio/balance.rb +123 -0
  55. data/lib/cryptum/portfolio.rb +15 -0
  56. data/lib/cryptum/ui/command.rb +274 -0
  57. data/lib/cryptum/ui/key_press_event.rb +22 -0
  58. data/lib/cryptum/ui/market_trend.rb +117 -0
  59. data/lib/cryptum/ui/order_execution.rb +478 -0
  60. data/lib/cryptum/ui/order_plan.rb +376 -0
  61. data/lib/cryptum/ui/order_timer.rb +119 -0
  62. data/lib/cryptum/ui/portfolio.rb +231 -0
  63. data/lib/cryptum/ui/signal_engine.rb +122 -0
  64. data/lib/cryptum/ui/terminal_window.rb +95 -0
  65. data/lib/cryptum/ui/ticker.rb +317 -0
  66. data/lib/cryptum/ui.rb +306 -0
  67. data/lib/cryptum/version.rb +5 -0
  68. data/lib/cryptum/web_sock/coinbase.rb +94 -0
  69. data/lib/cryptum/web_sock/event_machine.rb +182 -0
  70. data/lib/cryptum/web_sock.rb +16 -0
  71. data/lib/cryptum.rb +183 -0
  72. data/order_books/.gitkeep +0 -0
  73. data/reinstall_cryptum_gemset.sh +29 -0
  74. data/spec/lib/cryptum/api_spec.rb +10 -0
  75. data/spec/lib/cryptum/event_spec.rb +10 -0
  76. data/spec/lib/cryptum/log_spec.rb +10 -0
  77. data/spec/lib/cryptum/option_spec.rb +10 -0
  78. data/spec/lib/cryptum/order_book/generate_spec.rb +10 -0
  79. data/spec/lib/cryptum/order_book/market_trend_spec.rb +10 -0
  80. data/spec/lib/cryptum/order_book_spec.rb +10 -0
  81. data/spec/lib/cryptum/ui/command_spec.rb +10 -0
  82. data/spec/lib/cryptum/ui/ticker_spec.rb +10 -0
  83. data/spec/lib/cryptum/ui_spec.rb +10 -0
  84. data/spec/lib/cryptum/web_sock_spec.rb +10 -0
  85. data/spec/lib/cryptum_spec.rb +10 -0
  86. data/spec/spec_helper.rb +3 -0
  87. data/upgrade_Gemfile_gems.sh +20 -0
  88. data/upgrade_cryptum.sh +13 -0
  89. data/upgrade_gem.sh +4 -0
  90. data/upgrade_ruby.sh +46 -0
  91. metadata +472 -0
@@ -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