Skip to main content

APY Calculation

This document contains the formulas used to calculate the APY for Pendle markets.

In this document, we take the market 0x107a2e3cd2bb9a32b9ee2e4d51143149f8367eba on mainnet as an example.

Variables

nameDescription
market\text{market}0x107a2e3cd2bb9a32b9ee2e4d51143149f8367eba
sy\text{sy}0xC4ed348c56223C5953939e932E315F9d72Cd83fF
lpPriceUsd\text{lpPriceUsd}price of the lp token in terms of USD
syPriceUsd\text{syPriceUsd}price of the sy token in terms of USD
pendlePriceUSD\text{pendlePriceUSD}price of the Pendle token in terms of USD
totalVotedLastEpoch\text{totalVotedLastEpoch}total of vePendle voted for the pool in the last epoch
duration\text{duration}the interval that we use to calculate the APY. For example, duration=7\text{duration}=7 means we calculate the APY based on data of the last 7 days. In our system, we use 7 days as the default duration!
syIndex\text{syIndex}the current index of the SY token, can be taken from exchangeRate function of the sy contract
prevSyIndex\text{prevSyIndex}the syIndex\text{syIndex} at duration\text{duration} days ago.
yearsToExpiry\text{yearsToExpiry}the number of years until the expiry of the market.

Underlying APY

underlyingApy=underlyingInterestApy+underlyingRewardApr\text{underlyingApy} = \text{underlyingInterestApy} + \text{underlyingRewardApr}

underlyingApy\text{underlyingApy} comes in two part, below are how to calculate each of them

UnderlyingInterestApy

interestMultiple=syIndexprevSyIndex\text{interestMultiple} = \dfrac{\text{syIndex}}{\text{prevSyIndex}}

underlyingInterestApy=interestMultiple365days1\text{underlyingInterestApy} = \text{interestMultiple}^{\frac{365}{\text{days}}} - 1

  • Explanation:
    • underlyingInterestApy\text{underlyingInterestApy} estimates the current APY for the interest of the underlying protocol of the SY token. Interest = returns in the underlying asset, and it’s auto-compounding by default.
    • In this formula, we are taking the historical APY for the last 7 days, to extrapolate into the returns for the year.

UnderlyingRewardApr:

  • For each reward token:

    • prevRewardIndex=\text{prevRewardIndex} = rewardIndex\text{rewardIndex} at duration\text{duration} days ago

    • dailyRewardPerSy=rewardIndexprevRewardIndexdays\text{dailyRewardPerSy} = \dfrac{\text{rewardIndex} - \text{prevRewardIndex}}{\text{days}}

    • dailyRewardYield=dailyRewardPerSyrewardPricesyPrice\text{dailyRewardYield} = \text{dailyRewardPerSy} * \dfrac{\text{rewardPrice}}{\text{syPrice}}

    • tokenRewardApr=dailyRewardYield×365\text{tokenRewardApr} = \text{dailyRewardYield} \times 365

  • underlyingRewardApr=tokenRewardApr\text{underlyingRewardApr} = \sum \text{tokenRewardApr}

  • Explanation:

    • underlyingRewardApr\text{underlyingRewardApr} estimates the current APr for the rewards of the underlying protocol of the SY token. Rewards = returns in the reward token, and it’s not auto-compounding by default.

    • In this formula, we are taking the historical rewards rate for the last 7 days, to extrapolate into the returns for the year.

    • Each reward token has its own reward rate, so they have their own APR. We sum them up to get the total APR for all reward tokens.

impliedAPY:

apy=elnImpliedYield1\text{apy} = e^{\text{lnImpliedYield}} - 1

  • lnImpliedYield\text{lnImpliedYield} can be read from readState function of the market contract. Do remember to scale it by 1e18.

SwapFeeApy & voterApr

SwapFeeApy

swapFeeApy\text{swapFeeApy} is the APY that LP holders will get from the swap fees of the pool.

poolValue=lpPriceUsdtotalSupply\text{poolValue} = \text{lpPriceUsd} * \text{totalSupply}

swapFeeForLpHolder=explicitSwapFee20%+implicitSwapFee\text{swapFeeForLpHolder} = \text{explicitSwapFee} * 20\% + \text{implicitSwapFee}

swapFeeRateForLpHolder=swapFeeForLpHoldersyPriceUsdpoolValue\text{swapFeeRateForLpHolder} = \dfrac{\text{swapFeeForLpHolder} * \text{syPriceUsd}}{\text{poolValue}}

swapFeeApy=(1+swapFeeRateForLpHolder)365durations1\text{swapFeeApy} = (1 + \text{swapFeeRateForLpHolder})^\frac{{365}}{\text{durations}} - 1

  • Explanation:
    • LP Holder will received 20% from explicit swap fee, and 100% from the implicit swap fee
    • swapFeeRateForLpHolder\text{swapFeeRateForLpHolder} is the rate of swap fee that LP holder will get in terms of USD, then we interpolate it to get the swapFeeApyswapFeeApy

VoterApr

VoterApr\text{VoterApr} is the APR that vePendle voters will get from voting for the pool.

swapFeeForVoter=explicitSwapFee80%\text{swapFeeForVoter} = \text{explicitSwapFee} * 80\%

swapFeeRateForVoter=swapFeeForVoter × syPriceUsdPendlePriceUSD × totalVotedLastEpoch\text{swapFeeRateForVoter} = \dfrac{\text{swapFeeForVoter} \ \times \ \text{syPriceUsd}}{\text{PendlePriceUSD} \ \times \ \text{totalVotedLastEpoch}}

voterApr= swapFeeRateForVoter×365durationInDays\text{voterApr} =  \text{swapFeeRateForVoter} \times \dfrac{365}{\text{durationInDays}}

  • Explanation:
    • Voter will received 80% from explicit swap fee of the pool

longYieldApy:

interestReturns=(1+underlyingInterestApy)yearsToExpiry1\text{interestReturns} = (1+\text{underlyingInterestApy})^{\text{yearsToExpiry}} - 1 rewardsReturns=underlyingRewardApyyearsToExpiry\text{rewardsReturns} = \text{underlyingRewardApy} * \text{yearsToExpiry}

ytReturns=interestReturns+rewardsReturns\text{ytReturns} = \text{interestReturns} + \text{rewardsReturns} ytReturnsAfterFee=holdYtReturns×97%\text{ytReturnsAfterFee} = \text{holdYtReturns} \times 97\%

longYieldApy=ytReturnsAfterFeeytPriceInAsset1yearsToExpiry1\text{longYieldApy}=\dfrac{\text{ytReturnsAfterFee}}{\text{ytPriceInAsset}}^{\frac{1}{\text{yearsToExpiry}}}-1

  • Explanation:
    • interestReturns\text{interestReturns}:
      • interest returns, in terms of accounting asset, for holding 1 YT from now until expiry
    • rewardsReturns\text{rewardsReturns}:
      • rewards returns, in terms of accounting asset, for holding 1 YT from now until expiry
    • ytReturnsAfterFee\text{ytReturnsAfterFee}:
      • we charge 3% on YT yield, so we need to scale it down by 97%
    • longYieldApy\text{longYieldApy}:
      • This is the APY if we buy YT today, and hold it all the way to expiry, assuming the underlying APY will stay the same. This can be negative (if the returns from YT is less than YT price)
      • Starting with ytPriceInAsset\text{ytPriceInAsset}, we got back ytReturnsWithFee\text{ytReturnsWithFee} after yearsToExpiry\text{yearsToExpiry}.Then we just need to scale it to one year to get the APY

effectiveImpliedApy\text{effectiveImpliedApy}

Effective Implied APY is the APY based on the actual rate that the user used to swap.

To calculate effectiveImpliedApy\text{effectiveImpliedApy}, we need to get the ptExchangeRate\text{ptExchangeRate}: how much PT you can get from 1 underlying.

There are 3 type of swaps:

  • PT <-> any token except YT
  • YT <-> any token except PT
  • PT <-> YT

Each of them has different way to calculate the ptExchangeRateptExchangeRate

PT <-> any token

  • underlying\text{underlying}: input/output token amount in terms of the underlying token
  • ptAmount\text{ptAmount}: PT input/output amount

ptExchangeRate=ptAmountunderlying\text{ptExchangeRate} = \dfrac{\text{ptAmount}}{\text{underlying}}

YT <-> any token

  • ytAmount\text{ytAmount}: YT intput/output amount

ptExchangeRate=11underlyingytAmount\text{ptExchangeRate} = \dfrac{1}{1 - \dfrac{\text{underlying}}{\text{ytAmount}}}

PT <-> YT

ptExchangeRate=1+ptAmountytAmount\text{ptExchangeRate} = 1 + \dfrac{\text{ptAmount}}{\text{ytAmount}}

From ptExchangeRate\text{ptExchangeRate} you can calculate the effectiveImpliedApy as follow:

effectiveImpliedApy=ptExchangeRate365daysToExpiry1\text{effectiveImpliedApy} = \text{ptExchangeRate}^{\frac{365}{\text{daysToExpiry}}} - 1