class BitexBot::ClosingFlow

Close buy/sell positions.

Public Class Methods

close_open_positions() click to toggle source

Start a new CloseBuy that closes existing OpenBuy's by selling on another exchange what was just bought on bitex. rubocop:disable Metrics/AbcSize

# File lib/bitex_bot/models/closing_flow.rb, line 12
def self.close_open_positions
  return unless open_positions.any?

  positions = open_positions
  quantity = positions.sum(&:quantity)
  amount = positions.sum(&:amount) / fx_rate
  price = suggested_amount(positions) / quantity
  unless Robot.taker.enough_order_size?(quantity, price)
    Robot.log(
      :info,
      "Closing: #{Robot.taker.name} - enough order size for #{Robot.taker.base.upcase} #{quantity}"\
      " @ #{Robot.taker.quote.upcase} #{price}"
    )
    return
  end

  create_closing_flow!(price, quantity, amount, positions)
end
create_closing_flow!(price, quantity, amount, open_positions) click to toggle source
# File lib/bitex_bot/models/closing_flow.rb, line 41
def self.create_closing_flow!(price, quantity, amount, open_positions)
  flow = create!(desired_price: price, quantity: quantity, amount: amount, open_positions: open_positions)
  Robot.log(
    :info,
    "Closing: created #{self}##{flow.id}, desired price: #{flow.desired_price}, quantity: #{flow.quantity}, "\
    "amount: #{flow.amount}."
  )
  flow.create_initial_order_and_close_position!
  nil
end
open_positions() click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/bitex_bot/models/closing_flow.rb, line 32
def self.open_positions
  open_position_class.open
end
suggested_amount(positions) click to toggle source

close_open_positions helpers

# File lib/bitex_bot/models/closing_flow.rb, line 37
def self.suggested_amount(positions)
  positions.map { |p| p.quantity * p.opening_flow.suggested_closing_price }.sum
end

Public Instance Methods

create_initial_order_and_close_position!() click to toggle source

end: close_open_positions helpers

# File lib/bitex_bot/models/closing_flow.rb, line 53
def create_initial_order_and_close_position!
  create_order_and_close_position(quantity, desired_price)
end
estimate_fiat_profit() click to toggle source
# File lib/bitex_bot/models/closing_flow.rb, line 63
def estimate_fiat_profit
  raise 'self subclass responsibility'
end
positions_balance_amount() click to toggle source
# File lib/bitex_bot/models/closing_flow.rb, line 67
def positions_balance_amount
  close_positions.sum(:amount) * fx_rate
end
sync_closed_positions() click to toggle source

TODO: should receive a order_ids and user_transaccions array, then each Wrapper should know how to search for them.

# File lib/bitex_bot/models/closing_flow.rb, line 58
def sync_closed_positions
  # Maybe we couldn't create the bitstamp order when this flow was created, so we try again when syncing.
  latest_close.nil? ? create_initial_order_and_close_position! : create_or_cancel!
end

Private Instance Methods

cancel!(order) click to toggle source

create_or_cancel! helpers

# File lib/bitex_bot/models/closing_flow.rb, line 96
def cancel!(order)
  Robot.with_cooldown do
    Robot.log(:debug, "Finalising #{order.raw.class}##{order.id}")
    order.cancel!
    Robot.log(:debug, "Finalised #{order.raw.class}##{order.id}")
  end
rescue StandardError => error
  Robot.log(:debug, error)
  nil # just pass, we'll keep on trying until it's not in orders anymore.
end
create_next_position!() click to toggle source

This use hooks methods, these must be defined in the subclass:

estimate_crypto_profit
amount_positions_balance
next_price_and_quantity

rubocop:disable Metrics/AbcSize

# File lib/bitex_bot/models/closing_flow.rb, line 112
def create_next_position!
  next_price, next_quantity = next_price_and_quantity
  if Robot.taker.enough_order_size?(next_quantity, next_price)
    create_order_and_close_position(next_quantity, next_price)
  else
    update!(crypto_profit: estimate_crypto_profit, fiat_profit: estimate_fiat_profit, fx_rate: fx_rate, done: true)
    Robot.log(
      :info,
      "Closing: Finished #{self.class} ##{id} earned"\
      " #{Robot.maker.quote.upcase} #{fiat_profit} and #{Robot.maker.base.upcase} #{crypto_profit}."
    )
  end
end
create_or_cancel!() click to toggle source

sync_closed_positions helpers rubocop:disable Metrics/AbcSize

# File lib/bitex_bot/models/closing_flow.rb, line 75
def create_or_cancel!
  order_id = latest_close.order_id.to_s
  order = Robot.with_cooldown { Robot.taker.orders.find { |o| o.id.to_s == order_id } }

  # When order is nil it means the other exchange is done executing it so we can now have a look of all the sales that were
  # spawned from it.
  if order.nil?
    sync_position(order_id)
    create_next_position!
  elsif latest_close.created_at < close_time_to_live.seconds.ago
    cancel!(order)
  end
end
create_order_and_close_position(quantity, price) click to toggle source

This use hooks methods, these must be defined in the subclass:

order_type

rubocop:disable Metrics/AbcSize

# File lib/bitex_bot/models/closing_flow.rb, line 143
def create_order_and_close_position(quantity, price)
  # TODO: investigate how to generate an ID to insert in the fields of goals where possible.
  Robot.log(
    :info,
    "Closing: Going to place #{order_type} order for #{self.class} ##{id}"\
    " #{Robot.taker.base.upcase} #{quantity} @ #{Robot.taker.quote.upcase} #{price}"
  )
  order = Robot.taker.place_order(order_type, price, quantity)
  Robot.log(
    :info,
    "Closing: #{Robot.taker.name} placed #{order.type} with price: #{order.price} @ quantity #{order.amount}.\n"\
    "Closing: Going to create Close#{order.type.to_s.capitalize} position.\n"
  )

  close_positions.create!(order_id: order.id)
end
latest_close() click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/bitex_bot/models/closing_flow.rb, line 90
def latest_close
  close_positions.last
end
price_variation(closes_count) click to toggle source

next_price_and_quantity helpers

# File lib/bitex_bot/models/closing_flow.rb, line 135
def price_variation(closes_count)
  closes_count**2 * 0.03
end
sync_position(order_id) click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/bitex_bot/models/closing_flow.rb, line 127
def sync_position(order_id)
  latest = latest_close
  latest.amount, latest.quantity = Robot.taker.amount_and_quantity(order_id)
  latest.save!
end