# frozen_string_literal: true require 'logger' module Cryptum # This plugin is used to Refresh the Cryptum console UI module UI module OrderExecution # 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_execute_win = opts[:order_execute_win] env = opts[:env] 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] event_type = event_history.event_type if option_choice.autotrade event_side = event_history.event[:side].to_s.to_sym if option_choice.autotrade event_reason = event_history.event[:reason].to_s.to_sym if option_choice.autotrade ticker_price = event_history.order_book[:ticker_price].to_f open_24h = event_history.order_book[:open_24h].to_f this_product = event_history.order_book[:this_product] # base_min_size = this_product[:base_min_size] min_market_funds = this_product[:min_market_funds] base_increment = this_product[:base_increment] quote_increment = this_product[:quote_increment] # crypto_smallest_size_to_buy = base_min_size.to_s.split('.')[-1].length crypto_smallest_decimal = base_increment.to_s.split('.')[-1].length fiat_smallest_decimal = quote_increment.to_s.split('.')[-1].length # crypto_smallest_size_to_buy = format( # "%0.#{crypto_smallest_decimal}f", # min_market_funds.to_f / ticker_price # ) # crypto_smallest_size_to_buy = crypto_smallest_size_to_buy.to_s.split('.')[-1].length last_three_prices_arr = [] last_ticker_price = event_history.order_book[:ticker_price].to_f second_to_last_ticker_price = event_history.order_book[:ticker_price_second_to_last].to_f third_to_last_ticker_price = event_history.order_book[:ticker_price_third_to_last].to_f last_three_prices_arr.push(last_ticker_price) last_three_prices_arr.push(second_to_last_ticker_price) last_three_prices_arr.push(third_to_last_ticker_price) limit_price = last_three_prices_arr.sort[1] return event_history unless limit_price.positive? tpm = bot_conf[:target_profit_margin_percent].to_f tpm_cast_as_decimal = tpm / 100 order_history_meta = event_history.order_book[:order_history_meta] order_history = event_history.order_book[:order_history] if option_choice.autotrade if event_history.order_book[:order_plan].length.positive? if event_history.order_ready event_history.order_book[:last_order_exec] = Time.now.strftime( '%Y-%m-%d %H:%M:%S.%N%z' ) end # BUY margin_percent_open_24h = (1 - (open_24h / ticker_price)) * 100 cast_margin_to_sec = margin_percent_open_24h * 0.1 # Reset times to max or default depending on # BULL or BEAR market trend if cast_margin_to_sec.positive? event_history.bullish_trend = true event_history.time_between_orders = event_history.time_between_orders_max end if cast_margin_to_sec.negative? && event_history.bullish_trend event_history.bullish_trend = false event_history.time_between_orders = event_history.time_between_orders_reset end if event_history.order_ready && indicator_status.action_signal == :buy && !event_history.red_pill if option_choice.autotrade this_order = event_history.order_book[:order_plan].first price = format( "%0.#{fiat_smallest_decimal}f", limit_price ) size = this_order[:invest].to_f / limit_price loop do size = size.to_f + base_increment.to_f break if (size.to_f * price.to_f) > min_market_funds.to_f end size = format( "%0.#{crypto_smallest_decimal}f", size ) # size = size.to_i.floor if base_increment.to_i >= 1 # size = base_min_size if size.to_f < base_min_size.to_f # size = min_market_funds if size.to_f < min_market_funds.to_f fiat_invested_this_order = size.to_f * price.to_f fiat_portfolio = event_history.order_book[:fiat_portfolio] # fiat_balance = format('%0.2f', fiat_portfolio.first[:balance]) fiat_avail_for_trade = format('%0.2f', fiat_portfolio.first[:available]) event_history.red_pill = true if fiat_invested_this_order > fiat_avail_for_trade.to_f unless event_history.red_pill event_history = Cryptum::API.submit_limit_order( option_choice: option_choice, env: env, price: price, size: size, buy_or_sell: :buy, event_history: event_history, bot_conf: bot_conf ) end else this_order = event_history.order_book[:order_plan].shift # Mock Order ID this_order[:buy_order_id] = format( '%0.6i', Random.rand(0..999_999) ) this_order[:price] = limit_price.to_s this_order[:size] = format( "%0.#{crypto_smallest_decimal}f", this_order[:invest].to_f / limit_price ) targ_price = limit_price + (limit_price * tpm_cast_as_decimal) this_order[:tpm] = format( '%0.2f', tpm ) this_order[:target_price] = format( "%0.#{fiat_smallest_decimal}f", targ_price ) this_order[:color] = :cyan order_history_meta.push(this_order) end # Increment n Seconds between buys to # account for bearish and bullish trends dynamic_time_increment = cast_margin_to_sec * -1 # Lets also take balance into play balance_as_arbitrary_float = fiat_avail_for_trade.to_f / 1_000_000 tbo = dynamic_time_increment - balance_as_arbitrary_float event_history.time_between_orders += tbo # Time between orders should never # be less than event_history.time_between_orders_min event_history.time_between_orders = event_history.time_between_orders_min if event_history.time_between_orders < event_history.time_between_orders_min # Time between orders should never # be more than event_history.time_between_orders_max event_history.time_between_orders = event_history.time_between_orders_max if event_history.time_between_orders > event_history.time_between_orders_max end # SELL # Once buy arders are fulfilled submit a # limit sell order for fulfillment unless option_choice.autotrade # Testing logic via Mock event_type_arr = %i[received open done] last_et_index = event_type_arr.length - 1 rand_et_index = Random.rand(0..last_et_index) event_type = event_type_arr[rand_et_index] event_side_arr = %i[buy sell] last_es_index = event_side_arr.length - 1 rand_es_index = Random.rand(0..last_es_index) event_side = event_type_arr[rand_es_index].to_s.to_sym event_reason = 'mock' end end # Update Completed Sell Orders w/ Green if event_type == :open && event_side == :buy buy_order_id = event_history.event[:order_id] order_history_meta.each do |meta| meta[:color] = :red if meta[:buy_order_id] == buy_order_id end end if event_type == :done && event_side == :buy && event_reason == :canceled buy_order_id = event_history.event[:order_id] order_history_meta.each do |meta| next unless meta[:buy_order_id] == buy_order_id # buy_done_at_hash_arr = order_history.select do |oh| # oh[:id] == meta[:buy_order_id] # end meta[:done_at] = Time.now.strftime('%Y-%m-%d %H:%M:%S.%N%z') meta[:color] = :white end end if event_type == :done && event_side == :buy && event_reason != :canceled if option_choice.autotrade order_ready_to_sell_arr = order_history_meta.select do |meta| meta[:buy_order_id] == event_history.event[:order_id] end else last_index = order_history_meta.length - 1 rand_index = Random.rand(0..last_index) order_ready_to_sell_arr = [ order_history_meta[rand_index] ] end if order_ready_to_sell_arr.length.positive? order_ready_to_sell = order_ready_to_sell_arr.first buy_order_id = order_ready_to_sell[:buy_order_id] if option_choice.autotrade price = format( "%0.#{fiat_smallest_decimal}f", order_ready_to_sell[:target_price] ) size = order_ready_to_sell[:size] Cryptum::API.submit_limit_order( option_choice: option_choice, env: env, price: price, size: size, buy_or_sell: :sell, event_history: event_history, bot_conf: bot_conf, buy_order_id: buy_order_id ) else sell_order_id = format( '%0.2i', Random.rand(0..999_999) ) event_history.order_book[:order_history_meta].each do |meta| if meta[:buy_order_id] == buy_order_id meta[:sell_order_id] = sell_order_id meta[:color] = :yellow end end end end end # Update Canceled Sell Orders w/ Black && # Include done_at Timestamp for 24h gain calc if event_type == :done && event_side == :sell && event_reason == :canceled sell_order_id = event_history.event[:order_id] order_history_meta.each do |meta| next unless meta[:sell_order_id] == sell_order_id # sell_done_at_hash_arr = order_history.select do |oh| # oh[:id] == meta[:sell_order_id] # end meta[:done_at] = Time.now.strftime('%Y-%m-%d %H:%M:%S.%N%z') # TODO: Retry sell order if the original sell order expires. # Reinitiate GTFO if the previous GTFO Order Expires. terminal_win.key_press_event.key_g = true if meta[:color] == :magenta meta[:color] = :white end end # Update Completed Sell Orders w/ Green && # Include done_at Timestamp for 24h gain calc if event_type == :done && event_side == :sell && event_reason != :canceled sell_order_id = event_history.event[:order_id] order_history_meta.each do |meta| next unless meta[:sell_order_id] == sell_order_id # sell_done_at_hash_arr = order_history.select do |oh| # oh[:id] == meta[:sell_order_id] # end meta[:done_at] = Time.now.strftime('%Y-%m-%d %H:%M:%S.%N%z') # meta[:done_at] = sell_done_at_hash_arr.first[:done_at] unless sell_done_at_hash_arr.empty? meta[:color] = :green end end # OK, now let's tally up everything... twenty_four_hrs_ago = Time.now - 86_400 # Snag all sold orders oh_meta_sold_arr = order_history_meta.select do |ohm| ohm[:color].to_sym == :green && ohm.key?(:done_at) end # Snag all sold orders within past 24 hrs ohm_sold_twenty_four_arr = [] unless oh_meta_sold_arr.empty? ohm_sold_twenty_four_arr = oh_meta_sold_arr.select do |o| Time.parse(o[:done_at]) >= twenty_four_hrs_ago end end order_hist_meta_sold = ohm_sold_twenty_four_arr.length # Snag all expired orders oh_meta_expired_arr = order_history_meta.select do |ohm| ohm[:color].to_sym == :white && ohm.key?(:done_at) end # Snag all expired orders within past 24 hrs ohm_expire_twenty_four_arr = [] unless oh_meta_expired_arr.empty? ohm_expire_twenty_four_arr = oh_meta_expired_arr.select do |o| Time.parse(o[:done_at]) >= twenty_four_hrs_ago end end order_hist_meta_expired = ohm_expire_twenty_four_arr.length # Calculate gains within past 24 hrs gains_24h_sum = ohm_sold_twenty_four_arr.map do |ohms| ohms[:profit].to_f end.sum gains_24h_out = Cryptum.beautify_large_number( value: format( '%0.2f', gains_24h_sum ) ) total_to_sell = order_history.select do |oh| oh[:status].to_sym == :open && oh[:side].to_sym == :sell end.length total_to_sell = "#{total_to_sell}+" if total_to_sell == 1000 # 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 # ROW 1 out_line_no = 0 line_color = :white header_color = :white header_style = :bold style = :bold if event_history.order_execute_win_active line_color = :blue header_color = :blue header_style = :reverse end Cryptum::UI.line( ui_win: order_execute_win, out_line_no: out_line_no, color: line_color ) # ROW 2 out_line_no += 1 order_execute_win.setpos(out_line_no, Cryptum::UI.col_first) order_execute_win.clrtoeol Cryptum::UI.colorize( ui_win: order_execute_win, color: header_color, style: header_style, string: ''.ljust(col_just1, ' ') ) header_str = '- ORDER HISTORY -' order_execute_win.setpos( out_line_no, Cryptum::UI.col_center(str: header_str) ) Cryptum::UI.colorize( ui_win: order_execute_win, color: header_color, style: header_style, string: header_str ) order_execute_win.setpos(out_line_no, Cryptum::UI.col_fourth) order_execute_win.clrtoeol Cryptum::UI.colorize( ui_win: order_execute_win, color: header_color, style: header_style, string: ''.ljust(col_just4, ' ') ) # ROWS 3-10 remaining_blank_rows = 0 remaining_blank_rows = max_rows_to_display if order_history_meta.empty? max_rows_to_display = event_history.order_execute_max_rows_to_display first_row = event_history.order_execute_index_offset last_row = first_row + max_rows_to_display if last_row >= order_history_meta.length last_row = order_history_meta.length - 1 event_history.order_execute_max_records_available_to_display = last_row if last_row < max_rows_to_display first_row = last_row - event_history.order_execute_max_records_available_to_display event_history.order_execute_index_offset = first_row remaining_blank_rows = (max_rows_to_display - last_row) + 1 end if order_history_meta.any? selected_order = event_history.order_execute_selected_data order_history_meta.reverse[first_row..last_row].each do |meta| out_line_no += 1 current_line = out_line_no - 2 style = :normal if event_history.order_execute_row_to_select == current_line style = :highlight selected_order = meta selected_order[:color] = meta[:color] end # risk_alloc_out = Cryptum.beautify_large_number( # value: meta[:risk_alloc] # ) invest_out = Cryptum.beautify_large_number( value: meta[:invest] ) price_out = Cryptum.beautify_large_number( value: meta[:price] ) size_out = Cryptum.beautify_large_number( value: meta[:size] ) target_price_out = Cryptum.beautify_large_number( value: meta[:target_price] ) # profit_out = Cryptum.beautify_large_number( # value: meta[:profit] # ) plan_no = meta[:plan_no] buy_created_at_hash_arr = order_history.select do |oh| oh[:id] == meta[:buy_order_id] end buy_created_at = '____-__-__ __:__:__' unless buy_created_at_hash_arr.empty? buy_created_at = Time.parse( buy_created_at_hash_arr.first[:created_at] ).strftime('%Y-%m-%d %H:%M:%S') end invest = "$#{invest_out} @ " tick = "$#{price_out} = " size = "*#{size_out} + " tpm_out = "#{meta[:tpm]}% = " targ_tick = "$#{target_price_out}" profit = "|Profit: $#{meta[:profit]}" order_exec_ln = "#{buy_created_at}|#{invest}#{tick}#{size}#{tpm_out}#{targ_tick}#{profit}|#{plan_no}" order_execute_win.setpos(out_line_no, Cryptum::UI.col_first) order_execute_win.clrtoeol Cryptum::UI.colorize( ui_win: order_execute_win, color: meta[:color], style: style, string: order_exec_ln.ljust(col_just1, '.') ) Cryptum::UI.colorize( ui_win: order_execute_win, color: meta[:color], style: style, string: ''.ljust(col_just4, ' ') ) end event_history.order_execute_selected_data = selected_order end # Clear to SUMMARY # (Only Applicable if order_book[:order_history_meta] < max_rows_to_display) # out_line_no += 1 rows_to_blank = out_line_no + remaining_blank_rows - 1 (out_line_no..rows_to_blank).each do |clr_line| out_line_no = clr_line order_execute_win.setpos(clr_line, Cryptum::UI.col_first) order_execute_win.clrtoeol Cryptum::UI.colorize( ui_win: order_execute_win, color: :white, style: :normal, string: ''.ljust(col_just1, ' ') ) end # ROW 10 out_line_no += 1 order_execute_win.setpos(out_line_no, Cryptum::UI.col_first) order_execute_win.clrtoeol Cryptum::UI.colorize( ui_win: order_execute_win, color: header_color, style: header_style, string: ''.ljust(col_just1, ' ') ) header_str = "24 HR SUMMARY | Open Sell Orders: #{total_to_sell} | Sold: #{order_hist_meta_sold} | Gains: $#{gains_24h_out} | Expired: #{order_hist_meta_expired}" order_execute_win.setpos( out_line_no, Cryptum::UI.col_center(str: header_str) ) Cryptum::UI.colorize( ui_win: order_execute_win, color: header_color, style: header_style, string: header_str ) order_execute_win.setpos(out_line_no, Cryptum::UI.col_fourth) order_execute_win.clrtoeol Cryptum::UI.colorize( ui_win: order_execute_win, color: header_color, style: header_style, string: ''.ljust(col_just4, ' ') ) # ROW 11 out_line_no += 1 Cryptum::UI.line( ui_win: order_execute_win, out_line_no: out_line_no, color: line_color ) order_execute_win.refresh # Reset Order Ready Boolean event_history.order_ready = false 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