mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-19 05:09:38 +02:00
Use Synth for exchange rates (#514)
* Switch currency seeding over to Synth * Switch all exchange rates over to Synth
This commit is contained in:
parent
0f2c41477d
commit
4843cf22c6
4 changed files with 29 additions and 84 deletions
|
@ -6,8 +6,8 @@ HOSTED=false
|
|||
APP_DOMAIN=
|
||||
|
||||
# Exchange Rate API
|
||||
# This is used to convert between different currencies in the app. We're currently using Open Exchange Rates (openexchangerates.org) to sync exchange rate data and, at the moment, that requies a $12/mo subscription. This is NOT required to run Maybe with one currency, but it is required to sync exchange rate data if you need multiple currencies. In the future we'll be adding support for other exchange rate APIs that are cheaper/free.
|
||||
OPEN_EXCHANGE_APP_ID=
|
||||
# This is used to convert between different currencies in the app. We use Synth, which is a Maybe product. You can sign up for a free account at synthfinance.com.
|
||||
SYNTH_API_KEY=
|
||||
|
||||
# Currency Configuration
|
||||
# A list of currencies that you want to support. This is used to generate the list of currencies that users can select from when creating a new account.
|
||||
|
|
|
@ -2,8 +2,6 @@ class DailyExchangeRateJob < ApplicationJob
|
|||
queue_as :default
|
||||
|
||||
def perform
|
||||
app_id = ENV["OPEN_EXCHANGE_APP_ID"]
|
||||
|
||||
# Get the last date for which exchange rates were fetched for each currency
|
||||
last_fetched_dates = ExchangeRate.group(:base_currency).maximum(:date)
|
||||
|
||||
|
@ -11,10 +9,12 @@ class DailyExchangeRateJob < ApplicationJob
|
|||
Currency.all.each do |currency|
|
||||
last_fetched_date = last_fetched_dates[currency.iso_code] || Date.yesterday
|
||||
next_day = last_fetched_date + 1.day
|
||||
response = Faraday.get("https://openexchangerates.org/api/historical/#{next_day}.json") do |req|
|
||||
req.params["app_id"] = app_id
|
||||
req.params["base"] = currency.iso_code
|
||||
req.params["symbols"] = Currency.where.not(iso_code: currency.iso_code).pluck(:iso_code).join(",")
|
||||
|
||||
response = Faraday.get("https://api.synthfinance.com/rates/historical") do |req|
|
||||
req.headers["Authorization"] = "Bearer #{ENV["SYNTH_API_KEY"]}"
|
||||
req.params["date"] = next_day.to_s
|
||||
req.params["from"] = currency.iso_code
|
||||
req.params["to"] = Currency.where.not(iso_code: currency.iso_code).pluck(:iso_code).join(",")
|
||||
end
|
||||
|
||||
if response.success?
|
||||
|
|
|
@ -3,18 +3,18 @@ namespace :currencies do
|
|||
task seed: :environment do
|
||||
currencies = ENV["CURRENCIES"].split(",")
|
||||
|
||||
if currencies.count > 1 && ENV["OPEN_EXCHANGE_APP_ID"].present?
|
||||
url = "https://openexchangerates.org/api/currencies.json"
|
||||
if currencies.count > 1 && ENV["SYNTH_API_KEY"].present?
|
||||
url = "https://api.synthfinance.com/currencies"
|
||||
|
||||
response = Faraday.get(url) do |req|
|
||||
req.params["app_id"] = ENV["OPEN_EXCHANGE_APP_ID"]
|
||||
req.headers["Authorization"] = "Bearer #{ENV["SYNTH_API_KEY"]}"
|
||||
end
|
||||
|
||||
oxr_currencies = JSON.parse(response.body)
|
||||
synth_currencies = JSON.parse(response.body)
|
||||
|
||||
currencies.each do |iso_code|
|
||||
Currency.find_or_create_by(iso_code: iso_code) do |c|
|
||||
c.name = oxr_currencies[iso_code]
|
||||
c.name = synth_currencies["data"].find { |currency| currency["iso_code"] == iso_code.downcase }["name"]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,81 +1,26 @@
|
|||
namespace :exchange_rates do
|
||||
desc "Fetch exchange rates from openexchangerates.org"
|
||||
desc "Fetch exchange rates from Synth API"
|
||||
task sync: :environment do
|
||||
app_id = ENV["OPEN_EXCHANGE_APP_ID"]
|
||||
MININUM_DATE_RANGE = 30.days
|
||||
MAXIMUM_DATE_RANGE = 120.days
|
||||
|
||||
# First, check what plan the user is on at OXR
|
||||
# If the user is on the Developer plan, we can only fetch exchange rates for the past 30 days and must use the historical endpoint
|
||||
account_check = Faraday.get("https://openexchangerates.org/api/usage.json") do |req|
|
||||
req.params["app_id"] = app_id
|
||||
end
|
||||
account_details = JSON.parse(account_check.body)
|
||||
quota_limit = account_details["data"]["usage"]["requests_quota"]
|
||||
|
||||
if quota_limit <= 10000
|
||||
# First loop through all Currency records and fetch exchange rates for each, but use the historical endpoint, which only allows fetching one day at a time. For each currency, set the base currency to the currency's iso_code and the symbols to all other currencies' iso_codes
|
||||
Currency.all.each do |currency|
|
||||
(Date.today - MININUM_DATE_RANGE).upto(Date.today) do |date|
|
||||
response = Faraday.get("https://openexchangerates.org/api/historical/#{date}.json") do |req|
|
||||
req.params["app_id"] = app_id
|
||||
req.params["base"] = currency.iso_code
|
||||
req.params["symbols"] = Currency.where.not(iso_code: currency.iso_code).pluck(:iso_code).join(",")
|
||||
end
|
||||
|
||||
if response.success?
|
||||
rates = JSON.parse(response.body)["rates"]
|
||||
|
||||
rates.each do |currency_iso_code, value|
|
||||
ExchangeRate.find_or_create_by(date: date, base_currency: currency.iso_code, converted_currency: currency_iso_code) do |exchange_rate|
|
||||
exchange_rate.rate = value
|
||||
end
|
||||
puts "#{currency.iso_code} to #{currency_iso_code} on #{date}: #{value}"
|
||||
end
|
||||
else
|
||||
puts "Failed to fetch exchange rates for #{currency.iso_code} on #{date}: #{response.status}"
|
||||
end
|
||||
Currency.all.each do |currency|
|
||||
(Date.today - 30.days).upto(Date.today) do |date|
|
||||
response = Faraday.get("https://api.synthfinance.com/rates/historical") do |req|
|
||||
req.headers["Authorization"] = "Bearer #{ENV["SYNTH_API_KEY"]}"
|
||||
req.params["date"] = date.to_s
|
||||
req.params["from"] = currency.iso_code
|
||||
req.params["to"] = Currency.where.not(iso_code: currency.iso_code).pluck(:iso_code).join(",")
|
||||
end
|
||||
end
|
||||
else
|
||||
# Use Faraday to make a request openexchangerates.org time series endpoint
|
||||
# Use the response to create or update exchange rates in the database
|
||||
url = "https://openexchangerates.org/api/time-series.json"
|
||||
start_date = (Date.today - MAXIMUM_DATE_RANGE).to_s
|
||||
end_date = Date.today.to_s
|
||||
|
||||
# Loop through all Currency records and fetch exchange rates for each
|
||||
Currency.all.each do |currency|
|
||||
start_period = Date.parse(start_date)
|
||||
end_period = Date.parse(end_date)
|
||||
if response.success?
|
||||
rates = JSON.parse(response.body)["data"]["rates"]
|
||||
|
||||
while start_period < end_period
|
||||
current_end_date = [ start_period + 30.days, end_period ].min
|
||||
|
||||
response = Faraday.get(url) do |req|
|
||||
req.params["app_id"] = app_id
|
||||
req.params["start"] = start_period.to_s
|
||||
req.params["end"] = current_end_date.to_s
|
||||
req.params["base"] = currency.iso_code
|
||||
req.params["symbols"] = Currency.where.not(iso_code: currency.iso_code).pluck(:iso_code).join(",")
|
||||
end
|
||||
|
||||
if response.success?
|
||||
rates = JSON.parse(response.body)["rates"]
|
||||
|
||||
rates.each do |date, rate|
|
||||
rate.each do |currency_iso_code, value|
|
||||
ExchangeRate.find_or_create_by(date: date, base_currency: currency.iso_code, converted_currency: currency_iso_code) do |exchange_rate|
|
||||
exchange_rate.rate = value
|
||||
end
|
||||
puts "#{currency.iso_code} to #{currency_iso_code} on #{date}: #{value}"
|
||||
end
|
||||
rates.each do |currency_iso_code, value|
|
||||
ExchangeRate.find_or_create_by(date: date, base_currency: currency.iso_code, converted_currency: currency_iso_code) do |exchange_rate|
|
||||
exchange_rate.rate = value
|
||||
end
|
||||
else
|
||||
puts "Failed to fetch exchange rates for period #{start_period} to #{current_end_date}: #{response.status}"
|
||||
puts "#{currency.iso_code} to #{currency_iso_code} on #{date}: #{value}"
|
||||
end
|
||||
|
||||
start_period = current_end_date + 1.day
|
||||
else
|
||||
puts "Failed to fetch exchange rates for #{currency.iso_code} on #{date}: #{response.status}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue