R/impermanent_loss.R

Defines functions impermanent_loss

Documented in impermanent_loss

utils::globalVariables(c("Scenario", "Value"))

#' Impermanent Loss Calculator for Weighted AMM Pools
#'
#' Calculates the Nominal Impermanent Loss (IL), Percentage IL, and Net Profit and Loss (PnL)
#' for a liquidity position in a weighted Automated Market Maker (AMM) pool.
#' This function is crucial for assessing the performance of liquidity provider positions
#' in protocols like Balancer and Uniswap.
#' @param prices_old A numeric vector of initial prices for each asset.
#' @param prices_new A numeric vector of new prices for each asset.
#' @param weights A numeric vector of weights (must sum to 1) corresponding to the assets.
#' @param investment The initial total dollar value invested in the pool.
#' @param fees The total dollar value of trading fees earned by the LP during the period.
#' @param plot A logical value. If TRUE, generates a bar chart comparing the value if held,
#'   value in the pool, and the net value (pool + fees).
#' @return A list containing the core metrics:
#'   \itemize{
#'     \item \code{Value if held}: Total current value if assets were held outside the pool.
#'     \item \code{Value in pool}: Total current value of the tokens in the pool.
#'     \item \code{impermanent_loss_percent}: The IL as a percentage of the held portfolio value.
#'     \item \code{Nominal impermanent loss}: The IL as a dollar-value opportunity loss.
#'     \item \code{Fee offset ($)}: The total dollar fees earned.
#'     \item \code{Net gain}: The LP's net PnL (Fees MINUS Nominal IL) relative to holding.
#'   }
#' @references Tiruviluamala, N., Port, A., & Lewis, E. (2022). A general framework for impermanent loss in automated market makers. arXiv preprint arXiv:2203.11352.
#' @import ggplot2
#' @examples
#' library(impermanentlosscalc)
#' library(ggplot2)
#' # Example 1: 3-Asset Unbalanced Pool (Weights: 30/20/50)
#' impermanent_loss(
#' prices_old = c(10, 20, 40),
#' prices_new = c(9, 22, 35),
#' weights = c(0.3, 0.2, 0.5),
#' investment = 1000,
#' fees = 10,
#' plot = TRUE
#' )
#'
#'
#' # Example 2: No price change, demonstrating IL is zero.
#' impermanent_loss(
#'   prices_old = c(3, 3),
#'   prices_new = c(3, 3),
#'   weights = c(0.5, 0.5),
#'   investment = 500,
#'   fees = 0
#' )
#' @export


impermanent_loss <- function(
    prices_old,
    prices_new,
    weights,
    investment,
    fees,
    plot = FALSE){

  # Check inputs
  if(length(prices_old) != length(prices_new) ||
     length(prices_old) != length(weights)){stop(
       "Old Prices, New Prices, and Weights must be equal length"
     )}

  if(abs(sum(weights) - 1) > 1e-6){stop("Weights must sum to 1")}

  #Relative price changes
  r <- prices_new/prices_old


  #Weighted geometric mean
  geom_mean <- prod(r ^ weights)

  #Weighted arithmetic mean
  arithmetic_mean <- sum(weights * r)

  #Value if held outside pool
  value_if_held <- investment * arithmetic_mean

  #Impermanent loss factor
  impermanent_loss_factor <- geom_mean/arithmetic_mean

  #Value in pool
  value_in_pool <- value_if_held * impermanent_loss_factor

  #Nominal impermanent loss
  nominal_impermanent_loss <- value_if_held - value_in_pool

  #Percent impermanent loss
  impermanent_loss_percent <- nominal_impermanent_loss / value_if_held

  #Net Impermanent Loss
  net_gain <- fees - nominal_impermanent_loss

  #Net value adjusted for fees
  net_value <- value_in_pool + fees

  if(plot){
    # Inside the if(plot) block:
    plot_data <- data.frame(
      Scenario = c("Held","Pool","Pool + Fees"),
      Value = c(value_if_held, value_in_pool, net_value)
    )
    graph <- ggplot2::ggplot(data = plot_data, aes(x = Scenario,
                                                   y = Value, fill = Scenario))+
      ggplot2::geom_bar(stat = "identity")+
      ggplot2::labs(title = "Holding vs Lending")+
      ggplot2::theme(plot.title = ggplot2::element_text(hjust = .5))

    print(graph)
  }

  return(list(
    "Value if held" = value_if_held,
    "Value in pool" = value_in_pool,
    "impermanent_loss_percent" = impermanent_loss_percent,
    "Nominal impermanent loss" = nominal_impermanent_loss,
    "Fee offset ($)" = fees,
    "Net gain" = net_gain
  ))

}

Try the impermanentlosscalc package in your browser

Any scripts or data that you put into this service are public.

impermanentlosscalc documentation built on Dec. 11, 2025, 5:08 p.m.