88 lines
2.7 KiB
Ruby
88 lines
2.7 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require_relative "helper"
|
||
|
|
require "weighted_average"
|
||
|
|
|
||
|
|
describe WeightedAverage do
|
||
|
|
let(:date) { Date.parse("2024-01-15") }
|
||
|
|
|
||
|
|
it "averages rates from multiple providers" do
|
||
|
|
rates = [
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.10, provider: "BOC" },
|
||
|
|
]
|
||
|
|
|
||
|
|
result = WeightedAverage.new(rates).calculate
|
||
|
|
usd = result.find { |r| r[:quote] == "USD" }
|
||
|
|
|
||
|
|
_(usd[:rate]).must_be_close_to((1.08 + 1.10) / 2.0)
|
||
|
|
end
|
||
|
|
|
||
|
|
it "weights rates equally within the grace period" do
|
||
|
|
rates = [
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
|
||
|
|
{ date: date - 1, base: "EUR", quote: "USD", rate: 1.10, provider: "BOC" },
|
||
|
|
]
|
||
|
|
|
||
|
|
result = WeightedAverage.new(rates).calculate
|
||
|
|
usd = result.find { |r| r[:quote] == "USD" }
|
||
|
|
|
||
|
|
_(usd[:rate]).must_be_close_to((1.08 + 1.10) / 2.0)
|
||
|
|
end
|
||
|
|
|
||
|
|
it "picks the most recent date" do
|
||
|
|
rates = [
|
||
|
|
{ date: date - 1, base: "EUR", quote: "USD", rate: 1.10, provider: "BOC" },
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
|
||
|
|
]
|
||
|
|
|
||
|
|
result = WeightedAverage.new(rates).calculate
|
||
|
|
usd = result.find { |r| r[:quote] == "USD" }
|
||
|
|
|
||
|
|
_(usd[:date]).must_equal(date)
|
||
|
|
end
|
||
|
|
|
||
|
|
it "discounts stale rates beyond the grace period" do
|
||
|
|
rates = [
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
|
||
|
|
{ date: date - 7, base: "EUR", quote: "USD", rate: 1.20, provider: "BOC" },
|
||
|
|
]
|
||
|
|
|
||
|
|
result = WeightedAverage.new(rates).calculate
|
||
|
|
usd = result.find { |r| r[:quote] == "USD" }
|
||
|
|
|
||
|
|
_(usd[:rate]).must_be_close_to(1.08, 0.02)
|
||
|
|
end
|
||
|
|
|
||
|
|
it "exposes contributing providers with their individual rates, sorted by key" do
|
||
|
|
rates = [
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.10, provider: "BOC" },
|
||
|
|
]
|
||
|
|
|
||
|
|
result = WeightedAverage.new(rates).calculate
|
||
|
|
usd = result.find { |r| r[:quote] == "USD" }
|
||
|
|
|
||
|
|
_(usd[:providers]).must_equal([
|
||
|
|
{ key: "BOC", rate: 1.10 },
|
||
|
|
{ key: "ECB", rate: 1.08 },
|
||
|
|
])
|
||
|
|
end
|
||
|
|
|
||
|
|
it "picks the most recent rate per provider when a provider contributes multiple dates" do
|
||
|
|
rates = [
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.08, provider: "ECB" },
|
||
|
|
{ date: date, base: "EUR", quote: "USD", rate: 1.10, provider: "BOC" },
|
||
|
|
{ date: date - 1, base: "EUR", quote: "USD", rate: 1.09, provider: "BOC" },
|
||
|
|
]
|
||
|
|
|
||
|
|
result = WeightedAverage.new(rates).calculate
|
||
|
|
usd = result.find { |r| r[:quote] == "USD" }
|
||
|
|
|
||
|
|
_(usd[:providers]).must_equal([
|
||
|
|
{ key: "BOC", rate: 1.10 },
|
||
|
|
{ key: "ECB", rate: 1.08 },
|
||
|
|
])
|
||
|
|
end
|
||
|
|
end
|