mirror of
https://github.com/we-promise/sure.git
synced 2026-04-18 19:44:09 +00:00
* [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>
87 lines
2.4 KiB
Ruby
87 lines
2.4 KiB
Ruby
class Balance::SeriesAggregator
|
|
attr_reader :series_list, :favorable_direction, :currency, :align_to_common_start
|
|
|
|
def initialize(series_list:, currency:, favorable_direction:, align_to_common_start: false)
|
|
@series_list = Array(series_list).compact
|
|
@currency = currency
|
|
@favorable_direction = favorable_direction
|
|
@align_to_common_start = align_to_common_start
|
|
end
|
|
|
|
def aggregate
|
|
return empty_series if normalized_series_list.empty?
|
|
|
|
values_by_date = normalized_series_list.each_with_object(Hash.new { |hash, key| hash[key] = [] }) do |series, hash|
|
|
series.values.each do |value|
|
|
hash[value.date] << value
|
|
end
|
|
end
|
|
|
|
dates = values_by_date.keys.sort
|
|
return empty_series if dates.empty?
|
|
|
|
previous_value = nil
|
|
values = dates.map do |date|
|
|
current_value = Money.new(
|
|
values_by_date[date].sum { |value| value.value.amount },
|
|
currency
|
|
)
|
|
|
|
series_value = Series::Value.new(
|
|
date: date,
|
|
date_formatted: I18n.l(date, format: :long),
|
|
value: current_value,
|
|
trend: Trend.new(
|
|
current: current_value,
|
|
previous: previous_value,
|
|
favorable_direction: favorable_direction
|
|
)
|
|
)
|
|
|
|
previous_value = current_value
|
|
series_value
|
|
end
|
|
|
|
Series.new(
|
|
start_date: values.first.date,
|
|
end_date: values.last.date,
|
|
interval: normalized_series_list.first.interval,
|
|
values: values,
|
|
favorable_direction: favorable_direction
|
|
)
|
|
end
|
|
|
|
private
|
|
def normalized_series_list
|
|
@normalized_series_list ||= begin
|
|
return series_list unless align_to_common_start
|
|
|
|
common_start_date = series_list.map(&:start_date).compact.max
|
|
return series_list if common_start_date.blank?
|
|
|
|
series_list.filter_map do |series|
|
|
trimmed_values = series.values.select { |value| value.date >= common_start_date }
|
|
next if trimmed_values.blank?
|
|
|
|
Series.new(
|
|
start_date: trimmed_values.first.date,
|
|
end_date: trimmed_values.last.date,
|
|
interval: series.interval,
|
|
values: trimmed_values,
|
|
favorable_direction: series.favorable_direction
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
def empty_series
|
|
Series.new(
|
|
start_date: Date.current,
|
|
end_date: Date.current,
|
|
interval: "1 day",
|
|
values: [],
|
|
favorable_direction: favorable_direction
|
|
)
|
|
end
|
|
end
|