cryptum 0.0.381 → 0.0.383

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/.rubocop_todo.yml +11 -8
  4. data/Gemfile +1 -2
  5. data/bin/cryptum +2 -2
  6. data/lib/cryptum/api/exchange_rates.rb +0 -2
  7. data/lib/cryptum/api/orders.rb +9 -7
  8. data/lib/cryptum/api/portfolio.rb +0 -2
  9. data/lib/cryptum/api/rest.rb +3 -4
  10. data/lib/cryptum/api/signature.rb +0 -4
  11. data/lib/cryptum/api.rb +1 -40
  12. data/lib/cryptum/bot_conf.rb +14 -6
  13. data/lib/cryptum/event/exit.rb +1 -1
  14. data/lib/cryptum/event/history.rb +4 -1
  15. data/lib/cryptum/event/parse.rb +6 -6
  16. data/lib/cryptum/event.rb +0 -2
  17. data/lib/cryptum/log.rb +18 -4
  18. data/lib/cryptum/open_ai.rb +129 -32
  19. data/lib/cryptum/option/choice.rb +1 -1
  20. data/lib/cryptum/option/environment.rb +0 -2
  21. data/lib/cryptum/option/parser.rb +0 -2
  22. data/lib/cryptum/order_book/generate.rb +3 -8
  23. data/lib/cryptum/order_book.rb +0 -3
  24. data/lib/cryptum/portfolio.rb +0 -2
  25. data/lib/cryptum/ui/command.rb +1 -3
  26. data/lib/cryptum/ui/exit.rb +43 -0
  27. data/lib/cryptum/ui/key_press_event.rb +1 -1
  28. data/lib/cryptum/ui/market_trend.rb +4 -3
  29. data/lib/cryptum/ui/matrix.rb +185 -0
  30. data/lib/cryptum/ui/order/execute.rb +629 -0
  31. data/lib/cryptum/ui/order/execute_details.rb +300 -0
  32. data/lib/cryptum/ui/order/plan.rb +518 -0
  33. data/lib/cryptum/ui/order/plan_details.rb +243 -0
  34. data/lib/cryptum/ui/order/timer.rb +140 -0
  35. data/lib/cryptum/ui/order.rb +21 -0
  36. data/lib/cryptum/ui/portfolio.rb +5 -3
  37. data/lib/cryptum/ui/signal_engine.rb +1 -3
  38. data/lib/cryptum/ui/terminal_window.rb +1 -3
  39. data/lib/cryptum/ui/ticker.rb +4 -3
  40. data/lib/cryptum/ui.rb +17 -22
  41. data/lib/cryptum/version.rb +1 -1
  42. data/lib/cryptum/web_sock/coinbase.rb +1 -6
  43. data/lib/cryptum/web_sock/event_machine.rb +3 -7
  44. data/lib/cryptum.rb +16 -33
  45. data/spec/lib/cryptum/{matrix_spec.rb → ui/exit_spec.rb} +2 -2
  46. data/spec/lib/cryptum/ui/{order_plan_spec.rb → matrix_spec.rb} +2 -2
  47. data/spec/lib/cryptum/ui/{order_execute_details_spec.rb → order/execute_details_spec.rb} +2 -2
  48. data/spec/lib/cryptum/ui/{order_execution_spec.rb → order/execute_spec.rb} +2 -2
  49. data/spec/lib/cryptum/ui/{order_plan_details_spec.rb → order/plan_details_spec.rb} +2 -2
  50. data/spec/lib/cryptum/ui/order/plan_spec.rb +10 -0
  51. data/spec/lib/cryptum/ui/order/timer_spec.rb +10 -0
  52. data/spec/lib/cryptum/ui/{order_timer_spec.rb → order_spec.rb} +2 -2
  53. metadata +20 -30
  54. data/lib/cryptum/matrix.rb +0 -181
  55. data/lib/cryptum/ui/order_execute_details.rb +0 -297
  56. data/lib/cryptum/ui/order_execution.rb +0 -624
  57. data/lib/cryptum/ui/order_plan.rb +0 -514
  58. data/lib/cryptum/ui/order_plan_details.rb +0 -240
  59. data/lib/cryptum/ui/order_timer.rb +0 -136
@@ -0,0 +1,518 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cryptum
4
+ # This plugin is used to Refresh the Cryptum console UI
5
+ module UI
6
+ module Order
7
+ module Plan
8
+ # Supported Method Parameters::
9
+ # Cryptum::UI::Order::Plan.refresh(
10
+ # order_book: 'required - Order Book Data Structure',
11
+ # event: 'required - Event from Coinbase Web Socket'
12
+ # )
13
+
14
+ public_class_method def self.refresh(opts = {})
15
+ option_choice = opts[:option_choice]
16
+ order_plan_win = opts[:order_plan_win]
17
+ event_history = opts[:event_history]
18
+ indicator_status = opts[:indicator_status]
19
+ bot_conf = opts[:bot_conf]
20
+
21
+ ticker_price = event_history.order_book[:ticker_price].to_f
22
+ return event_history unless ticker_price.positive?
23
+
24
+ market_trend_color = plan_color = :white
25
+
26
+ this_product = event_history.order_book[:this_product]
27
+ base_increment = this_product[:base_increment]
28
+ min_market_funds = this_product[:min_market_funds]
29
+
30
+ crypto_smallest_decimal = base_increment.to_s.split('.')[-1].length
31
+
32
+ autotrade_percent = bot_conf[:autotrade_portfolio_percent].to_f
33
+ autotrade_cast_as_decimal = autotrade_percent / 100
34
+
35
+ tpm = bot_conf[:target_profit_margin_percent].to_f
36
+ tpm_cast_as_decimal = tpm / 100
37
+
38
+ crypto_currency = option_choice.symbol.to_s.upcase.split('_').first.to_sym
39
+ portfolio = event_history.order_book[:portfolio]
40
+ this_account = portfolio.select do |account|
41
+ account[:currency] == crypto_currency.to_s
42
+ end
43
+ raise "ID for Crypto Currency, #{crypto_currency} Not Found" if this_account.empty?
44
+
45
+ balance = format("%0.#{crypto_smallest_decimal}f", this_account.first[:balance])
46
+ fiat_portfolio = event_history.order_book[:fiat_portfolio]
47
+ total_holdings = format('%0.2f', fiat_portfolio.first[:total_holdings])
48
+ fiat_avail_for_trade = format('%0.2f', fiat_portfolio.first[:available])
49
+
50
+ fiat_budget = fiat_avail_for_trade.to_f
51
+
52
+ order_plan = event_history.order_book[:order_plan]
53
+
54
+ current_crypto_fiat_value = format(
55
+ '%0.2f',
56
+ balance.to_f * ticker_price
57
+ )
58
+
59
+ crypto_invested_percent = format(
60
+ '%0.2f',
61
+ current_crypto_fiat_value.to_f.fdiv(total_holdings.to_f) * 100
62
+ )
63
+
64
+ event_history.red_pill = true if crypto_invested_percent.to_f > autotrade_percent
65
+
66
+ # SAUCE 2
67
+ # Generating and/or recalculating order plan
68
+ if event_history.recalculate_order_plan || (
69
+ crypto_invested_percent.to_f <= autotrade_percent &&
70
+ autotrade_percent.positive? && (
71
+ order_plan.empty? || (
72
+ indicator_status.action_signal == :buy &&
73
+ indicator_status.last_action_signal == :sell
74
+ )
75
+ )
76
+ )
77
+
78
+ event_history.red_pill = false
79
+ if indicator_status.action_signal == :buy &&
80
+ indicator_status.last_action_signal == :sell
81
+
82
+ order_plan = []
83
+ # Reset time between orders
84
+ event_history.time_between_orders = event_history.time_between_orders_reset
85
+ event_history.plan_no += 1
86
+ end
87
+
88
+ plan_no_slice = 1
89
+ plan_no = event_history.plan_no
90
+ # Sum up currently invested amount so we don't
91
+ # exceed autotrade % for next order plan generation
92
+ allocation_decimal = 0.0
93
+ risk_target = fiat_budget * autotrade_cast_as_decimal
94
+ risk_alloc = risk_target
95
+
96
+ # TODO: Order Plan <= event_history.max_open_sell_orders
97
+ previous_slice_fiat_investing = 0.00
98
+ last_slice_detected = false
99
+ loop do
100
+ # Calculate min order size
101
+ allocation_decimal += 0.0001
102
+ fiat_investing = risk_alloc * allocation_decimal
103
+
104
+ next unless fiat_investing > min_market_funds.to_f
105
+
106
+ # Increase amount invested in each slice as we increment
107
+ # plan numbers (i.e. slices) in the order plan cycle
108
+ slice_alloc = fiat_budget * allocation_decimal
109
+ fiat_investing = slice_alloc + previous_slice_fiat_investing
110
+
111
+ risk_alloc = fiat_budget * autotrade_cast_as_decimal
112
+ allocation_percent = allocation_decimal * 100
113
+
114
+ break if order_plan.map { |op| op[:invest].to_f }.sum > risk_target ||
115
+ allocation_percent > 100 ||
116
+ last_slice_detected
117
+
118
+ next unless fiat_budget >= min_market_funds.to_f
119
+
120
+ if fiat_investing > fiat_budget
121
+ last_slice_detected = true
122
+ fiat_investing = fiat_budget
123
+ end
124
+
125
+ fiat_returning = fiat_investing + (
126
+ fiat_investing * tpm_cast_as_decimal
127
+ )
128
+ profit = fiat_returning - fiat_investing
129
+
130
+ this_plan_no = "#{plan_no}.#{plan_no_slice}"
131
+ if event_history.recalculate_order_plan
132
+ order_slice = order_plan.find do |order|
133
+ order[:plan_no] == this_plan_no
134
+ end
135
+ end
136
+ order_slice ||= {}
137
+ order_slice[:plan_no] = this_plan_no
138
+ order_slice[:fiat_available] = format('%0.2f', fiat_budget)
139
+ order_slice[:risk_alloc] = format('%0.2f', risk_alloc)
140
+ order_slice[:allocation_decimal] = format(
141
+ '%0.8f',
142
+ allocation_decimal
143
+ )
144
+ order_slice[:allocation_percent] = format(
145
+ '%0.2f',
146
+ allocation_percent
147
+ )
148
+ order_slice[:slice_alloc] = format('%0.2f', slice_alloc)
149
+ order_slice[:risk_target] = format('%0.2f', risk_target)
150
+ order_slice[:previous_slice_invest] = format(
151
+ '%0.2f',
152
+ previous_slice_fiat_investing
153
+ )
154
+ order_slice[:invest] = format('%0.2f', fiat_investing)
155
+ order_slice[:return] = format('%0.2f', fiat_returning)
156
+ order_slice[:profit] = format('%0.2f', profit)
157
+ order_slice[:tpm] = tpm
158
+ order_slice[:autotrade_percent] = autotrade_percent
159
+ order_slice[:color] = plan_color
160
+ order_slice[:last_slice] = false
161
+
162
+ order_plan.push(order_slice) unless event_history.recalculate_order_plan
163
+ fiat_budget -= fiat_investing
164
+ previous_slice_fiat_investing = fiat_investing
165
+ plan_no_slice += 1
166
+ end
167
+ order_plan.last[:last_slice] = true if order_plan.any?
168
+ op_last_slice_invest = order_plan.last[:invest].to_f if order_plan.any?
169
+ order_plan.last[:invest] = fiat_budget if order_plan.any? &&
170
+ op_last_slice_invest > fiat_budget &&
171
+ fiat_budget > min_market_funds.to_f
172
+
173
+ event_history.order_book[:order_plan] = order_plan
174
+ end
175
+
176
+ red_pill_alert = '| RED PILL ALERT |'
177
+ red_pill_msg = '- Autotrade % Exhausted -'
178
+ event_history.red_pill = true if order_plan.empty?
179
+
180
+ if event_history.red_pill
181
+ order_plan_prefix = '--'
182
+ # max_order_plan_slices = '0'
183
+ order_plan_volume_out = '0.00'
184
+ order_plan_profit_sum_out = '0.00'
185
+ order_plan_exec_percent = '0.00'
186
+ else
187
+ order_plan_len = order_plan.length
188
+ order_plan_prefix = order_plan.last[:plan_no].split('.').first
189
+ max_order_plan_slices = order_plan.last[:plan_no].split('.').last.to_i
190
+ calc_order_plan_exec = (
191
+ 1 - (order_plan_len / max_order_plan_slices.to_f)
192
+ ) * 100
193
+ order_plan_volume = order_plan.map do |op|
194
+ op[:invest].to_f
195
+ end.sum
196
+ order_plan_volume_out = Cryptum.beautify_large_number(
197
+ value: format(
198
+ '%0.2f',
199
+ order_plan_volume
200
+ )
201
+ )
202
+ order_plan_profit_sum = order_plan.map do |op|
203
+ op[:profit].to_f
204
+ end.sum
205
+ order_plan_profit_sum_out = Cryptum.beautify_large_number(
206
+ value: format(
207
+ '%0.2f',
208
+ order_plan_profit_sum
209
+ )
210
+ )
211
+ order_plan_exec_percent = format('%0.2f', calc_order_plan_exec)
212
+ end
213
+
214
+ # TODO: Everything Above this Line Needs to be Indicators ^
215
+
216
+ # UI
217
+ col_just1 = (Curses.cols - Cryptum::UI.col_first) - 1
218
+ col_just4 = Curses.cols - Cryptum::UI.col_fourth
219
+
220
+ # ROW 1
221
+ out_line_no = 0
222
+ line_color = :white
223
+ header_color = :white
224
+ header_style = :bold
225
+ style = :bold
226
+ if event_history.order_plan_win_active
227
+ line_color = :blue
228
+ header_color = :blue
229
+ header_style = :reverse
230
+ end
231
+
232
+ Cryptum::UI.line(
233
+ ui_win: order_plan_win,
234
+ out_line_no: out_line_no,
235
+ color: line_color
236
+ )
237
+
238
+ # ROW 2
239
+ out_line_no += 1
240
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
241
+ order_plan_win.clrtoeol
242
+ Cryptum::UI.colorize(
243
+ ui_win: order_plan_win,
244
+ color: header_color,
245
+ style: header_style,
246
+ string: ''.ljust(col_just1, ' ')
247
+ )
248
+
249
+ header_str = "- ORDER PLAN | CYCLE ##{order_plan_prefix} -"
250
+ header_str = '- ORDER PLAN | UNAVAILABLE -' if event_history.red_pill
251
+ order_plan_win.setpos(
252
+ out_line_no,
253
+ Cryptum::UI.col_center(str: header_str)
254
+ )
255
+
256
+ Cryptum::UI.colorize(
257
+ ui_win: order_plan_win,
258
+ color: header_color,
259
+ style: header_style,
260
+ string: header_str
261
+ )
262
+
263
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
264
+ Cryptum::UI.colorize(
265
+ ui_win: order_plan_win,
266
+ color: header_color,
267
+ style: header_style,
268
+ string: ''.ljust(col_just4, ' ')
269
+ )
270
+
271
+ # ROWS 3-10
272
+ remaining_blank_rows = 0
273
+ max_rows_to_display = event_history.order_plan_max_rows_to_display
274
+ remaining_blank_rows = max_rows_to_display if order_plan.empty?
275
+ if event_history.red_pill
276
+ out_line_no += 1
277
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
278
+ order_plan_win.clrtoeol
279
+
280
+ Cryptum::UI.colorize(
281
+ ui_win: order_plan_win,
282
+ color: :red,
283
+ style: :highlight,
284
+ string: ''.ljust(col_just1, ' ')
285
+ )
286
+
287
+ order_plan_win.setpos(
288
+ out_line_no,
289
+ Cryptum::UI.col_center(str: red_pill_alert)
290
+ )
291
+ Cryptum::UI.colorize(
292
+ ui_win: order_plan_win,
293
+ color: :red,
294
+ style: :highlight,
295
+ string: red_pill_alert
296
+ )
297
+
298
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
299
+ Cryptum::UI.colorize(
300
+ ui_win: order_plan_win,
301
+ color: :red,
302
+ style: :highlight,
303
+ string: ''.ljust(col_just4, ' ')
304
+ )
305
+
306
+ out_line_no += 1
307
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
308
+ order_plan_win.clrtoeol
309
+
310
+ Cryptum::UI.colorize(
311
+ ui_win: order_plan_win,
312
+ color: :yellow,
313
+ string: ''.ljust(col_just1, ' ')
314
+ )
315
+
316
+ order_plan_win.setpos(
317
+ out_line_no,
318
+ Cryptum::UI.col_center(str: red_pill_msg)
319
+ )
320
+ Cryptum::UI.colorize(
321
+ ui_win: order_plan_win,
322
+ color: :yellow,
323
+ style: :bold,
324
+ string: red_pill_msg
325
+ )
326
+
327
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
328
+ Cryptum::UI.colorize(
329
+ ui_win: order_plan_win,
330
+ color: :yellow,
331
+ string: ''.ljust(col_just4, ' ')
332
+ )
333
+
334
+ max_rows_to_display.times.each do
335
+ out_line_no += 1
336
+ this_matrix_row = Cryptum::UI::Matrix.generate(cols: Curses.cols)
337
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
338
+ order_plan_win.clrtoeol
339
+ Cryptum::UI.colorize(
340
+ ui_win: order_plan_win,
341
+ color: :red,
342
+ style: :bold,
343
+ string: this_matrix_row
344
+ )
345
+ end
346
+ else
347
+ market_trend_color = indicator_status.market_trend[:color] if indicator_status.market_trend
348
+ plan_color = :cyan if market_trend_color == :red
349
+ plan_color = :green if market_trend_color == :green
350
+
351
+ # ROWS 3-10
352
+ max_rows_to_display = event_history.order_plan_max_rows_to_display
353
+ first_row = event_history.order_plan_index_offset
354
+ last_row = first_row + max_rows_to_display
355
+ if last_row >= order_plan.length
356
+ last_row = order_plan.length - 1
357
+ event_history.order_plan_max_records_available_to_display = last_row if last_row < max_rows_to_display
358
+ first_row = last_row - event_history.order_plan_max_records_available_to_display
359
+ event_history.order_plan_index_offset = first_row
360
+ remaining_blank_rows = max_rows_to_display - last_row
361
+ end
362
+
363
+ selected_order = event_history.order_plan_selected_data
364
+ order_plan[first_row..last_row].each do |order|
365
+ out_line_no += 1
366
+ current_line = out_line_no - 2
367
+
368
+ style = :normal
369
+ if event_history.order_plan_row_to_select == current_line
370
+ style = :highlight
371
+ selected_order = order
372
+ selected_order[:color] = plan_color
373
+ end
374
+
375
+ fiat_avail_out = Cryptum.beautify_large_number(
376
+ value: order[:fiat_available]
377
+ )
378
+ risk_alloc_out = Cryptum.beautify_large_number(
379
+ value: order[:risk_alloc]
380
+ )
381
+ slice_alloc_out = Cryptum.beautify_large_number(
382
+ value: order[:slice_alloc]
383
+ )
384
+ previous_slice_invest_out = Cryptum.beautify_large_number(
385
+ value: order[:previous_slice_invest]
386
+ )
387
+ invest_out = Cryptum.beautify_large_number(
388
+ value: order[:invest]
389
+ )
390
+ profit_out = Cryptum.beautify_large_number(
391
+ value: order[:profit]
392
+ )
393
+ tpm_out = format('%0.2f', tpm)
394
+ return_out = Cryptum.beautify_large_number(
395
+ value: order[:return]
396
+ )
397
+ plan_no = "#{order[:plan_no]}|"
398
+ fiat = "#{autotrade_percent}% of $#{fiat_avail_out} = "
399
+ alloc = "$#{risk_alloc_out} @ #{order[:allocation_percent]}% = "
400
+ alloc = "$#{risk_alloc_out}" if order[:last_slice]
401
+ invest = "$#{slice_alloc_out} + $#{previous_slice_invest_out} = $#{invest_out} + #{tpm_out}% = "
402
+ invest = " + #{tpm_out}% = " if order[:last_slice]
403
+
404
+ returns = "$#{return_out}|"
405
+ profit = "Profit: $#{profit_out}"
406
+
407
+ order_plan_invest = "#{plan_no}#{fiat}#{alloc}#{invest}"
408
+ order_plan_return = "#{returns}#{profit}"
409
+
410
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
411
+ order_plan_win.clrtoeol
412
+ Cryptum::UI.colorize(
413
+ ui_win: order_plan_win,
414
+ color: plan_color,
415
+ style: style,
416
+ string: "#{order_plan_invest}#{order_plan_return}".ljust(col_just1, '.')
417
+ )
418
+
419
+ Cryptum::UI.colorize(
420
+ ui_win: order_plan_win,
421
+ color: plan_color,
422
+ style: style,
423
+ string: ''.ljust(col_just4, ' ')
424
+ )
425
+ end
426
+ event_history.order_plan_selected_data = selected_order
427
+
428
+ # Clear to SUMMARY
429
+ # (Only Applicable if order_book[:order_plan] < max_rows_to_display)
430
+ # out_line_no += 1
431
+ if remaining_blank_rows.positive?
432
+ rows_to_blank = (out_line_no + remaining_blank_rows)
433
+ out_line_no += 1
434
+ (out_line_no..rows_to_blank).each do |clr_line|
435
+ out_line_no = clr_line
436
+ order_plan_win.setpos(clr_line, Cryptum::UI.col_first)
437
+ order_plan_win.clrtoeol
438
+ Cryptum::UI.colorize(
439
+ ui_win: order_plan_win,
440
+ color: :white,
441
+ style: :normal,
442
+ string: ''.ljust(col_just1, ' ')
443
+ )
444
+ end
445
+ end
446
+
447
+ # ROW 10
448
+ out_line_no += 1
449
+ order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
450
+ order_plan_win.clrtoeol
451
+ Cryptum::UI.colorize(
452
+ ui_win: order_plan_win,
453
+ color: header_color,
454
+ style: header_style,
455
+ string: ''.ljust(col_just1, ' ')
456
+ )
457
+
458
+ header_str = "RISK ALLOCATED: $#{order_plan_volume_out} | "
459
+ header_str += "PROJECTED PROFIT: $#{order_plan_profit_sum_out} | "
460
+ header_str += "#{order_plan_exec_percent}% DONE"
461
+ order_plan_win.setpos(
462
+ out_line_no,
463
+ Cryptum::UI.col_center(str: header_str)
464
+ )
465
+
466
+ Cryptum::UI.colorize(
467
+ ui_win: order_plan_win,
468
+ color: header_color,
469
+ style: header_style,
470
+ string: header_str
471
+ )
472
+
473
+ # order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
474
+ # order_plan_win.clrtoeol
475
+ # Cryptum::UI.colorize(
476
+ # ui_win: order_plan_win,
477
+ # color: header_color,
478
+ # style: header_style,
479
+ # string: ''.ljust(col_just4, ' ')
480
+ # )
481
+ end
482
+
483
+ # ROW 11
484
+ out_line_no += 1
485
+ Cryptum::UI.line(
486
+ ui_win: order_plan_win,
487
+ out_line_no: out_line_no,
488
+ color: line_color
489
+ )
490
+
491
+ order_plan_win.refresh
492
+
493
+ event_history
494
+ rescue Interrupt
495
+ # Exit Gracefully if CTRL+C is Pressed During Session
496
+ Cryptum::UI::Exit.gracefully(
497
+ which_self: self,
498
+ event_history: event_history,
499
+ option_choice: option_choice
500
+ )
501
+ rescue StandardError => e
502
+ raise e
503
+ end
504
+
505
+ # Display Usage for this Module
506
+
507
+ public_class_method def self.help
508
+ puts "USAGE:
509
+ #{self}.refresh(
510
+ order_book: 'required - Order Book Data Structure',
511
+ event: 'required - Event from Coinbase Web Socket'
512
+ )
513
+ "
514
+ end
515
+ end
516
+ end
517
+ end
518
+ end