class Devilicious::OrderBook

Attributes

asks[R]
bids[R]
market[RW]

Public Class Methods

new(hash) click to toggle source
# File lib/devilicious/order_book.rb, line 6
def initialize(hash)
  @asks = hash.delete(:asks).sort_by(&:price).freeze # buy
  @bids = hash.delete(:bids).sort_by(&:price).freeze # sell

  raise ArgumentError unless hash.empty?
end

Public Instance Methods

highest_bid() click to toggle source
# File lib/devilicious/order_book.rb, line 13
def highest_bid
  bids.last
end
lowest_ask() click to toggle source
# File lib/devilicious/order_book.rb, line 17
def lowest_ask
  asks.first
end
max_bid_price_for_volume(min_price, max_volume) click to toggle source
# File lib/devilicious/order_book.rb, line 34
def max_bid_price_for_volume(min_price, max_volume)
  interesting_bids = interesting_offers(bids, ->(price) { price >= min_price }).reverse # reverse to start from most expensive
  best_offer_price_for_volume(interesting_bids, max_volume)
end
min_ask_price_for_volume(max_price, max_volume) click to toggle source
# File lib/devilicious/order_book.rb, line 29
def min_ask_price_for_volume(max_price, max_volume)
  interesting_asks = interesting_offers(asks, ->(price) { price <= max_price })
  best_offer_price_for_volume(interesting_asks, max_volume)
end
weighted_asks_up_to(max_price) click to toggle source
# File lib/devilicious/order_book.rb, line 21
def weighted_asks_up_to(max_price)
  weighted_offers(asks, ->(price) { price <= max_price })
end
weighted_bids_down_to(min_price) click to toggle source
# File lib/devilicious/order_book.rb, line 25
def weighted_bids_down_to(min_price)
  weighted_offers(bids, ->(price) { price >= min_price })
end

Private Instance Methods

best_offer_price_for_volume(offers, max_volume) click to toggle source
# File lib/devilicious/order_book.rb, line 58
def best_offer_price_for_volume(offers, max_volume)
  total_volume = 0
  good_offers = []

  offers.each do |offer|
    if total_volume <= max_volume
      good_offers << offer.dup # NOTE: dup because we're gonna mess with its volume below
      total_volume += offer.volume
    end
  end

  if total_volume > max_volume
    substract_volume = total_volume - max_volume
    good_offers.last.volume -= substract_volume
    total_volume -= substract_volume
  end

  total_weight_price = good_offers.map { |offer| offer.price * offer.volume }.inject(:+) || 0
  weighted_price = total_weight_price / total_volume

  Offer.new(
    price: good_offers.last.price,
    volume: total_volume,
    weighted_price: weighted_price,
  )
end
currency() click to toggle source
# File lib/devilicious/order_book.rb, line 85
def currency
  lowest_ask.price.currency
end
interesting_offers(offers, condition) click to toggle source
# File lib/devilicious/order_book.rb, line 41
def interesting_offers(offers, condition)
  offers.select { |offer| condition.call(offer.price) }
end
weighted_offers(offers, condition) click to toggle source
# File lib/devilicious/order_book.rb, line 45
def weighted_offers(offers, condition)
  interesting_offers = interesting_offers(offers, condition)

  total_volume = interesting_offers.map(&:volume).inject(:+) || 0
  total_weight_price = interesting_offers.map { |offer| offer.price * offer.volume }.inject(:+) || 0
  weighted_price = total_weight_price / total_volume

  Offer.new(
    price: Money.new(weighted_price, currency),
    volume: total_volume
  )
end