# frozen_string_literal: true module Cryptum # This plugin is used to Establish a Web # Socket Connection with Coinbase module WebSock # This module is the primary module to handle # Web Socket Events from Coinbase module EventMachine # Supported Method Parameters:: # Cryptum::WS.run( # ) public_class_method def self.run(opts = {}) env = opts[:env] option_choice = opts[:option_choice] terminal_win = opts[:terminal_win] event_history = opts[:event_history] # Instantiate Our Status Indicator Objects indicator_status = Cryptum::OrderBook::Indicator.new # Automatically Create Bot Confs if they don't # Exist and Initialize Automated Trading Parameters bot_conf = Cryptum::BotConf.read( option_choice: option_choice, event_history: event_history ) max_conn_attempts = 30 conn_attempt = 0 begin conn_attempt += 1 event_history.reconnected = true if conn_attempt > 1 EM.run do # Iterate as fast as possible # This ensures candle timing is accurate # and everything is fast as possible # Defaults to 100ms, 5ms is the lowest possible delay_ms = 5 delay_ms_cast_as_decimal = delay_ms * 0.001 EM.set_quantum(delay_ms) ws = Cryptum::WebSock::Coinbase.connect( option_choice: option_choice, env: env ) ws.on :open do |_event| ws.send( Cryptum::WebSock::Coinbase.subscribe_message( option_choice: option_choice, env: env ) ) end ws.on :message do |event| # Convert Web Socket Response JSON Message to Hash event_history.event = JSON.parse( event.data, symbolize_names: true ) event_history.event_type = event_history.event[:type].to_s.to_sym event_history = Cryptum::Event::Parse.websocket_msg( env: env, terminal_win: terminal_win, option_choice: option_choice, event_history: event_history, indicator_status: indicator_status, bot_conf: bot_conf ) # Detect Key Press Events Cryptum::Event::KeyPress.detect(terminal_win: terminal_win) # Cancel ALL Open Orders when C is pressed if terminal_win.key_press_event.key_c Cryptum::Event::Cancel.open_orders( terminal_win: terminal_win, option_choice: option_choice, env: env ) end # Get the F* Out (GTFO) when G is pressed if terminal_win.key_press_event.key_g event_history = Cryptum::Event::GTFO.now( terminal_win: terminal_win, option_choice: option_choice, env: env, event_history: event_history, bot_conf: bot_conf ) end # Reload Bot Conf when r is Pressed if terminal_win.key_press_event.key_r bot_conf = Cryptum::Event::BotConf.reload( terminal_win: terminal_win, event_history: event_history, option_choice: option_choice ) end # Write Order Book to File when W is Pressed if terminal_win.key_press_event.key_w Cryptum::Event::OrderBook.write( terminal_win: terminal_win, event_history: event_history ) end # Exit if x is Pressed if terminal_win.key_press_event.key_x Cryptum::Event::Exit.gracefully( event_history: event_history ) end # TAB through Order Plan / Order Execution Window Panes if terminal_win.key_press_event.key_tab Cryptum::Event::Pane.switch( terminal_win: terminal_win, event_history: event_history ) end # Scroll Up Order Plan / Order Execution Window Panes if terminal_win.key_press_event.key_up_arrow Cryptum::Event::Scroll.up( terminal_win: terminal_win, event_history: event_history ) end # Scroll Down Order Plan / Order Execution Window Panes if terminal_win.key_press_event.key_down_arrow Cryptum::Event::Scroll.down( terminal_win: terminal_win, event_history: event_history ) end # Scroll Up Order Plan / Order Execution Window Panes Faster if terminal_win.key_press_event.key_page_up Cryptum::Event::Scroll.page_up( terminal_win: terminal_win, event_history: event_history ) end # Scroll Down Order Plan / Order Execution Window Panes Faster if terminal_win.key_press_event.key_page_down Cryptum::Event::Scroll.page_down( terminal_win: terminal_win, event_history: event_history ) end # Scroll to Top of Order Plan / Order Execution Window Panes if terminal_win.key_press_event.key_home Cryptum::Event::Scroll.top( terminal_win: terminal_win, event_history: event_history ) end # Scroll to Bottom of Order Plan / Order Execution Window Panes if terminal_win.key_press_event.key_end Cryptum::Event::Scroll.bottom( terminal_win: terminal_win, event_history: event_history ) end # Open / Close Order Plan / Order Execution Details Window if terminal_win.key_press_event.key_enter Cryptum::Event::Pane.toggle_details( terminal_win: terminal_win, event_history: event_history ) end end ws.on :close do # raise Errno::ECONNRESET when remote peer forces reset... # This will be caught in the rescue block below which reattempts # to connect until conn_attempt > max_conn_attempts raise Errno::ECONNRESET end EM.add_periodic_timer(delay_ms_cast_as_decimal) do order_countdown = Cryptum::UI::Order::Timer.refresh( option_choice: option_choice, event_history: event_history, order_timer_win: terminal_win.order_timer_section, indicator_status: indicator_status, key_press_event: terminal_win.key_press_event ) if (order_countdown.zero? || order_countdown.negative?) && !event_history.red_pill # Ready to Submit a BUY order event_history.order_ready = true # Reload Bot Conf (i.e. Risk Allocation), # Recalculate Order Plan, and Write to File terminal_win.key_press_event.key_r = true end end EM.add_periodic_timer(option_choice.market_trend_reset) do # NOTE: To ensure the integrity of event_history is maintained, # changes to its contents _MUST_ stay in this block. # event_history.order_book[:market_trend][:buy] = 0 # event_history.order_book[:market_trend][:sell] = 0 # event_history.order_book[:last_trend_reset] = Time.now.strftime( # '%Y-%m-%d %H:%M:%S.%N%z' # ) event_history = Cryptum::OrderBook::MarketTrend.reset(event_history: event_history) # Reload Bot Conf (i.e. Risk Allocation) # Recalculate Order Plan, and Write to File terminal_win.key_press_event.key_r = true # IMPORTANT: # Wait for Order Plan recalculation to occur # once Cryptum::UI::Order::Plan is refreshed # in Cryptum::Event _BEFORE_ writing the order # book to file. end end rescue Faye::WebSocket::API::ErrorEvent, Errno::ECONNREFUSED, Errno::ECONNRESET, LoadError => e Cryptum::Log.append(level: :debug, msg: e, which_self: self, event_history: event_history) if conn_attempt > max_conn_attempts Cryptum::Log.append( level: :error, msg: e, which_self: self, event_history: event_history ) end sleep 1 retry ensure $stdout.flush end rescue Interrupt, StandardError => e Cryptum::Log.append(level: :error, msg: e, which_self: self, event_history: event_history) end # Display Usage for this Module public_class_method def self.help puts "USAGE: " end end end end