# 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] key_press_event = opts[:key_press_event] indicator_status = opts[:indicator_status] bot_conf = opts[:bot_conf] fiat_portfolio_file = opts[:fiat_portfolio_file] ticker_price = event_history.order_book[:ticker_price].to_f return unless ticker_price.positive? this_product = event_history.order_book[:this_product] symbol_out = this_product[:id] quote_increment = this_product[:quote_increment] base_increment = this_product[:base_increment] # base_min_size = this_product[:base_min_size].to_f min_market_funds = this_product[:min_market_funds] fiat_smallest_decimal = quote_increment.to_s.split('.')[-1].length 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]) avail_for_trade = format("%0.#{crypto_smallest_decimal}f", this_account.first[:available]) fiat_portfolio = event_history.order_book[:fiat_portfolio] total_holdings = format('%0.2f', fiat_portfolio.first[:total_holdings]) fiat_balance = format('%0.2f', fiat_portfolio.first[:balance]) fiat_avail_for_trade = format('%0.2f', fiat_portfolio.first[:available]) fiat_budget = fiat_avail_for_trade.to_f current_fiat_invested_percent = ( 1 - (fiat_budget / total_holdings.to_f) ) * 100 order_history = event_history.order_book[:order_history] open_orders = order_history.select do |order| order[:status] == 'open' end total_open_orders = open_orders.length 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 / total_holdings.to_f) * 100 ) event_history.red_pill = true if crypto_invested_percent.to_f > autotrade_percent if crypto_invested_percent.to_f <= autotrade_percent && ( order_plan.empty? || ( indicator_status.action_signal == :buy && indicator_status.last_action_signal == :sell ) ) event_history.red_pill = false # Reset time between orders when generating new order plan event_history.time_between_orders = event_history.time_between_orders_reset if order_plan.empty? order_plan = [] plan_no_slice = 1 event_history.plan_no += 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 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 # fiat_investing = min_market_funds.to_f # allocation_decimal = fiat_investing / ticker_price risk_alloc = fiat_budget * autotrade_cast_as_decimal allocation_percent = allocation_decimal * 100 fiat_returning = fiat_investing + ( fiat_investing * tpm_cast_as_decimal ) profit = fiat_returning - fiat_investing # Implemented a bugfix here to avoid a bogus single order when Tradeable # Balances are low. Ensure everything still works as expected when # balances are higher. break if order_plan.map { |op| op[:invest].to_f }.sum > risk_target || allocation_percent > 100 order_slice = {} order_slice[:plan_no] = "#{plan_no}.#{plan_no_slice}" 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[:invest] = format('%0.2f', fiat_investing) order_slice[:return] = format('%0.2f', fiat_returning) order_slice[:profit] = format('%0.2f', profit) order_plan.push(order_slice) fiat_budget -= fiat_investing plan_no_slice += 1 end event_history.order_book[:order_plan] = order_plan end red_pill_alert = '| RED PILL ALERT |' red_pill_msg = "% #{symbol_out} > Autotrade %" 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_just3 = (Curses.cols - Cryptum::UI.col_third) - 1 col_just4 = Curses.cols - Cryptum::UI.col_fourth Cryptum::UI.detect_key_press_in_ui( key_press_event: key_press_event, ui_win: order_plan_win ) # ROW 1 out_line_no = 0 line_color = :white style = :bold line_color = :red if event_history.order_plan_win_highlighted 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: :white, style: style, string: "Order Plan ##{order_plan_prefix} Summary:" ) order_plan_win.setpos(out_line_no, Cryptum::UI.col_third) Cryptum::UI.colorize( ui_win: order_plan_win, color: :white, style: style, string: "$#{order_plan_volume_out} w #{max_order_plan_slices} Slices | $#{order_plan_profit_sum_out} 2 Gain | #{order_plan_exec_percent}% Done".rjust( col_just3, '.' ) ) # ROW 3 out_line_no += 1 Cryptum::UI.line( ui_win: order_plan_win, out_line_no: out_line_no, color: line_color ) # ROWS 4-10 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, ' ') ) 5.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 color = plan_color = :white color = indicator_status.market_trend[:color] if indicator_status.market_trend plan_color = :cyan if color == :red plan_color = :green if color == :green first_row = event_history.order_plan_line last_row = first_row + 7 if last_row >= order_plan.length last_row = order_plan.length - 1 first_row = last_row - 7 event_history.order_plan_line = first_row end order_plan[first_row..last_row].each do |order| out_line_no += 1 style = :normal style = :highlight if event_history.order_plan_win_highlighted fiat_avail_out = Cryptum.beautify_large_number( value: order[:fiat_available] ) risk_alloc_out = Cryptum.beautify_large_number( value: order[:risk_alloc] ) 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]}% = " invest = "$#{invest_out} + #{tpm_out}% = " 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, '.') ) end if order_plan.length < 9 lines_to_clear = 9 - order_plan.length (1..lines_to_clear).each do |_line| out_line_no += 1 order_plan_win.setpos(out_line_no, Cryptum::UI.col_first) order_plan_win.clrtoeol end end end 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