Class: BitexBot::OpeningFlow
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- BitexBot::OpeningFlow
- 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
Statuses collapse
- .active ⇒ Object
- .old_active ⇒ Object
-
#statuses ⇒ Array<String>
All possible flow statuses.
Class Method Summary collapse
-
.active_transaction?(transaction, threshold) ⇒ Boolean
sought_transaction helpers.
-
.calc_remote_value(maker_fee, taker_fee, order_book, transactions) ⇒ Object
create_for_market helpers.
-
.create_for_market(remote_balance, order_book, transactions, maker_fee, taker_fee, store) ⇒ Object
This use hooks methods, these must be defined in the subclass: #maker_price #order_class #remote_value_to_use #safest_price #value_to_use rubocop:disable Metrics/AbcSize.
-
.create_open_position!(transaction, flow) ⇒ Object
sync_open_positions helpers.
- .create_order!(bitex_price) ⇒ Object
- .enough_funds?(order) ⇒ Boolean
- .enough_remote_funds?(remote_balance, remote_value) ⇒ Boolean
- .expected_order_book?(transaction) ⇒ Boolean
- .maker_plus(fee) ⇒ Object
- .open_position?(transaction) ⇒ Boolean
-
.sought_transaction?(threshold, transaction) ⇒ Boolean
This use hooks methods, these must be defined in the subclass: #transaction_class.
-
.sync_open_positions ⇒ Object
Buys on bitex represent open positions, we mirror them locally so that we can plan on how to close them.
Instance Method Summary collapse
Class Method Details
.active ⇒ Object
16 17 18 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 16 def self.active where.not(status: :finalised) end |
.active_transaction?(transaction, threshold) ⇒ Boolean
sought_transaction helpers
133 134 135 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 133 def self.active_transaction?(transaction, threshold) threshold.present? && transaction.created_at < (threshold - 30.minutes) end |
.calc_remote_value(maker_fee, taker_fee, order_book, transactions) ⇒ Object
create_for_market helpers
63 64 65 66 67 68 69 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 63 def self.calc_remote_value(maker_fee, taker_fee, order_book, transactions) value_to_use_needed = (value_to_use + maker_plus(maker_fee)) / (1 - taker_fee / 100) safest_price = safest_price(transactions, order_book, value_to_use_needed) remote_value = remote_value_to_use(value_to_use_needed, safest_price) [remote_value, safest_price] end |
.create_for_market(remote_balance, order_book, transactions, maker_fee, taker_fee, store) ⇒ Object
This use hooks methods, these must be defined in the subclass:
#maker_price
#order_class
#remote_value_to_use
#safest_price
#value_to_use
rubocop:disable Metrics/AbcSize
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 32 def self.create_for_market(remote_balance, order_book, transactions, maker_fee, taker_fee, store) self.store = store remote_value, safest_price = calc_remote_value(maker_fee, taker_fee, order_book, transactions) raise CannotCreateFlow, "Needed #{remote_value} but you only have #{remote_balance}" unless enough_remote_funds?(remote_balance, remote_value) bitex_price = maker_price(remote_value) order = create_order!(bitex_price) raise CannotCreateFlow, "You need to have #{value_to_use} on bitex to place this #{order_class.name}." unless enough_funds?(order) Robot.log( :info, "Opening: Placed #{order_class.name} ##{order.id} #{value_to_use} @ #{Settings.quote.upcase} #{bitex_price}"\ " (#{remote_value})" ) 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, e. end |
.create_open_position!(transaction, flow) ⇒ Object
sync_open_positions helpers
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 107 def self.create_open_position!(transaction, flow) Robot.log( :info, "Opening: #{name} ##{flow.id} was hit for #{transaction.quantity} #{Settings.base.upcase} @ #{Settings.quote.upcase}"\ " #{transaction.price}" ) open_position_class.create!( transaction_id: transaction.id, price: transaction.price, amount: transaction.amount, quantity: transaction.quantity, opening_flow: flow ) end |
.create_order!(bitex_price) ⇒ Object
71 72 73 74 75 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 71 def self.create_order!(bitex_price) order_class.create!(Settings.maker_settings.order_book, value_to_use, bitex_price, true) rescue StandardError => e raise CannotCreateFlow, e. end |
.enough_funds?(order) ⇒ Boolean
77 78 79 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 77 def self.enough_funds?(order) !order.reason.to_s.inquiry.not_enough_funds? end |
.enough_remote_funds?(remote_balance, remote_value) ⇒ Boolean
81 82 83 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 81 def self.enough_remote_funds?(remote_balance, remote_value) remote_balance >= remote_value end |
.expected_order_book?(transaction) ⇒ Boolean
141 142 143 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 141 def self.expected_order_book?(transaction) transaction.order_book == Settings.maker_settings.order_book end |
.maker_plus(fee) ⇒ Object
85 86 87 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 85 def self.maker_plus(fee) value_to_use * fee / 100 end |
.old_active ⇒ Object
20 21 22 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 20 def self.old_active active.where('created_at < ?', Settings.time_to_live.seconds.ago) end |
.open_position?(transaction) ⇒ Boolean
137 138 139 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 137 def self.open_position?(transaction) open_position_class.find_by_transaction_id(transaction.id) end |
.sought_transaction?(threshold, transaction) ⇒ Boolean
This use hooks methods, these must be defined in the subclass:
#transaction_class
124 125 126 127 128 129 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 124 def self.sought_transaction?(threshold, transaction) transaction.is_a?(transaction_class) && !active_transaction?(transaction, threshold) && !open_position?(transaction) && expected_order_book?(transaction) end |
.sync_open_positions ⇒ Object
Buys on bitex represent open positions, we mirror them locally so that we can plan on how to close them. This use hooks methods, these must be defined in the subclass:
#transaction_order_id(transaction)
#open_position_class
94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 94 def self.sync_open_positions threshold = open_position_class.order('created_at DESC').first.try(:created_at) Bitex::Trade.all.map do |transaction| next unless sought_transaction?(threshold, transaction) flow = find_by_order_id(transaction_order_id(transaction)) next unless flow.present? create_open_position!(transaction, flow) end.compact end |
Instance Method Details
#finalise! ⇒ Object
159 160 161 162 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 159 def finalise! order = self.class.order_class.find(order_id) canceled_or_completed?(order) ? do_finalize : do_cancel(order) end |
#statuses ⇒ Array<String>
All possible flow statuses
14 |
# File 'lib/bitex_bot/models/opening_flow.rb', line 14 cattr_accessor(:statuses) { %w[executing settling finalised] } |