lib/danconia/exchanges/exchange.rb in danconia-0.2.8 vs lib/danconia/exchanges/exchange.rb in danconia-0.2.9

- old
+ new

@@ -1,33 +1,47 @@ +require 'danconia/pair' + module Danconia module Exchanges class Exchange attr_reader :store def initialize store: Stores::InMemory.new @store = store end def rate from, to - if from == to - 1.0 - elsif from == 'USD' and direct_rate = @store.direct_rate(from, to) - direct_rate - elsif to == 'USD' and inverse_rate = @store.direct_rate(to, from) - (1.0 / inverse_rate).round 6 - elsif from != 'USD' and to != 'USD' and from_in_usd = rate(from, 'USD') and to_per_usd = rate('USD', to) - (from_in_usd * to_per_usd).round 6 - else - raise Errors::ExchangeRateNotFound.new(from, to) - end + return 1.0 if from == to + + pair = Pair.new(from, to) + rates = direct_and_inverted_rates() + rates[pair] or indirect_rate(pair, rates) or raise Errors::ExchangeRateNotFound.new(from, to) end def rates @store.rates end def update_rates! @store.save_rates fetch_rates + end + + private + + # Returns the original rates plus the inverted ones, to simplify rate finding logic. + def direct_and_inverted_rates + rates.each_with_object({}) do |(pair_str, rate), rs| + pair = Pair.parse(pair_str) + rs[pair] = rate + rs[pair.invert] ||= 1.0 / rate + end + end + + def indirect_rate ind_pair, rates + if (from_pair = rates.keys.detect { |(pair, rate)| pair.from == ind_pair.from }) && + (to_pair = rates.keys.detect { |(pair, rate)| pair.to == ind_pair.to }) + rates[from_pair] * rates[to_pair] + end end end end end