// Copyright (C) 2024-2026 Whiterun LLC // // This software is licensed under the GNU Affero General Public License (AGPL), version 3.0 or later. // A copy of the license can be found in the LICENSE file or at https://www.gnu.org/licenses/agpl-3.0.html use anyhow::Result; use rust_decimal::Decimal; use super::poolperiod::PoolPeriod; pub struct APYAggregator; impl APYAggregator { pub fn aggregate_apy(pools: I, period_start: Option) -> Result where I: Iterator, { let mut weighted_apy_sum = Decimal::ZERO; let mut total_weight = Decimal::ZERO; for pool in pools { let days_active = pool.duration_days(&period_start)?; if !days_active.is_zero() { let (_pool_yield, apy) = pool.yield_and_apy(&period_start)?; // we give larger pools more weight in the aggregated apy. They have more liquidity, // so the aggregated number will be more accurate. let pool_size = pool.end_k_sqrt()?; let weighted_apy = apy * days_active * pool_size; weighted_apy_sum += weighted_apy; total_weight += days_active * pool_size; } } if total_weight.is_zero() { Ok(Decimal::ZERO) } else { Ok(weighted_apy_sum / total_weight) } } }