@lifi/perps-sdk-provider-lighter 23.0.0 → 24.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/dist/cjs/LighterProvider.d.ts.map +1 -1
- package/dist/cjs/LighterProvider.js +43 -0
- package/dist/cjs/LighterProvider.js.map +1 -1
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/cjs/types/index.js +1 -0
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/pnl.d.ts +25 -0
- package/dist/cjs/types/pnl.d.ts.map +1 -0
- package/dist/cjs/types/pnl.js +3 -0
- package/dist/cjs/types/pnl.js.map +1 -0
- package/dist/cjs/utils/index.d.ts +1 -0
- package/dist/cjs/utils/index.d.ts.map +1 -1
- package/dist/cjs/utils/index.js +3 -1
- package/dist/cjs/utils/index.js.map +1 -1
- package/dist/cjs/utils/mapPortfolioHistory.d.ts +5 -0
- package/dist/cjs/utils/mapPortfolioHistory.d.ts.map +1 -0
- package/dist/cjs/utils/mapPortfolioHistory.js +40 -0
- package/dist/cjs/utils/mapPortfolioHistory.js.map +1 -0
- package/dist/cjs/websocket/LighterWsProvider.d.ts.map +1 -1
- package/dist/cjs/websocket/LighterWsProvider.js +1 -5
- package/dist/cjs/websocket/LighterWsProvider.js.map +1 -1
- package/dist/esm/LighterProvider.d.ts.map +1 -1
- package/dist/esm/LighterProvider.js +52 -2
- package/dist/esm/LighterProvider.js.map +1 -1
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/pnl.d.ts +33 -0
- package/dist/esm/types/pnl.d.ts.map +1 -0
- package/dist/esm/types/pnl.js +4 -0
- package/dist/esm/types/pnl.js.map +1 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.d.ts.map +1 -1
- package/dist/esm/utils/index.js +1 -0
- package/dist/esm/utils/index.js.map +1 -1
- package/dist/esm/utils/mapPortfolioHistory.d.ts +12 -0
- package/dist/esm/utils/mapPortfolioHistory.d.ts.map +1 -0
- package/dist/esm/utils/mapPortfolioHistory.js +40 -0
- package/dist/esm/utils/mapPortfolioHistory.js.map +1 -0
- package/dist/esm/websocket/LighterWsProvider.d.ts +1 -1
- package/dist/esm/websocket/LighterWsProvider.d.ts.map +1 -1
- package/dist/esm/websocket/LighterWsProvider.js +2 -12
- package/dist/esm/websocket/LighterWsProvider.js.map +1 -1
- package/dist/types/LighterProvider.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +1 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/types/types/pnl.d.ts +33 -0
- package/dist/types/types/pnl.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/utils/mapPortfolioHistory.d.ts +12 -0
- package/dist/types/utils/mapPortfolioHistory.d.ts.map +1 -0
- package/dist/types/websocket/LighterWsProvider.d.ts +1 -1
- package/dist/types/websocket/LighterWsProvider.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/LighterProvider.ts +89 -0
- package/src/types/index.ts +1 -0
- package/src/types/pnl.ts +36 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/mapPortfolioHistory.ts +52 -0
- package/src/websocket/LighterWsProvider.ts +10 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,SAAS,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One PnL bucket. `timestamp` is Unix milliseconds. Every other field is a
|
|
3
|
+
* JSON number in USD for that bucket alone; the endpoint reports no account
|
|
4
|
+
* value.
|
|
5
|
+
*
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export interface LtPnLEntry {
|
|
9
|
+
timestamp: number;
|
|
10
|
+
trade_pnl: number;
|
|
11
|
+
inflow: number;
|
|
12
|
+
outflow: number;
|
|
13
|
+
pool_pnl: number;
|
|
14
|
+
pool_inflow: number;
|
|
15
|
+
pool_outflow: number;
|
|
16
|
+
pool_total_shares: number;
|
|
17
|
+
spot_inflow: number;
|
|
18
|
+
spot_outflow: number;
|
|
19
|
+
staked_lit: number;
|
|
20
|
+
staking_inflow: number;
|
|
21
|
+
staking_outflow: number;
|
|
22
|
+
staking_pnl: number;
|
|
23
|
+
trade_spot_pnl: number;
|
|
24
|
+
volume: number;
|
|
25
|
+
}
|
|
26
|
+
/** `GET /api/v1/pnl` response envelope. @public */
|
|
27
|
+
export interface LtAccountPnL {
|
|
28
|
+
code: number;
|
|
29
|
+
message?: string;
|
|
30
|
+
resolution: string;
|
|
31
|
+
pnl: LtPnLEntry[] | null;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=pnl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pnl.d.ts","sourceRoot":"","sources":["../../../src/types/pnl.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,iBAAiB,EAAE,MAAM,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;CACzB"}
|
|
@@ -10,6 +10,7 @@ export { mapFill } from './mapFill.js';
|
|
|
10
10
|
export { mapMarketContext } from './mapMarketContext.js';
|
|
11
11
|
export { mapOpenPositions } from './mapOpenPositions.js';
|
|
12
12
|
export { classifyAndMapOrders, isTriggerOrder, isTriggerType, mapOrder, mapOrderDetail, mapStatusReason, mapTriggerOrder, } from './mapOrder.js';
|
|
13
|
+
export { mapPortfolioHistory } from './mapPortfolioHistory.js';
|
|
13
14
|
export { leverageFromImf, mapPosition } from './mapPosition.js';
|
|
14
15
|
export { mapMarketOrderLimits } from './marketLimits.js';
|
|
15
16
|
export { mapInterval } from './ohlcvInterval.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAIA,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,aAAa,EACb,QAAQ,EACR,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,2BAA2B,EAC3B,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/index.ts"],"names":[],"mappings":"AAIA,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EACL,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EACL,oBAAoB,EACpB,cAAc,EACd,aAAa,EACb,QAAQ,EACR,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAChD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,2BAA2B,EAC3B,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PortfolioHistoryRange, PortfolioHistoryResponse } from '@lifi/perps-types';
|
|
2
|
+
import Big from 'big.js';
|
|
3
|
+
import type { LtPnLEntry } from '../types/pnl.js';
|
|
4
|
+
/**
|
|
5
|
+
* Build the portfolio series from Lighter PnL buckets and the account's
|
|
6
|
+
* current value. Lighter reports no historical account value, so each
|
|
7
|
+
* point's `accountValue` is `currentValue` with every later bucket's
|
|
8
|
+
* `trade_pnl + trade_spot_pnl + inflow - outflow` removed. `pnl` is the
|
|
9
|
+
* running `trade_pnl + trade_spot_pnl`, so both series unwind the same PnL.
|
|
10
|
+
*/
|
|
11
|
+
export declare const mapPortfolioHistory: (range: PortfolioHistoryRange, entries: LtPnLEntry[], currentValue: Big) => PortfolioHistoryResponse;
|
|
12
|
+
//# sourceMappingURL=mapPortfolioHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapPortfolioHistory.d.ts","sourceRoot":"","sources":["../../../src/utils/mapPortfolioHistory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACzB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,GAAG,MAAM,QAAQ,CAAA;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,qBAAqB,EAC5B,SAAS,UAAU,EAAE,EACrB,cAAc,GAAG,KAChB,wBAiCF,CAAA"}
|
|
@@ -41,7 +41,7 @@ export interface LighterWsProviderOptions {
|
|
|
41
41
|
resolveAuthToken?: LighterAuthTokenResolver;
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
* Lighter
|
|
44
|
+
* Lighter WebSocket provider (extends {@link WsProviderBase}): subscribes to
|
|
45
45
|
* Lighter's WS channels (orderbook, marketsContext, orders, positions), attaching auth
|
|
46
46
|
* tokens to gated channels. Construct via {@link lighterWsProvider}.
|
|
47
47
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAKlB,cAAc,EACd,KAAK,iBAAiB,
|
|
1
|
+
{"version":3,"file":"LighterWsProvider.d.ts","sourceRoot":"","sources":["../../../src/websocket/LighterWsProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EAKlB,cAAc,EACd,KAAK,iBAAiB,EAGvB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AA4EnC;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,wBAAwB,GAAG,CACrC,OAAO,EAAE,OAAO,KACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;AAEhC,UAAU,QAAQ;IAChB,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yEAAyE;IACzE,SAAS,EAAE,OAAO,CAAA;CACnB;AAkBD;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,wBAAwB,CAAA;CAC5C;AAED;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAC7D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAE5B;IACb,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IAEnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoC;IAC/D,OAAO,CAAC,cAAc,CAAoC;IAE1D;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2C;IAE9E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IAErD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA4B;IAC9D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAqC;gBAGxE,KAAK,GAAE,MAA+B,EACtC,WAAW,GAAE,MAA6B,EAC1C,OAAO,GAAE,wBAA6B,EACtC,MAAM,CAAC,EAAE,cAAc;IAsBzB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;;;OAKG;IACG,cAAc,CAClB,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;cAkBN,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;cA6ChD,OAAO,IAAI,IAAI;cAMlB,aAAa,CAAC,EAC5B,OAAO,EACP,SAAS,EACT,OAAO,GACR,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAW3B;;;;;;OAMG;YACW,gBAAgB;IAsB9B,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM;YAwB5B,cAAc;YAsFd,mBAAmB;YAqBnB,iBAAiB;IAK/B,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAqB1C,OAAO,CAAC,QAAQ;IAkFhB,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,eAAe;IAuDvB,OAAO,CAAC,mBAAmB;IAiB3B,OAAO,CAAC,sBAAsB;IAiC9B;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,mBAAmB;CAc5B;AAkID;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAU,wBAAwB,KACjC,iBAKA,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/perps-sdk-provider-lighter",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "24.0.0",
|
|
4
4
|
"description": "Lighter provider plugin for @lifi/perps-sdk",
|
|
5
5
|
"homepage": "https://github.com/lifinance/perps-sdk",
|
|
6
6
|
"bugs": {
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"big.js": "^7.0.1",
|
|
46
46
|
"viem": "^2.55.18",
|
|
47
|
-
"@lifi/perps-types": "^12.
|
|
47
|
+
"@lifi/perps-types": "^12.3.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@lifi/perps-sdk": "^
|
|
50
|
+
"@lifi/perps-sdk": "^13.0.0"
|
|
51
51
|
},
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
package/src/LighterProvider.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type ProviderGetMarketSettingsParams,
|
|
18
18
|
type ProviderGetOrderParams,
|
|
19
19
|
type ProviderGetOrdersParams,
|
|
20
|
+
type ProviderGetPortfolioHistoryParams,
|
|
20
21
|
type ProviderGetPositionsParams,
|
|
21
22
|
type ProviderGetQuoteParams,
|
|
22
23
|
type ProviderGetRunningTwapsParams,
|
|
@@ -46,6 +47,8 @@ import type {
|
|
|
46
47
|
MarketSettings,
|
|
47
48
|
Order,
|
|
48
49
|
OrdersResponse,
|
|
50
|
+
PortfolioHistoryRange,
|
|
51
|
+
PortfolioHistoryResponse,
|
|
49
52
|
Position,
|
|
50
53
|
PositionsResponse,
|
|
51
54
|
ProviderAction,
|
|
@@ -91,6 +94,7 @@ import type {
|
|
|
91
94
|
LtAccount,
|
|
92
95
|
LtAccountLimits,
|
|
93
96
|
LtAccountOrdersResponse,
|
|
97
|
+
LtAccountPnL,
|
|
94
98
|
LtDepositHistoryItem,
|
|
95
99
|
LtDepositHistoryResponse,
|
|
96
100
|
LtDetailedAccountPosition,
|
|
@@ -119,6 +123,7 @@ import {
|
|
|
119
123
|
import {
|
|
120
124
|
LIGHTER_RETRY_DEFAULTS,
|
|
121
125
|
LighterApiClient,
|
|
126
|
+
LighterAuthRejectedError,
|
|
122
127
|
LighterTokenRevokedError,
|
|
123
128
|
} from './utils/apiClient.js'
|
|
124
129
|
import { isAssetMarginEnabled } from './utils/assetCollateral.js'
|
|
@@ -134,6 +139,7 @@ import {
|
|
|
134
139
|
mapFill,
|
|
135
140
|
mapOpenPositions,
|
|
136
141
|
mapOrderDetail,
|
|
142
|
+
mapPortfolioHistory,
|
|
137
143
|
positionMarginConstraints,
|
|
138
144
|
toBigOrNull,
|
|
139
145
|
toIsoFromMs,
|
|
@@ -181,6 +187,24 @@ const CLIENT_ORDER_INDEX_PATTERN = /^\d+$/
|
|
|
181
187
|
|
|
182
188
|
const INACTIVE_ORDERS_LOOKUP_LIMIT = 100
|
|
183
189
|
|
|
190
|
+
interface PnlWindow {
|
|
191
|
+
resolution: '1h' | '4h' | '1d'
|
|
192
|
+
bucketMs: number
|
|
193
|
+
countBack: number
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const HOUR_MS = 60 * 60 * 1000
|
|
197
|
+
const DAY_MS = 24 * HOUR_MS
|
|
198
|
+
|
|
199
|
+
// `all` has no natural bucket count; 1000 daily buckets reach back past the
|
|
200
|
+
// venue's launch for every account.
|
|
201
|
+
const PNL_WINDOWS: Record<PortfolioHistoryRange, PnlWindow> = {
|
|
202
|
+
'24h': { resolution: '1h', bucketMs: HOUR_MS, countBack: 24 },
|
|
203
|
+
'7d': { resolution: '4h', bucketMs: 4 * HOUR_MS, countBack: 42 },
|
|
204
|
+
'30d': { resolution: '1d', bucketMs: DAY_MS, countBack: 30 },
|
|
205
|
+
all: { resolution: '1d', bucketMs: DAY_MS, countBack: 1000 },
|
|
206
|
+
}
|
|
207
|
+
|
|
184
208
|
/** Activity surfaces whose rows name a market, so they need the market registry. */
|
|
185
209
|
const MARKET_BEARING_TYPES: ReadonlySet<ActivityType> = new Set([
|
|
186
210
|
ActivityType.FUNDING,
|
|
@@ -1305,6 +1329,71 @@ export const createLighterProvider = (
|
|
|
1305
1329
|
}
|
|
1306
1330
|
},
|
|
1307
1331
|
|
|
1332
|
+
async getPortfolioHistory(
|
|
1333
|
+
params: ProviderGetPortfolioHistoryParams,
|
|
1334
|
+
opts?: SDKRequestOptions
|
|
1335
|
+
): Promise<PortfolioHistoryResponse> {
|
|
1336
|
+
const sdkOwnsToken =
|
|
1337
|
+
opts?.lighterAuthToken === undefined && authTokenSource === undefined
|
|
1338
|
+
const apiKey = sdkOwnsToken ? await keyStore.get(params.address) : null
|
|
1339
|
+
const token = await resolveAuthToken(
|
|
1340
|
+
opts,
|
|
1341
|
+
params.address,
|
|
1342
|
+
apiKey ?? undefined
|
|
1343
|
+
)
|
|
1344
|
+
if (token === undefined) {
|
|
1345
|
+
return { range: params.range, points: [] }
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
const client = apiClient(opts)
|
|
1349
|
+
const account = await fetchDetailedAccount(client, params.address)
|
|
1350
|
+
const window = PNL_WINDOWS[params.range]
|
|
1351
|
+
const endTimestamp = Date.now()
|
|
1352
|
+
const queryParams: Record<string, string | number | boolean> = {
|
|
1353
|
+
by: 'index',
|
|
1354
|
+
value: String(account.index),
|
|
1355
|
+
resolution: window.resolution,
|
|
1356
|
+
start_timestamp:
|
|
1357
|
+
params.range === 'all'
|
|
1358
|
+
? 0
|
|
1359
|
+
: endTimestamp - window.countBack * window.bucketMs,
|
|
1360
|
+
end_timestamp: endTimestamp,
|
|
1361
|
+
count_back: window.countBack,
|
|
1362
|
+
ignore_transfers: false,
|
|
1363
|
+
}
|
|
1364
|
+
const read = (tok: string) =>
|
|
1365
|
+
client.getAuthed<LtAccountPnL>('/api/v1/pnl', tok, queryParams)
|
|
1366
|
+
|
|
1367
|
+
// The read-only token may not be accepted on `/pnl`; the standard token
|
|
1368
|
+
// is, so a read signed from the SDK's own key retries once with it. The
|
|
1369
|
+
// fallback sits outside `retryOnRevoked`, so a revocation the standard
|
|
1370
|
+
// token reports never replaces the read-only one. The key is re-read at
|
|
1371
|
+
// retry time because `REGISTER_API_KEY` can rotate it.
|
|
1372
|
+
const response = await retryOnRevoked(
|
|
1373
|
+
opts,
|
|
1374
|
+
params.address,
|
|
1375
|
+
token,
|
|
1376
|
+
read
|
|
1377
|
+
).catch(async (err: unknown) => {
|
|
1378
|
+
if (!(err instanceof LighterAuthRejectedError) || apiKey === null) {
|
|
1379
|
+
throw err
|
|
1380
|
+
}
|
|
1381
|
+
const current = (await keyStore.get(params.address)) ?? apiKey
|
|
1382
|
+
return read(
|
|
1383
|
+
await getStandardAuthToken(params.address, current.apiKeyPrivateKey, {
|
|
1384
|
+
apiKeyIndex: current.apiKeyIndex,
|
|
1385
|
+
accountIndex: current.accountIndex,
|
|
1386
|
+
})
|
|
1387
|
+
)
|
|
1388
|
+
})
|
|
1389
|
+
|
|
1390
|
+
return mapPortfolioHistory(
|
|
1391
|
+
params.range,
|
|
1392
|
+
wireList(response.pnl),
|
|
1393
|
+
toRequiredBig(account.total_asset_value, 'total_asset_value')
|
|
1394
|
+
)
|
|
1395
|
+
},
|
|
1396
|
+
|
|
1308
1397
|
async getActivity(
|
|
1309
1398
|
params: ProviderGetActivityParams,
|
|
1310
1399
|
opts?: SDKRequestOptions
|
package/src/types/index.ts
CHANGED
package/src/types/pnl.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Account PnL shapes returned by Lighter's `/api/v1/pnl` endpoint.
|
|
2
|
+
// Lighter serializes an empty list as JSON `null`, so list members are nullable.
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* One PnL bucket. `timestamp` is Unix milliseconds. Every other field is a
|
|
6
|
+
* JSON number in USD for that bucket alone; the endpoint reports no account
|
|
7
|
+
* value.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
export interface LtPnLEntry {
|
|
12
|
+
timestamp: number
|
|
13
|
+
trade_pnl: number
|
|
14
|
+
inflow: number
|
|
15
|
+
outflow: number
|
|
16
|
+
pool_pnl: number
|
|
17
|
+
pool_inflow: number
|
|
18
|
+
pool_outflow: number
|
|
19
|
+
pool_total_shares: number
|
|
20
|
+
spot_inflow: number
|
|
21
|
+
spot_outflow: number
|
|
22
|
+
staked_lit: number
|
|
23
|
+
staking_inflow: number
|
|
24
|
+
staking_outflow: number
|
|
25
|
+
staking_pnl: number
|
|
26
|
+
trade_spot_pnl: number
|
|
27
|
+
volume: number
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** `GET /api/v1/pnl` response envelope. @public */
|
|
31
|
+
export interface LtAccountPnL {
|
|
32
|
+
code: number
|
|
33
|
+
message?: string
|
|
34
|
+
resolution: string
|
|
35
|
+
pnl: LtPnLEntry[] | null
|
|
36
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export {
|
|
|
25
25
|
mapStatusReason,
|
|
26
26
|
mapTriggerOrder,
|
|
27
27
|
} from './mapOrder.js'
|
|
28
|
+
export { mapPortfolioHistory } from './mapPortfolioHistory.js'
|
|
28
29
|
export { leverageFromImf, mapPosition } from './mapPosition.js'
|
|
29
30
|
export { mapMarketOrderLimits } from './marketLimits.js'
|
|
30
31
|
export { mapInterval } from './ohlcvInterval.js'
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
PortfolioHistoryRange,
|
|
3
|
+
PortfolioHistoryResponse,
|
|
4
|
+
} from '@lifi/perps-types'
|
|
5
|
+
import Big from 'big.js'
|
|
6
|
+
import type { LtPnLEntry } from '../types/pnl.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Build the portfolio series from Lighter PnL buckets and the account's
|
|
10
|
+
* current value. Lighter reports no historical account value, so each
|
|
11
|
+
* point's `accountValue` is `currentValue` with every later bucket's
|
|
12
|
+
* `trade_pnl + trade_spot_pnl + inflow - outflow` removed. `pnl` is the
|
|
13
|
+
* running `trade_pnl + trade_spot_pnl`, so both series unwind the same PnL.
|
|
14
|
+
*/
|
|
15
|
+
export const mapPortfolioHistory = (
|
|
16
|
+
range: PortfolioHistoryRange,
|
|
17
|
+
entries: LtPnLEntry[],
|
|
18
|
+
currentValue: Big
|
|
19
|
+
): PortfolioHistoryResponse => {
|
|
20
|
+
const ordered = [...entries].sort((a, b) => a.timestamp - b.timestamp)
|
|
21
|
+
|
|
22
|
+
const accountValues: Big[] = []
|
|
23
|
+
let value = currentValue
|
|
24
|
+
for (let i = ordered.length - 1; i >= 0; i -= 1) {
|
|
25
|
+
accountValues[i] = value
|
|
26
|
+
const entry = ordered[i]
|
|
27
|
+
value = value
|
|
28
|
+
.minus(new Big(entry.trade_pnl))
|
|
29
|
+
.minus(new Big(entry.trade_spot_pnl))
|
|
30
|
+
.minus(new Big(entry.inflow))
|
|
31
|
+
.plus(new Big(entry.outflow))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let pnl = new Big(0)
|
|
35
|
+
let volume = new Big(0)
|
|
36
|
+
const points = ordered.map((entry, i) => {
|
|
37
|
+
pnl = pnl.plus(new Big(entry.trade_pnl)).plus(new Big(entry.trade_spot_pnl))
|
|
38
|
+
volume = volume.plus(new Big(entry.volume))
|
|
39
|
+
return {
|
|
40
|
+
timestamp: entry.timestamp,
|
|
41
|
+
accountValue: accountValues[i].toFixed(),
|
|
42
|
+
pnl: pnl.toFixed(),
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
range,
|
|
48
|
+
points,
|
|
49
|
+
volume: volume.toFixed(),
|
|
50
|
+
totalPnl: points.at(-1)?.pnl,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
toPerpsMarketDisplay,
|
|
14
14
|
WsProviderBase,
|
|
15
15
|
type WsProviderFactory,
|
|
16
|
+
type WsProviderFactoryParams,
|
|
16
17
|
wsLog,
|
|
17
18
|
} from '@lifi/perps-sdk'
|
|
18
19
|
import {
|
|
@@ -159,7 +160,7 @@ export interface LighterWsProviderOptions {
|
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
/**
|
|
162
|
-
* Lighter
|
|
163
|
+
* Lighter WebSocket provider (extends {@link WsProviderBase}): subscribes to
|
|
163
164
|
* Lighter's WS channels (orderbook, marketsContext, orders, positions), attaching auth
|
|
164
165
|
* tokens to gated channels. Construct via {@link lighterWsProvider}.
|
|
165
166
|
*
|
|
@@ -257,14 +258,6 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
|
|
|
257
258
|
}
|
|
258
259
|
|
|
259
260
|
protected async openChannel(sub: Subscription): Promise<() => void> {
|
|
260
|
-
// Lighter has no live OHLC channel — there's nothing to subscribe to.
|
|
261
|
-
// Return a no-op unsubscribe so the caller's UX (chart still rendering
|
|
262
|
-
// from REST history + price-tick mid line) is unaffected, instead of
|
|
263
|
-
// throwing and surfacing a console error on every chart mount.
|
|
264
|
-
if (sub.channel === 'candle') {
|
|
265
|
-
return () => {}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
261
|
// Only the auth channels (orders/fills/positions) resolve markets.
|
|
269
262
|
// `marketsContext`/`orderbook` are keyed purely by `String(market_id)`, so
|
|
270
263
|
// gating them on the registry sync would let a failed `/markets` fetch kill
|
|
@@ -377,10 +370,7 @@ export class LighterWsProvider extends WsProviderBase<SubState> {
|
|
|
377
370
|
return `positions:${sub.address.toLowerCase()}`
|
|
378
371
|
case 'accountSummary':
|
|
379
372
|
return `accountSummary:${sub.address.toLowerCase()}`
|
|
380
|
-
// No live wire sub (openChannel returns a no-op), but a stable key is
|
|
381
|
-
// still needed so the base's fan-out registry can track/release it.
|
|
382
373
|
case 'candle':
|
|
383
|
-
return `candle:${sub.marketId}:${sub.interval}`
|
|
384
374
|
case 'spotBalances':
|
|
385
375
|
throw new Error(`Lighter WS does not support channel: ${sub.channel}.`)
|
|
386
376
|
}
|
|
@@ -1006,7 +996,11 @@ function collectAuthChannelItems<T>(
|
|
|
1006
996
|
*
|
|
1007
997
|
* @public
|
|
1008
998
|
*/
|
|
1009
|
-
export const lighterWsProvider =
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
999
|
+
export const lighterWsProvider = (
|
|
1000
|
+
options?: LighterWsProviderOptions
|
|
1001
|
+
): WsProviderFactory =>
|
|
1002
|
+
Object.assign(
|
|
1003
|
+
({ provider, wsUrl, client }: WsProviderFactoryParams) =>
|
|
1004
|
+
new LighterWsProvider(wsUrl, provider, options, client),
|
|
1005
|
+
{ streamsCandles: false }
|
|
1006
|
+
)
|