@lifi/perps-sdk 15.0.0 → 17.0.0
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 +38 -0
- package/dist/cjs/client/PerpsClient.d.ts +7 -2
- package/dist/cjs/client/PerpsClient.d.ts.map +1 -1
- package/dist/cjs/client/PerpsClient.js +67 -11
- package/dist/cjs/client/PerpsClient.js.map +1 -1
- package/dist/cjs/index.d.ts +4 -5
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +6 -7
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/registry/assetRegistry.d.ts +2 -1
- package/dist/cjs/registry/assetRegistry.d.ts.map +1 -1
- package/dist/cjs/registry/assetRegistry.js +11 -1
- package/dist/cjs/registry/assetRegistry.js.map +1 -1
- package/dist/cjs/types/provider.d.ts +7 -2
- package/dist/cjs/types/provider.d.ts.map +1 -1
- package/dist/cjs/types/withdrawal.d.ts +2 -0
- package/dist/cjs/types/withdrawal.d.ts.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/websocket/decodeChain.d.ts +11 -0
- package/dist/cjs/websocket/decodeChain.d.ts.map +1 -0
- package/dist/cjs/websocket/decodeChain.js +37 -0
- package/dist/cjs/websocket/decodeChain.js.map +1 -0
- package/dist/esm/client/PerpsClient.d.ts +39 -10
- package/dist/esm/client/PerpsClient.d.ts.map +1 -1
- package/dist/esm/client/PerpsClient.js +109 -20
- package/dist/esm/client/PerpsClient.js.map +1 -1
- package/dist/esm/index.d.ts +4 -5
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/registry/assetRegistry.d.ts +7 -1
- package/dist/esm/registry/assetRegistry.d.ts.map +1 -1
- package/dist/esm/registry/assetRegistry.js +14 -0
- package/dist/esm/registry/assetRegistry.js.map +1 -1
- package/dist/esm/types/provider.d.ts +29 -7
- package/dist/esm/types/provider.d.ts.map +1 -1
- package/dist/esm/types/withdrawal.d.ts +12 -0
- package/dist/esm/types/withdrawal.d.ts.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/websocket/decodeChain.d.ts +30 -0
- package/dist/esm/websocket/decodeChain.d.ts.map +1 -0
- package/dist/esm/websocket/decodeChain.js +44 -0
- package/dist/esm/websocket/decodeChain.js.map +1 -0
- package/dist/types/client/PerpsClient.d.ts +39 -10
- package/dist/types/client/PerpsClient.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -5
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/registry/assetRegistry.d.ts +7 -1
- package/dist/types/registry/assetRegistry.d.ts.map +1 -1
- package/dist/types/types/provider.d.ts +29 -7
- package/dist/types/types/provider.d.ts.map +1 -1
- package/dist/types/types/withdrawal.d.ts +12 -0
- package/dist/types/types/withdrawal.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/websocket/decodeChain.d.ts +30 -0
- package/dist/types/websocket/decodeChain.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/client/PerpsClient.ts +146 -28
- package/src/index.ts +8 -7
- package/src/registry/assetRegistry.ts +16 -1
- package/src/types/provider.ts +34 -9
- package/src/types/withdrawal.ts +12 -0
- package/src/version.ts +1 -1
- package/src/websocket/decodeChain.ts +54 -0
- package/dist/cjs/utils/accountSummary.d.ts +0 -4
- package/dist/cjs/utils/accountSummary.d.ts.map +0 -1
- package/dist/cjs/utils/accountSummary.js +0 -35
- package/dist/cjs/utils/accountSummary.js.map +0 -1
- package/dist/cjs/utils/transferMargin.d.ts +0 -7
- package/dist/cjs/utils/transferMargin.d.ts.map +0 -1
- package/dist/cjs/utils/transferMargin.js +0 -50
- package/dist/cjs/utils/transferMargin.js.map +0 -1
- package/dist/esm/utils/accountSummary.d.ts +0 -32
- package/dist/esm/utils/accountSummary.d.ts.map +0 -1
- package/dist/esm/utils/accountSummary.js +0 -46
- package/dist/esm/utils/accountSummary.js.map +0 -1
- package/dist/esm/utils/transferMargin.d.ts +0 -24
- package/dist/esm/utils/transferMargin.d.ts.map +0 -1
- package/dist/esm/utils/transferMargin.js +0 -56
- package/dist/esm/utils/transferMargin.js.map +0 -1
- package/dist/types/utils/accountSummary.d.ts +0 -32
- package/dist/types/utils/accountSummary.d.ts.map +0 -1
- package/dist/types/utils/transferMargin.d.ts +0 -24
- package/dist/types/utils/transferMargin.d.ts.map +0 -1
- package/src/utils/accountSummary.ts +0 -90
- package/src/utils/transferMargin.ts +0 -98
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.summarizeAccount = summarizeAccount;
|
|
4
|
-
const parse_js_1 = require("./parse.js");
|
|
5
|
-
const sumValueUsd = (balances) => balances.reduce((sum, b) => sum + (0, parse_js_1.stringToFloat)(b.valueUsd), 0);
|
|
6
|
-
const sumMarginUsd = (balances) => balances.reduce((sum, b) => sum + (0, parse_js_1.stringToFloat)(b.valueUsd) * (b.collateralWeight ?? 1), 0);
|
|
7
|
-
function summarizeAccount(account, positions, semantics) {
|
|
8
|
-
let marginUsed = 0;
|
|
9
|
-
let unrealizedPnl = 0;
|
|
10
|
-
for (const p of positions) {
|
|
11
|
-
marginUsed += (0, parse_js_1.stringToFloat)(p.marginUsed);
|
|
12
|
-
unrealizedPnl += (0, parse_js_1.stringToFloat)(p.unrealizedPnl);
|
|
13
|
-
}
|
|
14
|
-
const collateral = sumValueUsd(account.collateralBalances);
|
|
15
|
-
const marginCollateral = sumMarginUsd(account.collateralBalances);
|
|
16
|
-
const balances = sumValueUsd(account.balances);
|
|
17
|
-
const withLocked = semantics === 'free' || semantics === 'net';
|
|
18
|
-
const grossCollateral = withLocked ? collateral + marginUsed : collateral;
|
|
19
|
-
const grossMarginCollateral = withLocked
|
|
20
|
-
? marginCollateral + marginUsed
|
|
21
|
-
: marginCollateral;
|
|
22
|
-
const equity = semantics === 'equity' || semantics === 'net'
|
|
23
|
-
? grossCollateral
|
|
24
|
-
: grossCollateral + unrealizedPnl;
|
|
25
|
-
const availableMargin = grossMarginCollateral +
|
|
26
|
-
(semantics === 'gross' ? unrealizedPnl : 0) -
|
|
27
|
-
marginUsed;
|
|
28
|
-
return {
|
|
29
|
-
portfolioValue: (balances + equity).toString(),
|
|
30
|
-
availableMargin: availableMargin.toString(),
|
|
31
|
-
marginUsed: marginUsed.toString(),
|
|
32
|
-
unrealizedPnl: unrealizedPnl.toString(),
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
//# sourceMappingURL=accountSummary.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"accountSummary.js","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":";;AA8CA,4CA2CC;AApFD,yCAA0C;AAE1C,MAAM,WAAW,GAAG,CAAC,QAAqC,EAAU,EAAE,CACpE,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAA,wBAAa,EAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;AAEjE,MAAM,YAAY,GAAG,CAAC,QAAqC,EAAU,EAAE,CACrE,QAAQ,CAAC,MAAM,CACb,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,IAAA,wBAAa,EAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,EACvE,CAAC,CACF,CAAA;AAgCH,SAAgB,gBAAgB,CAC9B,OAAwB,EACxB,SAAqB,EACrB,SAA8B;IAE9B,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,UAAU,IAAI,IAAA,wBAAa,EAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QACzC,aAAa,IAAI,IAAA,wBAAa,EAAC,CAAC,CAAC,aAAa,CAAC,CAAA;IACjD,CAAC;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAI1D,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACjE,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE9C,MAAM,UAAU,GAAG,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,KAAK,CAAA;IAC9D,MAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAA;IACzE,MAAM,qBAAqB,GAAG,UAAU;QACtC,CAAC,CAAC,gBAAgB,GAAG,UAAU;QAC/B,CAAC,CAAC,gBAAgB,CAAA;IACpB,MAAM,MAAM,GACV,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,KAAK;QAC3C,CAAC,CAAC,eAAe;QACjB,CAAC,CAAC,eAAe,GAAG,aAAa,CAAA;IAKrC,MAAM,eAAe,GACnB,qBAAqB;QACrB,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,UAAU,CAAA;IAEZ,OAAO;QACL,cAAc,EAAE,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,QAAQ,EAAE;QAC9C,eAAe,EAAE,eAAe,CAAC,QAAQ,EAAE;QAC3C,UAAU,EAAE,UAAU,CAAC,QAAQ,EAAE;QACjC,aAAa,EAAE,aAAa,CAAC,QAAQ,EAAE;KACxC,CAAA;AACH,CAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type Position, type PositionMarginConstraints } from '@lifi/perps-types';
|
|
2
|
-
export interface RemovableIsolatedMarginParams {
|
|
3
|
-
position: Position;
|
|
4
|
-
constraints: PositionMarginConstraints;
|
|
5
|
-
}
|
|
6
|
-
export declare function removableIsolatedMargin({ position, constraints, }: RemovableIsolatedMarginParams): string;
|
|
7
|
-
//# sourceMappingURL=transferMargin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transferMargin.d.ts","sourceRoot":"","sources":["../../../src/utils/transferMargin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,yBAAyB,EAE/B,MAAM,mBAAmB,CAAA;AAyC1B,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,QAAQ,CAAA;IAClB,WAAW,EAAE,yBAAyB,CAAA;CACvC;AAcD,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,WAAW,GACZ,EAAE,6BAA6B,GAAG,MAAM,CA+BxC"}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.removableIsolatedMargin = removableIsolatedMargin;
|
|
7
|
-
const perps_types_1 = require("@lifi/perps-types");
|
|
8
|
-
const big_js_1 = __importDefault(require("big.js"));
|
|
9
|
-
const PerpsError_js_1 = require("../errors/PerpsError.js");
|
|
10
|
-
function positionAmount(value, field) {
|
|
11
|
-
try {
|
|
12
|
-
return new big_js_1.default(value);
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
throw new PerpsError_js_1.PerpsError(perps_types_1.PerpsErrorCode.ValidationError, `Invalid decimal string on Position.${field}: '${value}'`);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function constraintAmount(value, field) {
|
|
19
|
-
try {
|
|
20
|
-
return new big_js_1.default(value);
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
throw new PerpsError_js_1.PerpsError(perps_types_1.PerpsErrorCode.ValidationError, `Invalid decimal string on PositionMarginConstraints.${field}: '${value}'`);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function requirePositive(value, field) {
|
|
27
|
-
if (value.lte(0)) {
|
|
28
|
-
throw new PerpsError_js_1.PerpsError(perps_types_1.PerpsErrorCode.ValidationError, `${field} must be greater than zero.`);
|
|
29
|
-
}
|
|
30
|
-
return value;
|
|
31
|
-
}
|
|
32
|
-
function removableIsolatedMargin({ position, constraints, }) {
|
|
33
|
-
if (!(0, perps_types_1.positionSupportsMarginRemoval)(position)) {
|
|
34
|
-
return '0';
|
|
35
|
-
}
|
|
36
|
-
const marginUsed = requirePositive(positionAmount(position.marginUsed, 'marginUsed'), 'Position.marginUsed');
|
|
37
|
-
const unrealizedPnl = positionAmount(position.unrealizedPnl, 'unrealizedPnl');
|
|
38
|
-
const minimumMargin = requirePositive(constraintAmount(constraints.minimumMarginRequirement, 'minimumMarginRequirement'), 'PositionMarginConstraints.minimumMarginRequirement');
|
|
39
|
-
const amountIncrement = requirePositive(constraintAmount(constraints.amountIncrement, 'amountIncrement'), 'PositionMarginConstraints.amountIncrement');
|
|
40
|
-
const removable = marginUsed.plus(unrealizedPnl).minus(minimumMargin);
|
|
41
|
-
if (removable.lte(0)) {
|
|
42
|
-
return '0';
|
|
43
|
-
}
|
|
44
|
-
return removable
|
|
45
|
-
.div(amountIncrement)
|
|
46
|
-
.round(0, big_js_1.default.roundDown)
|
|
47
|
-
.times(amountIncrement)
|
|
48
|
-
.toFixed();
|
|
49
|
-
}
|
|
50
|
-
//# sourceMappingURL=transferMargin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transferMargin.js","sourceRoot":"","sources":["../../../src/utils/transferMargin.ts"],"names":[],"mappings":";;;;;AA+DA,0DAkCC;AAjGD,mDAK0B;AAC1B,oDAAwB;AACxB,2DAAoD;AAEpD,SAAS,cAAc,CAAC,KAAa,EAAE,KAAa;IAClD,IAAI,CAAC;QACH,OAAO,IAAI,gBAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,0BAAU,CAClB,4BAAc,CAAC,eAAe,EAC9B,sCAAsC,KAAK,MAAM,KAAK,GAAG,CAC1D,CAAA;IACH,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa,EAAE,KAAa;IACpD,IAAI,CAAC;QACH,OAAO,IAAI,gBAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,0BAAU,CAClB,4BAAc,CAAC,eAAe,EAC9B,uDAAuD,KAAK,MAAM,KAAK,GAAG,CAC3E,CAAA;IACH,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAU,EAAE,KAAa;IAChD,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACjB,MAAM,IAAI,0BAAU,CAClB,4BAAc,CAAC,eAAe,EAC9B,GAAG,KAAK,6BAA6B,CACtC,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAwBD,SAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,WAAW,GACmB;IAC9B,IAAI,CAAC,IAAA,2CAA6B,EAAC,QAAQ,CAAC,EAAE,CAAC;QAC7C,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,MAAM,UAAU,GAAG,eAAe,CAChC,cAAc,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,EACjD,qBAAqB,CACtB,CAAA;IACD,MAAM,aAAa,GAAG,cAAc,CAAC,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC,CAAA;IAC7E,MAAM,aAAa,GAAG,eAAe,CACnC,gBAAgB,CACd,WAAW,CAAC,wBAAwB,EACpC,0BAA0B,CAC3B,EACD,oDAAoD,CACrD,CAAA;IACD,MAAM,eAAe,GAAG,eAAe,CACrC,gBAAgB,CAAC,WAAW,CAAC,eAAe,EAAE,iBAAiB,CAAC,EAChE,2CAA2C,CAC5C,CAAA;IAED,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;IACrE,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,OAAO,SAAS;SACb,GAAG,CAAC,eAAe,CAAC;SACpB,KAAK,CAAC,CAAC,EAAE,gBAAG,CAAC,SAAS,CAAC;SACvB,KAAK,CAAC,eAAe,CAAC;SACtB,OAAO,EAAE,CAAA;AACd,CAAC"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { AccountResponse, AccountSummary, Position } from '@lifi/perps-types';
|
|
2
|
-
/**
|
|
3
|
-
* What the summed `collateralBalances` rows already contain, relative to the
|
|
4
|
-
* positions' locked margin and unrealized PnL:
|
|
5
|
-
*
|
|
6
|
-
* - `'free'` — free collateral only; locked margin and unrealized PnL are
|
|
7
|
-
* both carried by the positions. Available margin is the free collateral
|
|
8
|
-
* as-is; unrealized PnL is not counted toward it.
|
|
9
|
-
* - `'net'` — free collateral with unrealized PnL already marked in; only
|
|
10
|
-
* the locked margin is carried by the positions (e.g. a venue-reported
|
|
11
|
-
* available balance).
|
|
12
|
-
* - `'gross'` — locked margin included, unrealized PnL carried by the
|
|
13
|
-
* positions (e.g. spot holdings backing a unified account). The venue
|
|
14
|
-
* counts unrealized PnL toward buying power, so it is added to available
|
|
15
|
-
* margin on top of the gross collateral.
|
|
16
|
-
* - `'equity'` — total equity: locked margin AND unrealized PnL included
|
|
17
|
-
* (e.g. a venue-reported account value). Unrealized PnL is thus already
|
|
18
|
-
* counted toward available margin.
|
|
19
|
-
*
|
|
20
|
-
* @public
|
|
21
|
-
*/
|
|
22
|
-
export type CollateralSemantics = 'free' | 'net' | 'gross' | 'equity';
|
|
23
|
-
/**
|
|
24
|
-
* Roll an {@link AccountResponse} and its open positions up into an
|
|
25
|
-
* {@link AccountSummary}.
|
|
26
|
-
*
|
|
27
|
-
* @param semantics - How the collateral rows relate to the positions'
|
|
28
|
-
* locked margin and unrealized PnL; see {@link CollateralSemantics}.
|
|
29
|
-
* @public
|
|
30
|
-
*/
|
|
31
|
-
export declare function summarizeAccount(account: AccountResponse, positions: Position[], semantics: CollateralSemantics): AccountSummary;
|
|
32
|
-
//# sourceMappingURL=accountSummary.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"accountSummary.d.ts","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,QAAQ,EACT,MAAM,mBAAmB,CAAA;AAY1B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAErE;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,EAAE,mBAAmB,GAC7B,cAAc,CAuChB"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { stringToFloat } from './parse.js';
|
|
2
|
-
const sumValueUsd = (balances) => balances.reduce((sum, b) => sum + stringToFloat(b.valueUsd), 0);
|
|
3
|
-
const sumMarginUsd = (balances) => balances.reduce((sum, b) => sum + stringToFloat(b.valueUsd) * (b.collateralWeight ?? 1), 0);
|
|
4
|
-
/**
|
|
5
|
-
* Roll an {@link AccountResponse} and its open positions up into an
|
|
6
|
-
* {@link AccountSummary}.
|
|
7
|
-
*
|
|
8
|
-
* @param semantics - How the collateral rows relate to the positions'
|
|
9
|
-
* locked margin and unrealized PnL; see {@link CollateralSemantics}.
|
|
10
|
-
* @public
|
|
11
|
-
*/
|
|
12
|
-
export function summarizeAccount(account, positions, semantics) {
|
|
13
|
-
let marginUsed = 0;
|
|
14
|
-
let unrealizedPnl = 0;
|
|
15
|
-
for (const p of positions) {
|
|
16
|
-
marginUsed += stringToFloat(p.marginUsed);
|
|
17
|
-
unrealizedPnl += stringToFloat(p.unrealizedPnl);
|
|
18
|
-
}
|
|
19
|
-
const collateral = sumValueUsd(account.collateralBalances);
|
|
20
|
-
// Margin-eligible collateral: each row's value scaled by its loan-to-value
|
|
21
|
-
// weight (1 when unset), so a haircut asset backs buying power at less than
|
|
22
|
-
// face while `portfolioValue` still reflects its full value.
|
|
23
|
-
const marginCollateral = sumMarginUsd(account.collateralBalances);
|
|
24
|
-
const balances = sumValueUsd(account.balances);
|
|
25
|
-
const withLocked = semantics === 'free' || semantics === 'net';
|
|
26
|
-
const grossCollateral = withLocked ? collateral + marginUsed : collateral;
|
|
27
|
-
const grossMarginCollateral = withLocked
|
|
28
|
-
? marginCollateral + marginUsed
|
|
29
|
-
: marginCollateral;
|
|
30
|
-
const equity = semantics === 'equity' || semantics === 'net'
|
|
31
|
-
? grossCollateral
|
|
32
|
-
: grossCollateral + unrealizedPnl;
|
|
33
|
-
// Buying power is equity net of locked margin, so unrealized PnL counts
|
|
34
|
-
// toward it. The `'free'` rows exclude uPnL from available margin, holding
|
|
35
|
-
// it purely as free collateral.
|
|
36
|
-
const availableMargin = grossMarginCollateral +
|
|
37
|
-
(semantics === 'gross' ? unrealizedPnl : 0) -
|
|
38
|
-
marginUsed;
|
|
39
|
-
return {
|
|
40
|
-
portfolioValue: (balances + equity).toString(),
|
|
41
|
-
availableMargin: availableMargin.toString(),
|
|
42
|
-
marginUsed: marginUsed.toString(),
|
|
43
|
-
unrealizedPnl: unrealizedPnl.toString(),
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=accountSummary.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"accountSummary.js","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,MAAM,WAAW,GAAG,CAAC,QAAqC,EAAU,EAAE,CACpE,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAA;AAEjE,MAAM,YAAY,GAAG,CAAC,QAAqC,EAAU,EAAE,CACrE,QAAQ,CAAC,MAAM,CACb,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,CAAC,EACvE,CAAC,CACF,CAAA;AAwBH;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAwB,EACxB,SAAqB,EACrB,SAA8B;IAE9B,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,aAAa,GAAG,CAAC,CAAA;IACrB,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,UAAU,IAAI,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;QACzC,aAAa,IAAI,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAA;IACjD,CAAC;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC1D,2EAA2E;IAC3E,4EAA4E;IAC5E,6DAA6D;IAC7D,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IACjE,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE9C,MAAM,UAAU,GAAG,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,KAAK,CAAA;IAC9D,MAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAA;IACzE,MAAM,qBAAqB,GAAG,UAAU;QACtC,CAAC,CAAC,gBAAgB,GAAG,UAAU;QAC/B,CAAC,CAAC,gBAAgB,CAAA;IACpB,MAAM,MAAM,GACV,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,KAAK;QAC3C,CAAC,CAAC,eAAe;QACjB,CAAC,CAAC,eAAe,GAAG,aAAa,CAAA;IAErC,wEAAwE;IACxE,2EAA2E;IAC3E,gCAAgC;IAChC,MAAM,eAAe,GACnB,qBAAqB;QACrB,CAAC,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,UAAU,CAAA;IAEZ,OAAO;QACL,cAAc,EAAE,CAAC,QAAQ,GAAG,MAAM,CAAC,CAAC,QAAQ,EAAE;QAC9C,eAAe,EAAE,eAAe,CAAC,QAAQ,EAAE;QAC3C,UAAU,EAAE,UAAU,CAAC,QAAQ,EAAE;QACjC,aAAa,EAAE,aAAa,CAAC,QAAQ,EAAE;KACxC,CAAA;AACH,CAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type Position, type PositionMarginConstraints } from '@lifi/perps-types';
|
|
2
|
-
/**
|
|
3
|
-
* Exact inputs for {@link removableIsolatedMargin}.
|
|
4
|
-
*
|
|
5
|
-
* @public
|
|
6
|
-
*/
|
|
7
|
-
export interface RemovableIsolatedMarginParams {
|
|
8
|
-
position: Position;
|
|
9
|
-
constraints: PositionMarginConstraints;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Calculate margin that can be removed from an isolated position using the
|
|
13
|
-
* provider's exact retained-margin requirement. Position equity is allocated
|
|
14
|
-
* margin plus unrealized PnL.
|
|
15
|
-
*
|
|
16
|
-
* The result snaps down to the provider's accepted amount increment. Markets
|
|
17
|
-
* that are add-only and cross-margined positions return `'0'`.
|
|
18
|
-
*
|
|
19
|
-
* @throws {PerpsError} `ValidationError` for malformed, non-positive, or
|
|
20
|
-
* inconsistent risk inputs.
|
|
21
|
-
* @public
|
|
22
|
-
*/
|
|
23
|
-
export declare function removableIsolatedMargin({ position, constraints, }: RemovableIsolatedMarginParams): string;
|
|
24
|
-
//# sourceMappingURL=transferMargin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transferMargin.d.ts","sourceRoot":"","sources":["../../../src/utils/transferMargin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,yBAAyB,EAE/B,MAAM,mBAAmB,CAAA;AAoC1B;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,QAAQ,CAAA;IAClB,WAAW,EAAE,yBAAyB,CAAA;CACvC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,WAAW,GACZ,EAAE,6BAA6B,GAAG,MAAM,CA+BxC"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { PerpsErrorCode, positionSupportsMarginRemoval, } from '@lifi/perps-types';
|
|
2
|
-
import Big from 'big.js';
|
|
3
|
-
import { PerpsError } from '../errors/PerpsError.js';
|
|
4
|
-
function positionAmount(value, field) {
|
|
5
|
-
try {
|
|
6
|
-
return new Big(value);
|
|
7
|
-
}
|
|
8
|
-
catch {
|
|
9
|
-
throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid decimal string on Position.${field}: '${value}'`);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
function constraintAmount(value, field) {
|
|
13
|
-
try {
|
|
14
|
-
return new Big(value);
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
throw new PerpsError(PerpsErrorCode.ValidationError, `Invalid decimal string on PositionMarginConstraints.${field}: '${value}'`);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function requirePositive(value, field) {
|
|
21
|
-
if (value.lte(0)) {
|
|
22
|
-
throw new PerpsError(PerpsErrorCode.ValidationError, `${field} must be greater than zero.`);
|
|
23
|
-
}
|
|
24
|
-
return value;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Calculate margin that can be removed from an isolated position using the
|
|
28
|
-
* provider's exact retained-margin requirement. Position equity is allocated
|
|
29
|
-
* margin plus unrealized PnL.
|
|
30
|
-
*
|
|
31
|
-
* The result snaps down to the provider's accepted amount increment. Markets
|
|
32
|
-
* that are add-only and cross-margined positions return `'0'`.
|
|
33
|
-
*
|
|
34
|
-
* @throws {PerpsError} `ValidationError` for malformed, non-positive, or
|
|
35
|
-
* inconsistent risk inputs.
|
|
36
|
-
* @public
|
|
37
|
-
*/
|
|
38
|
-
export function removableIsolatedMargin({ position, constraints, }) {
|
|
39
|
-
if (!positionSupportsMarginRemoval(position)) {
|
|
40
|
-
return '0';
|
|
41
|
-
}
|
|
42
|
-
const marginUsed = requirePositive(positionAmount(position.marginUsed, 'marginUsed'), 'Position.marginUsed');
|
|
43
|
-
const unrealizedPnl = positionAmount(position.unrealizedPnl, 'unrealizedPnl');
|
|
44
|
-
const minimumMargin = requirePositive(constraintAmount(constraints.minimumMarginRequirement, 'minimumMarginRequirement'), 'PositionMarginConstraints.minimumMarginRequirement');
|
|
45
|
-
const amountIncrement = requirePositive(constraintAmount(constraints.amountIncrement, 'amountIncrement'), 'PositionMarginConstraints.amountIncrement');
|
|
46
|
-
const removable = marginUsed.plus(unrealizedPnl).minus(minimumMargin);
|
|
47
|
-
if (removable.lte(0)) {
|
|
48
|
-
return '0';
|
|
49
|
-
}
|
|
50
|
-
return removable
|
|
51
|
-
.div(amountIncrement)
|
|
52
|
-
.round(0, Big.roundDown)
|
|
53
|
-
.times(amountIncrement)
|
|
54
|
-
.toFixed();
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=transferMargin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transferMargin.js","sourceRoot":"","sources":["../../../src/utils/transferMargin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAGd,6BAA6B,GAC9B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,GAAG,MAAM,QAAQ,CAAA;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEpD,SAAS,cAAc,CAAC,KAAa,EAAE,KAAa;IAClD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,sCAAsC,KAAK,MAAM,KAAK,GAAG,CAC1D,CAAA;IACH,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa,EAAE,KAAa;IACpD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,uDAAuD,KAAK,MAAM,KAAK,GAAG,CAC3E,CAAA;IACH,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,KAAU,EAAE,KAAa;IAChD,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACjB,MAAM,IAAI,UAAU,CAClB,cAAc,CAAC,eAAe,EAC9B,GAAG,KAAK,6BAA6B,CACtC,CAAA;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAYD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CAAC,EACtC,QAAQ,EACR,WAAW,GACmB;IAC9B,IAAI,CAAC,6BAA6B,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7C,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,MAAM,UAAU,GAAG,eAAe,CAChC,cAAc,CAAC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC,EACjD,qBAAqB,CACtB,CAAA;IACD,MAAM,aAAa,GAAG,cAAc,CAAC,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC,CAAA;IAC7E,MAAM,aAAa,GAAG,eAAe,CACnC,gBAAgB,CACd,WAAW,CAAC,wBAAwB,EACpC,0BAA0B,CAC3B,EACD,oDAAoD,CACrD,CAAA;IACD,MAAM,eAAe,GAAG,eAAe,CACrC,gBAAgB,CAAC,WAAW,CAAC,eAAe,EAAE,iBAAiB,CAAC,EAChE,2CAA2C,CAC5C,CAAA;IAED,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;IACrE,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,CAAA;IACZ,CAAC;IACD,OAAO,SAAS;SACb,GAAG,CAAC,eAAe,CAAC;SACpB,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC;SACvB,KAAK,CAAC,eAAe,CAAC;SACtB,OAAO,EAAE,CAAA;AACd,CAAC"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { AccountResponse, AccountSummary, Position } from '@lifi/perps-types';
|
|
2
|
-
/**
|
|
3
|
-
* What the summed `collateralBalances` rows already contain, relative to the
|
|
4
|
-
* positions' locked margin and unrealized PnL:
|
|
5
|
-
*
|
|
6
|
-
* - `'free'` — free collateral only; locked margin and unrealized PnL are
|
|
7
|
-
* both carried by the positions. Available margin is the free collateral
|
|
8
|
-
* as-is; unrealized PnL is not counted toward it.
|
|
9
|
-
* - `'net'` — free collateral with unrealized PnL already marked in; only
|
|
10
|
-
* the locked margin is carried by the positions (e.g. a venue-reported
|
|
11
|
-
* available balance).
|
|
12
|
-
* - `'gross'` — locked margin included, unrealized PnL carried by the
|
|
13
|
-
* positions (e.g. spot holdings backing a unified account). The venue
|
|
14
|
-
* counts unrealized PnL toward buying power, so it is added to available
|
|
15
|
-
* margin on top of the gross collateral.
|
|
16
|
-
* - `'equity'` — total equity: locked margin AND unrealized PnL included
|
|
17
|
-
* (e.g. a venue-reported account value). Unrealized PnL is thus already
|
|
18
|
-
* counted toward available margin.
|
|
19
|
-
*
|
|
20
|
-
* @public
|
|
21
|
-
*/
|
|
22
|
-
export type CollateralSemantics = 'free' | 'net' | 'gross' | 'equity';
|
|
23
|
-
/**
|
|
24
|
-
* Roll an {@link AccountResponse} and its open positions up into an
|
|
25
|
-
* {@link AccountSummary}.
|
|
26
|
-
*
|
|
27
|
-
* @param semantics - How the collateral rows relate to the positions'
|
|
28
|
-
* locked margin and unrealized PnL; see {@link CollateralSemantics}.
|
|
29
|
-
* @public
|
|
30
|
-
*/
|
|
31
|
-
export declare function summarizeAccount(account: AccountResponse, positions: Position[], semantics: CollateralSemantics): AccountSummary;
|
|
32
|
-
//# sourceMappingURL=accountSummary.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"accountSummary.d.ts","sourceRoot":"","sources":["../../../src/utils/accountSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,QAAQ,EACT,MAAM,mBAAmB,CAAA;AAY1B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAErE;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,QAAQ,EAAE,EACrB,SAAS,EAAE,mBAAmB,GAC7B,cAAc,CAuChB"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type Position, type PositionMarginConstraints } from '@lifi/perps-types';
|
|
2
|
-
/**
|
|
3
|
-
* Exact inputs for {@link removableIsolatedMargin}.
|
|
4
|
-
*
|
|
5
|
-
* @public
|
|
6
|
-
*/
|
|
7
|
-
export interface RemovableIsolatedMarginParams {
|
|
8
|
-
position: Position;
|
|
9
|
-
constraints: PositionMarginConstraints;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Calculate margin that can be removed from an isolated position using the
|
|
13
|
-
* provider's exact retained-margin requirement. Position equity is allocated
|
|
14
|
-
* margin plus unrealized PnL.
|
|
15
|
-
*
|
|
16
|
-
* The result snaps down to the provider's accepted amount increment. Markets
|
|
17
|
-
* that are add-only and cross-margined positions return `'0'`.
|
|
18
|
-
*
|
|
19
|
-
* @throws {PerpsError} `ValidationError` for malformed, non-positive, or
|
|
20
|
-
* inconsistent risk inputs.
|
|
21
|
-
* @public
|
|
22
|
-
*/
|
|
23
|
-
export declare function removableIsolatedMargin({ position, constraints, }: RemovableIsolatedMarginParams): string;
|
|
24
|
-
//# sourceMappingURL=transferMargin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transferMargin.d.ts","sourceRoot":"","sources":["../../../src/utils/transferMargin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,yBAAyB,EAE/B,MAAM,mBAAmB,CAAA;AAoC1B;;;;GAIG;AACH,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,QAAQ,CAAA;IAClB,WAAW,EAAE,yBAAyB,CAAA;CACvC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,WAAW,GACZ,EAAE,6BAA6B,GAAG,MAAM,CA+BxC"}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AccountResponse,
|
|
3
|
-
AccountSummary,
|
|
4
|
-
Position,
|
|
5
|
-
} from '@lifi/perps-types'
|
|
6
|
-
import { stringToFloat } from './parse.js'
|
|
7
|
-
|
|
8
|
-
const sumValueUsd = (balances: AccountResponse['balances']): number =>
|
|
9
|
-
balances.reduce((sum, b) => sum + stringToFloat(b.valueUsd), 0)
|
|
10
|
-
|
|
11
|
-
const sumMarginUsd = (balances: AccountResponse['balances']): number =>
|
|
12
|
-
balances.reduce(
|
|
13
|
-
(sum, b) => sum + stringToFloat(b.valueUsd) * (b.collateralWeight ?? 1),
|
|
14
|
-
0
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* What the summed `collateralBalances` rows already contain, relative to the
|
|
19
|
-
* positions' locked margin and unrealized PnL:
|
|
20
|
-
*
|
|
21
|
-
* - `'free'` — free collateral only; locked margin and unrealized PnL are
|
|
22
|
-
* both carried by the positions. Available margin is the free collateral
|
|
23
|
-
* as-is; unrealized PnL is not counted toward it.
|
|
24
|
-
* - `'net'` — free collateral with unrealized PnL already marked in; only
|
|
25
|
-
* the locked margin is carried by the positions (e.g. a venue-reported
|
|
26
|
-
* available balance).
|
|
27
|
-
* - `'gross'` — locked margin included, unrealized PnL carried by the
|
|
28
|
-
* positions (e.g. spot holdings backing a unified account). The venue
|
|
29
|
-
* counts unrealized PnL toward buying power, so it is added to available
|
|
30
|
-
* margin on top of the gross collateral.
|
|
31
|
-
* - `'equity'` — total equity: locked margin AND unrealized PnL included
|
|
32
|
-
* (e.g. a venue-reported account value). Unrealized PnL is thus already
|
|
33
|
-
* counted toward available margin.
|
|
34
|
-
*
|
|
35
|
-
* @public
|
|
36
|
-
*/
|
|
37
|
-
export type CollateralSemantics = 'free' | 'net' | 'gross' | 'equity'
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Roll an {@link AccountResponse} and its open positions up into an
|
|
41
|
-
* {@link AccountSummary}.
|
|
42
|
-
*
|
|
43
|
-
* @param semantics - How the collateral rows relate to the positions'
|
|
44
|
-
* locked margin and unrealized PnL; see {@link CollateralSemantics}.
|
|
45
|
-
* @public
|
|
46
|
-
*/
|
|
47
|
-
export function summarizeAccount(
|
|
48
|
-
account: AccountResponse,
|
|
49
|
-
positions: Position[],
|
|
50
|
-
semantics: CollateralSemantics
|
|
51
|
-
): AccountSummary {
|
|
52
|
-
let marginUsed = 0
|
|
53
|
-
let unrealizedPnl = 0
|
|
54
|
-
for (const p of positions) {
|
|
55
|
-
marginUsed += stringToFloat(p.marginUsed)
|
|
56
|
-
unrealizedPnl += stringToFloat(p.unrealizedPnl)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const collateral = sumValueUsd(account.collateralBalances)
|
|
60
|
-
// Margin-eligible collateral: each row's value scaled by its loan-to-value
|
|
61
|
-
// weight (1 when unset), so a haircut asset backs buying power at less than
|
|
62
|
-
// face while `portfolioValue` still reflects its full value.
|
|
63
|
-
const marginCollateral = sumMarginUsd(account.collateralBalances)
|
|
64
|
-
const balances = sumValueUsd(account.balances)
|
|
65
|
-
|
|
66
|
-
const withLocked = semantics === 'free' || semantics === 'net'
|
|
67
|
-
const grossCollateral = withLocked ? collateral + marginUsed : collateral
|
|
68
|
-
const grossMarginCollateral = withLocked
|
|
69
|
-
? marginCollateral + marginUsed
|
|
70
|
-
: marginCollateral
|
|
71
|
-
const equity =
|
|
72
|
-
semantics === 'equity' || semantics === 'net'
|
|
73
|
-
? grossCollateral
|
|
74
|
-
: grossCollateral + unrealizedPnl
|
|
75
|
-
|
|
76
|
-
// Buying power is equity net of locked margin, so unrealized PnL counts
|
|
77
|
-
// toward it. The `'free'` rows exclude uPnL from available margin, holding
|
|
78
|
-
// it purely as free collateral.
|
|
79
|
-
const availableMargin =
|
|
80
|
-
grossMarginCollateral +
|
|
81
|
-
(semantics === 'gross' ? unrealizedPnl : 0) -
|
|
82
|
-
marginUsed
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
portfolioValue: (balances + equity).toString(),
|
|
86
|
-
availableMargin: availableMargin.toString(),
|
|
87
|
-
marginUsed: marginUsed.toString(),
|
|
88
|
-
unrealizedPnl: unrealizedPnl.toString(),
|
|
89
|
-
}
|
|
90
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PerpsErrorCode,
|
|
3
|
-
type Position,
|
|
4
|
-
type PositionMarginConstraints,
|
|
5
|
-
positionSupportsMarginRemoval,
|
|
6
|
-
} from '@lifi/perps-types'
|
|
7
|
-
import Big from 'big.js'
|
|
8
|
-
import { PerpsError } from '../errors/PerpsError.js'
|
|
9
|
-
|
|
10
|
-
function positionAmount(value: string, field: string): Big {
|
|
11
|
-
try {
|
|
12
|
-
return new Big(value)
|
|
13
|
-
} catch {
|
|
14
|
-
throw new PerpsError(
|
|
15
|
-
PerpsErrorCode.ValidationError,
|
|
16
|
-
`Invalid decimal string on Position.${field}: '${value}'`
|
|
17
|
-
)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function constraintAmount(value: string, field: string): Big {
|
|
22
|
-
try {
|
|
23
|
-
return new Big(value)
|
|
24
|
-
} catch {
|
|
25
|
-
throw new PerpsError(
|
|
26
|
-
PerpsErrorCode.ValidationError,
|
|
27
|
-
`Invalid decimal string on PositionMarginConstraints.${field}: '${value}'`
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function requirePositive(value: Big, field: string): Big {
|
|
33
|
-
if (value.lte(0)) {
|
|
34
|
-
throw new PerpsError(
|
|
35
|
-
PerpsErrorCode.ValidationError,
|
|
36
|
-
`${field} must be greater than zero.`
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
return value
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Exact inputs for {@link removableIsolatedMargin}.
|
|
44
|
-
*
|
|
45
|
-
* @public
|
|
46
|
-
*/
|
|
47
|
-
export interface RemovableIsolatedMarginParams {
|
|
48
|
-
position: Position
|
|
49
|
-
constraints: PositionMarginConstraints
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Calculate margin that can be removed from an isolated position using the
|
|
54
|
-
* provider's exact retained-margin requirement. Position equity is allocated
|
|
55
|
-
* margin plus unrealized PnL.
|
|
56
|
-
*
|
|
57
|
-
* The result snaps down to the provider's accepted amount increment. Markets
|
|
58
|
-
* that are add-only and cross-margined positions return `'0'`.
|
|
59
|
-
*
|
|
60
|
-
* @throws {PerpsError} `ValidationError` for malformed, non-positive, or
|
|
61
|
-
* inconsistent risk inputs.
|
|
62
|
-
* @public
|
|
63
|
-
*/
|
|
64
|
-
export function removableIsolatedMargin({
|
|
65
|
-
position,
|
|
66
|
-
constraints,
|
|
67
|
-
}: RemovableIsolatedMarginParams): string {
|
|
68
|
-
if (!positionSupportsMarginRemoval(position)) {
|
|
69
|
-
return '0'
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const marginUsed = requirePositive(
|
|
73
|
-
positionAmount(position.marginUsed, 'marginUsed'),
|
|
74
|
-
'Position.marginUsed'
|
|
75
|
-
)
|
|
76
|
-
const unrealizedPnl = positionAmount(position.unrealizedPnl, 'unrealizedPnl')
|
|
77
|
-
const minimumMargin = requirePositive(
|
|
78
|
-
constraintAmount(
|
|
79
|
-
constraints.minimumMarginRequirement,
|
|
80
|
-
'minimumMarginRequirement'
|
|
81
|
-
),
|
|
82
|
-
'PositionMarginConstraints.minimumMarginRequirement'
|
|
83
|
-
)
|
|
84
|
-
const amountIncrement = requirePositive(
|
|
85
|
-
constraintAmount(constraints.amountIncrement, 'amountIncrement'),
|
|
86
|
-
'PositionMarginConstraints.amountIncrement'
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
const removable = marginUsed.plus(unrealizedPnl).minus(minimumMargin)
|
|
90
|
-
if (removable.lte(0)) {
|
|
91
|
-
return '0'
|
|
92
|
-
}
|
|
93
|
-
return removable
|
|
94
|
-
.div(amountIncrement)
|
|
95
|
-
.round(0, Big.roundDown)
|
|
96
|
-
.times(amountIncrement)
|
|
97
|
-
.toFixed()
|
|
98
|
-
}
|