scifi
Search…
Real world rebalancing

# Initial token configuration

At the time of writing, the top ten ERC20 tokens by market cap are:
token
market-cap
price
relative-market-cap
percentage-value
units
raw-units
USDT
0xdac17f958d2ee523a2206206994597c13d831ec7
19000M
1
55.304
30
30.00000
30000000000000000000
0x514910771af9ca656af840dff83e8264ecf986ca
5000M
12
14.553
17
1.416666
1416666000000000000
USDC
0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
3000M
1
8.732
12
12.00000
12000000
WBTC
0x2260fac5e5542a773aa44fbcfedf7c193bc2c599
2000M
17000
5.821
9
0.000529
52900
CRO
0xa0b73e1ff0b80914ab6fe0444e65848c4c34450b
1370M
0.06
3.987
7
116.6666
11666660000
LEO
1330M
1.33
3.871
7
5.263157
5263157000000000000
DAI
0x6b175474e89094c44da98b954eedeac495271d0f
1020M
1
2.968
6
6.000000
6000000000000000000
HT
0x6f259637dcd74c767781e37bc6133cd6a68aa161
829M
4
2.413
5
1.250000
1250000000000000000
UNI
806M
3
2.346
5
1.666666
1666666000000000000
SPICE
0.42M
0.01
0.001
2
200.0000
200000000000000000000
The 10th token is not set by market cap, as SCIFI will always have 2.5% allocated to SPICE (2% used in this illustration), its governance token.
Note: The market cap and prices of the SPICE token are assumed to be stable at those values after trading in public exchanges.
Sum of market caps 34355.42

# Units computation

• Subtract 25.3% from USDT, to honor the 30% cap
• Add (25.3/9)% == 2.81 to every other token
Token
Percentage-value
USDT
30
17.363
USDC
11.542
WBTC
8.631
CRO
6.797
LEO
6.681
DAI
5.778
HT
5.223
UNI
5.156
SPICE
2.811
• Subtract 0.81 from SPICE so it goes to the target 2%
• Add (0.81/8)% ~= 0.1 to the 8 tokens below the 30% threshold
• Round the values to whole numbers
• Bump the lowest token that wouldn't change the order until the percentages add up to 100 again, or
• Decrease the highest token that wouldn't change the order until the percentages add up to 100 again
Token
Percentage-value
USDT
30
17
USDC
12
WBTC
9
CRO
7
LEO
7
DAI
6
HT
5
UNI
5
SPICE
2
Now we know how the index will be configured by value, and have to take into consideration the price of each token to compute the actual units.
For that, we divide the percentage of the index a token will have by its price:
Token
Price
Percentage-value
High-level-units
USDT
1
30
30.00000
12
17
1.416666
USDC
1
12
12.00000
WBTC
17000
9
0.000529
CRO
0.06
7
116.6666
LEO
1.33
7
5.263157
DAI
1
6
6.000000
HT
4
5
1.250000
UNI
3
5
1.666666
SPICE
0.01
2
200.0000
And then we should multiply those values by the decimals of each token:
Token
Price
Percentage-value
Units
Raw-units
USDT
1
30
30.00000
30000000000000000000
12
17
1.416666
1416666000000000000
USDC
1
12
12.00000
12000000
WBTC
17000
9
0.000529
52900
CRO
0.06
7
116.6666
11666660000
LEO
1.33
7
5.263157
5263157000000000000
DAI
1
6
6.000000
6000000000000000000
HT
4
5
1.250000
1250000000000000000
UNI
3
5
1.666666
1666666000000000000
SPICE
0.01
2
200.0000
200000000000000000000

# Rebalancing

When the prices of tokens change, but the units remain the same, the percentage by value of the token will deviate from the intended distribution.
For example, let's say a few very intense weeks have passed and now the prices and market caps of the different tokens look like this:
Token
Market-cap
Price
USDT
14000M
1
6000M
12
USDC
3000M
1
WBTC
2000M
14000
CRO
1370M
0.06
LEO
1330M
1.33
DAI
1920M
1
HT
829M
3
UNI
806M
3
SPICE
3.36M
0.08
There are two things to consider:
• The changes in price made the composition of the token change (in value, not in units) from the initial spec.
• The changes in market cap changed what the composition of the tokens (in units) should be, as per the algorithm defined in the paper.
First of all, let's see how the price changes changed composition of the token by value.
For that it's important to define the current percentage by value of a token in the index as units * marketValue
Token
Past-value
Current-value
USDT
30
30
17
17
USDC
12
12
WBTC
9
7.4
CRO
7
7
LEO
7
7
DAI
6
6
HT
5
3.75
UNI
5
5
SPICE
2
16
However, here we can see the values no longer add up to 100, but to a higher number (in this case 111.1).
This is because the index no longer has the value of U$100 initially determined, since the price of its components rose. Now we have to take into consideration the changes in market cap to see what composition the token should be rebalanced towards: Token Market-cap Price Market-cap-% Market-cap-%-corrected USDT 14000M 1 44.78801 30 LINK 6000M 12 19.19486 21 USDC 3000M 1 9.597432 11 WBTC 2000M 14000 6.398288 8 CRO 1370M 0.06 4.382827 6 LEO 1330M 1.33 4.254861 6 DAI 1920M 1 6.142356 8 HT 829M 3 2.652090 4 UNI 806M 3 2.578510 4 SPICE 3.36M 0.08 0.010749 2 The sum of market caps: 31258.36 This implies the token should have that composition by percentage, however this will not translate directly to composition in U$ dividing by the price, as now said magnitude shouldn't add up to 100, but to 111.1
The proper definiton of U$value by component would be: .. math:: 1 newUnit = \frac{correctedPercentage*\frac{newIndexLevel}{oldIndexLevel}}{currentPrice} Copied! That value is then divided by the price to obtain the units: Token Value-in-U$-per-index-unit
Price
Units
USDT
33.330
1
33.330000000
23.331
12
1.9442500000
USDC
12.221
1
12.221000000
WBTC
8.888
14000
0.0006348571
CRO
6.666
0.06
111.10000000
LEO
6.666
1.33
5.0120300751
DAI
8.888
1
8.8880000000
HT
4.444
3
1.4813333333
UNI
4.444
3
1.4813333333
SPICE
2.222
0.08
27.775000000
To wrap this point up, let's see the difference in units, what they're now vs what they should be:
Token
Units-current
Units-target
USDT
30.00000
33.330000000
1.416666
1.9442500000
USDC
12.00000
12.221000000
WBTC
0.000529
0.0006348571
CRO
116.6666
111.10000000
LEO
5.263157
5.0120300751
DAI
6.000000
8.8880000000
HT
1.250000
1.4813333333
UNI
1.666666
1.4813333333
SPICE
200.0000
27.775000000
And now, compute the amount to be traded (in USD) for each unit of the index token, defined as:
.. math::
1
Copied!
Positive ones should be sourceAmount parameters and negative ones minReturn
Token
U$-amount-to-trade USDT -3.330000000 LINK -6.3310080000 USDC -.221000000 WBTC -1.4819994000 CRO .3339960000 LEO .333998810117 DAI -2.8880000000 HT -.6939999999 UNI .5559980001 SPICE 13.77800000000 This amounts should always add up to zero, sans rounding errors, since trading should always be zero-sum. It's also worth noting that some value will be lost doing the rebalance to price slippage and exchange fees, so it might not be possible to get exactly the target units, and due to said fees it'd be harmful to try to get it too close. The worst case scenario would be having a script do trades until the difference between the target and current units is zero, so if this is automated special care would have to be taken. # Rebalancing operations The proposed rebalancing algorithm is as follows: • Divide the token list in those with a negative or a positive amount to trade Token U$-amount-to-trade
CRO
.3339960000
LEO
.333998810117
UNI
.5559980001
SPICE
13.77800000000
Token
U$-amount-to-trade USDT -3.330000000 LINK -6.3310080000 USDC -.221000000 WBTC -1.4819994000 DAI -2.8880000000 HT -.6939999999 • Sort both lists so the biggest value rebalances are at the top Token U$-amount-to-trade
SPICE
13.77800000000
UNI
.5559980001
LEO
.333998810117
CRO
.3339960000
Token
U$-amount-to-trade LINK -6.3310080000 USDT -3.330000000 DAI -2.8880000000 WBTC -1.4819994000 HT -.6939999999 USDC -.221000000 • Pick the top entries from both lists • Choose the minimum absolute value of the two as the amount to trade Source-token U$-amount-to-send
Target-token
U$-amount-to-receive SPICE 6.3310080000 LINK -6.3310080000 • If the amount to trade is higher than a preset threshold (U$1 per index unit with this example), continue with the next step. Otherwise, rebalance can be consider finished.
• Prepare to execute the trade. For this we'll need
• To convert both values to their units, from the amount in U$described above: 79.13760000000000000000 SPICE, 75.9720960000 LINK • To convert the units value to the raw units, using the token's decimals: 79137600000000000000 SPICE, 527584000000000000 LINK • To compute the minReturn amount taking into consideration the acceptable slippage (5% in this example): 501204800000000000 LINK • Execute the trade: node scripts/poc.js SYMBOL spiceAddress 79137600000000000000 linkAddress 501204800000000000 5 • With the values returned from the trade (not the parameters sent to it, since the transaction might have executed with a lower slippage than the worst-case 5%), update and re-sort the tables. For this example we assume a slippage of 2%. Token U$-amount-to-trade
SPICE
7.44699200000
UNI
.5559980001
LEO
.333998810117
CRO
.3339960000
Token
U$-amount-to-trade USDT -3.330000000 DAI -2.8880000000 WBTC -1.4819994000 HT -.6939999999 USDC -.221000000 LINK -.126620160000 .. TODO .. also, the value distribution and units should now look like: • Go back to picking the tokens with the most volume to trade: Source-token U$-amount-to-send
Target-token
U$-amount-to-receive SPICE 3.330000000 USDT 3.330000000 • Prepare to execute the trade: • High-level units: 41.62500000000000000000 SPICE, 3.33 USDT • Raw units: 41625000000000000000 SPICE, 3330000 USDT • minReturn, with 5% slippage: 3163500 USDT • Execute the trade: node scripts/poc.js SYMBOL spiceAddress 41625000000000000000 usdtAddress 3163500 5 • Update the tables (assuming slippage of 2%) Token U$-amount-to-trade
SPICE
4.11699200000
UNI
.5559980001
LEO
.333998810117
CRO
.3339960000
Token
U$-amount-to-trade DAI -2.8880000000 WBTC -1.4819994000 HT -.6939999999 USDC -.221000000 LINK -.126620160000 USDT -.06660000000 • Go back to picking the tokens with the most volume to trade: Source-token U$-amount-to-send
Target-token
U$-amount-to-receive SPICE 2.8880000000 DAI -2.8880000000 • Prepare to execute the trade: • High-level units value: 36.10000000000000000000 SPICE, 2.888 DAI • Raw units: 36100000000000000000 SPICE, 2880000 DAI • minReturn, with 5% slippage: 2736000 DAI • Execute the trade: node scripts/poc.js SYMBOL spiceAddress 36100000000000000000 daiAddress 2736000 5 • Update the tables. Only for the purposes of highlighting a possible scenario, let's assume a negative slippage of -3% (for the case where the trade executes at a rate better than expected) Token U$-amount-to-trade
SPICE
1.228992000000
UNI
.5559980001
LEO
.333998810117
CRO
.3339960000
DAI
.08664
Token
U$-amount-to-trade WBTC -1.4819994000 HT -.6939999999 USDC -.221000000 LINK -.126620160000 USDT -.06660000000 This is pretty inocuous, but it showcases that a token moved from the 'get more of' to the 'get rid of' list • Go back to picking the tokens with the most volume to trade: Source-token U$-amount-to-send
Target-token
U$-amount-to-receive SPICE 1.228992000000 WBTC 1.228992000000 • Prepare to execute the trade: • High-level units: 15.36240000000000000000 SPICE, .00008778514285714285 WBTC • Raw units: 15362400000000000000 SPICE, 8778 WBTC • minReturn, with 5% slippage: 8339 WBTC • Execute the trade: node scripts/poc.js SYMBOL spiceAddress 15362400000000000000 wbtcAddress 8339 5 • Update the tables (assuming slippage of 2%) Token U$-amount-to-trade
UNI
.5559980001
LEO
.333998810117
CRO
.3339960000
DAI
.08664
SPICE
0
Token
U$-amount-to-trade HT -.6939999999 USDC -.221000000 LINK -.126620160000 USDT -.06660000000 WBTC -.029639988000 • Go back to picking the tokens with the most volume to trade: Source-token U$-amount-to-send
Target-token
UNI
.5559980001
HT
.6939999999
But now the amount to trade per index unit is below our threshold, so we consider rebalancing finished.
Wrapping up, we sold:
1
79137600000000000000 + 41625000000000000000 + 36100000000000000000 + 15362400000000000000 == 172225000000000000000 SPICE
Copied!
and bought:
1
2
3330000 USDT
3
2880000 DAI
4
8778 WBTC
Copied!
So the token's raw units changed as following:
Token
Original-raw-units
New-raw-units
USDT
30000000000000000000
30000000000003330000
1416666000000000000
1944250000000000000
USDC
12000000
12000000
WBTC
52900
61678
CRO
11666660000
11666660000
LEO
5263157000000000000
5263157000000000000
DAI
6000000000000000000
6000000000002880000
HT
1250000000000000000
1250000000000000000
UNI
1666666000000000000
1666666000000000000
SPICE
200000000000000000000
27775000000000000000