@pear-protocol/exchanges-sdk 0.6.6 → 0.7.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 +105 -25
- package/dist/client/bybit/rest.js +8 -1
- package/dist/client/hyperliquid/rest.js +21 -1
- package/dist/client/lighter/rest.js +6 -12
- package/dist/client/okx/rest.js +5 -1
- package/dist/helper/lighter/helper.js +6 -2
- package/dist/index.d.ts +1112 -74
- package/dist/sdk.js +9 -2
- package/dist/tracker/balance-core.js +89 -0
- package/dist/tracker/balance.js +25 -0
- package/dist/tracker/basket-size.js +194 -0
- package/dist/tracker/binance/balance.js +11 -0
- package/dist/tracker/binance/mapper.js +87 -42
- package/dist/tracker/binance/tracker.js +29 -14
- package/dist/tracker/binance/types.js +0 -6
- package/dist/tracker/bybit/balance.js +14 -0
- package/dist/tracker/bybit/mapper.js +109 -52
- package/dist/tracker/bybit/tracker.js +242 -33
- package/dist/tracker/bybit/types.js +0 -7
- package/dist/tracker/hyperliquid/account-mode.js +14 -0
- package/dist/tracker/hyperliquid/balance.js +184 -0
- package/dist/tracker/hyperliquid/basket-size.js +93 -0
- package/dist/tracker/hyperliquid/coin-name.js +18 -0
- package/dist/tracker/hyperliquid/collateral.js +48 -0
- package/dist/tracker/hyperliquid/decimal.js +28 -0
- package/dist/tracker/hyperliquid/mapper.js +399 -176
- package/dist/tracker/hyperliquid/spot-pricing.js +106 -0
- package/dist/tracker/hyperliquid/tracker.js +237 -78
- package/dist/tracker/hyperliquid/types.js +1 -7
- package/dist/tracker/index.js +9 -7
- package/dist/tracker/lighter/balance.js +87 -0
- package/dist/tracker/lighter/basket-size.js +74 -0
- package/dist/tracker/lighter/mapper.js +324 -145
- package/dist/tracker/lighter/tracker.js +228 -117
- package/dist/tracker/lighter/types.js +1 -7
- package/dist/tracker/okx/balance.js +17 -0
- package/dist/tracker/okx/mapper.js +156 -58
- package/dist/tracker/okx/tracker.js +228 -29
- package/dist/tracker/okx/types.js +0 -8
- package/dist/tracker/types.js +0 -24
- package/package.json +7 -9
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { DecimalString, SignedDecimalString, AccountBalanceCore } from '../balance-core';
|
|
3
|
+
|
|
4
|
+
const lighterShared = {
|
|
5
|
+
/** Perpetuals + Spot. Null whenever either half is — one unknown term makes the sum unknown. */
|
|
6
|
+
tradingEquity: DecimalString.nullable(),
|
|
7
|
+
/**
|
|
8
|
+
* Collateral posted against perps, which is the quote asset's `margin_balance` alone.
|
|
9
|
+
*
|
|
10
|
+
* Null when the venue sends that one field unreadably or omits it: it is not a term of this
|
|
11
|
+
* figure, it IS the figure, so there is nothing left to report and a zero would say the account
|
|
12
|
+
* has posted no collateral at all.
|
|
13
|
+
*/
|
|
14
|
+
perpetualsEquity: DecimalString.nullable(),
|
|
15
|
+
/**
|
|
16
|
+
* Spot holdings valued in USD.
|
|
17
|
+
*
|
|
18
|
+
* Null when a NON-ZERO holding cannot be priced — no spot book, an inactive book, or a book that
|
|
19
|
+
* has never traded. Lighter's spot books publish neither a mark nor an index price, so the only
|
|
20
|
+
* price available is the last trade, and counting an unpriceable holding as zero would report a
|
|
21
|
+
* number the venue never stated.
|
|
22
|
+
*/
|
|
23
|
+
spotEquity: DecimalString.nullable(),
|
|
24
|
+
/** Null until a source is found for each — all three are UI rows with no API field. */
|
|
25
|
+
publicPoolsEquity: DecimalString.nullable(),
|
|
26
|
+
stakingEquity: DecimalString.nullable(),
|
|
27
|
+
creditedInLit: DecimalString.nullable(),
|
|
28
|
+
/**
|
|
29
|
+
* Open profit and loss across every position.
|
|
30
|
+
*
|
|
31
|
+
* Null when ANY position's own PnL is unreadable: the missing term could be a profit or a loss
|
|
32
|
+
* of any size, so the rest of the sum is not a smaller version of the answer — `+0` in
|
|
33
|
+
* particular would read as a flat book.
|
|
34
|
+
*/
|
|
35
|
+
unrealizedPnl: SignedDecimalString.nullable(),
|
|
36
|
+
/**
|
|
37
|
+
* Cross exposure over cross equity.
|
|
38
|
+
*
|
|
39
|
+
* A MULTIPLE, not a ratio: `0.72` reads 0.72x, and the venue publishes it that way in both
|
|
40
|
+
* scopes. The fraction scale the two fields below carry does not reach it — a multiple is
|
|
41
|
+
* already the same figure on every venue.
|
|
42
|
+
*
|
|
43
|
+
* Null when either side is unreadable, and null when equity is zero against real exposure —
|
|
44
|
+
* that is a division by zero, and calling it `0.00` would report the safest possible account at
|
|
45
|
+
* the exact moment the venue can no longer measure the riskiest.
|
|
46
|
+
*/
|
|
47
|
+
crossLeverage: DecimalString.nullable(),
|
|
48
|
+
/**
|
|
49
|
+
* Maintenance margin across both margin modes.
|
|
50
|
+
*
|
|
51
|
+
* Null when the venue's own cross requirement is unreadable, or when any position feeding the
|
|
52
|
+
* isolated half is: a requirement understated by a missing term reads as headroom that is not
|
|
53
|
+
* there. Null on the same terms when a position sits on a market the tracker's market read never
|
|
54
|
+
* listed — the market carries the maintenance fraction that prices it, so without one there is no
|
|
55
|
+
* term to add rather than a term worth zero.
|
|
56
|
+
*/
|
|
57
|
+
maintenanceMargin: DecimalString.nullable(),
|
|
58
|
+
/**
|
|
59
|
+
* A FRACTION, not a percentage: `0.0221` is what the venue's own page badges as 2.21%.
|
|
60
|
+
*
|
|
61
|
+
* The venue publishes `margin_usage` in percent points and the mapper divides them down, because
|
|
62
|
+
* every venue in this SDK states a ratio at one scale — a field whose scale depended on the
|
|
63
|
+
* venue behind it could not be compared across two of them, which is the whole defect the model
|
|
64
|
+
* exists to remove. Four decimals carry the venue's two decimals of percent exactly.
|
|
65
|
+
*
|
|
66
|
+
* Verified to exceed 1 on a live account, which reads 115.22% on the venue — never clamp.
|
|
67
|
+
*
|
|
68
|
+
* Null on the same terms as `crossLeverage`: unreadable in, unknown out, and a requirement
|
|
69
|
+
* standing against zero equity is unmeasurable rather than full or empty. The ratio is null on
|
|
70
|
+
* one term more: the live path computes it from the positions, so an unlisted market leaves it
|
|
71
|
+
* unknown wherever it leaves `maintenanceMargin` unknown.
|
|
72
|
+
*/
|
|
73
|
+
crossMarginUsage: DecimalString.nullable(),
|
|
74
|
+
crossMarginRatio: DecimalString.nullable()
|
|
75
|
+
};
|
|
76
|
+
const LighterClassicBalance = AccountBalanceCore.extend({
|
|
77
|
+
accountMode: z.literal("lighter:classic"),
|
|
78
|
+
...lighterShared
|
|
79
|
+
});
|
|
80
|
+
const LighterUnifiedBalance = AccountBalanceCore.extend({
|
|
81
|
+
accountMode: z.literal("lighter:unified"),
|
|
82
|
+
...lighterShared,
|
|
83
|
+
/** Null — no source in `/account` or `user_stats`. */
|
|
84
|
+
portfolioMargin: DecimalString.nullable()
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
export { LighterClassicBalance, LighterUnifiedBalance };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import BigNumber from 'bignumber.js';
|
|
2
|
+
import { QUOTE_ASSET } from './const';
|
|
3
|
+
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
+
const MARGIN_FRACTION_SCALE = 1e4;
|
|
7
|
+
const CROSS_POOL = QUOTE_ASSET;
|
|
8
|
+
const DECIMAL_PATTERN = /^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;
|
|
9
|
+
function toLighterBasketCalculation(legs, context) {
|
|
10
|
+
const capped = [];
|
|
11
|
+
for (const leg of legs) {
|
|
12
|
+
const market = context.perpBySymbol.get(leg.asset);
|
|
13
|
+
if (!market) {
|
|
14
|
+
return {
|
|
15
|
+
budgets: {},
|
|
16
|
+
legs: []
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
capped.push(toCappedLeg(leg, market, context.settingsByMarketId.get(String(market.market_id))));
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
// Every leg draws on the same pool, so one entry carries the whole basket's budget.
|
|
23
|
+
budgets: {
|
|
24
|
+
[CROSS_POOL]: context.availableBalance
|
|
25
|
+
},
|
|
26
|
+
legs: capped
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
__name(toLighterBasketCalculation, "toLighterBasketCalculation");
|
|
30
|
+
function toCappedLeg(leg, market, currentSetting) {
|
|
31
|
+
return {
|
|
32
|
+
asset: leg.asset,
|
|
33
|
+
pool: CROSS_POOL,
|
|
34
|
+
weight: leg.weight,
|
|
35
|
+
effectiveLeverage: effectiveLeverage(leg.leverage, market, currentSetting),
|
|
36
|
+
marginMode: leg.marginMode,
|
|
37
|
+
maxNotional: null
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
__name(toCappedLeg, "toCappedLeg");
|
|
41
|
+
function effectiveLeverage(requested, market, currentSetting) {
|
|
42
|
+
const accountLeverage = currentSetting === void 0 ? defaultAccountLeverage(market) : toDecimal(currentSetting.leverage);
|
|
43
|
+
const granted = BigNumber.min(toDecimal(requested), venueMaxLeverage(market), accountLeverage);
|
|
44
|
+
return granted.isFinite() && granted.isGreaterThan(0) ? granted.toFixed() : "1";
|
|
45
|
+
}
|
|
46
|
+
__name(effectiveLeverage, "effectiveLeverage");
|
|
47
|
+
function venueMaxLeverage(market) {
|
|
48
|
+
return leverageFromMarginFraction(market.min_initial_margin_fraction);
|
|
49
|
+
}
|
|
50
|
+
__name(venueMaxLeverage, "venueMaxLeverage");
|
|
51
|
+
function defaultAccountLeverage(market) {
|
|
52
|
+
return leverageFromMarginFraction(market.default_initial_margin_fraction).integerValue(BigNumber.ROUND_FLOOR);
|
|
53
|
+
}
|
|
54
|
+
__name(defaultAccountLeverage, "defaultAccountLeverage");
|
|
55
|
+
function leverageFromMarginFraction(marginFraction) {
|
|
56
|
+
const fraction = toDecimal(marginFraction);
|
|
57
|
+
if (!fraction.isGreaterThan(0)) {
|
|
58
|
+
return new BigNumber(1);
|
|
59
|
+
}
|
|
60
|
+
return new BigNumber(MARGIN_FRACTION_SCALE).div(fraction);
|
|
61
|
+
}
|
|
62
|
+
__name(leverageFromMarginFraction, "leverageFromMarginFraction");
|
|
63
|
+
function toDecimal(value) {
|
|
64
|
+
if (typeof value === "number") {
|
|
65
|
+
return Number.isFinite(value) ? new BigNumber(value) : new BigNumber(0);
|
|
66
|
+
}
|
|
67
|
+
if (typeof value !== "string" || !DECIMAL_PATTERN.test(value)) {
|
|
68
|
+
return new BigNumber(0);
|
|
69
|
+
}
|
|
70
|
+
return new BigNumber(value);
|
|
71
|
+
}
|
|
72
|
+
__name(toDecimal, "toDecimal");
|
|
73
|
+
|
|
74
|
+
export { toLighterBasketCalculation, venueMaxLeverage };
|