Files
sure/app/models/account/syncer.rb
Gian-Reto Tarnutzer ce5d7dd736 Add Interactive Brokers Provider (#1722)
* Display multi-currency holdings correctly

* Implement IBKR provider

* Fix: Use historical exchange rate for historical prices

* Add brokerage exchange rate for trades

* Sync historical balances from IBKR

* Add logos in activity history

* Fix privacy mode blur in account view

* Improve IBKR XML Flex report parser errors
2026-05-12 23:45:19 +02:00

51 lines
1.8 KiB
Ruby

class Account::Syncer
attr_reader :account
def initialize(account)
@account = account
end
def perform_sync(sync)
Rails.logger.info("Processing balances (#{account.linked? ? 'reverse' : 'forward'})")
import_market_data
materialize_balances(window_start_date: sync.window_start_date)
apply_provider_balance_overrides
end
def perform_post_sync
account.family.auto_match_transfers!
end
private
def materialize_balances(window_start_date: nil)
strategy = account.linked? ? :reverse : :forward
Balance::Materializer.new(account, strategy: strategy, window_start_date: window_start_date).materialize_balances
end
# Syncs all the exchange rates + security prices this account needs to display historical chart data
#
# This is a *supplemental* sync. The daily market data sync should have already populated
# a majority or all of this data, so this is often a no-op.
#
# We rescue errors here because if this operation fails, we don't want to fail the entire sync since
# we have reasonable fallbacks for missing market data.
def import_market_data
Account::MarketDataImporter.new(account).import_all
rescue => e
Rails.logger.error("Error syncing market data for account #{account.id}: #{e.message}")
Sentry.capture_exception(e)
end
def apply_provider_balance_overrides
return unless account.linked_to?("IbkrAccount")
ibkr_account = account.account_providers.find_by(provider_type: "IbkrAccount")&.provider
return unless ibkr_account
IbkrAccount::HistoricalBalancesSync.new(ibkr_account).sync!
rescue => e
Rails.logger.error("Error syncing IBKR historical balances for account #{account.id}: #{e.class} - #{e.message}")
Sentry.capture_exception(e)
end
end