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.
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,376 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module Cryptum
6
+ # This plugin is used to Refresh the Cryptum console UI
7
+ module UI
8
+ module OrderPlan
9
+ # Supported Method Parameters::
10
+ # Cryptum::UI::Candle.refresh(
11
+ # order_book: 'required - Order Book Data Structure',
12
+ # event: 'required - Event from Coinbase Web Socket'
13
+ # )
14
+
15
+ public_class_method def self.refresh(opts = {})
16
+ option_choice = opts[:option_choice]
17
+ order_plan_win = opts[:order_plan_win]
18
+ event_history = opts[:event_history]
19
+ key_press_event = opts[:key_press_event]
20
+ indicator_status = opts[:indicator_status]
21
+ bot_conf = opts[:bot_conf]
22
+ fiat_portfolio_file = opts[:fiat_portfolio_file]
23
+
24
+ ticker_price = event_history.order_book[:ticker_price].to_f
25
+ return unless ticker_price.positive?
26
+
27
+ this_product = event_history.order_book[:this_product]
28
+ symbol_out = this_product[:id]
29
+ quote_increment = this_product[:quote_increment]
30
+ base_increment = this_product[:base_increment]
31
+ base_min_size = this_product[:base_min_size].to_f
32
+
33
+ fiat_smallest_decimal = quote_increment.to_s.split('.')[-1].length
34
+ crypto_smallest_decimal = base_increment.to_s.split('.')[-1].length
35
+
36
+ autotrade_percent = bot_conf[:autotrade_portfolio_percent].to_f
37
+ autotrade_cast_as_decimal = autotrade_percent / 100
38
+
39
+ tpm = bot_conf[:target_profit_margin_percent].to_f
40
+ tpm_cast_as_decimal = tpm / 100
41
+
42
+ crypto_currency = option_choice.symbol.to_s.upcase.split('_').first.to_sym
43
+ portfolio = event_history.order_book[:portfolio]
44
+ this_account = portfolio.select do |account|
45
+ account[:currency] == crypto_currency.to_s
46
+ end
47
+ raise "ID for Crypto Currency, #{crypto_currency} Not Found" if this_account.empty?
48
+
49
+ balance = format("%0.#{crypto_smallest_decimal}f", this_account.first[:balance])
50
+ avail_for_trade = format("%0.#{crypto_smallest_decimal}f", this_account.first[:available])
51
+
52
+ fiat_portfolio = event_history.order_book[:fiat_portfolio]
53
+ total_holdings = format('%0.2f', fiat_portfolio.first[:total_holdings])
54
+ fiat_balance = format('%0.2f', fiat_portfolio.first[:balance])
55
+ fiat_avail_for_trade = format('%0.2f', fiat_portfolio.first[:available])
56
+
57
+ fiat_budget = fiat_avail_for_trade.to_f
58
+ current_fiat_invested_percent = (
59
+ 1 - (fiat_budget / total_holdings.to_f)
60
+ ) * 100
61
+
62
+ order_history = event_history.order_book[:order_history]
63
+ open_orders = order_history.select do |order|
64
+ order[:status] == 'open'
65
+ end
66
+ total_open_orders = open_orders.length
67
+
68
+ order_plan = event_history.order_book[:order_plan]
69
+
70
+ current_crypto_fiat_value = format(
71
+ '%0.2f',
72
+ balance.to_f * ticker_price
73
+ )
74
+
75
+ crypto_invested_percent = format(
76
+ '%0.2f',
77
+ (current_crypto_fiat_value.to_f / total_holdings.to_f) * 100
78
+ )
79
+
80
+ event_history.red_pill = true if crypto_invested_percent.to_f > autotrade_percent
81
+
82
+ if crypto_invested_percent.to_f <= autotrade_percent && (
83
+ order_plan.empty? || (
84
+ indicator_status.action_signal == :buy &&
85
+ indicator_status.last_action_signal == :sell
86
+ )
87
+ )
88
+
89
+ event_history.red_pill = false
90
+ # Reset time between orders when generating new order plan
91
+ event_history.time_between_orders = event_history.time_between_orders_reset if order_plan.empty?
92
+
93
+ order_plan = []
94
+ plan_no_slice = 1
95
+ event_history.plan_no += 1
96
+ plan_no = event_history.plan_no
97
+ # Sum up currently invested amount so we don't
98
+ # exceed autotrade % for next order plan generation
99
+ allocation_decimal = 0.0
100
+ risk_target = fiat_budget * autotrade_cast_as_decimal
101
+ risk_alloc = risk_target
102
+ while order_plan.map { |op| op[:invest].to_f }.sum < risk_target
103
+ # Calculate min order size
104
+ allocation_decimal += 0.0001
105
+ fiat_investing = risk_alloc * allocation_decimal
106
+ min_fiat_allowed_to_invest = base_min_size * ticker_price
107
+
108
+ next unless fiat_investing >= min_fiat_allowed_to_invest
109
+
110
+ risk_alloc = fiat_budget * autotrade_cast_as_decimal
111
+ allocation_percent = allocation_decimal * 100
112
+ fiat_returning = fiat_investing + (
113
+ fiat_investing * tpm_cast_as_decimal
114
+ )
115
+ profit = fiat_returning - fiat_investing
116
+
117
+ order_slice = {}
118
+ order_slice[:plan_no] = "#{plan_no}.#{plan_no_slice}"
119
+ order_slice[:fiat_available] = format('%0.2f', fiat_budget)
120
+ order_slice[:risk_alloc] = format('%0.2f', risk_alloc)
121
+ order_slice[:allocation_decimal] = format(
122
+ '%0.8f',
123
+ allocation_decimal
124
+ )
125
+ order_slice[:allocation_percent] = format(
126
+ '%0.2f',
127
+ allocation_percent
128
+ )
129
+ order_slice[:invest] = format('%0.2f', fiat_investing)
130
+ order_slice[:return] = format('%0.2f', fiat_returning)
131
+ order_slice[:profit] = format('%0.2f', profit)
132
+
133
+ order_plan.push(order_slice)
134
+ fiat_budget -= fiat_investing
135
+ plan_no_slice += 1
136
+ end
137
+ event_history.order_book[:order_plan] = order_plan
138
+ end
139
+
140
+ red_pill_alert = '| RED PILL ALERT |'
141
+ red_pill_msg = "% #{symbol_out} > Autotrade %"
142
+ event_history.red_pill = true if order_plan.empty?
143
+
144
+ if event_history.red_pill
145
+ order_plan_prefix = '--'
146
+ max_order_plan_slices = '0'
147
+ order_plan_volume_out = '0.00'
148
+ order_plan_profit_sum_out = '0.00'
149
+ order_plan_exec_percent = '0.00'
150
+ else
151
+ order_plan_len = order_plan.length
152
+ order_plan_prefix = order_plan.last[:plan_no].split('.').first
153
+ max_order_plan_slices = order_plan.last[:plan_no].split('.').last.to_i
154
+ calc_order_plan_exec = (
155
+ 1 - (order_plan_len / max_order_plan_slices.to_f)
156
+ ) * 100
157
+ order_plan_volume = order_plan.map do |op|
158
+ op[:invest].to_f
159
+ end.sum
160
+ order_plan_volume_out = Cryptum.beautify_large_number(
161
+ value: format(
162
+ '%0.2f',
163
+ order_plan_volume
164
+ )
165
+ )
166
+ order_plan_profit_sum = order_plan.map do |op|
167
+ op[:profit].to_f
168
+ end.sum
169
+ order_plan_profit_sum_out = Cryptum.beautify_large_number(
170
+ value: format(
171
+ '%0.2f',
172
+ order_plan_profit_sum
173
+ )
174
+ )
175
+ order_plan_exec_percent = format('%0.2f', calc_order_plan_exec)
176
+ end
177
+
178
+ # TODO: Everything Above this Line Needs to be Indicators ^
179
+
180
+ # UI
181
+ col_just1 = (Curses.cols - Cryptum::UI.col_first) - 1
182
+ col_just3 = (Curses.cols - Cryptum::UI.col_third) - 1
183
+ col_just4 = Curses.cols - Cryptum::UI.col_fourth
184
+
185
+ Cryptum::UI.detect_key_press_in_ui(
186
+ key_press_event: key_press_event,
187
+ ui_win: order_plan_win
188
+ )
189
+
190
+ # ROW 1
191
+ out_line_no = 0
192
+ Cryptum::UI.line(
193
+ ui_win: order_plan_win,
194
+ out_line_no: out_line_no
195
+ )
196
+
197
+ # ROW 2
198
+ out_line_no += 1
199
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
200
+ order_plan_win.clrtoeol
201
+ Cryptum::UI.colorize(
202
+ ui_win: order_plan_win,
203
+ color: :white,
204
+ style: :bold,
205
+ string: "Order Plan ##{order_plan_prefix} Summary:"
206
+ )
207
+
208
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_third)
209
+ Cryptum::UI.colorize(
210
+ ui_win: order_plan_win,
211
+ color: :white,
212
+ string: "$#{order_plan_volume_out} w #{max_order_plan_slices} Slices | $#{order_plan_profit_sum_out} 2 Gain | #{order_plan_exec_percent}% Done".rjust(
213
+ col_just3,
214
+ '.'
215
+ )
216
+ )
217
+
218
+ # ROW 3
219
+ out_line_no += 1
220
+ Cryptum::UI.line(
221
+ ui_win: order_plan_win,
222
+ out_line_no: out_line_no
223
+ )
224
+
225
+ # ROWS 4-10
226
+ if event_history.red_pill
227
+ out_line_no += 1
228
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
229
+ order_plan_win.clrtoeol
230
+
231
+ Cryptum::UI.colorize(
232
+ ui_win: order_plan_win,
233
+ color: :red,
234
+ style: :highlight,
235
+ string: ''.ljust(col_just1, ' ')
236
+ )
237
+
238
+ order_plan_win.setpos(
239
+ out_line_no,
240
+ Cryptum::UI.col_center(str: red_pill_alert)
241
+ )
242
+ Cryptum::UI.colorize(
243
+ ui_win: order_plan_win,
244
+ color: :red,
245
+ style: :highlight,
246
+ string: red_pill_alert
247
+ )
248
+
249
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
250
+ Cryptum::UI.colorize(
251
+ ui_win: order_plan_win,
252
+ color: :red,
253
+ style: :highlight,
254
+ string: ''.ljust(col_just4, ' ')
255
+ )
256
+
257
+ out_line_no += 1
258
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
259
+ order_plan_win.clrtoeol
260
+
261
+ Cryptum::UI.colorize(
262
+ ui_win: order_plan_win,
263
+ color: :yellow,
264
+ string: ''.ljust(col_just1, ' ')
265
+ )
266
+
267
+ order_plan_win.setpos(
268
+ out_line_no,
269
+ Cryptum::UI.col_center(str: red_pill_msg)
270
+ )
271
+ Cryptum::UI.colorize(
272
+ ui_win: order_plan_win,
273
+ color: :yellow,
274
+ style: :bold,
275
+ string: red_pill_msg
276
+ )
277
+
278
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
279
+ Cryptum::UI.colorize(
280
+ ui_win: order_plan_win,
281
+ color: :yellow,
282
+ string: ''.ljust(col_just4, ' ')
283
+ )
284
+
285
+ 5.times.each do
286
+ out_line_no += 1
287
+ this_matrix_row = Cryptum::Matrix.generate(cols: Curses.cols)
288
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
289
+ order_plan_win.clrtoeol
290
+ Cryptum::UI.colorize(
291
+ ui_win: order_plan_win,
292
+ color: :red,
293
+ style: :bold,
294
+ string: this_matrix_row
295
+ )
296
+ end
297
+ else
298
+ color = plan_color = :white
299
+ color = indicator_status.market_trend[:color] if indicator_status.market_trend
300
+ plan_color = :cyan if color == :red
301
+ plan_color = :green if color == :green
302
+
303
+ order_plan[0..6].each do |order|
304
+ out_line_no += 1
305
+ style = :normal
306
+ style = :highlight if out_line_no == 1
307
+ fiat_avail_out = Cryptum.beautify_large_number(
308
+ value: order[:fiat_available]
309
+ )
310
+ risk_alloc_out = Cryptum.beautify_large_number(
311
+ value: order[:risk_alloc]
312
+ )
313
+ invest_out = Cryptum.beautify_large_number(
314
+ value: order[:invest]
315
+ )
316
+ profit_out = Cryptum.beautify_large_number(
317
+ value: order[:profit]
318
+ )
319
+ tpm_out = format('%0.2f', tpm)
320
+ return_out = Cryptum.beautify_large_number(
321
+ value: order[:return]
322
+ )
323
+ plan_no = "#{order[:plan_no]}|"
324
+ fiat = "#{autotrade_percent}% of $#{fiat_avail_out} = "
325
+ alloc = "$#{risk_alloc_out} @ #{order[:allocation_percent]}% = "
326
+ invest = "$#{invest_out} + #{tpm_out}% = "
327
+
328
+ returns = "$#{return_out}|"
329
+ profit = "Profit: $#{profit_out}"
330
+
331
+ order_plan_invest = "#{plan_no}#{fiat}#{alloc}#{invest}"
332
+ order_plan_return = "#{returns}#{profit}"
333
+
334
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
335
+ order_plan_win.clrtoeol
336
+ Cryptum::UI.colorize(
337
+ ui_win: order_plan_win,
338
+ color: plan_color,
339
+ style: style,
340
+ string: "#{order_plan_invest}#{order_plan_return}".ljust(col_just1, '.')
341
+ )
342
+ end
343
+
344
+ if order_plan.length < 9
345
+ lines_to_clear = 9 - order_plan.length
346
+ (1..lines_to_clear).each do |_line|
347
+ out_line_no += 1
348
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
349
+ order_plan_win.clrtoeol
350
+ end
351
+ end
352
+ end
353
+
354
+ order_plan_win.refresh
355
+
356
+ # event_history
357
+ rescue Interrupt
358
+ # Exit Gracefully if CTRL+C is Pressed During Session
359
+ Cryptum.exit_gracefully(which_self: self)
360
+ rescue StandardError => e
361
+ raise e
362
+ end
363
+
364
+ # Display Usage for this Module
365
+
366
+ public_class_method def self.help
367
+ puts "USAGE:
368
+ #{self}.refresh(
369
+ order_book: 'required - Order Book Data Structure',
370
+ event: 'required - Event from Coinbase Web Socket'
371
+ )
372
+ "
373
+ end
374
+ end
375
+ end
376
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module Cryptum
6
+ module UI
7
+ # This plugin is used to Refresh the Cryptum Status Section UI
8
+ module OrderTimer
9
+ # Supported Method Parameters::
10
+ # Cryptum::UI::Timer.refresh(
11
+ # )
12
+
13
+ public_class_method def self.refresh(opts = {})
14
+ option_choice = opts[:option_choice]
15
+ event_history = opts[:event_history]
16
+ order_timer_win = opts[:order_timer_win]
17
+ indicator_status = opts[:indicator_status]
18
+ key_press_event = opts[:key_press_event]
19
+
20
+ last_trend_reset_time = event_history.order_book[:last_trend_reset]
21
+ last_order_exec_time = event_history.order_book[:last_order_exec]
22
+
23
+ Cryptum::UI.detect_key_press_in_ui(
24
+ key_press_event: key_press_event,
25
+ ui_win: order_timer_win
26
+ )
27
+
28
+ # Market Trend Reset Timer
29
+ time_between_trend_reset = option_choice.market_trend_reset
30
+ trend_timer_begin = Time.parse(last_trend_reset_time)
31
+ trend_timer_end = trend_timer_begin + time_between_trend_reset
32
+ trend_time_remaining = trend_timer_end - Time.now
33
+ trend_countdown = format('%0.4f', trend_time_remaining)
34
+
35
+ # Market Trend Reset Timer
36
+ time_between_order_exec = event_history.time_between_orders
37
+ time_between_order_exec_out = format(
38
+ '%0.4f',
39
+ time_between_order_exec
40
+ )
41
+ order_begin_time = Time.parse(last_order_exec_time)
42
+ order_end_time = order_begin_time + time_between_order_exec
43
+ order_exec_time_remaining = order_end_time - Time.now
44
+ order_countdown = format('%0.4f', order_exec_time_remaining)
45
+
46
+ color = :white
47
+ color = indicator_status.market_trend[:color] if indicator_status.market_trend
48
+ case color
49
+ when :green
50
+ intent = "- Wait for Open Sell Orders -"
51
+ else
52
+ intent = "Next BUY: #{order_countdown} of #{time_between_order_exec_out}"
53
+ intent = '- BUYING PAUSED -' if event_history.red_pill
54
+ end
55
+
56
+ # Have a Clock
57
+ clock = Time.now.strftime('%Y-%m-%d %H:%M:%S%z')
58
+
59
+ # UI
60
+ col_just4 = (Curses.cols - Cryptum::UI.col_fourth) - 1
61
+
62
+ # ROW 1
63
+ out_line_no = 0
64
+ Cryptum::UI.line(
65
+ ui_win: order_timer_win,
66
+ out_line_no: out_line_no
67
+ )
68
+
69
+ # ROW 2
70
+ out_line_no += 1
71
+ order_timer_win.setpos(out_line_no, Cryptum::UI.col_first)
72
+ order_timer_win.clrtoeol
73
+ Cryptum::UI.colorize(
74
+ ui_win: order_timer_win,
75
+ color: :white,
76
+ style: :bold,
77
+ string: "Market Trend Reset: #{trend_countdown}"
78
+ )
79
+
80
+ order_timer_win.setpos(
81
+ out_line_no,
82
+ Cryptum::UI.col_center(str: intent)
83
+ )
84
+ Cryptum::UI.colorize(
85
+ ui_win: order_timer_win,
86
+ color: :white,
87
+ style: :bold,
88
+ string: intent
89
+ )
90
+
91
+ order_timer_win.setpos(out_line_no, Cryptum::UI.col_fourth)
92
+ Cryptum::UI.colorize(
93
+ ui_win: order_timer_win,
94
+ color: :white,
95
+ style: :bold,
96
+ string: clock.rjust(col_just4)
97
+ )
98
+
99
+ order_timer_win.refresh
100
+
101
+ order_countdown.to_f
102
+ rescue Interrupt
103
+ # Exit Gracefully if CTRL+C is Pressed During Session
104
+ Cryptum.exit_gracefully(which_self: self)
105
+ rescue StandardError => e
106
+ raise e
107
+ end
108
+
109
+ # Display Usage for this Module
110
+
111
+ public_class_method def self.help
112
+ puts "USAGE:
113
+ #{self}.refresh(
114
+ )
115
+ "
116
+ end
117
+ end
118
+ end
119
+ end