rex/lib/rex/book/limit_order_book.rb

92 lines
1.9 KiB
Ruby

require "rbtree"
module Rex
module Book
class LimitOrderBook
def initialize(matcher: Matcher.new)
@matcher = matcher
@sell_side = RBTree.new
@buy_side = RBTree.new
@order_ids = {} # order_id => order
@current_order_id = 0
end
def add_order(order)
side = side_for_order(order)
order.id = next_order_id
side[order.price] ||= Limit.new(order.price)
side[order.price].add_order(order)
order_ids[order.id] = order
end
def add_and_match_order(order)
add_order(order)
@matcher.match(self)
end
def remove_order(order_id)
order = order_ids[order_id]
return nil if order.nil?
side = side_for_order(order)
limit = side[order.price]
limit.remove_order(order)
if limit.empty?
side.delete(limit.price)
end
order_ids.delete(order.id)
end
alias_method :cancel_order, :remove_order
def process_trade(trade)
trade.buy_order.remaining_quantity -= trade.quantity
trade.sell_order.remaining_quantity -= trade.quantity
remove_order(trade.buy_order.id) if trade.buy_order.filled?
remove_order(trade.sell_order.id) if trade.sell_order.filled?
end
def highest_buy_order
buy_side.last&.[](1)&.peek_first_order
end
def lowest_sell_order
sell_side.first&.[](1)&.peek_first_order
end
def best_buy_price
buy_side.last&.[](0)
end
def best_sell_price
sell_side.first&.[](0)
end
private
attr_reader(
:order_ids,
:buy_side,
:sell_side
)
def next_order_id
@current_order_id += 1
end
def side_for_order(order)
if order.is_buy
buy_side
else
sell_side
end
end
end
end
end