1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-25 08:09:38 +02:00
Maybe/app/models/security/provided.rb
2025-03-28 17:34:29 -04:00

92 lines
2.7 KiB
Ruby

module Security::Provided
extend ActiveSupport::Concern
class_methods do
def provider
registry = Provider::Registry.for_concept(:securities)
registry.get_provider(:synth)
end
def search_provider(symbol, country_code: nil, exchange_operating_mic: nil)
return [] if symbol.blank? || symbol.length < 2
response = provider.search_securities(symbol, country_code: country_code, exchange_operating_mic: exchange_operating_mic)
if response.success?
response.data.map do |provider_security|
# Need to map to domain model so Combobox can display via to_combobox_option
Security.new(
ticker: provider_security.symbol,
name: provider_security.name,
logo_url: provider_security.logo_url,
exchange_operating_mic: provider_security.exchange_operating_mic,
)
end
else
[]
end
end
end
def sync_provider_prices(start_date:, end_date: Date.current)
unless has_prices?
Rails.logger.warn("Security id=#{id} ticker=#{ticker} is not known by provider, skipping price sync")
return 0
end
unless provider.present?
Rails.logger.warn("No security provider configured, cannot sync prices for id=#{id} ticker=#{ticker}")
return 0
end
response = provider.fetch_security_prices(self, start_date: start_date, end_date: end_date)
unless response.success?
Rails.logger.error("Provider error for sync_provider_prices with id=#{id} ticker=#{ticker}: #{response.error}")
return 0
end
fetched_prices = response.data.map do |price|
{
security_id: price.security.id,
date: price.date,
price: price.price,
currency: price.currency
}
end
valid_prices = fetched_prices.reject do |price|
is_invalid = price[:date].nil? || price[:price].nil? || price[:currency].nil?
if is_invalid
Rails.logger.warn("Invalid price data for security_id=#{id}: Missing required fields in price record: #{price.inspect}")
end
is_invalid
end
Security::Price.upsert_all(valid_prices, unique_by: %i[security_id date currency])
end
def find_or_fetch_price(date: Date.current, cache: true)
price = prices.find_by(date: date)
return price if price.present?
response = provider.fetch_security_price(self, date: date)
return nil unless response.success? # Provider error
price = response.data
Security::Price.find_or_create_by!(
security_id: price.security.id,
date: price.date,
price: price.price,
currency: price.currency
) if cache
price
end
private
def provider
self.class.provider
end
end