Class: BitexBot::OpeningFlow

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
lib/bitex_bot/models/opening_flow.rb

Overview

Any arbitrage workflow has 2 stages, opening positions and then closing them. The OpeningFlow stage places an order on bitex, detecting and storing all transactions spawn from that order as Open positions.

Direct Known Subclasses

BuyOpeningFlow, SellOpeningFlow

Statuses collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.activeObject



11
12
13
# File 'lib/bitex_bot/models/opening_flow.rb', line 11

def self.active
  where('status != "finalised"')
end

.create_for_market(remote_balance, order_book, transactions, bitex_fee, other_fee, store) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/bitex_bot/models/opening_flow.rb', line 43

def self.create_for_market(remote_balance, order_book, transactions,
  bitex_fee, other_fee, store)

  self.store = store

  plus_bitex = value_to_use + (value_to_use * bitex_fee / 100.0)
  value_to_use_needed = plus_bitex / (1 - other_fee / 100.0)
  
  safest_price = get_safest_price(transactions, order_book,
    value_to_use_needed)

  remote_value_to_use = get_remote_value_to_use(value_to_use_needed, safest_price)
  
  if remote_value_to_use > remote_balance
    raise CannotCreateFlow.new(
      "Needed #{remote_value_to_use} but you only have #{remote_balance}")
  end

  bitex_price = get_bitex_price(value_to_use, remote_value_to_use)      

  begin 
    order = order_class.create!(:btc, value_to_use, bitex_price, true)
  rescue StandardError => e
    raise CannotCreateFlow.new(e.message)
  end

  if order.reason == :not_enough_funds
    raise CannotCreateFlow.new(
      "You need to have #{value_to_use} on bitex to place this
      #{order_class.name}.")
  end

  Robot.logger.info("Opening: Placed #{order_class.name} ##{order.id} " \
    "#{value_to_use} @ $#{bitex_price} (#{remote_value_to_use})")

  begin 
    self.create!(price: bitex_price, value_to_use: value_to_use,
      suggested_closing_price: safest_price, status: 'executing', order_id: order.id)
  rescue StandardError => e
    raise CannotCreateFlow.new(e.message)
  end
end

.old_activeObject



15
16
17
18
# File 'lib/bitex_bot/models/opening_flow.rb', line 15

def self.old_active
  where('status != "finalised" AND created_at < ?',
    Settings.time_to_live.seconds.ago)
end

.statusesArray<String>

All possible flow statuses

Returns:

  • (Array<String>)


24
25
26
# File 'lib/bitex_bot/models/opening_flow.rb', line 24

def self.statuses
  %w(executing settling finalised)
end

.sync_open_positionsObject

Buys on bitex represent open positions, we mirror them locally so that we can plan on how to close them.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/bitex_bot/models/opening_flow.rb', line 88

def self.sync_open_positions
  threshold = open_position_class
    .order('created_at DESC').first.try(:created_at)
  Bitex::Trade.all.collect do |transaction|
    next unless transaction.is_a?(transaction_class)
    next if threshold && transaction.created_at < (threshold - 30.minutes)
    next if open_position_class.find_by_transaction_id(transaction.id)
    next if transaction.specie != :btc
    next unless flow = find_by_order_id(transaction_order_id(transaction))
    Robot.logger.info("Opening: #{name} ##{flow.id} "\
      "was hit for #{transaction.quantity} BTC @ $#{transaction.price}")
    open_position_class.create!(
      transaction_id: transaction.id,
      price: transaction.price,
      amount: transaction.amount,
      quantity: transaction.quantity,
      opening_flow: flow)
  end.compact
end

Instance Method Details

#executing?Boolean

The Bitex order has been placed, its id stored as order_id.

Returns:

  • (Boolean)


29
# File 'lib/bitex_bot/models/opening_flow.rb', line 29

def executing?; status == 'executing'; end

#finalise!Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/bitex_bot/models/opening_flow.rb', line 108

def finalise!
  order = self.class.order_class.find(order_id)
  if order.status == :cancelled || order.status == :completed
    Robot.logger.info(
      "Opening: #{self.class.order_class.name} ##{order_id} finalised.")
    self.status = 'finalised'
    save!
  else
    order.cancel!
    unless settling?
      self.status = 'settling'
      save!
    end
  end
end

#finalised?Boolean

Successfully settled or finished executing.

Returns:

  • (Boolean)


36
# File 'lib/bitex_bot/models/opening_flow.rb', line 36

def finalised?; status == 'finalised'; end

#settling?Boolean

In process of cancelling the Bitex order and any other outstanding order in the other exchange.

Returns:

  • (Boolean)


33
# File 'lib/bitex_bot/models/opening_flow.rb', line 33

def settling?; status == 'settling'; end