module BitexBot
Get version and bitex-bot as user-agent
Constants
- Settings
- VERSION
Public Class Methods
start_robot()
click to toggle source
# File lib/bitex_bot/robot.rb, line 72 def self.start_robot setup log(:info, "Loading trading robot, ctrl+c *once* to exit gracefully.\n") new end
user_agent()
click to toggle source
# File lib/bitex_bot.rb, line 29 def self.user_agent "Bitexbot/#{VERSION} (https://github.com/bitex-la/bitex-bot)" end
Public Instance Methods
active_closing_flows?()
click to toggle source
rubocop:enable Metrics/AbcSize
# File lib/bitex_bot/robot.rb, line 104 def active_closing_flows? [BuyClosingFlow, SellClosingFlow].map(&:active).any?(&:exists?) end
active_opening_flows?()
click to toggle source
# File lib/bitex_bot/robot.rb, line 108 def active_opening_flows? [BuyOpeningFlow, SellOpeningFlow].map(&:active).any?(&:exists?) end
store()
click to toggle source
The trader has a Store
# File lib/bitex_bot/robot.rb, line 113 def store @store ||= Store.first || Store.create end
trade!()
click to toggle source
rubocop:disable Metrics/AbcSize
# File lib/bitex_bot/robot.rb, line 79 def trade! sync_opening_flows if active_opening_flows? finalise_some_opening_flows shutdown! if shutdable? start_closing_flows if open_positions? sync_closing_flows if active_closing_flows? start_opening_flows_if_needed rescue CannotCreateFlow => e notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}") sleep_for(60 * 3) rescue Curl::Err::TimeoutError => e notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}") sleep_for(15) rescue OrderNotFound => e notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}") rescue ApiWrapperError => e notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}") rescue OrderArgumentError => e notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}") rescue StandardError => e notify("#{e.class} - #{e.message}\n\n#{e.backtrace.join("\n")}") sleep_for(60 * 2) end
Private Instance Methods
active_flows(opening_flow_class)
click to toggle source
# File lib/bitex_bot/robot.rb, line 144 def active_flows(opening_flow_class) turn_off? ? opening_flow_class.active : opening_flow_class.old_active end
active_flows?()
click to toggle source
# File lib/bitex_bot/robot.rb, line 132 def active_flows? active_opening_flows? || active_closing_flows? end
alert?(currency, flag)
click to toggle source
# File lib/bitex_bot/robot.rb, line 229 def alert?(currency, flag) return unless store.send("#{currency}_#{flag}").present? balance(currency) <= store.send("#{currency}_#{flag}") end
balance(currency)
click to toggle source
# File lib/bitex_bot/robot.rb, line 235 def balance(currency) fx_rate = currency == :fiat ? Settings.buying_fx_rate : 1 store.send("maker_#{currency}") / fx_rate + store.send("taker_#{currency}") end
check_balance_warning()
click to toggle source
# File lib/bitex_bot/robot.rb, line 224 def check_balance_warning notify_balance_warning(maker.base, balance(:crypto), store.crypto_warning) if alert?(:crypto, :warning) notify_balance_warning(maker.quote, balance(:fiat), store.fiat_warning) if alert?(:fiat, :warning) end
expired_last_warning?()
click to toggle source
rubocop:enable Metrics/AbcSize
# File lib/bitex_bot/robot.rb, line 215 def expired_last_warning? store.last_warning.nil? || store.last_warning < 30.minutes.ago end
finalise_some_opening_flows()
click to toggle source
# File lib/bitex_bot/robot.rb, line 140 def finalise_some_opening_flows [BuyOpeningFlow, SellOpeningFlow].each { |kind| active_flows(kind).each(&:finalise!) } end
log_balances(header)
click to toggle source
rubocop:disable Metrics/AbcSize
# File lib/bitex_bot/robot.rb, line 205 def log_balances(header) log( :info, "#{header}\n"\ "Store: #{maker.name} maker - #{maker.base.upcase}: #{store.maker_crypto}, #{maker.quote.upcase}: #{store.maker_fiat}.\n"\ "Store: #{taker.name} taker - #{taker.base.upcase}: #{store.taker_crypto}, #{taker.quote.upcase}: #{store.taker_fiat}.\n" ) end
new_mail(subj, message)
click to toggle source
# File lib/bitex_bot/robot.rb, line 254 def new_mail(subj, message) Mail.new do from Settings.mailer.from to Settings.mailer.to subject subj body message end end
notify(message, subj = 'Notice from your robot trader')
click to toggle source
# File lib/bitex_bot/robot.rb, line 245 def notify(message, subj = 'Notice from your robot trader') log(:info, "Sending mail with subject: #{subj}\n\n#{message}") return unless Settings.mailer.present? new_mail(subj, message).tap do |mail| mail.delivery_method(Settings.mailer.delivery_method.to_sym, Settings.mailer.options.to_hash) end.deliver! end
notify_balance_warning(currency, amount, warning_amount)
click to toggle source
# File lib/bitex_bot/robot.rb, line 240 def notify_balance_warning(currency, amount, warning_amount) notify("#{currency.upcase} balance is too low, it's #{amount}, make it #{warning_amount} to stop this warning.") store.update(last_warning: Time.now) end
open_positions?()
click to toggle source
# File lib/bitex_bot/robot.rb, line 152 def open_positions? [OpenBuy, OpenSell].map(&:open).any?(&:exists?) end
recent_operations()
click to toggle source
rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
# File lib/bitex_bot/robot.rb, line 187 def recent_operations threshold = (Settings.time_to_live / 2).seconds.ago [BuyOpeningFlow, SellOpeningFlow].map { |kind| kind.active.where('created_at > ?', threshold).first } end
shutdable?()
click to toggle source
# File lib/bitex_bot/robot.rb, line 123 def shutdable? !(active_flows? || open_positions?) && turn_off? end
shutdown!()
click to toggle source
# File lib/bitex_bot/robot.rb, line 127 def shutdown! log(:info, 'Shutdown completed') exit end
start_closing_flows()
click to toggle source
# File lib/bitex_bot/robot.rb, line 148 def start_closing_flows [BuyClosingFlow, SellClosingFlow].each(&:close_open_positions) end
start_opening_flows_if_needed()
click to toggle source
rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
# File lib/bitex_bot/robot.rb, line 161 def start_opening_flows_if_needed return log(:debug, 'Not placing new orders, because Store is held') if store.reload.hold? return log(:debug, 'Not placing new orders, has active closing flows.') if active_closing_flows? return log(:debug, 'Not placing new orders, shutting down.') if turn_off? recent_buying, recent_selling = recent_operations return log(:debug, 'Not placing new orders, recent ones exist.') if recent_buying && recent_selling maker_balance = with_cooldown { maker.balance } taker_balance = with_cooldown { taker.balance } sync_log_and_store(maker_balance, taker_balance) log_balances('Store: Current balances.') check_balance_warning if expired_last_warning? return if stop_opening_flows? order_book = with_cooldown { taker.order_book } transactions = with_cooldown { taker.transactions } args = [transactions, maker_balance.fee, taker_balance.fee, store] BuyOpeningFlow.create_for_market(*[taker_balance.crypto.available, order_book.bids] + args) unless recent_buying SellOpeningFlow.create_for_market(*[taker_balance.fiat.available, order_book.asks] + args) unless recent_selling end
stop_opening_flows?()
click to toggle source
# File lib/bitex_bot/robot.rb, line 219 def stop_opening_flows? (log(:info, "Opening: Not placing new orders, #{maker.quote.upcase} target not met") if alert?(:fiat, :stop)) || (log(:info, "Opening: Not placing new orders, #{maker.base.upcase} target not met") if alert?(:crypto, :stop)) end
sync_closing_flows()
click to toggle source
# File lib/bitex_bot/robot.rb, line 156 def sync_closing_flows [BuyClosingFlow, SellClosingFlow].each { |kind| kind.active.each(&:sync_closed_positions) } end
sync_log_and_store(maker_balance, taker_balance)
click to toggle source
# File lib/bitex_bot/robot.rb, line 192 def sync_log_and_store(maker_balance, taker_balance) log_balances('Store: Updating log, maker and taker balances...') file = Settings.log.try(:file) last_log = `tail -c 61440 #{file}` if file.present? store.update( maker_fiat: maker_balance.fiat.total, maker_crypto: maker_balance.crypto.total, taker_fiat: taker_balance.fiat.total, taker_crypto: taker_balance.crypto.total, log: last_log ) end
sync_opening_flows()
click to toggle source
# File lib/bitex_bot/robot.rb, line 119 def sync_opening_flows [SellOpeningFlow, BuyOpeningFlow].each(&:sync_open_positions) end
turn_off?()
click to toggle source
# File lib/bitex_bot/robot.rb, line 136 def turn_off? self.class.graceful_shutdown end