mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-24 23:59:40 +02:00
* Rename MarketDataSyncer to MarketDataImporter * Materializers * Importers * More reference replacements
82 lines
2.2 KiB
Ruby
82 lines
2.2 KiB
Ruby
class Account::MarketDataImporter
|
||
attr_reader :account
|
||
|
||
def initialize(account)
|
||
@account = account
|
||
end
|
||
|
||
def import_all
|
||
import_exchange_rates
|
||
import_security_prices
|
||
end
|
||
|
||
def import_exchange_rates
|
||
return unless needs_exchange_rates?
|
||
return unless ExchangeRate.provider
|
||
|
||
pair_dates = {}
|
||
|
||
# 1. ENTRY-BASED PAIRS – currencies that differ from the account currency
|
||
account.entries
|
||
.where.not(currency: account.currency)
|
||
.group(:currency)
|
||
.minimum(:date)
|
||
.each do |source_currency, date|
|
||
key = [ source_currency, account.currency ]
|
||
pair_dates[key] = [ pair_dates[key], date ].compact.min
|
||
end
|
||
|
||
# 2. ACCOUNT-BASED PAIR – convert the account currency to the family currency (if different)
|
||
if foreign_account?
|
||
key = [ account.currency, account.family.currency ]
|
||
pair_dates[key] = [ pair_dates[key], account.start_date ].compact.min
|
||
end
|
||
|
||
pair_dates.each do |(source, target), start_date|
|
||
ExchangeRate.import_provider_rates(
|
||
from: source,
|
||
to: target,
|
||
start_date: start_date,
|
||
end_date: Date.current
|
||
)
|
||
end
|
||
end
|
||
|
||
def import_security_prices
|
||
return unless Security.provider
|
||
|
||
account_securities = account.trades.map(&:security).uniq
|
||
|
||
return if account_securities.empty?
|
||
|
||
account_securities.each do |security|
|
||
security.import_provider_prices(
|
||
start_date: first_required_price_date(security),
|
||
end_date: Date.current
|
||
)
|
||
|
||
security.import_provider_details
|
||
end
|
||
end
|
||
|
||
private
|
||
# Calculates the first date we require a price for the given security scoped to this account
|
||
def first_required_price_date(security)
|
||
account.trades.with_entry
|
||
.where(security: security)
|
||
.where(entries: { account_id: account.id })
|
||
.minimum("entries.date")
|
||
end
|
||
|
||
def needs_exchange_rates?
|
||
has_multi_currency_entries? || foreign_account?
|
||
end
|
||
|
||
def has_multi_currency_entries?
|
||
account.entries.where.not(currency: account.currency).exists?
|
||
end
|
||
|
||
def foreign_account?
|
||
account.currency != account.family.currency
|
||
end
|
||
end
|