> For the complete documentation index, see [llms.txt](https://liqui.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://liqui.gitbook.io/docs/hedgehog-strategy/procedures/rebalance.md).

# Rebalance

Auction mechanism design

To remain in the profitability range, the strategy performs so-called rebalance auctions - a procedure, during which the strategy contract adjusts its token holding proportion to bring back the desired price exposure.

There a 2 types of rebalance auctions:

1. Time rebalances - periodical tokens adjustments based on the rebalance time threshold.
2. Price rebalances - token adjustments to cut the losses in a case of huge price change between the regular time rebalances&#x20;

Both types have the same auction design, the only difference between them is trigger conditions. Time rebalance auction activates when enough time was elapsed since the previous rebalance (for example, 12h), while the Price rebalances auction activates on huge drops in ETH price (for example, -7%).&#x20;

## Mechanism

To handle rebalance procedure, we will use a value-based Dutch auction, where amounts that need to be exchanged with the bidder are calculated based on the total ETH value (NAV) held by the strategy before and after the rebalance procedure.

### Rebalance

The flow is next:

1. The keeper calls one of the `timeRebalance, priceRebalance` functions
2. Contract checks for the rebalance conditions (whether enough time has passed or price deviation is large enough)
3. Withdraw all the liquidity from Uniswap pools
4. Calculate the auction parameters
5. Exchange with the keeper the current set of tokens for the desired one to achieve the target price exposure&#x20;
6. Mint new liquidity positions
7. Record snapshot

#### 1) Price Multiplier

The first step is to calculate the price multiplier based on the auction completion ratio (the time when the bidder has called the rebalance function).

There is an auction time of 10 min during which the keeper can call the rebalance function.

```html
function getPriceMultiplier(uint256 _auctionTriggerTime) external view override
    returns (uint256)
{
    uint256 maxPriceMultiplier = IVaultStorage(vaultStorage).maxPriceMultiplier();
    uint256 minPriceMultiplier = IVaultStorage(vaultStorage).minPriceMultiplier();
    uint256 auctionTime = IVaultStorage(vaultStorage).auctionTime();

        uint256 auctionCompletionRatio = block.timestamp.sub(_auctionTriggerTime) >= auctionTime
        ? 1e18
        : (block.timestamp.sub(_auctionTriggerTime)).div(auctionTime);

        return maxPriceMultiplier.sub(auctionCompletionRatio.mul(maxPriceMultiplier.sub(minPriceMultiplier)));
}
```

$$
auctionCompletionRatio=\frac{block.timestamp-auctionTriggerTime}{auctionTime}
\\
\
\\
pm=minPM+auctionCompletionRatio\cdot(maxPM-minPM)
$$

Where `auctionTriggerTime` is a timestamp at which the bidder has called the rebalance function, while `minPriceMultiplier` and `maxPriceMultiplier` is min = 0.95 and max = 1.05 price multipliers.

![](https://835753755-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxfKpLTwsT2MlXPZero3Z%2Fuploads%2FKR0rH6zuU8fwXfVIUdtI%2FGroup%201494.png?alt=media\&token=02eb9bf7-6524-415a-920f-0aa5a48946da)

So at the beginning of the auction, when the completion ratio will be 0, the price multiplier will be equal to 1.05, while at the end of the auction the multiplier will be equal to 0.95.&#x20;

In the case that there are no bids during the auction period, the price multiplier will remain at the minimum levels till the execution call by some keeper.

#### 2) Auction prices

The next step is to calculate the auction prices aEthUsdc and aOsqthEth for ETH/USDC and oSQTH/ETH respectively.

$$
aEthUsdc = pm \cdot EthUsdc
\newline
\
\newline
aOsqthEth = pm \cdot OsqthEth
$$

#### 3) Total Value

Then, we calculate the ETH value that we will use to provide liquidity on Uniswap, as the current ETH value of tokens held by the strategy, calculated at the current prices:

$$
V=pm\cdot(ETH+oSQTH\cdot OsqthEth+\frac{USDC}{EthUsdc})
$$

In order to make sure, that even in the extreme market (or liquidity) conditions there is enough incentive for the keeper to rebalance, we discount total value by the current price multiplier. So there will be up to 4% arbitrage profit.

​Where, ETH, oSQTH, and USDC are the current amount of tokens, while OsqthEth and EthUsdc are the current market prices of the correspondent tokens.

#### 3) Weight

The next step is weight - a coefficient that is needed to achieve target price exposure at auction prices.

The problem here is that the current prices in pools are different from the auction prices around which we would like our liquidity. So, if we will just naively place the liquidity in a 50:50 proportion, or even after adjusting for the IV, we will get the incorrect value split between the ETH-USDC and oSQTH-ETH LP pools.

Thus, we need again to adjust the value split to that one that will provide us with the target price exposure after the rebalance auction.

$$
w^{pos}=\frac{pm}{1+pm}+\frac{0.01}{IV}
\newline
\
\newline
w^{neg}=\frac{pm}{1+pm}-\frac{0.01}{IV}
$$

Where $$w^{pos}$$ and $$w^{neg}$$ are weights for the rebalance auction when we expect a positive or negative IV bump respectively.

So, the values for LP will be:

$$
V\_{EthUsdc}=w\cdot V
\newline
\
\newline
V\_{OsqthEth} = (1-w)\cdot V
$$

#### 3)​ Implied Volatility bump

Depending on whether or not we observe a positive or negative IV bump, we calculate the expected IV bump over the next period as:

```
//current implied volatility
uint256 cIV = IVaultMath(vaultMath).getIV();

//previous implied volatility
uint256 pIV = IVaultStorage(vaultStorage).ivAtLastRebalance();

//is a positive IV bump
bool isPosIVbump = cIV < pIV;

uint256 expIVbump;
if (isPosIVbump) {
    expIVbump = pIV.div(cIV);
    } else {
    expIVbump = cIV.div(pIV);
    }
 expIVbump = expIVbump > uint256(2e18) ? uint256(2e18) : (expIVbump.mul(2e18)).sub(2e18);
```

With the additional check on its value, because the value of `expIVbump > 2` will lead to the negative value of one of the lower or upper boundaries.

#### 4) Boundaries

Based on these auction prices calculate the boundaries of liquidity placement

$$
EthUsdcLower = \frac{1e12}{1.0001^{\frac{ln{\frac{1e12}{EthUsdc}}}{ln{1.0001}}+TS+baseThreshold+tickAdj}}
\newline
\
\newline
EthUsdcUpper = \frac{1e12}{1.0001^{\frac{ln{\frac{1e12}{EthUsdc}}}{ln{1.0001}}-baseThreshold+tickAdj}}
$$

Similarly, for the oSQTH-ETH pool:

$$
OsqthEthLower = \frac{1}{1.0001^{-\frac{ln{OsqthEth}}{ln{}1.0001}+TS+baseThreshold+tickAdj}}
\newline
\
\newline
OsqthEthUpper = \frac{1}{1.0001^{-\frac{ln{OsqthEth}}{ln{}1.0001}-baseThreshold+tickAdj}}
$$

Where `baseThreshold` is the parameter that defines the base size of the boundaries and  `tickAdj` is boundaries adjustment, which depends on whether we expect a positive or negative IV bump and its amplitude.

$$
baseAdj = \frac{expIVbump}{adjParam}\cdot tickSpacing
\\
\
\\
tickAdj = ifelse(baseAdj<120, 60, baseAdj)
\\
\
\\
tickAdj = ifelse(isPosIVbump, tickAdj, -tickAdj)
$$

```
int24 tickAdj;
    {
        int24 baseAdj = toInt24(
        int256(
            ((expIVbump.div(IVaultStorage(vaultStorage).adjParam())).floor() *
            uint256(int256(tickSpacing))).div(1e36)
            ));
        tickAdj = baseAdj < int24(120) ? int24(60) : baseAdj;
    }
```

#### 5) Liquidities

Based on the total LP value calculate the desired liquidities:

$$
L\_{EthUsdc}=\frac{V\_{EthUsdc}\cdot EthUsdc}{2\sqrt{aEthUsdc} - \sqrt{EthUsdcLower} - \frac{aEthUsdc}{\sqrt{EthUsdcUpper}}}
$$

$$
L\_{OsqthEth} = \frac{V\_{OsqthEth}}{2\sqrt{aOsqthEth}-\sqrt{OsqthEthLower}-\frac{aOsqthEth}{\sqrt{OsqthEthUpper}}}
$$

Note, that we calculate liquidities around the auction prices $$aEthUsdc$$ and $$aOsqthEth$$, rather than around the current prices.​

#### 7) Amount of tokens

Now, we can get the required amount of tokens that need to be provided to mint desired amount of liquidity:

$$
amountEth0 = L\_{EthUsdc}\cdot \frac{\sqrt{aEthUsdcUpper}-\sqrt{EthUsdc}}{\sqrt{aEthUsdcUpper \cdot EthUsdc}}
\newline
\
\newline
amountUsdc = L\_{EthUsdc} \cdot (\sqrt{EthUsdc}-\sqrt{aEthUsdcLower})
\newline
\
\newline
amountEth1 = L\_{OsqthEth}\cdot (\sqrt{OsqthEth}-\sqrt{aOsqthEthLower})
\newline
\
\newline
amountOsqth = L\_{OsqthEth}\cdot \frac{\sqrt{aOsqthEthUpper}-\sqrt{OsqthEth}}{\sqrt{aOsqthEthUpper\cdot OsqthEth}}
$$

The Deltas (amount of tokens) that need to be exchanged with the keeper:

$$
\Delta Eth = amountEth0 +amountEth1-balanceEth
\newline
\
\newline
\Delta Usdc = amountUsdc-balanceUsdc
\newline
\
\newline
\Delta Osqth = amount Osqth - balanceOsqth
$$

Where `balanceEth`, `balanceUsdc`, and `balanceOsqth` are the current amounts of assets held by the strategy.

Negative deltas mean that the strategy gives these tokens in exchange for the requested one (with a positive sign).
