2024-10-21 15:13:16 +02:00
|
|
|
// Copyright (C) 2024 Riften Labs AS
|
|
|
|
|
//
|
|
|
|
|
// 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<I>(pools: I, period_start: Option<u64>) -> Result<Decimal>
|
|
|
|
|
where
|
|
|
|
|
I: Iterator<Item = PoolPeriod>,
|
|
|
|
|
{
|
|
|
|
|
let mut weighted_apy_sum = Decimal::ZERO;
|
2024-11-13 22:32:32 +01:00
|
|
|
let mut total_weight = Decimal::ZERO;
|
2024-10-21 15:13:16 +02:00
|
|
|
|
|
|
|
|
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)?;
|
2024-11-13 22:32:32 +01:00
|
|
|
|
|
|
|
|
// 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;
|
2024-10-21 15:13:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-13 22:32:32 +01:00
|
|
|
if total_weight.is_zero() {
|
2024-10-21 15:13:16 +02:00
|
|
|
Ok(Decimal::ZERO)
|
|
|
|
|
} else {
|
2024-11-13 22:32:32 +01:00
|
|
|
Ok(weighted_apy_sum / total_weight)
|
2024-10-21 15:13:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|