@reserve-protocol/dtf-rebalance-lib 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/open-auction.d.ts +2 -2
- package/dist/open-auction.js +113 -103
- package/dist/start-rebalance.d.ts +2 -2
- package/dist/start-rebalance.js +16 -14
- package/package.json +2 -2
package/dist/open-auction.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { PriceRange, Rebalance, RebalanceLimits, WeightRange } from
|
1
|
+
import { PriceRange, Rebalance, RebalanceLimits, WeightRange } from "./types";
|
2
2
|
export declare enum AuctionRound {
|
3
3
|
EJECT = 0,
|
4
4
|
PROGRESS = 1,
|
@@ -59,4 +59,4 @@ export declare const getTargetBasket: (_initialWeights: WeightRange[], _prices:
|
|
59
59
|
* @param _priceError {1} Price error to use for each token during auction pricing; should be smaller than price error during startRebalance
|
60
60
|
* @param _finalStageAt {1} The % rebalanced from the initial Folio to determine when is the final stage of the rebalance
|
61
61
|
*/
|
62
|
-
export declare const getOpenAuction: (rebalance: Rebalance, _supply: bigint, _initialFolio: bigint[] | undefined, _targetBasket: bigint[] | undefined, _folio: bigint[], _decimals: bigint[], _prices: number[], _priceError: number[], _finalStageAt: number,
|
62
|
+
export declare const getOpenAuction: (rebalance: Rebalance, _supply: bigint, _initialFolio: bigint[] | undefined, _targetBasket: bigint[] | undefined, _folio: bigint[], _decimals: bigint[], _prices: number[], _priceError: number[], _finalStageAt: number, debug?: boolean) => [OpenAuctionArgs, AuctionMetrics];
|
package/dist/open-auction.js
CHANGED
@@ -27,17 +27,13 @@ var AuctionRound;
|
|
27
27
|
*/
|
28
28
|
const getTargetBasket = (_initialWeights, _prices, _decimals) => {
|
29
29
|
if (_initialWeights.length != _prices.length) {
|
30
|
-
throw new Error(
|
30
|
+
throw new Error("length mismatch");
|
31
31
|
}
|
32
32
|
const vals = _initialWeights.map((initialWeight, i) => {
|
33
33
|
const price = new decimal_js_light_1.default(_prices[i]);
|
34
34
|
const decimalScale = new decimal_js_light_1.default(`1e${_decimals[i]}`);
|
35
35
|
// {USD/wholeBU} = D27{tok/BU} * {BU/wholeBU} / {tok/wholeTok} / D27 * {USD/wholeTok}
|
36
|
-
return new decimal_js_light_1.default(initialWeight.spot.toString())
|
37
|
-
.mul(numbers_1.D18d)
|
38
|
-
.div(decimalScale)
|
39
|
-
.div(numbers_1.D27d)
|
40
|
-
.mul(price);
|
36
|
+
return new decimal_js_light_1.default(initialWeight.spot.toString()).mul(numbers_1.D18d).div(decimalScale).div(numbers_1.D27d).mul(price);
|
41
37
|
});
|
42
38
|
const totalValue = vals.reduce((a, b) => a.add(b));
|
43
39
|
// D18{1} = {USD/wholeBU} / {USD/wholeBU} * D18
|
@@ -59,19 +55,19 @@ exports.getTargetBasket = getTargetBasket;
|
|
59
55
|
* @param _priceError {1} Price error to use for each token during auction pricing; should be smaller than price error during startRebalance
|
60
56
|
* @param _finalStageAt {1} The % rebalanced from the initial Folio to determine when is the final stage of the rebalance
|
61
57
|
*/
|
62
|
-
const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket = [], _folio, _decimals, _prices, _priceError, _finalStageAt,
|
63
|
-
if (
|
64
|
-
console.log(
|
58
|
+
const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket = [], _folio, _decimals, _prices, _priceError, _finalStageAt, debug) => {
|
59
|
+
if (debug) {
|
60
|
+
console.log("getOpenAuction", rebalance, _supply, _initialFolio, _targetBasket, _folio, _decimals, _prices, _priceError, _finalStageAt);
|
65
61
|
}
|
66
62
|
if (rebalance.tokens.length != _targetBasket.length ||
|
67
63
|
_targetBasket.length != _folio.length ||
|
68
64
|
_folio.length != _decimals.length ||
|
69
65
|
_decimals.length != _prices.length ||
|
70
66
|
_prices.length != _priceError.length) {
|
71
|
-
throw new Error(
|
67
|
+
throw new Error("length mismatch");
|
72
68
|
}
|
73
69
|
if (_finalStageAt > 1) {
|
74
|
-
throw new Error(
|
70
|
+
throw new Error("finalStageAt must be less than 1");
|
75
71
|
}
|
76
72
|
// ================================================================
|
77
73
|
// {wholeShare} = {share} / {share/wholeShare}
|
@@ -96,18 +92,9 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
96
92
|
// {wholeTok/wholeBU} = D27{tok/BU} * {BU/wholeBU} / {tok/wholeTok} / D27
|
97
93
|
let weightRanges = rebalance.weights.map((range, i) => {
|
98
94
|
return {
|
99
|
-
low: new decimal_js_light_1.default(range.low.toString())
|
100
|
-
|
101
|
-
|
102
|
-
.div(numbers_1.D27d),
|
103
|
-
spot: new decimal_js_light_1.default(range.spot.toString())
|
104
|
-
.mul(numbers_1.D18d)
|
105
|
-
.div(decimalScale[i])
|
106
|
-
.div(numbers_1.D27d),
|
107
|
-
high: new decimal_js_light_1.default(range.high.toString())
|
108
|
-
.mul(numbers_1.D18d)
|
109
|
-
.div(decimalScale[i])
|
110
|
-
.div(numbers_1.D27d),
|
95
|
+
low: new decimal_js_light_1.default(range.low.toString()).mul(numbers_1.D18d).div(decimalScale[i]).div(numbers_1.D27d),
|
96
|
+
spot: new decimal_js_light_1.default(range.spot.toString()).mul(numbers_1.D18d).div(decimalScale[i]).div(numbers_1.D27d),
|
97
|
+
high: new decimal_js_light_1.default(range.high.toString()).mul(numbers_1.D18d).div(decimalScale[i]).div(numbers_1.D27d),
|
111
98
|
};
|
112
99
|
});
|
113
100
|
const finalStageAt = new decimal_js_light_1.default(_finalStageAt.toString());
|
@@ -115,15 +102,18 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
115
102
|
// calculate ideal spot limit, the actual BU<->share ratio
|
116
103
|
// {USD/wholeShare} = {wholeTok/wholeShare} * {USD/wholeTok}
|
117
104
|
const shareValue = folio
|
118
|
-
.map((f, i) =>
|
105
|
+
.map((f, i) => {
|
106
|
+
return rebalance.inRebalance[i] ? f.mul(prices[i]) : numbers_1.ZERO;
|
107
|
+
})
|
119
108
|
.reduce((a, b) => a.add(b));
|
120
109
|
// {USD/wholeBU} = {wholeTok/wholeBU} * {USD/wholeTok}
|
121
|
-
const buValue = weightRanges
|
122
|
-
|
123
|
-
.
|
124
|
-
|
125
|
-
|
126
|
-
|
110
|
+
const buValue = weightRanges.map((weightRange, i) => weightRange.spot.mul(prices[i])).reduce((a, b) => a.add(b));
|
111
|
+
if (debug) {
|
112
|
+
console.log("shareValue", shareValue.toString());
|
113
|
+
console.log("buValue", buValue.toString());
|
114
|
+
}
|
115
|
+
if (buValue.div(shareValue).gt(10) || shareValue.div(buValue).gt(100)) {
|
116
|
+
throw new Error("buValue and shareValue are too different");
|
127
117
|
}
|
128
118
|
// ================================================================
|
129
119
|
// calculate rebalanceTarget
|
@@ -135,7 +125,9 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
135
125
|
}
|
136
126
|
// {1} = {wholeTok/wholeShare} * {USD/wholeTok} / {USD/wholeShare}
|
137
127
|
const portionBeingEjected = ejectionIndices
|
138
|
-
.map((i) =>
|
128
|
+
.map((i) => {
|
129
|
+
return rebalance.inRebalance[i] ? folio[i].mul(prices[i]) : numbers_1.ZERO;
|
130
|
+
})
|
139
131
|
.reduce((a, b) => a.add(b), numbers_1.ZERO)
|
140
132
|
.div(shareValue);
|
141
133
|
// {1} = {USD/wholeShare} / {USD/wholeShare}
|
@@ -144,9 +136,7 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
144
136
|
// {wholeTok/wholeShare} = {USD/wholeShare} * {1} / {USD/wholeTok}
|
145
137
|
const balanceExpected = shareValue.mul(targetBasket[i]).div(prices[i]);
|
146
138
|
// {wholeTok/wholeShare} = {wholeTok/wholeBU} * {wholeBU/wholeShare}
|
147
|
-
const balanceInBU = balanceExpected.gt(actualBalance)
|
148
|
-
? actualBalance
|
149
|
-
: balanceExpected;
|
139
|
+
const balanceInBU = balanceExpected.gt(actualBalance) ? actualBalance : balanceExpected;
|
150
140
|
// {USD/wholeShare} = {wholeTok/wholeShare} * {USD/wholeTok}
|
151
141
|
return balanceInBU.mul(prices[i]);
|
152
142
|
})
|
@@ -158,9 +148,7 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
158
148
|
// {wholeTok/wholeShare} = {USD/wholeShare} * {1} / {USD/wholeTok}
|
159
149
|
const balanceExpected = shareValue.mul(targetBasket[i]).div(prices[i]);
|
160
150
|
// {wholeTok/wholeShare} = {wholeTok/wholeBU} * {wholeBU/wholeShare}
|
161
|
-
const balanceInBU = balanceExpected.gt(initialBalance)
|
162
|
-
? initialBalance
|
163
|
-
: balanceExpected;
|
151
|
+
const balanceInBU = balanceExpected.gt(initialBalance) ? initialBalance : balanceExpected;
|
164
152
|
// {USD/wholeShare} = {wholeTok/wholeShare} * {USD/wholeTok}
|
165
153
|
return balanceInBU.mul(prices[i]);
|
166
154
|
})
|
@@ -175,40 +163,45 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
175
163
|
: progression.sub(initialProgression).div(numbers_1.ONE.sub(initialProgression));
|
176
164
|
let rebalanceTarget = numbers_1.ONE;
|
177
165
|
let round = AuctionRound.FINAL;
|
178
|
-
if (
|
179
|
-
console.log(
|
180
|
-
console.log(
|
181
|
-
console.log(
|
182
|
-
console.log(
|
183
|
-
console.log(
|
166
|
+
if (debug) {
|
167
|
+
console.log("initialProgression", initialProgression.toString());
|
168
|
+
console.log("progression", progression.toString());
|
169
|
+
console.log("relativeProgression", relativeProgression.toString());
|
170
|
+
console.log("portionBeingEjected", portionBeingEjected.toString());
|
171
|
+
console.log("finalStageAt", finalStageAt.toString());
|
184
172
|
}
|
185
|
-
//
|
186
|
-
if (
|
187
|
-
round = AuctionRound.EJECT;
|
188
|
-
if (relativeProgression.lt(finalStageAt.sub(0.02))) {
|
189
|
-
rebalanceTarget = progression.add(portionBeingEjected.mul(1.1)); // set rebalanceTarget to 10% more than needed to ensure ejection completes
|
190
|
-
// do not finish trading yet
|
191
|
-
if (rebalanceTarget.gte(numbers_1.ONE)) {
|
192
|
-
rebalanceTarget = initialProgression.add(numbers_1.ONE.sub(initialProgression).mul(finalStageAt));
|
193
|
-
}
|
194
|
-
}
|
195
|
-
}
|
196
|
-
else if (relativeProgression.lt(finalStageAt.sub(0.02))) {
|
197
|
-
// wiggle room to prevent having to re-run an auction at the same stage after price movement
|
173
|
+
// approach finalStageAt first
|
174
|
+
if (progression.lt(0.99) && relativeProgression.lt(finalStageAt.sub(0.02))) {
|
198
175
|
round = AuctionRound.PROGRESS;
|
199
176
|
rebalanceTarget = initialProgression.add(numbers_1.ONE.sub(initialProgression).mul(finalStageAt));
|
177
|
+
if (numbers_1.ONE.sub(rebalanceTarget).lt(0.99)) {
|
178
|
+
rebalanceTarget = numbers_1.ONE;
|
179
|
+
}
|
200
180
|
if (rebalanceTarget.eq(numbers_1.ONE)) {
|
201
181
|
round = AuctionRound.FINAL;
|
202
182
|
}
|
203
183
|
}
|
204
|
-
|
205
|
-
|
184
|
+
// EJECT
|
185
|
+
if (portionBeingEjected.gt(0)) {
|
186
|
+
round = AuctionRound.EJECT;
|
187
|
+
// if the ejections are everything that's left, keep the finalStageAt targeting from above
|
188
|
+
if (progression.add(portionBeingEjected).lt(numbers_1.ONE)) {
|
189
|
+
// else: get rid of all the dust
|
190
|
+
let ejectionTarget = progression.add(portionBeingEjected.mul(1.02)); // buy 2% extra
|
191
|
+
if (ejectionTarget.gt(numbers_1.ONE)) {
|
192
|
+
ejectionTarget = numbers_1.ONE;
|
193
|
+
}
|
194
|
+
if (ejectionTarget.gt(rebalanceTarget)) {
|
195
|
+
rebalanceTarget = ejectionTarget;
|
196
|
+
}
|
197
|
+
}
|
206
198
|
}
|
207
|
-
if (rebalanceTarget.
|
208
|
-
|
199
|
+
if (rebalanceTarget.lte(numbers_1.ZERO) || rebalanceTarget.gt(numbers_1.ONE)) {
|
200
|
+
throw new Error("something has gone very wrong");
|
209
201
|
}
|
210
|
-
if (
|
211
|
-
console.log(
|
202
|
+
if (debug) {
|
203
|
+
console.log("round", round);
|
204
|
+
console.log("rebalanceTarget", rebalanceTarget.toString());
|
212
205
|
}
|
213
206
|
// {1}
|
214
207
|
const delta = numbers_1.ONE.sub(rebalanceTarget);
|
@@ -222,11 +215,21 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
222
215
|
spot: (0, numbers_1.bn)(spotLimit.mul(numbers_1.D18d)),
|
223
216
|
high: (0, numbers_1.bn)(spotLimit.add(spotLimit.mul(delta)).mul(numbers_1.D18d)),
|
224
217
|
};
|
225
|
-
|
226
|
-
|
227
|
-
|
218
|
+
// hold some surpluses aside if ejecting
|
219
|
+
if (round == AuctionRound.EJECT) {
|
220
|
+
// buy 0.1% more
|
221
|
+
newLimits.low += newLimits.low / 1000n;
|
222
|
+
// aim 1% higher
|
223
|
+
newLimits.spot += newLimits.spot / 100n;
|
228
224
|
// leave 10% room to increase low in the future if ejection leaves dust behind
|
229
|
-
newLimits.high += newLimits.high
|
225
|
+
newLimits.high += newLimits.high / 10n;
|
226
|
+
}
|
227
|
+
else if (round == AuctionRound.FINAL && progression.gt(0.999)) {
|
228
|
+
// if it's the final round and we're within 0.1%, buy 10% more than we need to
|
229
|
+
const delta = (0, numbers_1.bn)(numbers_1.ONE.sub(progression).mul(numbers_1.D18d).div(10));
|
230
|
+
newLimits.low += (newLimits.low * delta) / 10n ** 18n;
|
231
|
+
newLimits.spot += (newLimits.spot * delta) / 10n ** 18n;
|
232
|
+
newLimits.high += (newLimits.high * delta) / 10n ** 18n;
|
230
233
|
}
|
231
234
|
// low
|
232
235
|
if (newLimits.low < rebalance.limits.low) {
|
@@ -249,8 +252,8 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
249
252
|
if (newLimits.high > rebalance.limits.high) {
|
250
253
|
newLimits.high = rebalance.limits.high;
|
251
254
|
}
|
252
|
-
if (
|
253
|
-
console.log(
|
255
|
+
if (debug) {
|
256
|
+
console.log("newLimits", newLimits);
|
254
257
|
}
|
255
258
|
// ================================================================
|
256
259
|
// get new weights, constrained by extremes
|
@@ -263,10 +266,7 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
263
266
|
// D27{tok/BU}
|
264
267
|
const newWeights = rebalance.weights.map((weightRange, i) => {
|
265
268
|
// {wholeTok/wholeBU} = {USD/wholeShare} * {1} / {wholeBU/wholeShare} / {USD/wholeTok}
|
266
|
-
const idealWeight = shareValue
|
267
|
-
.mul(targetBasket[i])
|
268
|
-
.div(actualLimits.spot)
|
269
|
-
.div(prices[i]);
|
269
|
+
const idealWeight = shareValue.mul(targetBasket[i]).div(actualLimits.spot).div(prices[i]);
|
270
270
|
// D27{tok/BU} = {wholeTok/wholeBU} * D27 * {tok/wholeTok} / {BU/wholeBU}
|
271
271
|
const newWeightsD27 = {
|
272
272
|
low: (0, numbers_1.bn)(idealWeight
|
@@ -281,11 +281,21 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
281
281
|
.mul(decimalScale[i])
|
282
282
|
.div(numbers_1.D18d)),
|
283
283
|
};
|
284
|
-
|
285
|
-
|
286
|
-
|
284
|
+
// hold some surpluses aside if ejecting
|
285
|
+
if (round == AuctionRound.EJECT) {
|
286
|
+
// buy 0.1% more
|
287
|
+
newWeightsD27.low += newWeightsD27.low / 1000n;
|
288
|
+
// aim 1% higher
|
289
|
+
newWeightsD27.spot += newWeightsD27.spot / 100n;
|
287
290
|
// leave 10% room to increase low in the future if ejection leaves dust behind
|
288
|
-
newWeightsD27.high += newWeightsD27.high
|
291
|
+
newWeightsD27.high += newWeightsD27.high / 10n;
|
292
|
+
}
|
293
|
+
else if (round == AuctionRound.FINAL && progression.gt(0.999)) {
|
294
|
+
// if it's the final round and we're within 0.1%, buy 10% more than we need to
|
295
|
+
const delta = (0, numbers_1.bn)(numbers_1.ONE.sub(progression).mul(numbers_1.D18d).div(10));
|
296
|
+
newWeightsD27.low += (newWeightsD27.low * delta) / 10n ** 18n;
|
297
|
+
newWeightsD27.spot += (newWeightsD27.spot * delta) / 10n ** 18n;
|
298
|
+
newWeightsD27.high += (newWeightsD27.high * delta) / 10n ** 18n;
|
289
299
|
}
|
290
300
|
if (newWeightsD27.low < weightRange.low) {
|
291
301
|
newWeightsD27.low = weightRange.low;
|
@@ -307,8 +317,8 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
307
317
|
}
|
308
318
|
return newWeightsD27;
|
309
319
|
});
|
310
|
-
if (
|
311
|
-
console.log(
|
320
|
+
if (debug) {
|
321
|
+
console.log("newWeights", newWeights);
|
312
322
|
}
|
313
323
|
// ================================================================
|
314
324
|
// get new prices, constrained by extremes
|
@@ -317,7 +327,7 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
317
327
|
// revert if price out of bounds
|
318
328
|
const spotPrice = (0, numbers_1.bn)(prices[i].mul(numbers_1.D27d).div(decimalScale[i]));
|
319
329
|
if (spotPrice < initialPrice.low || spotPrice > initialPrice.high) {
|
320
|
-
throw new Error(
|
330
|
+
throw new Error("spot price out of bounds! auction launcher MUST closeRebalance to prevent loss!");
|
321
331
|
}
|
322
332
|
if (rebalance.priceControl == types_1.PriceControl.NONE) {
|
323
333
|
return initialPrice;
|
@@ -342,57 +352,57 @@ const getOpenAuction = (rebalance, _supply, _initialFolio = [], _targetBasket =
|
|
342
352
|
pricesD27.high = initialPrice.high;
|
343
353
|
}
|
344
354
|
if (pricesD27.low == pricesD27.high && priceError[i].gt(numbers_1.ZERO)) {
|
345
|
-
throw new Error(
|
355
|
+
throw new Error("no price range");
|
346
356
|
}
|
347
357
|
return pricesD27;
|
348
358
|
});
|
349
|
-
if (
|
350
|
-
console.log(
|
359
|
+
if (debug) {
|
360
|
+
console.log("newPrices", newPrices);
|
351
361
|
}
|
352
362
|
// ================================================================
|
353
363
|
// calculate metrics
|
354
364
|
// {USD} = {1} * {USD/wholeShare} * {wholeShare}
|
355
|
-
const valueBeingTraded = rebalanceTarget
|
356
|
-
.sub(progression)
|
357
|
-
.mul(shareValue)
|
358
|
-
.mul(supply);
|
365
|
+
const valueBeingTraded = rebalanceTarget.sub(progression).mul(shareValue).mul(supply);
|
359
366
|
const surplusTokens = [];
|
360
367
|
const deficitTokens = [];
|
361
368
|
// update Decimal weightRanges
|
362
369
|
// {wholeTok/wholeBU} = D27{tok/BU} * {BU/wholeBU} / {tok/wholeTok} / D27
|
363
370
|
weightRanges = newWeights.map((range, i) => {
|
364
371
|
return {
|
365
|
-
low: new decimal_js_light_1.default(range.low.toString())
|
366
|
-
|
367
|
-
|
368
|
-
.div(numbers_1.D27d),
|
369
|
-
spot: new decimal_js_light_1.default(range.spot.toString())
|
370
|
-
.mul(numbers_1.D18d)
|
371
|
-
.div(decimalScale[i])
|
372
|
-
.div(numbers_1.D27d),
|
373
|
-
high: new decimal_js_light_1.default(range.high.toString())
|
374
|
-
.mul(numbers_1.D18d)
|
375
|
-
.div(decimalScale[i])
|
376
|
-
.div(numbers_1.D27d),
|
372
|
+
low: new decimal_js_light_1.default(range.low.toString()).mul(numbers_1.D18d).div(decimalScale[i]).div(numbers_1.D27d),
|
373
|
+
spot: new decimal_js_light_1.default(range.spot.toString()).mul(numbers_1.D18d).div(decimalScale[i]).div(numbers_1.D27d),
|
374
|
+
high: new decimal_js_light_1.default(range.high.toString()).mul(numbers_1.D18d).div(decimalScale[i]).div(numbers_1.D27d),
|
377
375
|
};
|
378
376
|
});
|
379
377
|
rebalance.tokens.forEach((token, i) => {
|
380
378
|
// {wholeTok/wholeShare} = {wholeTok/wholeBU} * {wholeBU/wholeShare}
|
381
379
|
const buyUpTo = weightRanges[i].low.mul(actualLimits.low);
|
382
380
|
const sellDownTo = weightRanges[i].high.mul(actualLimits.high);
|
383
|
-
if (folio[i].lt(buyUpTo)) {
|
381
|
+
if (rebalance.inRebalance[i] && folio[i].lt(buyUpTo)) {
|
384
382
|
deficitTokens.push(token);
|
385
383
|
}
|
386
|
-
else if (folio[i].gt(sellDownTo)) {
|
384
|
+
else if (rebalance.inRebalance[i] && folio[i].gt(sellDownTo)) {
|
387
385
|
surplusTokens.push(token);
|
388
386
|
}
|
389
387
|
});
|
388
|
+
// ================================================================
|
389
|
+
// only return tokens that are in the rebalance
|
390
|
+
const returnTokens = [];
|
391
|
+
const returnWeights = [];
|
392
|
+
const returnPrices = [];
|
393
|
+
for (let i = 0; i < rebalance.tokens.length; i++) {
|
394
|
+
if (rebalance.inRebalance[i]) {
|
395
|
+
returnTokens.push(rebalance.tokens[i]);
|
396
|
+
returnWeights.push(newWeights[i]);
|
397
|
+
returnPrices.push(newPrices[i]);
|
398
|
+
}
|
399
|
+
}
|
390
400
|
return [
|
391
401
|
{
|
392
402
|
rebalanceNonce: rebalance.nonce,
|
393
|
-
tokens:
|
394
|
-
newWeights:
|
395
|
-
newPrices:
|
403
|
+
tokens: returnTokens,
|
404
|
+
newWeights: returnWeights,
|
405
|
+
newPrices: returnPrices,
|
396
406
|
newLimits: newLimits,
|
397
407
|
},
|
398
408
|
{
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { PriceRange, RebalanceLimits, WeightRange } from
|
1
|
+
import { PriceRange, RebalanceLimits, WeightRange } from "./types";
|
2
2
|
export interface StartRebalanceArgsPartial {
|
3
3
|
weights: WeightRange[];
|
4
4
|
prices: PriceRange[];
|
@@ -19,4 +19,4 @@ export interface StartRebalanceArgsPartial {
|
|
19
19
|
* @param _dtfPrice {USD/wholeShare} DTF price
|
20
20
|
* @param weightControl TRACKING=false, NATIVE=true
|
21
21
|
*/
|
22
|
-
export declare const getStartRebalance: (_supply: bigint, tokens: string[], _folio: bigint[], decimals: bigint[], _targetBasket: bigint[], _prices: number[], _priceError: number[], weightControl: boolean,
|
22
|
+
export declare const getStartRebalance: (_supply: bigint, tokens: string[], _folio: bigint[], decimals: bigint[], _targetBasket: bigint[], _prices: number[], _priceError: number[], weightControl: boolean, debug?: boolean) => StartRebalanceArgsPartial;
|
package/dist/start-rebalance.js
CHANGED
@@ -21,9 +21,9 @@ const numbers_1 = require("./numbers");
|
|
21
21
|
* @param _dtfPrice {USD/wholeShare} DTF price
|
22
22
|
* @param weightControl TRACKING=false, NATIVE=true
|
23
23
|
*/
|
24
|
-
const getStartRebalance = (_supply, tokens, _folio, decimals, _targetBasket, _prices, _priceError, weightControl,
|
25
|
-
if (
|
26
|
-
console.log(
|
24
|
+
const getStartRebalance = (_supply, tokens, _folio, decimals, _targetBasket, _prices, _priceError, weightControl, debug) => {
|
25
|
+
if (debug) {
|
26
|
+
console.log("getStartRebalance", _supply, tokens, _folio, decimals, _targetBasket, _prices, _priceError, weightControl);
|
27
27
|
}
|
28
28
|
// {wholeTok/wholeShare} = D18{tok/share} * {share/wholeShare} / {tok/wholeTok} / D18
|
29
29
|
const folio = _folio.map((c, i) => new decimal_js_light_1.default(c.toString()).div(new decimal_js_light_1.default(`1e${decimals[i]}`)));
|
@@ -43,24 +43,26 @@ const getStartRebalance = (_supply, tokens, _folio, decimals, _targetBasket, _pr
|
|
43
43
|
const newWeights = [];
|
44
44
|
const newPrices = [];
|
45
45
|
const newLimits = {
|
46
|
-
low: (0, numbers_1.bn)(
|
47
|
-
spot: (0, numbers_1.bn)(
|
48
|
-
high: (0, numbers_1.bn)(
|
46
|
+
low: (0, numbers_1.bn)("1e18"),
|
47
|
+
spot: (0, numbers_1.bn)("1e18"),
|
48
|
+
high: (0, numbers_1.bn)("1e18"),
|
49
49
|
};
|
50
50
|
// ================================================================
|
51
51
|
for (let i = 0; i < tokens.length; i++) {
|
52
52
|
if (priceError[i].gte(numbers_1.ONE)) {
|
53
|
-
throw new Error(
|
53
|
+
throw new Error("cannot defer prices");
|
54
54
|
}
|
55
55
|
// === newWeights ===
|
56
56
|
// {USD/wholeShare} = {wholeTok/wholeShare} * {USD/wholeTok}
|
57
|
-
const dtfPrice = folio
|
57
|
+
const dtfPrice = folio
|
58
|
+
.map((f, i) => f.mul(prices[i]))
|
59
|
+
.reduce((a, b) => a.add(b));
|
58
60
|
// {wholeTok/wholeShare} = {1} * {USD/wholeShare} / {USD/wholeTok}
|
59
61
|
const spotWeight = targetBasket[i].mul(dtfPrice).div(prices[i]);
|
60
62
|
// D27{tok/share}{wholeShare/wholeTok} = D27 * {tok/wholeTok} / {share/wholeShare}
|
61
63
|
const limitMultiplier = numbers_1.D27d.mul(new decimal_js_light_1.default(`1e${decimals[i]}`)).div(numbers_1.D18d);
|
62
|
-
if (
|
63
|
-
console.log(
|
64
|
+
if (debug) {
|
65
|
+
console.log("limitMultiplier", limitMultiplier.toString());
|
64
66
|
}
|
65
67
|
if (!weightControl) {
|
66
68
|
// D27{tok/BU} = {wholeTok/wholeShare} * D27{tok/share}{wholeShare/wholeTok} / {BU/share}
|
@@ -101,16 +103,16 @@ const getStartRebalance = (_supply, tokens, _folio, decimals, _targetBasket, _pr
|
|
101
103
|
.map((portion, i) => portion.mul(priceError[i]))
|
102
104
|
.reduce((a, b) => a.add(b));
|
103
105
|
if (totalPortion.gte(numbers_1.ONE)) {
|
104
|
-
throw new Error(
|
106
|
+
throw new Error("totalPortion > 1");
|
105
107
|
}
|
106
108
|
// D18{BU/share} = {1} * D18 * {BU/share}
|
107
109
|
newLimits.low = (0, numbers_1.bn)(numbers_1.ONE.div(numbers_1.ONE.add(totalPortion)).mul(numbers_1.D18d));
|
108
110
|
newLimits.high = (0, numbers_1.bn)(numbers_1.ONE.add(totalPortion).mul(numbers_1.D18d));
|
109
111
|
}
|
110
|
-
if (
|
112
|
+
if (debug) {
|
111
113
|
console.log("newWeights", newWeights);
|
112
|
-
console.log(
|
113
|
-
console.log(
|
114
|
+
console.log("newPrices", newPrices);
|
115
|
+
console.log("newLimits", newLimits);
|
114
116
|
}
|
115
117
|
return {
|
116
118
|
weights: newWeights,
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@reserve-protocol/dtf-rebalance-lib",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.4",
|
4
4
|
"description": "Rebalancing library for DTFs in typescript",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"module": "dist/index.js",
|
@@ -17,7 +17,7 @@
|
|
17
17
|
"prepublishOnly": "npm run build",
|
18
18
|
"test": "npm run test:unit && npm run test:e2e",
|
19
19
|
"test:unit": "node --test --require ts-node/register test/unit/*.test.ts",
|
20
|
-
"test:e2e": "hardhat test --bail"
|
20
|
+
"test:e2e": "hardhat test test/e2e/*.test.ts --bail"
|
21
21
|
},
|
22
22
|
"publishConfig": {
|
23
23
|
"access": "public"
|