# frozen_string_literal: true require 'logger' module Cryptum # This plugin is used to Refresh the Cryptum console UI module UI module OrderPlan # Supported Method Parameters:: # Cryptum::UI::Candle.refresh( # order_book: 'required - Order Book Data Structure', # event: 'required - Event from Coinbase Web Socket' # ) public_class_method def self.refresh(opts = {}) option_choice = opts[:option_choice] order_plan_win = opts[:order_plan_win] event_history = opts[:event_history] indicator_status = opts[:indicator_status] bot_conf = opts[:bot_conf] ticker_price = event_history.order_book[:ticker_price].to_f return event_history unless ticker_price.positive? market_trend_color = plan_color = :white this_product = event_history.order_book[:this_product] base_increment = this_product[:base_increment] min_market_funds = this_product[:min_market_funds] crypto_smallest_decimal = base_increment.to_s.split('.')[-1].length autotrade_percent = bot_conf[:autotrade_portfolio_percent].to_f autotrade_cast_as_decimal = autotrade_percent / 100 tpm = bot_conf[:target_profit_margin_percent].to_f tpm_cast_as_decimal = tpm / 100 crypto_currency = option_choice.symbol.to_s.upcase.split('_').first.to_sym portfolio = event_history.order_book[:portfolio] this_account = portfolio.select do |account| account[:currency] == crypto_currency.to_s end raise "ID for Crypto Currency, #{crypto_currency} Not Found" if this_account.empty? balance = format("%0.#{crypto_smallest_decimal}f", this_account.first[:balance]) fiat_portfolio = event_history.order_book[:fiat_portfolio] total_holdings = format('%0.2f', fiat_portfolio.first[:total_holdings]) fiat_avail_for_trade = format('%0.2f', fiat_portfolio.first[:available]) fiat_budget = fiat_avail_for_trade.to_f order_plan = event_history.order_book[:order_plan] current_crypto_fiat_value = format( '%0.2f', balance.to_f * ticker_price ) crypto_invested_percent = format( '%0.2f', current_crypto_fiat_value.to_f.fdiv(total_holdings.to_f) * 100 ) event_history.red_pill = true if crypto_invested_percent.to_f > autotrade_percent # SAUCE 2 # Generating and/or recalculating order plan if event_history.recalculate_order_plan || ( crypto_invested_percent.to_f <= autotrade_percent && autotrade_percent.positive? && ( order_plan.empty? || ( indicator_status.action_signal == :buy && indicator_status.last_action_signal == :sell ) ) ) event_history.red_pill = false if indicator_status.action_signal == :buy && indicator_status.last_action_signal == :sell order_plan = [] # Reset time between orders event_history.time_between_orders = event_history.time_between_orders_reset event_history.plan_no += 1 end plan_no_slice = 1 plan_no = event_history.plan_no # Sum up currently invested amount so we don't # exceed autotrade % for next order plan generation allocation_decimal = 0.0 risk_target = fiat_budget * autotrade_cast_as_decimal risk_alloc = risk_target # TODO: Order Plan <= event_history.max_open_sell_orders previous_slice_fiat_investing = 0.00 last_slice_detected = false loop do # Calculate min order size allocation_decimal += 0.0001 fiat_investing = risk_alloc * allocation_decimal next unless fiat_investing > min_market_funds.to_f # Increase amount invested in each slice as we increment # plan numbers (i.e. slices) in the order plan cycle slice_alloc = fiat_budget * allocation_decimal fiat_investing = slice_alloc + previous_slice_fiat_investing risk_alloc = fiat_budget * autotrade_cast_as_decimal allocation_percent = allocation_decimal * 100 break if order_plan.map { |op| op[:invest].to_f }.sum > risk_target || allocation_percent > 100 || last_slice_detected next unless fiat_budget >= min_market_funds.to_f if fiat_investing > fiat_budget last_slice_detected = true fiat_investing = fiat_budget end fiat_returning = fiat_investing + ( fiat_investing * tpm_cast_as_decimal ) profit = fiat_returning - fiat_investing this_plan_no = "#{plan_no}.#{plan_no_slice}" if event_history.recalculate_order_plan order_slice = order_plan.find do |order| order[:plan_no] == this_plan_no end end order_slice ||= {} order_slice[:plan_no] = this_plan_no order_slice[:fiat_available] = format('%0.2f', fiat_budget) order_slice[:risk_alloc] = format('%0.2f', risk_alloc) order_slice[:allocation_decimal] = format( '%0.8f', allocation_decimal ) order_slice[:allocation_percent] = format( '%0.2f', allocation_percent ) order_slice[:slice_alloc] = format('%0.2f', slice_alloc) order_slice[:risk_target] = format('%0.2f', risk_target) order_slice[:previous_slice_invest] = format( '%0.2f', previous_slice_fiat_investing ) order_slice[:invest] = format('%0.2f', fiat_investing) order_slice[:return] = format('%0.2f', fiat_returning) order_slice[:profit] = format('%0.2f', profit) order_slice[:tpm] = tpm order_slice[:autotrade_percent] = autotrade_percent order_slice[:color] = plan_color order_slice[:last_slice] = false order_plan.push(order_slice) unless event_history.recalculate_order_plan fiat_budget -= fiat_investing previous_slice_fiat_investing = fiat_investing plan_no_slice += 1 end order_plan.last[:last_slice] = true if order_plan.any? op_last_slice_invest = order_plan.last[:invest].to_f if order_plan.any? order_plan.last[:invest] = fiat_budget if order_plan.any? && op_last_slice_invest > fiat_budget && fiat_budget > min_market_funds.to_f event_history.order_book[:order_plan] = order_plan end red_pill_alert = '| RED PILL ALERT |' red_pill_msg = '- Autotrade % Exhausted -' event_history.red_pill = true if order_plan.empty? if event_history.red_pill order_plan_prefix = '--' # max_order_plan_slices = '0' order_plan_volume_out = '0.00' order_plan_profit_sum_out = '0.00' order_plan_exec_percent = '0.00' else order_plan_len = order_plan.length order_plan_prefix = order_plan.last[:plan_no].split('.').first max_order_plan_slices = order_plan.last[:plan_no].split('.').last.to_i calc_order_plan_exec = ( 1 - (order_plan_len / max_order_plan_slices.to_f) ) * 100 order_plan_volume = order_plan.map do |op| op[:invest].to_f end.sum order_plan_volume_out = Cryptum.beautify_large_number( value: format( '%0.2f', order_plan_volume ) ) order_plan_profit_sum = order_plan.map do |op| op[:profit].to_f end.sum order_plan_profit_sum_out = Cryptum.beautify_large_number( value: format( '%0.2f', order_plan_profit_sum ) ) order_plan_exec_percent = format('%0.2f', calc_order_plan_exec) end # TODO: Everything Above this Line Needs to be Indicators ^ # UI col_just1 = (Curses.cols - Cryptum::UI.col_first) - 1 col_just4 = Curses.cols - Cryptum::UI.col_fourth # ROW 1 out_line_no = 0 line_color = :white header_color = :white header_style = :bold style = :bold if event_history.order_plan_win_active line_color = :blue header_color = :blue header_style = :reverse end Cryptum::UI.line( ui_win: order_plan_win, out_line_no: out_line_no, color: line_color ) # ROW 2 out_line_no += 1 order_plan_win.setpos(out_line_no, Cryptum::UI.col_first) order_plan_win.clrtoeol Cryptum::UI.colorize( ui_win: order_plan_win, color: header_color, style: header_style, string: ''.ljust(col_just1, ' ') ) header_str = "- ORDER PLAN | CYCLE ##{order_plan_prefix} -" header_str = '- ORDER PLAN | UNAVAILABLE -' if event_history.red_pill order_plan_win.setpos( out_line_no, Cryptum::UI.col_center(str: header_str) ) Cryptum::UI.colorize( ui_win: order_plan_win, color: header_color, style: header_style, string: header_str ) order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth) Cryptum::UI.colorize( ui_win: order_plan_win, color: header_color, style: header_style, string: ''.ljust(col_just4, ' ') ) # ROWS 3-10 remaining_blank_rows = 0 max_rows_to_display = event_history.order_plan_max_rows_to_display remaining_blank_rows = max_rows_to_display if order_plan.empty? if event_history.red_pill out_line_no += 1 order_plan_win.setpos(out_line_no, Cryptum::UI.col_first) order_plan_win.clrtoeol Cryptum::UI.colorize( ui_win: order_plan_win, color: :red, style: :highlight, string: ''.ljust(col_just1, ' ') ) order_plan_win.setpos( out_line_no, Cryptum::UI.col_center(str: red_pill_alert) ) Cryptum::UI.colorize( ui_win: order_plan_win, color: :red, style: :highlight, string: red_pill_alert ) order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth) Cryptum::UI.colorize( ui_win: order_plan_win, color: :red, style: :highlight, string: ''.ljust(col_just4, ' ') ) out_line_no += 1 order_plan_win.setpos(out_line_no, Cryptum::UI.col_first) order_plan_win.clrtoeol Cryptum::UI.colorize( ui_win: order_plan_win, color: :yellow, string: ''.ljust(col_just1, ' ') ) order_plan_win.setpos( out_line_no, Cryptum::UI.col_center(str: red_pill_msg) ) Cryptum::UI.colorize( ui_win: order_plan_win, color: :yellow, style: :bold, string: red_pill_msg ) order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth) Cryptum::UI.colorize( ui_win: order_plan_win, color: :yellow, string: ''.ljust(col_just4, ' ') ) max_rows_to_display.times.each do out_line_no += 1 this_matrix_row = Cryptum::Matrix.generate(cols: Curses.cols) order_plan_win.setpos(out_line_no, Cryptum::UI.col_first) order_plan_win.clrtoeol Cryptum::UI.colorize( ui_win: order_plan_win, color: :red, style: :bold, string: this_matrix_row ) end else market_trend_color = indicator_status.market_trend[:color] if indicator_status.market_trend plan_color = :cyan if market_trend_color == :red plan_color = :green if market_trend_color == :green # ROWS 3-10 max_rows_to_display = event_history.order_plan_max_rows_to_display first_row = event_history.order_plan_index_offset last_row = first_row + max_rows_to_display if last_row >= order_plan.length last_row = order_plan.length - 1 event_history.order_plan_max_records_available_to_display = last_row if last_row < max_rows_to_display first_row = last_row - event_history.order_plan_max_records_available_to_display event_history.order_plan_index_offset = first_row remaining_blank_rows = max_rows_to_display - last_row end selected_order = event_history.order_plan_selected_data order_plan[first_row..last_row].each do |order| out_line_no += 1 current_line = out_line_no - 2 style = :normal if event_history.order_plan_row_to_select == current_line style = :highlight selected_order = order selected_order[:color] = plan_color end fiat_avail_out = Cryptum.beautify_large_number( value: order[:fiat_available] ) risk_alloc_out = Cryptum.beautify_large_number( value: order[:risk_alloc] ) slice_alloc_out = Cryptum.beautify_large_number( value: order[:slice_alloc] ) previous_slice_invest_out = Cryptum.beautify_large_number( value: order[:previous_slice_invest] ) invest_out = Cryptum.beautify_large_number( value: order[:invest] ) profit_out = Cryptum.beautify_large_number( value: order[:profit] ) tpm_out = format('%0.2f', tpm) return_out = Cryptum.beautify_large_number( value: order[:return] ) plan_no = "#{order[:plan_no]}|" fiat = "#{autotrade_percent}% of $#{fiat_avail_out} = " alloc = "$#{risk_alloc_out} @ #{order[:allocation_percent]}% = " alloc = "$#{risk_alloc_out}" if order[:last_slice] invest = "$#{slice_alloc_out} + $#{previous_slice_invest_out} = $#{invest_out} + #{tpm_out}% = " invest = " + #{tpm_out}% = " if order[:last_slice] returns = "$#{return_out}|" profit = "Profit: $#{profit_out}" order_plan_invest = "#{plan_no}#{fiat}#{alloc}#{invest}" order_plan_return = "#{returns}#{profit}" order_plan_win.setpos(out_line_no, Cryptum::UI.col_first) order_plan_win.clrtoeol Cryptum::UI.colorize( ui_win: order_plan_win, color: plan_color, style: style, string: "#{order_plan_invest}#{order_plan_return}".ljust(col_just1, '.') ) Cryptum::UI.colorize( ui_win: order_plan_win, color: plan_color, style: style, string: ''.ljust(col_just4, ' ') ) end event_history.order_plan_selected_data = selected_order # Clear to SUMMARY # (Only Applicable if order_book[:order_plan] < max_rows_to_display) # out_line_no += 1 if remaining_blank_rows.positive? rows_to_blank = (out_line_no + remaining_blank_rows) out_line_no += 1 (out_line_no..rows_to_blank).each do |clr_line| out_line_no = clr_line order_plan_win.setpos(clr_line, Cryptum::UI.col_first) order_plan_win.clrtoeol Cryptum::UI.colorize( ui_win: order_plan_win, color: :white, style: :normal, string: ''.ljust(col_just1, ' ') ) end end # ROW 10 out_line_no += 1 order_plan_win.setpos(out_line_no, Cryptum::UI.col_first) order_plan_win.clrtoeol Cryptum::UI.colorize( ui_win: order_plan_win, color: header_color, style: header_style, string: ''.ljust(col_just1, ' ') ) header_str = "CYCLE SUMMARY | Risk Allocated: $#{order_plan_volume_out} | Profit: $#{order_plan_profit_sum_out} | #{order_plan_exec_percent}% Done" order_plan_win.setpos( out_line_no, Cryptum::UI.col_center(str: header_str) ) Cryptum::UI.colorize( ui_win: order_plan_win, color: header_color, style: header_style, string: header_str ) order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth) order_plan_win.clrtoeol Cryptum::UI.colorize( ui_win: order_plan_win, color: header_color, style: header_style, string: ''.ljust(col_just4, ' ') ) end # ROW 11 out_line_no += 1 Cryptum::UI.line( ui_win: order_plan_win, out_line_no: out_line_no, color: line_color ) order_plan_win.refresh event_history rescue Interrupt # Exit Gracefully if CTRL+C is Pressed During Session Cryptum.exit_gracefully(which_self: self) rescue StandardError => e raise e end # Display Usage for this Module public_class_method def self.help puts "USAGE: #{self}.refresh( order_book: 'required - Order Book Data Structure', event: 'required - Event from Coinbase Web Socket' ) " end end end end