# Balancer Simulations Math Challenge - Advanced

This notebook provides a collection of challenges for an advanced understanding of Balancer Math.


```python
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import math
```

# Challenge No. 1

For the following questions, there are two tokens $X$ and $Y$, with $x$ representing the number of Token $X$ in the pool, and $y$ representing the number of Token $Y$ in the pool. 

The plots below represent the invariant curves for two Balancer Pools. Both curves are of the form $2 = x^ay^{1-a}$ for some value of $a$. Try as many of the exercises below as you want -- discuss them with others and have fun!

1. Explain how the equation $V = B_1^{W_1}B_2^{W_2}$ becomes $2 = x^ay^{1-a}$ in this context. 

#### Solution

$V$ is the invariant and the specific value for this case is 2
$a$ and $1-a$ are the weights of token $x$ and token $y$ respectively

2. Give one possible value of $a$ and a pair of possible legal values for $x$ and $y$ in this context. 

#### Solution
The only restriction for $a$ is it to be a positive value in range (0,1).
Let´s assume $x = 10$ and let´s see how $y$ changes with regard to $a$


```python
a_vals = pd.Series(range(1,10,1))

List = pd.DataFrame(a_vals/10, columns=['a'])

List['1-a'] = 1-List.a
List['token_A'] = 10
List['token_B'] = (2/(List.token_A**List.a))**(1/(1-List.a))

List
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>a</th>
      <th>1-a</th>
      <th>token_A</th>
      <th>token_B</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>0.1</td>
      <td>0.9</td>
      <td>10</td>
      <td>1.672502</td>
    </tr>
    <tr>
      <th>1</th>
      <td>0.2</td>
      <td>0.8</td>
      <td>10</td>
      <td>1.337481</td>
    </tr>
    <tr>
      <th>2</th>
      <td>0.3</td>
      <td>0.7</td>
      <td>10</td>
      <td>1.003394</td>
    </tr>
    <tr>
      <th>3</th>
      <td>0.4</td>
      <td>0.6</td>
      <td>10</td>
      <td>0.683990</td>
    </tr>
    <tr>
      <th>4</th>
      <td>0.5</td>
      <td>0.5</td>
      <td>10</td>
      <td>0.400000</td>
    </tr>
    <tr>
      <th>5</th>
      <td>0.6</td>
      <td>0.4</td>
      <td>10</td>
      <td>0.178885</td>
    </tr>
    <tr>
      <th>6</th>
      <td>0.7</td>
      <td>0.3</td>
      <td>10</td>
      <td>0.046784</td>
    </tr>
    <tr>
      <th>7</th>
      <td>0.8</td>
      <td>0.2</td>
      <td>10</td>
      <td>0.003200</td>
    </tr>
    <tr>
      <th>8</th>
      <td>0.9</td>
      <td>0.1</td>
      <td>10</td>
      <td>0.000001</td>
    </tr>
  </tbody>
</table>
</div>



3. Rewrite the curve $2 = x^ay^{1-a}$ in the form "$y =$ (some expression involving x)" and plot it using the Python tool of your choice. 

#### Solution

$$ y = (\frac{2}{x^a})^{1/(1-a)} $$

4. Generate 100 $(x,y)$ points on the curve $2 = x^{0.6}y^{0.4}$. Now take the **logarithm** of both $x$ and $y$ in your 100 points. Plot $\log(x)$ against $\log(y)$. What do you notice? 


```python
x = pd.Series(range(10,0,-1))
a = .6
b = .4

List = pd.DataFrame(x, columns=['token_A'])
List['token_B'] = (2/(List.token_A**a))**(1/(b))
List['log_A'] = np.log(List.token_A)
List['log_B'] = np.log(List.token_B)

List
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>token_A</th>
      <th>token_B</th>
      <th>log_A</th>
      <th>log_B</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>10</td>
      <td>0.178885</td>
      <td>2.302585</td>
      <td>-1.721010</td>
    </tr>
    <tr>
      <th>1</th>
      <td>9</td>
      <td>0.209513</td>
      <td>2.197225</td>
      <td>-1.562969</td>
    </tr>
    <tr>
      <th>2</th>
      <td>8</td>
      <td>0.250000</td>
      <td>2.079442</td>
      <td>-1.386294</td>
    </tr>
    <tr>
      <th>3</th>
      <td>7</td>
      <td>0.305441</td>
      <td>1.945910</td>
      <td>-1.185997</td>
    </tr>
    <tr>
      <th>4</th>
      <td>6</td>
      <td>0.384900</td>
      <td>1.791759</td>
      <td>-0.954771</td>
    </tr>
    <tr>
      <th>5</th>
      <td>5</td>
      <td>0.505964</td>
      <td>1.609438</td>
      <td>-0.681289</td>
    </tr>
    <tr>
      <th>6</th>
      <td>4</td>
      <td>0.707107</td>
      <td>1.386294</td>
      <td>-0.346574</td>
    </tr>
    <tr>
      <th>7</th>
      <td>3</td>
      <td>1.088662</td>
      <td>1.098612</td>
      <td>0.084950</td>
    </tr>
    <tr>
      <th>8</th>
      <td>2</td>
      <td>2.000000</td>
      <td>0.693147</td>
      <td>0.693147</td>
    </tr>
    <tr>
      <th>9</th>
      <td>1</td>
      <td>5.656854</td>
      <td>0.000000</td>
      <td>1.732868</td>
    </tr>
  </tbody>
</table>
</div>




```python
#plot curves with all 

fig = px.line(List, x='log_B', y='log_A')

fig.update_xaxes(range=[-6, 6])
fig.update_yaxes(range=[-1, 6])
fig.update_layout(height=800, width=800, title_text='<b>AMM Curve</b>')

fig.show()
```



#### Solutions

The relationship between the variables is linear and the slope of the line is the ration between the weights of the tokens


5. Both pictures above represent AMM curves of the form $2 = x^{a}y^{1-a}$. One of the curves has $a =0.6$ and the other has $a = 0.8$. Which is which? How can you tell? 

#### Solution - There are no pics

6. Both of the curves pictured above contain the point $(2,2)$. Explain why any curve of the form $2= x^{a}y^{1-a}$ will pass through $(2,2)$. Is this a special property of the number 2, or will any curve of the form $k = x^{a}y^{1-a}$ pass through $(k,k)$? (You can determine this with an algebraic proof, or by playing with Python graphs.)

#### Solution

Proof by contradiction. (Attempt 1)

Suppose there is no point $(k, k)$ in the curve $k = x^{a}y^{1-a}$.

$\begin{align}
& \text{Let $ y := x $} \quad (\textit{Is this sound?})\tag{1}. \\
& k = x^{a}y^{1-a} \quad \text{(given)} \tag{2} \\
& k = x^{a}x^{1-a} \quad \text{(substituting from (1))} \tag{3} \\
& k = x^{a+1-a} \quad \text{(product of exponents)} \tag{4} \\
& k = x^{1} \tag{5} \\
& k = x \tag{6}
\end{align} $

However, since $x = k$, per (1) this means $y = k$ also, meaning that point $(k, k)$ exists, contradicting the original assumption. $\square$




Proof by contradiction. (Attempt 2)

Suppose there is no point $(k, k)$ in the curve $k = x^{a}y^{1-a}$.
$
\begin{align*}
\text{Let}\ x &:= k  \tag{1}. \\
k &= x^{a}y^{1-a} \quad \text{(Given.)} \tag{2} \\
k &= k^{a}y^{1-a} \quad \text{(Substituting from (1).)} \tag{3} \\
\frac{k}{k^{a}} &= y^{1-a} \tag{4} \\
\log \frac{k}{k^{a}} &= \log y^{1-a} \tag{5} \\
\log {k} - \log {k^{a}} &= \log y^{1-a} \tag{6} \\
\log {k} - a \log {k} &= (1-a) \log y \tag{7} \\
\log {k} - a \log {k} &= \log y - a \log y\tag{8} \\
k &= y \tag{9} \quad \text{(Since a $\log$ function has only one $x$ mapping to every $\log x$.)}
\end{align*}
$

However, since $x = k$ per (1) and also $y=k$ per (9) this means point $(k, k)$ exists, contradicting the original assumption. $\square$

7. Suppose a curve $2 = x^ay^{1-a}$ passes through the point $(2,2)$ and $(p,q)$. Explain how you can use the values of $p$ and $q$ to determine the weights of Token $X$ and Token $Y$. 

#### Solution

$
\begin{align*}
  2 &= x^a y^{(1-a)} \\
  2 &= p^a q^{(1-a)} \\
  2 &= x^a y^{(1-a)} \\
  p^a q^{(1-a)} &=  x^a y^{(1-a)}\\
  \log \left(p^a q^{(1-a)}\right) &=  \log \left( x^a y^{(1-a)} \right)\\
  \log (p^a) + \log (q^{(1-a)}) &=  \log (x^a) + \log (y^{(1-a)}) \\
  a \log p + (1-a) \log q &=  a \log x + (1-a) \log y  \\
  a \log p + \log q - a \log q &=  a \log x + \log y - a \log y  \\
  a (\log p - \log q) + \log q  &=  a (\log x - \log y) + \log y \\
  \log q  - \log y &=  a (\log x - \log y) - a (\log p - \log q)\\
  \log q  - \log y &=  a ((\log x - \log y) - (\log p - \log q))\\
  \log q  - \log y &=  a (\log x + \log q - \log y - \log p )\\
  \frac{\log q  - \log y}{\log x + \log q - \log y - \log p }&=  a \\
\end{align*}
$

$
\begin{align}
a = \frac{\log q  - \log y}{\log x + \log q - \log y - \log p } \tag{1}
\end{align}
$


Check:


```python
a = 0.8 # Let a = 0.8; we'll use this to check the Equation 1. 
x = 2 # Per premise
y = 2 # Per premise
p = 5 # Arbitrary point
q = (2/(p**a))**(1/(1-a)) # Calculated from p via invariant function

"""Check equality in Equation 1."""
(math.log(q)- math.log(y))/(math.log(x) + math.log(q) - math.log(y) - math.log(p)) == a 
```

8. In **Alice's Pool**, which point has the highest spot price $SP_X^{Y}$: **A**, **B** or **C**? (You may be able to answer this without calculation.)

9. Suppose Alice is actively managing her pool against Bob's pool and wishes to trade it against Bob's pool. Identify a pair of points -- one in her pool and one in Bob's pool -- that would represent an arbitrage opportunity for Alice. 


```python
x = pd.Series(range(100,0,-1))
a = .6
b = .4
List = pd.DataFrame(x/10, columns=['token_A'])
List['token_B'] = (2/(List.token_A**a))**(1/(b))

a = .8
b = .2
List2 = pd.DataFrame(x/10, columns=['token_A2'])
List2['token_B2'] = (2/(List2.token_A2**a))**(1/(b))

L = pd.concat([List, List2], axis=1)
L.head(20)

```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>token_A</th>
      <th>token_B</th>
      <th>token_A2</th>
      <th>token_B2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>10.0</td>
      <td>0.178885</td>
      <td>10.0</td>
      <td>0.003200</td>
    </tr>
    <tr>
      <th>1</th>
      <td>9.9</td>
      <td>0.181603</td>
      <td>9.9</td>
      <td>0.003331</td>
    </tr>
    <tr>
      <th>2</th>
      <td>9.8</td>
      <td>0.184389</td>
      <td>9.8</td>
      <td>0.003469</td>
    </tr>
    <tr>
      <th>3</th>
      <td>9.7</td>
      <td>0.187248</td>
      <td>9.7</td>
      <td>0.003615</td>
    </tr>
    <tr>
      <th>4</th>
      <td>9.6</td>
      <td>0.190181</td>
      <td>9.6</td>
      <td>0.003768</td>
    </tr>
    <tr>
      <th>5</th>
      <td>9.5</td>
      <td>0.193192</td>
      <td>9.5</td>
      <td>0.003929</td>
    </tr>
    <tr>
      <th>6</th>
      <td>9.4</td>
      <td>0.196283</td>
      <td>9.4</td>
      <td>0.004099</td>
    </tr>
    <tr>
      <th>7</th>
      <td>9.3</td>
      <td>0.199458</td>
      <td>9.3</td>
      <td>0.004278</td>
    </tr>
    <tr>
      <th>8</th>
      <td>9.2</td>
      <td>0.202718</td>
      <td>9.2</td>
      <td>0.004467</td>
    </tr>
    <tr>
      <th>9</th>
      <td>9.1</td>
      <td>0.206069</td>
      <td>9.1</td>
      <td>0.004666</td>
    </tr>
    <tr>
      <th>10</th>
      <td>9.0</td>
      <td>0.209513</td>
      <td>9.0</td>
      <td>0.004877</td>
    </tr>
    <tr>
      <th>11</th>
      <td>8.9</td>
      <td>0.213054</td>
      <td>8.9</td>
      <td>0.005100</td>
    </tr>
    <tr>
      <th>12</th>
      <td>8.8</td>
      <td>0.216696</td>
      <td>8.8</td>
      <td>0.005336</td>
    </tr>
    <tr>
      <th>13</th>
      <td>8.7</td>
      <td>0.220443</td>
      <td>8.7</td>
      <td>0.005586</td>
    </tr>
    <tr>
      <th>14</th>
      <td>8.6</td>
      <td>0.224299</td>
      <td>8.6</td>
      <td>0.005850</td>
    </tr>
    <tr>
      <th>15</th>
      <td>8.5</td>
      <td>0.228269</td>
      <td>8.5</td>
      <td>0.006130</td>
    </tr>
    <tr>
      <th>16</th>
      <td>8.4</td>
      <td>0.232357</td>
      <td>8.4</td>
      <td>0.006427</td>
    </tr>
    <tr>
      <th>17</th>
      <td>8.3</td>
      <td>0.236569</td>
      <td>8.3</td>
      <td>0.006743</td>
    </tr>
    <tr>
      <th>18</th>
      <td>8.2</td>
      <td>0.240910</td>
      <td>8.2</td>
      <td>0.007078</td>
    </tr>
    <tr>
      <th>19</th>
      <td>8.1</td>
      <td>0.245385</td>
      <td>8.1</td>
      <td>0.007434</td>
    </tr>
  </tbody>
</table>
</div>




```python
# In pool 1, to buy 0.1 tokens A $0.181603 - 0.178885 = 0.0027179$ tokens_B are required

# In pool 2, to buy 0.1 tokens A $0.003331 - 0.003200 = 0.0001310$ tokens_B are required

# Considering the point token_A = 9.9, if we sell 0.1 token_A in pool 1 we get 0.0027179 token_B but the price of buying 0.1 token_A in pool 2 is only $0.003469-0.003331=0.0001379$ so we end up with the same amount of token_A + $0.0027179 - 0.0001379 = 0.002580$ token_B.
# If we want to buy more token_A in pool 2, our next 0.1 token_A would cost $0.003615-0.003469=0.0001460$ so we could have now .2 token_A plus $0.002580-0.0001460=0.002434$ token_B

```




    0.002434




```python
cash = L.token_B.iloc[1]-L.token_B.iloc[0]

expense = 0
i = 1
count = 0.1
while expense < cash:
    expense_new = L.token_B2.iloc[i+1]-L.token_B2.iloc[i]
    i+=1
    expense += expense_new
    count += 0.1
count
```




    1.5000000000000002




```python
#plot curves with all 
List = List[['token_A', 'token_B']]
List2 = List2[['token_B2']]

df = pd.concat([List, List2], axis=1, ignore_index=False)
fig = px.line(df, x="token_A", y=["token_B", 'token_B2'])
fig.update_xaxes(range=[0, 10])
fig.update_yaxes(range=[0, 10])
fig.update_layout(height=1000, width=1000, title_text='<b>AMM Curve</b>')

fig.show()
```



10. Create the invariant curves for Alice's pool and Bob's pool in Python using the graphing tool of your choice. Choose one point on Bob's curve and highlight it in Blue. Call this point **Z**. On your graph of Alice's curve, color in red **all of the points that represent arbitrage opportunities for Alice against Z**, i.e. color red all of the points on Alice's curve that represent where she could make a profit if she traded with Bob while he held the position represented by **Z**. (**Note**: This is the hardest one in terms of symbolic math, since it involves solving an inequality involving power functions.)

# Challenge No. 2

Alice wants to set up another pool.  

She knows that the current price of 1 token C is 37 token D.  
She owns 57000 token C, and 510000 token D. She plans to set a fee to 1%, and maximize her capital returns via this pool.  

#### 1.
What is the optimal set up for Alice’s new pool? Think about how you’d approach it and explain why.

#### 2.
Due to a huge price dump, the price of token C on external markets drops to 28 token D. Now, Arbitrage traders get to work. Image Alice wanted to re-balance the pool herself, how much token C would she need in order to re-balance the pool in one trade? Keep in mind swap fees and slippage!

#### 3.
Imagine Alice’s pool would be twice as big. How much liquidity would she need for the same price change?

#### 4.
Explore the general relation between the size of the pool (liquidity m in token C and n in token D) and price changes with a series of experiments.  
	• derive an expression  
	• plot a graph  

#### SOLUTION 1.

We understand that profit comes from trading and to be effective and maximize the return, the equilibrium of the pool should be around the trading price. In that sens, we need to calculate the weights of each token according to a Spot Price (SP) equal to the current price 

$$ SP = \frac{\frac{B_c}{W_c}}{\frac{B_d}{W_d}} = \frac{1}{37} $$

with $$ W_c + W_d = 1 $$
$$ W_d = 1 - W_c $$

$$ SP = \frac{B_c*W_d}{B_d*W_c} = \frac{B_c}{B_d} * \frac{W_d}{1-W_d} $$
$$ SP * \frac{B_d}{B_c} * (1-W_d) = W_d $$

$$ SP * \frac{B_d}{B_c} = x $$

$$ x * (1-W_d) = x - x*W_d = W_d $$
$$ x = W_d (1+x)$$
$$ W_d = \frac{x}{1+x} $$


```python
SP = 1/37
Bc = 57000
Bd = 510000

x = SP*Bd/Bc

Wd = x/(1+x)
Wd
```




    0.19473081328751435




```python
Wc = 1-Wd
Wc
```




    0.8052691867124857




```python
# Checking:

SP_check = (Bc/Wc)/(Bd/Wd)
SP_check
```




    0.027027027027027032




```python
# What should be the same as:
1/37
```




    0.02702702702702703



#### SOLUTION 2.

Now the $ Price = 1/28 $ but the pool $ SP = 1/37$ so arbitrage is possible. To avoid it through one swap (including fees) we need to look for the trade that moves the price in the pool to $1/28$.

As a simplification we are going to consider:

$W_c = 0.805$

$W_b = 0.195$




```python
# FIRST WITHOUT FEES !

Bc = 57000 # initial balance
Bd = 510000 # initial balance
Wc = 0.805 #define weight
Wd = 0.195 #define weight
s_f = 0.01 #swap fee
inv = (Bc**Wc)*(Bd**Wd) #calculate invariant
a_vals = pd.Series(range(60160,60170,1))
#create dataframe with based on a_vals
List = pd.DataFrame(a_vals, columns=['token_C'])

#create values for plot, add Y_balances according to current invariant
List['invariant'] = inv #value required to calculate token B value
List['token_D'] = (List.invariant/(List.token_C**Wc))**(1/Wd)# calculate corresponding token_B value according to invariant
List['Price_C'] = 1/((List.token_C/Wc) / (List.token_D/Wd))

# List['In-Given-Out'] = List.token_D * (( List.token_C / (List.token_C-1) )**(Wc/Wd) -1)
List['Out-Given-Out'] = List.token_D * (( List.token_C / (List.token_C-1) )**(Wc/Wd) -1)

List
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>token_C</th>
      <th>invariant</th>
      <th>token_D</th>
      <th>Price_C</th>
      <th>In-Given-Out</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>60160</td>
      <td>87388.733071</td>
      <td>408163.402192</td>
      <td>28.008349</td>
      <td>28.009542</td>
    </tr>
    <tr>
      <th>1</th>
      <td>60161</td>
      <td>87388.733071</td>
      <td>408135.395038</td>
      <td>28.005961</td>
      <td>28.007155</td>
    </tr>
    <tr>
      <th>2</th>
      <td>60162</td>
      <td>87388.733071</td>
      <td>408107.390270</td>
      <td>28.003574</td>
      <td>28.004768</td>
    </tr>
    <tr>
      <th>3</th>
      <td>60163</td>
      <td>87388.733071</td>
      <td>408079.387889</td>
      <td>28.001187</td>
      <td>28.002381</td>
    </tr>
    <tr>
      <th>4</th>
      <td>60164</td>
      <td>87388.733071</td>
      <td>408051.387896</td>
      <td>27.998800</td>
      <td>27.999994</td>
    </tr>
    <tr>
      <th>5</th>
      <td>60165</td>
      <td>87388.733071</td>
      <td>408023.390288</td>
      <td>27.996414</td>
      <td>27.997607</td>
    </tr>
    <tr>
      <th>6</th>
      <td>60166</td>
      <td>87388.733071</td>
      <td>407995.395067</td>
      <td>27.994028</td>
      <td>27.995221</td>
    </tr>
    <tr>
      <th>7</th>
      <td>60167</td>
      <td>87388.733071</td>
      <td>407967.402233</td>
      <td>27.991642</td>
      <td>27.992835</td>
    </tr>
    <tr>
      <th>8</th>
      <td>60168</td>
      <td>87388.733071</td>
      <td>407939.411783</td>
      <td>27.989256</td>
      <td>27.990449</td>
    </tr>
    <tr>
      <th>9</th>
      <td>60169</td>
      <td>87388.733071</td>
      <td>407911.423720</td>
      <td>27.986871</td>
      <td>27.988064</td>
    </tr>
  </tbody>
</table>
</div>



An approximation: Bc should be between 60100 and 60200 so the owner would need to bring ~3,1k token_C into the pool and would get 510k-408k = 102k token_B

The exact calculation can be done with the In-Given-Price formula:

$$ A_i = B_i ((\frac{SP_{new}}{SP})^{(\frac{w_0}{w_0+w_i})})-1)$$


```python
SP = 1/37
SP_new = 1/28

A = Bc * (((SP_new/SP)**(Wd/(Wd+Wc)))-1)
A
# Amount of token_C to bring to the pool (in exchange for token_B)
```




    3183.6295721159863



#### SOLUTION 2. with fees

In-Given-Out formula with fees:

a) paying the fee in the token I am getting

$$ A_i = B_i * ((\frac{B_o}{B_o + A_o(1-fee)})^{\frac{w_o}{w_i}}  -1) $$

or b) if I pay the fee in the token I am giving

$$ A_i*(1-fee) = B_i * ((\frac{B_o}{B_o + A_o})^{\frac{w_o}{w_i}}  -1) $$


```python
# WITH FEES

# First considerations: the amount of tokens to be paid should be higher as some of them goes directly to pay fees

Bc = 57000 # initial balance
Bd = 510000 # initial balance
Wc = 0.805 #define weight
Wd = 0.195 #define weight
s_f = 0 #swap fee

inv = (Bc**Wc)*(Bd**Wd) #calculate invariant

a_vals = pd.Series(range(0,5,1))
delta = 1-s_f

#create dataframe with based on a_vals
List = pd.DataFrame(a_vals, columns=['index'])
List['token_C'] = Bc + List.index*(delta)

#create values for plot, add Y_balances according to current invariant
List['invariant'] = inv #value required to calculate token B value
List['token_D'] = (List.invariant/(List.token_C**Wc))**(1/Wd)       # calculate corresponding token_B value according to invariant
List['Price_C'] = 1/((List.token_C/Wc) / (List.token_D/Wd))

# List['In-Given-Out'] = (List.token_C * (( List.token_D / (List.token_D-1) )**(Wd/Wc) -1)) # / (1-s_f)
# List['Out-Given-In'] = (List.token_D * (( List.token_C / (List.token_C + 1) )**(Wc/Wd) -1))

List['New_Own'] = List.token_D * (List.token_C/(List.token_C + delta))**(Wc/Wd) - List.token_D

List
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>index</th>
      <th>token_C</th>
      <th>invariant</th>
      <th>token_D</th>
      <th>Price_C</th>
      <th>New_Own</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>0</td>
      <td>57000</td>
      <td>87388.733071</td>
      <td>510000.000000</td>
      <td>36.936572</td>
      <td>-36.934911</td>
    </tr>
    <tr>
      <th>1</th>
      <td>1</td>
      <td>57001</td>
      <td>87388.733071</td>
      <td>509963.065089</td>
      <td>36.933249</td>
      <td>-36.931588</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2</td>
      <td>57002</td>
      <td>87388.733071</td>
      <td>509926.133501</td>
      <td>36.929927</td>
      <td>-36.928266</td>
    </tr>
    <tr>
      <th>3</th>
      <td>3</td>
      <td>57003</td>
      <td>87388.733071</td>
      <td>509889.205236</td>
      <td>36.926604</td>
      <td>-36.924943</td>
    </tr>
    <tr>
      <th>4</th>
      <td>4</td>
      <td>57004</td>
      <td>87388.733071</td>
      <td>509852.280292</td>
      <td>36.923283</td>
      <td>-36.921622</td>
    </tr>
  </tbody>
</table>
</div>




```python
List.token_D.iloc[2] - List.token_D.iloc[1]
```




    -36.93158792384202




```python
a_vals = pd.Series(range(0,5,1))
s_f = 0.01
delta = 1-s_f

#create dataframe with based on a_vals
List2 = pd.DataFrame(a_vals, columns=['index'])
List2['token_C'] = Bc + List2.index*(delta)

#create values for plot, add Y_balances according to current invariant
List2['invariant'] = inv #value required to calculate token B value
List2['token_D'] = (List2.invariant/(List2.token_C**Wc))**(1/Wd)       # calculate corresponding token_B value according to invariant
List2['Price_C'] = 1/((List2.token_C/Wc) / (List2.token_D/Wd))

# List['In-Given-Out'] = (List.token_C * (( List.token_D / (List.token_D-1) )**(Wd/Wc) -1)) # / (1-s_f)
# List['Out-Given-In'] = (List.token_D * (( List.token_C / (List.token_C + 1) )**(Wc/Wd) -1))

List2['New_Own'] = List2.token_D * (List2.token_C/(List2.token_C +(delta)))**(Wc/Wd) - List2.token_D

List2
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>index</th>
      <th>token_C</th>
      <th>invariant</th>
      <th>token_D</th>
      <th>Price_C</th>
      <th>New_Own</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>0</td>
      <td>57000.00</td>
      <td>87388.733071</td>
      <td>510000.000000</td>
      <td>36.936572</td>
      <td>-36.565578</td>
    </tr>
    <tr>
      <th>1</th>
      <td>1</td>
      <td>57000.99</td>
      <td>87388.733071</td>
      <td>509963.434422</td>
      <td>36.933282</td>
      <td>-36.562321</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2</td>
      <td>57001.98</td>
      <td>87388.733071</td>
      <td>509926.872101</td>
      <td>36.929993</td>
      <td>-36.559065</td>
    </tr>
    <tr>
      <th>3</th>
      <td>3</td>
      <td>57002.97</td>
      <td>87388.733071</td>
      <td>509890.313035</td>
      <td>36.926704</td>
      <td>-36.555809</td>
    </tr>
    <tr>
      <th>4</th>
      <td>4</td>
      <td>57003.96</td>
      <td>87388.733071</td>
      <td>509853.757226</td>
      <td>36.923415</td>
      <td>-36.552554</td>
    </tr>
  </tbody>
</table>
</div>




```python
List2.token_D.iloc[2] - List2.token_D.iloc[1]
```




    -36.56232138548512




```python
1/(List2.token_D.iloc[3]/List.token_D.iloc[3])
```




    0.9999978273765967




```python
# Easy solution:

# The effective tokens in the trade should be the same as before: 3183.6295721159863 but fees need to be paid
# As the effective tokens going into the pool are X-fee = 3183.63 and fee = 1%, .99*X = 3183.63 -> 
# fee:
s_f = 0.01 

A_new = A / (1-s_f)
A_new
```




    3215.7874465818045




```python
# Paid fees:

3215.7874465818045 - 3183.6295721159863
```




    32.15787446581817



#### SOLUTION 3.


```python
SP = 1/37
SP_new = 1/28
Bc = 2*Bc

A = Bc * (((SP_new/SP)**(Wd/(Wd+Wc)))-1)
A
# Amount of token_C to bring to the pool (in exchange for token_B)
```




    6367.259144231973




```python
# Ratio
6367.259144231973 / 3183.6295721159863
```




    2.0




```python
# Variables
# Size: S
# Change in price: delta
# Number of tokens: T

# T produces a delta in a pool with size S
# n*t produces a delta in a pool with size n*S
```


$$ A_i = B_i ((\frac{SP_{new}}{SP})^{(\frac{w_0}{w_0+w_i})})-1)$$


$$ A_i = B_i*(cte)$$

New pool with $n*B_i$

$$ m*A_i = n*B_i*(cte)$$

$$ \frac{m*A_i}{A_i} = \frac{n*B_i (cte)}{B_i*(cte)}$$

$$ m = n $$

If size is double: $B_i -> 2*B_i$ means that $A_i -> 2*A_i$

So we need more tokens in the sam factor as times the new pool is bigger than the old one


# Challenge No. 3

Bob runs a 50-50 Token X-Token Y pool with a 5% swap fee. 

The following traders want to interact with this pool:
- Carlos wants to increase the amount of Token X by 10% by trading X for Y
- Diana wants to increase the amount of Token Y by 10% by trading Y for X
- Ellen wants to increase the spot price X:Y by 10%
- Fabricio wants to increase the spot price Y:X by 10%

#### 1.
For each action, specify the amount that the person will need to trade in to achieve the result. 

#### 2.
These actions can not occur simultaneously and will be processed in some order. There are 24 different total orders -- choose a few different ones and simulate the effect on spot price and liquidity. Can you make a conclusion about how increasing liquidity or changing balances affects spot price? If not, try running additional simulations with varying numbers besides 10%.

#### 3.
Now add in two agents who want to increase the pool liquidity by making a deposit. With 6 actors, there are 720 different orderings of the actions. Analyze some. Which actions work "together" (reducing the amount needed of the second action to achieve a particular effect) and which work "against each other"? 

#### SOLUTION 1.



```python
# Pool definition
Bc = 50000 # initial balance
Bd = 50000 # initial balance
Wc = 0.5 #define weight
Wd = 0.5 #define weight
s_f = 0.05 #swap fee

inv = (Bc**Wc)*(Bd**Wd) #calculate invariant
a_vals = pd.Series(range(50000,55000,1))
#create dataframe with based on a_vals
List = pd.DataFrame(a_vals, columns=['token_C'])

#create values for plot, add Y_balances according to current invariant
List['invariant'] = inv #value required to calculate token B value
List['token_D'] = (List.invariant/((List.token_C)**Wc))**(1/Wd)# calculate corresponding token_B value according to invariant

# List['In-Given-Out'] = List.token_D * (( List.token_C / (List.token_C-1) )**(Wc/Wd) -1)
# List['Out-Given-Out'] = List.token_D * (( List.token_C / (List.token_C-(1-s_f)) )**(Wc/Wd) -1)
List
```




<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

    .dataframe tbody tr th {
        vertical-align: top;
    }

    .dataframe thead th {
        text-align: right;
    }
</style>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>token_C</th>
      <th>invariant</th>
      <th>token_D</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>50000</td>
      <td>50000.0</td>
      <td>50000.000000</td>
    </tr>
    <tr>
      <th>1</th>
      <td>50001</td>
      <td>50000.0</td>
      <td>49999.000020</td>
    </tr>
    <tr>
      <th>2</th>
      <td>50002</td>
      <td>50000.0</td>
      <td>49998.000080</td>
    </tr>
    <tr>
      <th>3</th>
      <td>50003</td>
      <td>50000.0</td>
      <td>49997.000180</td>
    </tr>
    <tr>
      <th>4</th>
      <td>50004</td>
      <td>50000.0</td>
      <td>49996.000320</td>
    </tr>
    <tr>
      <th>...</th>
      <td>...</td>
      <td>...</td>
      <td>...</td>
    </tr>
    <tr>
      <th>4995</th>
      <td>54995</td>
      <td>50000.0</td>
      <td>45458.678062</td>
    </tr>
    <tr>
      <th>4996</th>
      <td>54996</td>
      <td>50000.0</td>
      <td>45457.851480</td>
    </tr>
    <tr>
      <th>4997</th>
      <td>54997</td>
      <td>50000.0</td>
      <td>45457.024929</td>
    </tr>
    <tr>
      <th>4998</th>
      <td>54998</td>
      <td>50000.0</td>
      <td>45456.198407</td>
    </tr>
    <tr>
      <th>4999</th>
      <td>54999</td>
      <td>50000.0</td>
      <td>45455.371916</td>
    </tr>
  </tbody>
</table>
<p>5000 rows × 3 columns</p>
</div>




```python
# Carlos wants to increase the amount of Token X by 10% by trading X for Y
# He needs to bring into the pool x*(1-s_f) = 0.1*B_x
# x = (0.1*B_x) / (1-s_f)

# Diana: same result changing X for Y

# Ellen & Fabricio:

```

$$ A_i = B_i ((\frac{SP_{new}}{SP})^{(\frac{w_0}{w_0+w_i})})-1)$$

$$ A_i = B_i ((1.1*SP)^{(\frac{w_0}{w_0+w_i})})-1)$$


```python
A_i = Bc*((1.1)**(0.5)-1)
A_i
```




    2440.4424085075816




```python
2440.4424085075816/Bc
```




    0.04880884817015163



#### BE CAREFUL: WEIGHTS HAVE CHANGED NOW

#### SOLUTION 2. 

acting in the same direction:

- trading X for Y and increasing SP bringing X to the pool
- trading Y for X and increasing SP bringing Y to the pool

# Challenge No. 4

A user has $a$ **TKNA** and $b$ **TKNB**: 
The TKNA-TKNB pool has 50:50 weights, and reserves of TKNA and TKNB of m and n, respectively.  
The user wishes to perform a swap such that the ratio of TKNA:TKNB in their wallet is p:q 

$$\frac{a + x}{b + y} = \frac{p}{q}$$

#### 1. 
Assuming the user performs a swap between TKNA and TKNB on the TKNA-TKNB pool, derive an expression for x and y.

#### 2.
Using data or algebra, which is the best option to reduce slippage when trading X for Y:  
    a) finding a pool with the same invariant but a different X balance value,  
    b) finding a pool with a different weight on X,  
    c) or finding a pool with a different invariant value?  
    Justify your answer in any way you like,  
    and explain whether "different" should be "smaller" or "larger" here.

#### SOLUTION 1.

$$ x = \frac{p}{q} * (b+y) - a $$

Out-Given-In

$$ A_o = B_o * (1-(\frac{B_i}{B_i + A_i})^{(\frac{w_i}{w_o}})) = B_o * (1- \frac{B_i}{B_i + A_i}) = n * (1- \frac{m}{m + \frac{p}{q} * (b+y) - a}) = b$$

where $A_i = x$ and $A_o = y$

#### SOLUTION 2.

a) if the pools have he same invariant, the depth (and resistance to slippage is the same). The exact value of slippage can be calculated according to the balance point and here we can add that, if the number of tokens X is bigger in the second pool, the slippage would be smaller and if the number of tokens X is smaller, the slippage would be bigger
b) if the weight of X is bigger, the pool is more resistant to slippage, however, if the weight is smaller, the impact of a swap is bigger
c) a bigger invariatn value (comming from a bigger depth of the pool, a bigger amount of tokens X and tokens Y) makes the pool more resitant to slippage




c7a5a424e6233ef9e90b16030822d07a0715158b
ipynb
Jupyter Notebook
Math Challenges-Advanced.ipynb
bloxmove-com/Token_Engineering_Math_Challenge_All
73fbff799cc4aa31dbea95cc80e2345219864aa5
MIT
Math Challenges-Advanced.ipynb
bloxmove-com/Token_Engineering_Math_Challenge_All
73fbff799cc4aa31dbea95cc80e2345219864aa5
MIT
Math Challenges-Advanced.ipynb
bloxmove-com/Token_Engineering_Math_Challenge_All
73fbff799cc4aa31dbea95cc80e2345219864aa5
MIT
Qwen/Qwen-72B
1. YES
2. YES