Files
sure/app/models/holding/portfolio_snapshot.rb
Anas Limouri a90f9b7317 Add CoinStats exchange portfolio sync and normalize linked investment charts (#1308)
* [FEATURE] Add CoinStats exchange portfolios and normalize linked investment charts

* [BUGFIX] Fix CoinStats PR regressions

* [BUGFIX] Fix CoinStats PR review findings

* [BUGFIX] Address follow-up CoinStats PR feedback

* [REFACTO] Extract CoinStats exchange account helpers

* [BUGFIX] Batch linked CoinStats chart normalization

* [BUGFIX] Fix CoinStats processor lint

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-04-01 20:25:06 +02:00

43 lines
1.2 KiB
Ruby

# Captures the most recent holding quantities for each security in an account's portfolio.
# Returns a portfolio hash compatible with the reverse calculator's format.
class Holding::PortfolioSnapshot
attr_reader :account
def initialize(account)
@account = account
end
# Returns a hash of {security_id => qty} representing today's starting portfolio.
# Includes all securities from trades (with 0 qty if no holdings exist).
def to_h
@portfolio ||= build_portfolio
end
private
def build_portfolio
# Start with all securities from trades initialized to 0
portfolio = account.trades
.pluck(:security_id)
.uniq
.each_with_object({}) { |security_id, hash| hash[security_id] = 0 }
latest_holdings_scope.each do |holding|
portfolio[holding.security_id] = holding.qty
end
portfolio
end
def latest_holdings_scope
if (provider_snapshot_date = account.latest_provider_holdings_snapshot_date)
account.holdings
.where.not(account_provider_id: nil)
.where(date: provider_snapshot_date)
else
account.holdings
.select("DISTINCT ON (security_id) holdings.*")
.order(:security_id, date: :desc)
end
end
end