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