@reyaxyz/common 0.364.1 → 0.364.3
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/README.md +1 -1
- package/dist/commands/exposure/command.js +2 -340
- package/dist/commands/exposure/command.js.map +1 -1
- package/dist/commands/exposure/types.js.map +1 -1
- package/dist/trading-api-types.js.map +1 -1
- package/dist/types/commands/exposure/command.d.ts +1 -44
- package/dist/types/commands/exposure/command.d.ts.map +1 -1
- package/dist/types/commands/exposure/types.d.ts +0 -10
- package/dist/types/commands/exposure/types.d.ts.map +1 -1
- package/dist/types/trading-api-types.d.ts +2 -51
- package/dist/types/trading-api-types.d.ts.map +1 -1
- package/dist/types/types.d.ts +0 -8
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils/calculate.d.ts +0 -125
- package/dist/types/utils/calculate.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/calculate.js +1 -324
- package/dist/utils/calculate.js.map +1 -1
- package/package.json +3 -5
- package/src/commands/exposure/command.ts +0 -550
- package/src/commands/exposure/types.ts +0 -12
- package/src/trading-api-types.ts +1 -66
- package/src/types.ts +0 -10
- package/src/utils/calculate.ts +0 -497
|
@@ -1,26 +1,21 @@
|
|
|
1
1
|
import BigNumber from 'bignumber.js';
|
|
2
|
-
import cloneDeep from 'lodash.clonedeep';
|
|
3
2
|
import {
|
|
4
3
|
AccountAssetBalance,
|
|
5
4
|
CollateralAddressToExchangePriceMap,
|
|
6
5
|
CollateralInfo,
|
|
7
6
|
ExchangeInfo,
|
|
8
|
-
ExposureCommandState,
|
|
9
7
|
MarginInfo,
|
|
10
8
|
MarketConfiguration,
|
|
11
9
|
MarketIdToOraclePriceMap,
|
|
12
|
-
MarketStorage,
|
|
13
10
|
PositionInfo,
|
|
14
11
|
PositionInfoMarketConfiguration,
|
|
15
12
|
RiskMatrix,
|
|
16
13
|
RiskMultipliersConfiguration,
|
|
17
|
-
EditCollateralAction,
|
|
18
14
|
} from './types';
|
|
19
15
|
import {
|
|
20
16
|
amountNormalizer,
|
|
21
17
|
MA_HEALTH_DANGER_THRESHOLD,
|
|
22
18
|
MA_HEALTH_WARNING_THRESHOLD,
|
|
23
|
-
POOL_IMR,
|
|
24
19
|
} from '../../utils';
|
|
25
20
|
|
|
26
21
|
export const MAX_FUNDING_RATE = BigNumber('0.07');
|
|
@@ -101,27 +96,6 @@ export class ExposureCommand {
|
|
|
101
96
|
this.collateralAddressToExchangePrice = collateralAddressToExchangePrice;
|
|
102
97
|
}
|
|
103
98
|
|
|
104
|
-
getState(): ExposureCommandState {
|
|
105
|
-
return {
|
|
106
|
-
accountId: this.accountId,
|
|
107
|
-
rootCollateralPoolId: this.rootCollateralPoolId,
|
|
108
|
-
oraclePricePerMarket: this.oraclePricePerMarket,
|
|
109
|
-
accountBalancePerAsset: this.accountBalancePerAsset,
|
|
110
|
-
groupedByCollateral: this.groupedByCollateral,
|
|
111
|
-
riskMultipliers: this.riskMultipliers,
|
|
112
|
-
riskMatrices: this.riskMatrices,
|
|
113
|
-
exchangeInfoPerAsset: this.exchangeInfoPerAsset,
|
|
114
|
-
positionInfoMarketConfiguration: this.positionInfoMarketConfiguration,
|
|
115
|
-
uniqueTokenAddresses: this.uniqueTokenAddresses,
|
|
116
|
-
uniqueQuoteCollaterals: this.uniqueQuoteCollaterals,
|
|
117
|
-
tokenMarginInfoPerAsset: this.tokenMarginInfoPerAsset,
|
|
118
|
-
realizedPnLSum: this.realizedPnLSum,
|
|
119
|
-
unrealizedPnLSum: this.unrealizedPnLSum,
|
|
120
|
-
mtmRpnlSum: this.mtmRpnlSum,
|
|
121
|
-
collateralAddressToExchangePrice: this.collateralAddressToExchangePrice,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
99
|
get getUsdNodeMarginInfo() {
|
|
126
100
|
return ExposureCommand.getUsdNodeMarginInfo(
|
|
127
101
|
this.rootCollateralPoolId,
|
|
@@ -134,273 +108,6 @@ export class ExposureCommand {
|
|
|
134
108
|
get balancePerAsset() {
|
|
135
109
|
return this.tokenMarginInfoPerAsset;
|
|
136
110
|
}
|
|
137
|
-
get exchangePricePerAsset() {
|
|
138
|
-
return this.exchangeInfoPerAsset;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
getUsdNodeMarginInfoPostTrade(
|
|
142
|
-
positionAmount: number,
|
|
143
|
-
collateralAddress: string,
|
|
144
|
-
marketConfiguration: MarketConfiguration,
|
|
145
|
-
riskBlockId: number,
|
|
146
|
-
) {
|
|
147
|
-
// perform deep copy of the object
|
|
148
|
-
const positionInfoMarketConfiguration: PositionInfoMarketConfiguration[] =
|
|
149
|
-
cloneDeep(this.positionInfoMarketConfiguration);
|
|
150
|
-
|
|
151
|
-
// Check if the market_id already exists in the array
|
|
152
|
-
const existingConfigIndex = positionInfoMarketConfiguration.findIndex(
|
|
153
|
-
(config) =>
|
|
154
|
-
config.market_id ===
|
|
155
|
-
BigNumber(String(marketConfiguration.market_id)).toNumber(),
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
if (existingConfigIndex !== -1) {
|
|
159
|
-
// If it exists, update the amount
|
|
160
|
-
positionInfoMarketConfiguration[existingConfigIndex].base = BigNumber(
|
|
161
|
-
positionInfoMarketConfiguration[existingConfigIndex].base,
|
|
162
|
-
).plus(positionAmount);
|
|
163
|
-
} else {
|
|
164
|
-
// If it doesn't exist, add a new element
|
|
165
|
-
positionInfoMarketConfiguration.push({
|
|
166
|
-
base: BigNumber(positionAmount),
|
|
167
|
-
realized_pnl: BigNumber(0),
|
|
168
|
-
realized_pnl_with_mtm: BigNumber(0),
|
|
169
|
-
realized_pnl_latest_snapshot: BigNumber(0),
|
|
170
|
-
latest_funding_cashflow: BigNumber(0),
|
|
171
|
-
last_price: BigNumber(0),
|
|
172
|
-
average_entry_price_off_chain_tracker: BigNumber(0),
|
|
173
|
-
funding_value_off_chain_tracker: BigNumber(0),
|
|
174
|
-
average_entry_price: BigNumber(0),
|
|
175
|
-
last_timestamp: BigNumber(0),
|
|
176
|
-
funding_value: BigNumber(0),
|
|
177
|
-
base_multiplier: BigNumber(0),
|
|
178
|
-
adl_unwind_price: BigNumber(0),
|
|
179
|
-
market_id: BigNumber(String(marketConfiguration.market_id)).toNumber(),
|
|
180
|
-
account_id: this.accountId,
|
|
181
|
-
market_configuration: marketConfiguration,
|
|
182
|
-
risk_block_id: riskBlockId,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const uniqueQuoteCollaterals = new Set(this.uniqueQuoteCollaterals);
|
|
187
|
-
uniqueQuoteCollaterals.add(collateralAddress);
|
|
188
|
-
|
|
189
|
-
const tokenMarginInfoPerAsset =
|
|
190
|
-
ExposureCommand.calculateTokenMarginInfoPerAsset(
|
|
191
|
-
this.groupedByCollateral,
|
|
192
|
-
this.rootCollateralPoolId,
|
|
193
|
-
this.riskMatrices,
|
|
194
|
-
this.riskMultipliers,
|
|
195
|
-
uniqueQuoteCollaterals,
|
|
196
|
-
this.realizedPnLSum,
|
|
197
|
-
this.unrealizedPnLSum,
|
|
198
|
-
positionInfoMarketConfiguration,
|
|
199
|
-
this.oraclePricePerMarket,
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
const uniqueTokenAddresses = [...this.uniqueTokenAddresses];
|
|
203
|
-
if (!this.uniqueTokenAddresses.includes(collateralAddress)) {
|
|
204
|
-
uniqueTokenAddresses.push(collateralAddress);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return {
|
|
208
|
-
usdNodeMarginInfo: ExposureCommand.getUsdNodeMarginInfo(
|
|
209
|
-
this.rootCollateralPoolId,
|
|
210
|
-
uniqueTokenAddresses,
|
|
211
|
-
this.exchangeInfoPerAsset,
|
|
212
|
-
tokenMarginInfoPerAsset,
|
|
213
|
-
),
|
|
214
|
-
tokenMarginInfoPerAsset: tokenMarginInfoPerAsset,
|
|
215
|
-
positionInfoMarketConfiguration: positionInfoMarketConfiguration,
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
getEditCollateralActionsToCoverMargin(
|
|
220
|
-
requiredMargin: number,
|
|
221
|
-
): EditCollateralAction[] {
|
|
222
|
-
/*
|
|
223
|
-
* Note, this function is implicitely making an assumption that required margin can be covered by
|
|
224
|
-
* the account without breaching account IMR
|
|
225
|
-
* */
|
|
226
|
-
const editCollateralActions: EditCollateralAction[] = [];
|
|
227
|
-
let marginToCover = requiredMargin;
|
|
228
|
-
|
|
229
|
-
const uniqueQuoteCollaterals = new Set(this.uniqueQuoteCollaterals);
|
|
230
|
-
|
|
231
|
-
const tokenMarginInfoPerAsset =
|
|
232
|
-
ExposureCommand.calculateTokenMarginInfoPerAsset(
|
|
233
|
-
this.groupedByCollateral,
|
|
234
|
-
this.rootCollateralPoolId,
|
|
235
|
-
this.riskMatrices,
|
|
236
|
-
this.riskMultipliers,
|
|
237
|
-
uniqueQuoteCollaterals,
|
|
238
|
-
this.realizedPnLSum,
|
|
239
|
-
this.unrealizedPnLSum,
|
|
240
|
-
this.positionInfoMarketConfiguration,
|
|
241
|
-
this.oraclePricePerMarket,
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// todo: p2: consider prioritising rUSD when looping through token infos & document math in comments
|
|
245
|
-
for (const tokenInfo of tokenMarginInfoPerAsset) {
|
|
246
|
-
if (tokenInfo.marginBalance < 0) {
|
|
247
|
-
continue;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// todo: p1: haircut and exchange rate adjustment should not be done for rUSD
|
|
251
|
-
// does exchangeInfo currently return haircut as zero and price as 1?
|
|
252
|
-
// todo: p2: can just look at net deposits rather than margin balance for non-rusd as non pnl
|
|
253
|
-
|
|
254
|
-
const exchangeInfo = this.exchangeInfoPerAsset.find((exchangeInfo) => {
|
|
255
|
-
return tokenInfo.assetAddress === exchangeInfo.tokenAddress;
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
if (!exchangeInfo) {
|
|
259
|
-
throw new Error(
|
|
260
|
-
'Unable to retrieve exchange info when calculating collaterals needed to cover margin',
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const marginBalanceWithHaircutInRUSD =
|
|
265
|
-
ExposureCommand.exchangeWithPriceHaircut(
|
|
266
|
-
tokenInfo.marginBalance,
|
|
267
|
-
exchangeInfo.price,
|
|
268
|
-
exchangeInfo.priceHaircut,
|
|
269
|
-
);
|
|
270
|
-
|
|
271
|
-
if (marginBalanceWithHaircutInRUSD > marginToCover) {
|
|
272
|
-
const collateralDelta =
|
|
273
|
-
-ExposureCommand.reverseExchangeWithPriceHaircut(
|
|
274
|
-
marginToCover,
|
|
275
|
-
exchangeInfo.price,
|
|
276
|
-
exchangeInfo.priceHaircut,
|
|
277
|
-
);
|
|
278
|
-
editCollateralActions.push({
|
|
279
|
-
collateralAddress: tokenInfo.assetAddress,
|
|
280
|
-
collateralDelta: collateralDelta,
|
|
281
|
-
});
|
|
282
|
-
break;
|
|
283
|
-
} else {
|
|
284
|
-
editCollateralActions.push({
|
|
285
|
-
collateralAddress: tokenInfo.assetAddress,
|
|
286
|
-
collateralDelta: -tokenInfo.marginBalance,
|
|
287
|
-
});
|
|
288
|
-
marginToCover = marginToCover - marginBalanceWithHaircutInRUSD;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return editCollateralActions;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
getUsdNodeMarginInfoPostEditCollaterals(
|
|
295
|
-
editCollateralActions: EditCollateralAction[],
|
|
296
|
-
) {
|
|
297
|
-
// todo: check if there's a way to simplify this function & deprecate the single edit collateral sim below as it's a
|
|
298
|
-
// subset of this function
|
|
299
|
-
|
|
300
|
-
// perform deep copy of the object
|
|
301
|
-
const groupedByCollateral: Record<string, AccountAssetBalance> = cloneDeep(
|
|
302
|
-
this.groupedByCollateral,
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
const uniqueQuoteCollaterals = new Set(this.uniqueQuoteCollaterals);
|
|
306
|
-
const uniqueTokenAddresses = [...this.uniqueTokenAddresses];
|
|
307
|
-
|
|
308
|
-
// counterfactual update deep copy
|
|
309
|
-
|
|
310
|
-
for (const action of editCollateralActions) {
|
|
311
|
-
if (groupedByCollateral[action.collateralAddress]) {
|
|
312
|
-
groupedByCollateral[action.collateralAddress] = {
|
|
313
|
-
...groupedByCollateral[action.collateralAddress],
|
|
314
|
-
amount:
|
|
315
|
-
groupedByCollateral[action.collateralAddress].amount +
|
|
316
|
-
action.collateralDelta,
|
|
317
|
-
};
|
|
318
|
-
} else {
|
|
319
|
-
groupedByCollateral[action.collateralAddress] = {
|
|
320
|
-
accountId: this.accountId,
|
|
321
|
-
collateral: action.collateralAddress,
|
|
322
|
-
amount: action.collateralDelta,
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
uniqueQuoteCollaterals.add(action.collateralAddress);
|
|
327
|
-
|
|
328
|
-
if (!this.uniqueTokenAddresses.includes(action.collateralAddress)) {
|
|
329
|
-
uniqueTokenAddresses.push(action.collateralAddress);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const tokenMarginInfoPerAsset =
|
|
334
|
-
ExposureCommand.calculateTokenMarginInfoPerAsset(
|
|
335
|
-
groupedByCollateral,
|
|
336
|
-
this.rootCollateralPoolId,
|
|
337
|
-
this.riskMatrices,
|
|
338
|
-
this.riskMultipliers,
|
|
339
|
-
uniqueQuoteCollaterals,
|
|
340
|
-
this.realizedPnLSum,
|
|
341
|
-
this.unrealizedPnLSum,
|
|
342
|
-
this.positionInfoMarketConfiguration,
|
|
343
|
-
this.oraclePricePerMarket,
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
return ExposureCommand.getUsdNodeMarginInfo(
|
|
347
|
-
this.rootCollateralPoolId,
|
|
348
|
-
uniqueTokenAddresses,
|
|
349
|
-
this.exchangeInfoPerAsset,
|
|
350
|
-
tokenMarginInfoPerAsset,
|
|
351
|
-
);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
getUsdNodeMarginInfoPostEditCollateral(
|
|
355
|
-
collateralDelta: number,
|
|
356
|
-
collateralAddress: string,
|
|
357
|
-
) {
|
|
358
|
-
// perform deep copy of the object
|
|
359
|
-
const groupedByCollateral: Record<string, AccountAssetBalance> = cloneDeep(
|
|
360
|
-
this.groupedByCollateral,
|
|
361
|
-
);
|
|
362
|
-
|
|
363
|
-
// counterfactual update deep copy
|
|
364
|
-
if (groupedByCollateral[collateralAddress]) {
|
|
365
|
-
groupedByCollateral[collateralAddress] = {
|
|
366
|
-
...groupedByCollateral[collateralAddress],
|
|
367
|
-
amount: groupedByCollateral[collateralAddress].amount + collateralDelta,
|
|
368
|
-
};
|
|
369
|
-
} else {
|
|
370
|
-
groupedByCollateral[collateralAddress] = {
|
|
371
|
-
accountId: this.accountId,
|
|
372
|
-
collateral: collateralAddress,
|
|
373
|
-
amount: collateralDelta,
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const uniqueQuoteCollaterals = new Set(this.uniqueQuoteCollaterals);
|
|
378
|
-
const tokenMarginInfoPerAsset =
|
|
379
|
-
ExposureCommand.calculateTokenMarginInfoPerAsset(
|
|
380
|
-
groupedByCollateral,
|
|
381
|
-
this.rootCollateralPoolId,
|
|
382
|
-
this.riskMatrices,
|
|
383
|
-
this.riskMultipliers,
|
|
384
|
-
uniqueQuoteCollaterals,
|
|
385
|
-
this.realizedPnLSum,
|
|
386
|
-
this.unrealizedPnLSum,
|
|
387
|
-
this.positionInfoMarketConfiguration,
|
|
388
|
-
this.oraclePricePerMarket,
|
|
389
|
-
);
|
|
390
|
-
|
|
391
|
-
const uniqueTokenAddresses = [...this.uniqueTokenAddresses];
|
|
392
|
-
if (!this.uniqueTokenAddresses.includes(collateralAddress)) {
|
|
393
|
-
uniqueTokenAddresses.push(collateralAddress);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
return ExposureCommand.getUsdNodeMarginInfo(
|
|
397
|
-
this.rootCollateralPoolId,
|
|
398
|
-
uniqueTokenAddresses,
|
|
399
|
-
this.exchangeInfoPerAsset,
|
|
400
|
-
tokenMarginInfoPerAsset,
|
|
401
|
-
);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
111
|
static calculateTokenMarginInfoPerAsset(
|
|
405
112
|
groupedByCollateral: Record<string, AccountAssetBalance>,
|
|
406
113
|
rootCollateralPoolId: number,
|
|
@@ -467,19 +174,6 @@ export class ExposureCommand {
|
|
|
467
174
|
return BigNumber.max(0, liquidationPrice);
|
|
468
175
|
}
|
|
469
176
|
|
|
470
|
-
static calculateImpliedLeverage(
|
|
471
|
-
notionalExposure: number,
|
|
472
|
-
oldIMR: number,
|
|
473
|
-
newIMR: number,
|
|
474
|
-
): number {
|
|
475
|
-
const changeInImr = BigNumber(newIMR).minus(oldIMR);
|
|
476
|
-
|
|
477
|
-
if (changeInImr.eq(0)) {
|
|
478
|
-
return 0;
|
|
479
|
-
}
|
|
480
|
-
return BigNumber(notionalExposure).div(changeInImr).toNumber();
|
|
481
|
-
}
|
|
482
|
-
|
|
483
177
|
static combineMarginInfo(
|
|
484
178
|
parentMarginInfo: MarginInfo,
|
|
485
179
|
sonMarginInfo: MarginInfo,
|
|
@@ -871,28 +565,6 @@ export class ExposureCommand {
|
|
|
871
565
|
return haircutPrice.multipliedBy(quantity).toNumber();
|
|
872
566
|
}
|
|
873
567
|
|
|
874
|
-
static reverseExchangeWithPriceHaircut(
|
|
875
|
-
quantity: number,
|
|
876
|
-
price: number,
|
|
877
|
-
haircut: number,
|
|
878
|
-
) {
|
|
879
|
-
/*
|
|
880
|
-
* this operation takes quantity in rUSD terms, price between collateral token (e.g. weth) and rusd
|
|
881
|
-
* alongside the haircut between weth and rusd
|
|
882
|
-
* it then returns a quantity in collateral token terms (e.g. weth) which would return quantity if it were to be
|
|
883
|
-
* passed through the exchangeWithPriceHaircut function
|
|
884
|
-
* */
|
|
885
|
-
// todo: p2: consider abstracting haircut price calculation into separate function as duplciated
|
|
886
|
-
// For positive quantities, the haircut is `quantity * (1 - haircut)`
|
|
887
|
-
// For negative values, the haircut is `quantity / (1 - haircut)` because a negative value means the haircut should be applied from B to A.
|
|
888
|
-
const calHelper = BigNumber(quantity).gt(0)
|
|
889
|
-
? BigNumber(1).minus(haircut)
|
|
890
|
-
: BigNumber(1).div(BigNumber(1).minus(haircut));
|
|
891
|
-
const haircutPrice = BigNumber(price).multipliedBy(calHelper);
|
|
892
|
-
|
|
893
|
-
return BigNumber(quantity).dividedBy(haircutPrice).toNumber();
|
|
894
|
-
}
|
|
895
|
-
|
|
896
568
|
static getBalanceWithHaircut(
|
|
897
569
|
exchangeInfoPerAsset: ExchangeInfo[],
|
|
898
570
|
assetAddress: string,
|
|
@@ -919,228 +591,6 @@ export class ExposureCommand {
|
|
|
919
591
|
);
|
|
920
592
|
}
|
|
921
593
|
|
|
922
|
-
getMaxExposure(
|
|
923
|
-
marketConfiguration: MarketConfiguration,
|
|
924
|
-
marketStorage: MarketStorage,
|
|
925
|
-
isPool: boolean,
|
|
926
|
-
) {
|
|
927
|
-
// todo: p2: cosider turning this into a hashmap vs. an array so that O(1) access
|
|
928
|
-
const riskMatrix = this.riskMatrices.find((riskMatrix) => {
|
|
929
|
-
return (
|
|
930
|
-
riskMatrix.risk_block_id ===
|
|
931
|
-
BigNumber(String(marketStorage.risk_block_id)).toNumber()
|
|
932
|
-
);
|
|
933
|
-
});
|
|
934
|
-
|
|
935
|
-
if (!riskMatrix) {
|
|
936
|
-
throw new Error("RiskMatrix Doesn't exist");
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
const riskMatrixIndex = BigNumber(
|
|
940
|
-
String(marketConfiguration.risk_matrix_index),
|
|
941
|
-
).toNumber();
|
|
942
|
-
|
|
943
|
-
let imrMultiplier;
|
|
944
|
-
if (isPool) {
|
|
945
|
-
imrMultiplier = POOL_IMR;
|
|
946
|
-
} else {
|
|
947
|
-
imrMultiplier = amountNormalizer(
|
|
948
|
-
String(this.riskMultipliers.im_multiplier),
|
|
949
|
-
).toNumber();
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
const marginInfo = this.tokenMarginInfoPerAsset.find((marginInfo) => {
|
|
953
|
-
return marginInfo.assetAddress === marketStorage.quote_collateral;
|
|
954
|
-
});
|
|
955
|
-
|
|
956
|
-
if (!marginInfo) {
|
|
957
|
-
throw new Error("marginInfo doesn't exist");
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
const exposures = ExposureCommand.getBlockExposures(
|
|
961
|
-
this.positionInfoMarketConfiguration,
|
|
962
|
-
this.oraclePricePerMarket,
|
|
963
|
-
BigNumber(String(marketStorage.risk_block_id)).toNumber(),
|
|
964
|
-
);
|
|
965
|
-
|
|
966
|
-
const { maxExposureShort, maxExposureLong } =
|
|
967
|
-
ExposureCommand.computeMaxExposures(
|
|
968
|
-
riskMatrix.matrix,
|
|
969
|
-
exposures,
|
|
970
|
-
marginInfo.liquidationMarginRequirement,
|
|
971
|
-
marginInfo.marginBalance < 0 ? 0 : marginInfo.marginBalance,
|
|
972
|
-
imrMultiplier,
|
|
973
|
-
riskMatrixIndex,
|
|
974
|
-
);
|
|
975
|
-
|
|
976
|
-
return {
|
|
977
|
-
maxExposureShort,
|
|
978
|
-
maxExposureLong,
|
|
979
|
-
exposures,
|
|
980
|
-
riskMatrixIndex,
|
|
981
|
-
};
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
static computeMaxExposures(
|
|
985
|
-
riskMatrix: BigNumber[][],
|
|
986
|
-
exposures: BigNumber[],
|
|
987
|
-
lmr: number,
|
|
988
|
-
balance: number,
|
|
989
|
-
imrMultiplier: number,
|
|
990
|
-
exposureIndex: number,
|
|
991
|
-
) {
|
|
992
|
-
let b = BigNumber(0);
|
|
993
|
-
|
|
994
|
-
for (let i = 0; i < exposures.length; i++) {
|
|
995
|
-
b = BigNumber(b).plus(
|
|
996
|
-
BigNumber(exposures[i]).multipliedBy(
|
|
997
|
-
BigNumber(riskMatrix[exposureIndex][i]).plus(
|
|
998
|
-
riskMatrix[i][exposureIndex],
|
|
999
|
-
),
|
|
1000
|
-
),
|
|
1001
|
-
);
|
|
1002
|
-
}
|
|
1003
|
-
const { x1, x2 } = this.solveQuadraticEquation(
|
|
1004
|
-
BigNumber(riskMatrix[exposureIndex][exposureIndex]).toNumber(), // changes here
|
|
1005
|
-
b.toNumber(),
|
|
1006
|
-
this.computeC(lmr, balance, imrMultiplier),
|
|
1007
|
-
);
|
|
1008
|
-
|
|
1009
|
-
const maxShortExposure = BigNumber(x1).plus(exposures[exposureIndex]);
|
|
1010
|
-
const maxLongExposure = BigNumber(x2).plus(exposures[exposureIndex]);
|
|
1011
|
-
|
|
1012
|
-
const availableShortExposure = maxShortExposure.lt(0)
|
|
1013
|
-
? maxShortExposure.negated().toNumber()
|
|
1014
|
-
: 0;
|
|
1015
|
-
|
|
1016
|
-
const availableLongExposure = maxLongExposure.gt(0)
|
|
1017
|
-
? maxLongExposure.toNumber()
|
|
1018
|
-
: 0;
|
|
1019
|
-
|
|
1020
|
-
return {
|
|
1021
|
-
maxExposureShort: availableShortExposure,
|
|
1022
|
-
maxExposureLong: availableLongExposure,
|
|
1023
|
-
};
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
static solveQuadraticEquation(a: number, b: number, c: number) {
|
|
1027
|
-
if (BigNumber(a).eq(0)) {
|
|
1028
|
-
throw new Error('ZeroQuadraticCoefficient');
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
const delta = BigNumber(b)
|
|
1032
|
-
.multipliedBy(b)
|
|
1033
|
-
.minus(BigNumber(4).multipliedBy(a).multipliedBy(c));
|
|
1034
|
-
|
|
1035
|
-
if (delta.lt(0)) {
|
|
1036
|
-
return {
|
|
1037
|
-
x1: BigNumber(0),
|
|
1038
|
-
x2: BigNumber(0),
|
|
1039
|
-
};
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
const rootDelta = delta.sqrt();
|
|
1043
|
-
|
|
1044
|
-
const x1 = BigNumber(b)
|
|
1045
|
-
.multipliedBy(-1)
|
|
1046
|
-
.minus(rootDelta)
|
|
1047
|
-
.div(BigNumber(2).multipliedBy(a));
|
|
1048
|
-
|
|
1049
|
-
const x2 = BigNumber(b)
|
|
1050
|
-
.multipliedBy(-1)
|
|
1051
|
-
.plus(rootDelta)
|
|
1052
|
-
.div(BigNumber(2).multipliedBy(a));
|
|
1053
|
-
|
|
1054
|
-
return {
|
|
1055
|
-
x1,
|
|
1056
|
-
x2,
|
|
1057
|
-
};
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
static computeC(lmr: number, balance: number, imrMultiplier: number): number {
|
|
1061
|
-
const lmrSD = BigNumber(lmr);
|
|
1062
|
-
const lmrSquared = lmrSD.multipliedBy(lmrSD);
|
|
1063
|
-
|
|
1064
|
-
const balanceSD = BigNumber(balance);
|
|
1065
|
-
const balanceSquared = balanceSD.multipliedBy(balanceSD);
|
|
1066
|
-
|
|
1067
|
-
const imrMultiplierSD = BigNumber(imrMultiplier);
|
|
1068
|
-
const imrMultiplierSquared = imrMultiplierSD.multipliedBy(imrMultiplierSD);
|
|
1069
|
-
|
|
1070
|
-
return lmrSquared
|
|
1071
|
-
.minus(balanceSquared.div(imrMultiplierSquared))
|
|
1072
|
-
.toNumber();
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
static calculateRebalancingOrderBase({
|
|
1076
|
-
poolBasePreTrade,
|
|
1077
|
-
orderBase,
|
|
1078
|
-
}: {
|
|
1079
|
-
poolBasePreTrade: number;
|
|
1080
|
-
orderBase: number;
|
|
1081
|
-
}): number {
|
|
1082
|
-
if (poolBasePreTrade > 0) {
|
|
1083
|
-
if (orderBase < 0) {
|
|
1084
|
-
return 0;
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
return Math.min(poolBasePreTrade, orderBase);
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
if (orderBase > 0) {
|
|
1091
|
-
return 0;
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
return Math.max(poolBasePreTrade, orderBase);
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
static calculateFee({
|
|
1098
|
-
oraclePrice,
|
|
1099
|
-
poolBasePreTrade,
|
|
1100
|
-
orderBase,
|
|
1101
|
-
feeParameter,
|
|
1102
|
-
rebalancingFeeParameter,
|
|
1103
|
-
}: {
|
|
1104
|
-
oraclePrice: number;
|
|
1105
|
-
poolBasePreTrade: number;
|
|
1106
|
-
orderBase: number;
|
|
1107
|
-
feeParameter: BigNumber;
|
|
1108
|
-
rebalancingFeeParameter: BigNumber;
|
|
1109
|
-
}): {
|
|
1110
|
-
rebalancingFee: number;
|
|
1111
|
-
imbalancingFee: number;
|
|
1112
|
-
fee: number;
|
|
1113
|
-
} {
|
|
1114
|
-
const rebalancingOrderBase = this.calculateRebalancingOrderBase({
|
|
1115
|
-
poolBasePreTrade,
|
|
1116
|
-
orderBase,
|
|
1117
|
-
});
|
|
1118
|
-
|
|
1119
|
-
const imbalancingOrderBase = orderBase - rebalancingOrderBase;
|
|
1120
|
-
|
|
1121
|
-
const imbalancingFee = BigNumber(oraclePrice)
|
|
1122
|
-
.times(imbalancingOrderBase)
|
|
1123
|
-
.times(feeParameter)
|
|
1124
|
-
.abs()
|
|
1125
|
-
.toNumber();
|
|
1126
|
-
|
|
1127
|
-
const rebalancingFee = BigNumber(oraclePrice)
|
|
1128
|
-
.times(rebalancingOrderBase)
|
|
1129
|
-
.times(rebalancingFeeParameter)
|
|
1130
|
-
.abs()
|
|
1131
|
-
.toNumber();
|
|
1132
|
-
|
|
1133
|
-
return {
|
|
1134
|
-
imbalancingFee,
|
|
1135
|
-
rebalancingFee,
|
|
1136
|
-
fee: imbalancingFee + rebalancingFee,
|
|
1137
|
-
};
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
|
-
static calculateEstimatedPrice(price: number, slippage: number): number {
|
|
1141
|
-
return BigNumber(price).times(BigNumber(1).plus(slippage)).toNumber();
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
594
|
static evaluateHealthStatus(marginRatioPercentage: number) {
|
|
1145
595
|
if (marginRatioPercentage >= MA_HEALTH_DANGER_THRESHOLD) {
|
|
1146
596
|
return 'danger';
|
|
@@ -15,8 +15,6 @@ export interface MarketConfiguration {
|
|
|
15
15
|
market_id: number;
|
|
16
16
|
risk_matrix_index: number;
|
|
17
17
|
max_open_base: number;
|
|
18
|
-
/** @deprecated Now sourced from Market.Data (MarketTrackers) */
|
|
19
|
-
velocity_multiplier: number;
|
|
20
18
|
minimum_order_base: number;
|
|
21
19
|
base_spacing: number;
|
|
22
20
|
price_spacing: number;
|
|
@@ -26,7 +24,6 @@ export interface MarketConfiguration {
|
|
|
26
24
|
dutch_config_min_base: number;
|
|
27
25
|
slippage_params_phi: number;
|
|
28
26
|
slippage_params_beta: number;
|
|
29
|
-
depth_factor: number;
|
|
30
27
|
block_timestamp: number;
|
|
31
28
|
block_number: number;
|
|
32
29
|
}
|
|
@@ -142,12 +139,3 @@ export type TradeSimulationState = {
|
|
|
142
139
|
exposureDataAccount: ExposureCommandState;
|
|
143
140
|
exposureDataPassivePool: ExposureCommandState;
|
|
144
141
|
};
|
|
145
|
-
|
|
146
|
-
export type EditCollateralSimulationState = {
|
|
147
|
-
exposureDataAccount: ExposureCommandState;
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
export type EditCollateralAction = {
|
|
151
|
-
collateralDelta: number;
|
|
152
|
-
collateralAddress: Lowercase<string>;
|
|
153
|
-
};
|