@pear-protocol/exchanges-sdk 0.1.1 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/client/binance/rest.d.ts +4 -2
  2. package/dist/client/binance/rest.js +75 -1
  3. package/dist/client/binance/types.d.ts +36 -1
  4. package/dist/client/bybit/rest.d.ts +3 -2
  5. package/dist/client/bybit/rest.js +34 -1
  6. package/dist/client/bybit/types.d.ts +14 -1
  7. package/dist/client/hyperliquid/types.d.ts +76 -1
  8. package/dist/client/lighter/rest.d.ts +4 -1
  9. package/dist/client/lighter/rest.js +36 -1
  10. package/dist/client/lighter/types.d.ts +22 -1
  11. package/dist/client/okx/rest.d.ts +3 -2
  12. package/dist/client/okx/rest.js +28 -1
  13. package/dist/client/okx/types.d.ts +18 -1
  14. package/dist/helper/factory.d.ts +1 -0
  15. package/dist/helper/index.d.ts +2 -1
  16. package/dist/helper/lighter/helper.d.ts +2 -1
  17. package/dist/helper/lighter/index.d.ts +3 -2
  18. package/dist/helper/lighter/index.js +1 -1
  19. package/dist/helper/lighter/types.d.ts +1 -0
  20. package/dist/helper/types.d.ts +1 -0
  21. package/dist/index.d.ts +13 -2
  22. package/dist/sdk.d.ts +3 -2
  23. package/dist/sdk.js +4 -3
  24. package/dist/syncer/base.d.ts +20 -6
  25. package/dist/syncer/base.js +47 -2
  26. package/dist/syncer/binance/syncer.d.ts +31 -0
  27. package/dist/syncer/binance/syncer.js +82 -0
  28. package/dist/syncer/bybit/syncer.d.ts +28 -0
  29. package/dist/syncer/bybit/syncer.js +36 -0
  30. package/dist/syncer/factory.d.ts +22 -0
  31. package/dist/syncer/factory.js +26 -0
  32. package/dist/syncer/hyperliquid/syncer.d.ts +28 -0
  33. package/dist/syncer/hyperliquid/syncer.js +53 -0
  34. package/dist/syncer/index.d.ts +12 -1
  35. package/dist/syncer/index.js +6 -0
  36. package/dist/syncer/lighter/syncer.d.ts +37 -0
  37. package/dist/syncer/lighter/syncer.js +94 -0
  38. package/dist/syncer/okx/syncer.d.ts +29 -0
  39. package/dist/syncer/okx/syncer.js +48 -0
  40. package/package.json +7 -9
@@ -1,5 +1,5 @@
1
1
  import PearSDK from '@pear-protocol/core-sdk';
2
- import { Connector } from '@pear-protocol/types';
2
+ import { Connector, HttpTypes } from '@pear-protocol/types';
3
3
  import { ExchangeWsByConnector } from '../client/index.js';
4
4
  import { SupportedCredentials } from '../types.js';
5
5
  import '../client/binance/exchange-ws.js';
@@ -16,18 +16,32 @@ import '../client/lighter/ws.js';
16
16
  import '../client/okx/exchange-ws.js';
17
17
  import '../client/okx/ws.js';
18
18
 
19
- type AccountPositionSyncerConfig = {
19
+ interface AccountSyncerConfig {
20
20
  sdk: PearSDK;
21
+ connector: Connector;
21
22
  credentials: SupportedCredentials;
22
23
  ws: ExchangeWsByConnector[Connector];
23
24
  demo: boolean;
24
- };
25
- declare class AccountPositionSyncer {
25
+ }
26
+ interface AccountSyncer {
27
+ synchronize(): Promise<void>;
28
+ }
29
+ interface ListExternalFillsParams {
30
+ since: Date;
31
+ instruments: HttpTypes.Instrument[];
32
+ openPositions: HttpTypes.OpenPositionLite[];
33
+ provisionalFills: HttpTypes.ProvisionalFill[];
34
+ }
35
+ declare abstract class BaseAccountSyncer<ExternalFill> implements AccountSyncer {
26
36
  protected sdk: PearSDK;
37
+ protected connector: Connector;
27
38
  protected credentials: SupportedCredentials;
28
39
  protected ws: ExchangeWsByConnector[Connector];
29
40
  protected demo: boolean;
30
- constructor(config: AccountPositionSyncerConfig);
41
+ constructor(config: AccountSyncerConfig);
42
+ protected abstract listExternalFills(params: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
43
+ protected abstract isReduceOnly(fill: ExternalFill): boolean;
44
+ synchronize(): Promise<void>;
31
45
  }
32
46
 
33
- export { AccountPositionSyncer, type AccountPositionSyncerConfig };
47
+ export { type AccountSyncer, type AccountSyncerConfig, BaseAccountSyncer, type ListExternalFillsParams };
@@ -1,14 +1,59 @@
1
- class AccountPositionSyncer {
1
+ import { computeSyncPayload } from '@pear-protocol/utils';
2
+
3
+ class BaseAccountSyncer {
2
4
  sdk;
5
+ connector;
3
6
  credentials;
4
7
  ws;
5
8
  demo;
6
9
  constructor(config) {
7
10
  this.sdk = config.sdk;
11
+ this.connector = config.connector;
8
12
  this.credentials = config.credentials;
9
13
  this.ws = config.ws;
10
14
  this.demo = config.demo;
11
15
  }
16
+ async synchronize() {
17
+ const [{ positions }, { fills: provisionalFills }] = await Promise.all([
18
+ this.sdk.core.positions.openLite(),
19
+ this.sdk.core.fills.provisionals()
20
+ ]);
21
+ if (!positions.length && !provisionalFills.length) {
22
+ return;
23
+ }
24
+ const [{ instruments }, since] = await Promise.all([
25
+ this.sdk.core.instruments.list({ connector: this.connector }),
26
+ this.sdk.core.sync.since({
27
+ overlapMs: 6e4,
28
+ nowMs: Date.now(),
29
+ bootstrapLookbackMs: 30 * 24 * 60 * 60 * 1e3
30
+ })
31
+ ]);
32
+ const externalFills = await this.listExternalFills({
33
+ since: new Date(since.since),
34
+ instruments,
35
+ openPositions: positions,
36
+ provisionalFills
37
+ });
38
+ const payload = await computeSyncPayload({
39
+ openPositions: positions,
40
+ provisionalFills,
41
+ confirmedExchangeFillIds: since.confirmedExchangeFillIds ?? [],
42
+ externalFills
43
+ });
44
+ if (!payload) {
45
+ return;
46
+ }
47
+ if (payload.reconcilables) {
48
+ await this.sdk.core.sync.reconcile(payload.reconcilables);
49
+ }
50
+ if (payload.confirmables) {
51
+ await this.sdk.core.sync.confirm(payload.confirmables);
52
+ }
53
+ if (payload.creatables) {
54
+ await this.sdk.core.sync.create(payload.creatables);
55
+ }
56
+ }
12
57
  }
13
58
 
14
- export { AccountPositionSyncer };
59
+ export { BaseAccountSyncer };
@@ -0,0 +1,31 @@
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { BinanceRawUserTrade } from '../../client/binance/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
4
+ import '@pear-protocol/core-sdk';
5
+ import '../../client/index.js';
6
+ import '../../types.js';
7
+ import '../../client/binance/exchange-ws.js';
8
+ import '../../client/base-ws.js';
9
+ import 'partysocket';
10
+ import '../../client/exchange-ws.js';
11
+ import '../../client/binance/ws.js';
12
+ import '../../client/bybit/exchange-ws.js';
13
+ import '../../client/bybit/ws.js';
14
+ import '../../client/hyperliquid/exchange-ws.js';
15
+ import '../../client/hyperliquid/ws.js';
16
+ import '../../client/lighter/exchange-ws.js';
17
+ import '../../client/lighter/ws.js';
18
+ import '../../client/okx/exchange-ws.js';
19
+ import '../../client/okx/ws.js';
20
+
21
+ declare class BinanceAccountSyncer extends BaseAccountSyncer<BinanceRawUserTrade> {
22
+ private readonly creds;
23
+ constructor(config: AccountSyncerConfig);
24
+ protected listExternalFills({ since, instruments, openPositions, provisionalFills, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
25
+ protected isReduceOnly(trade: BinanceRawUserTrade): boolean;
26
+ private collectRequestedInstrumentIds;
27
+ private mapOrdersBySymbolOrderId;
28
+ private orderKey;
29
+ }
30
+
31
+ export { BinanceAccountSyncer };
@@ -0,0 +1,82 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { fetchUserTradesSince, fetchAllOrdersSince } from '../../client/binance/rest';
3
+ import { BaseAccountSyncer } from '../base';
4
+
5
+ class BinanceAccountSyncer extends BaseAccountSyncer {
6
+ creds;
7
+ constructor(config) {
8
+ super(config);
9
+ this.creds = config.credentials;
10
+ }
11
+ async listExternalFills({
12
+ since,
13
+ instruments,
14
+ openPositions,
15
+ provisionalFills
16
+ }) {
17
+ const knownInstrumentIds = new Set(instruments.map((instrument) => instrument.id));
18
+ const requestedInstrumentIds = this.collectRequestedInstrumentIds(openPositions, provisionalFills);
19
+ const instrumentIds = [...requestedInstrumentIds].filter((instrumentId) => knownInstrumentIds.has(instrumentId));
20
+ if (!instrumentIds.length) {
21
+ return [];
22
+ }
23
+ const [trades, orders] = await Promise.all([
24
+ fetchUserTradesSince(this.creds, instrumentIds, since, this.demo),
25
+ fetchAllOrdersSince(this.creds, instrumentIds, since, this.demo)
26
+ ]);
27
+ const ordersBySymbolOrderId = this.mapOrdersBySymbolOrderId(orders);
28
+ return trades.reduce((acc, trade) => {
29
+ if (!requestedInstrumentIds.has(trade.symbol)) {
30
+ return acc;
31
+ }
32
+ const order = ordersBySymbolOrderId.get(this.orderKey(trade.symbol, trade.orderId));
33
+ acc.push({
34
+ connector: "binance",
35
+ exchangeFillId: trade.id.toString(),
36
+ cloid: order?.clientOrderId || null,
37
+ symbol: trade.symbol,
38
+ price: trade.price,
39
+ quantity: trade.qty,
40
+ side: trade.side,
41
+ reduceOnly: this.isReduceOnly(trade),
42
+ timestamp: trade.time,
43
+ tradeFee: new BigNumber(trade.commission || 0).abs().toFixed(),
44
+ builderFee: "0",
45
+ liquidation: null
46
+ });
47
+ return acc;
48
+ }, []);
49
+ }
50
+ isReduceOnly(trade) {
51
+ if (trade.positionSide === "LONG") return trade.side === "SELL";
52
+ if (trade.positionSide === "SHORT") return trade.side === "BUY";
53
+ if (trade.positionSide === "BOTH") {
54
+ return !new BigNumber(trade.realizedPnl || 0).isZero();
55
+ }
56
+ return false;
57
+ }
58
+ collectRequestedInstrumentIds(openPositions, provisionalFills) {
59
+ const instrumentIds = /* @__PURE__ */ new Set();
60
+ for (const position of openPositions) {
61
+ for (const instrumentId of Object.keys(position.exposure)) {
62
+ instrumentIds.add(instrumentId);
63
+ }
64
+ }
65
+ for (const fill of provisionalFills) {
66
+ instrumentIds.add(fill.symbol);
67
+ }
68
+ return instrumentIds;
69
+ }
70
+ mapOrdersBySymbolOrderId(orders) {
71
+ const bySymbolOrderId = /* @__PURE__ */ new Map();
72
+ for (const order of orders) {
73
+ bySymbolOrderId.set(this.orderKey(order.symbol, order.orderId), order);
74
+ }
75
+ return bySymbolOrderId;
76
+ }
77
+ orderKey(symbol, orderId) {
78
+ return `${symbol}:${orderId}`;
79
+ }
80
+ }
81
+
82
+ export { BinanceAccountSyncer };
@@ -0,0 +1,28 @@
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { BybitRawExecution } from '../../client/bybit/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
4
+ import '@pear-protocol/core-sdk';
5
+ import '../../client/index.js';
6
+ import '../../types.js';
7
+ import '../../client/binance/exchange-ws.js';
8
+ import '../../client/base-ws.js';
9
+ import 'partysocket';
10
+ import '../../client/exchange-ws.js';
11
+ import '../../client/binance/ws.js';
12
+ import '../../client/bybit/exchange-ws.js';
13
+ import '../../client/bybit/ws.js';
14
+ import '../../client/hyperliquid/exchange-ws.js';
15
+ import '../../client/hyperliquid/ws.js';
16
+ import '../../client/lighter/exchange-ws.js';
17
+ import '../../client/lighter/ws.js';
18
+ import '../../client/okx/exchange-ws.js';
19
+ import '../../client/okx/ws.js';
20
+
21
+ declare class BybitAccountSyncer extends BaseAccountSyncer<BybitRawExecution> {
22
+ private readonly creds;
23
+ constructor(config: AccountSyncerConfig);
24
+ protected listExternalFills({ since }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
25
+ protected isReduceOnly(execution: BybitRawExecution): boolean;
26
+ }
27
+
28
+ export { BybitAccountSyncer };
@@ -0,0 +1,36 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { fetchExecutionsSince } from '../../client/bybit/rest';
3
+ import { BaseAccountSyncer } from '../base';
4
+
5
+ class BybitAccountSyncer extends BaseAccountSyncer {
6
+ creds;
7
+ constructor(config) {
8
+ super(config);
9
+ this.creds = config.credentials;
10
+ }
11
+ async listExternalFills({ since }) {
12
+ const executions = await fetchExecutionsSince(this.creds, since, this.demo);
13
+ return executions.reduce((acc, execution) => {
14
+ acc.push({
15
+ connector: "bybit",
16
+ exchangeFillId: execution.execId,
17
+ cloid: execution.orderLinkId || null,
18
+ symbol: execution.symbol,
19
+ price: execution.execPrice,
20
+ quantity: execution.execQty,
21
+ side: execution.side === "Buy" ? "BUY" : "SELL",
22
+ reduceOnly: this.isReduceOnly(execution),
23
+ timestamp: Number(execution.execTime),
24
+ tradeFee: new BigNumber(execution.execFee || 0).abs().toFixed(),
25
+ builderFee: "0",
26
+ liquidation: null
27
+ });
28
+ return acc;
29
+ }, []);
30
+ }
31
+ isReduceOnly(execution) {
32
+ return Number(execution.closedSize || "0") > 0;
33
+ }
34
+ }
35
+
36
+ export { BybitAccountSyncer };
@@ -0,0 +1,22 @@
1
+ import { Connector } from '@pear-protocol/types';
2
+ import { AccountSyncerConfig, AccountSyncer } from './base.js';
3
+ import '@pear-protocol/core-sdk';
4
+ import '../client/index.js';
5
+ import '../types.js';
6
+ import '../client/binance/exchange-ws.js';
7
+ import '../client/base-ws.js';
8
+ import 'partysocket';
9
+ import '../client/exchange-ws.js';
10
+ import '../client/binance/ws.js';
11
+ import '../client/bybit/exchange-ws.js';
12
+ import '../client/bybit/ws.js';
13
+ import '../client/hyperliquid/exchange-ws.js';
14
+ import '../client/hyperliquid/ws.js';
15
+ import '../client/lighter/exchange-ws.js';
16
+ import '../client/lighter/ws.js';
17
+ import '../client/okx/exchange-ws.js';
18
+ import '../client/okx/ws.js';
19
+
20
+ declare function createAccountSyncer(exchange: Connector, config: AccountSyncerConfig): AccountSyncer;
21
+
22
+ export { createAccountSyncer };
@@ -0,0 +1,26 @@
1
+ import { BinanceAccountSyncer } from './binance/syncer';
2
+ import { BybitAccountSyncer } from './bybit/syncer';
3
+ import { HyperliquidAccountSyncer } from './hyperliquid/syncer';
4
+ import { LighterAccountSyncer } from './lighter/syncer';
5
+ import { OkxAccountSyncer } from './okx/syncer';
6
+
7
+ function createAccountSyncer(exchange, config) {
8
+ switch (exchange) {
9
+ case "binance":
10
+ return new BinanceAccountSyncer(config);
11
+ case "bybit":
12
+ return new BybitAccountSyncer(config);
13
+ case "okx":
14
+ return new OkxAccountSyncer(config);
15
+ case "hyperliquid":
16
+ return new HyperliquidAccountSyncer(config);
17
+ case "lighter":
18
+ return new LighterAccountSyncer(config);
19
+ default: {
20
+ const _exhaustive = exchange;
21
+ throw new Error(`Unsupported exchange: ${String(_exhaustive)}`);
22
+ }
23
+ }
24
+ }
25
+
26
+ export { createAccountSyncer };
@@ -0,0 +1,28 @@
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { UserFillsByTimeResponse } from '../../client/hyperliquid/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
4
+ import '@pear-protocol/core-sdk';
5
+ import '../../client/index.js';
6
+ import '../../types.js';
7
+ import '../../client/binance/exchange-ws.js';
8
+ import '../../client/base-ws.js';
9
+ import 'partysocket';
10
+ import '../../client/exchange-ws.js';
11
+ import '../../client/binance/ws.js';
12
+ import '../../client/bybit/exchange-ws.js';
13
+ import '../../client/bybit/ws.js';
14
+ import '../../client/hyperliquid/exchange-ws.js';
15
+ import '../../client/hyperliquid/ws.js';
16
+ import '../../client/lighter/exchange-ws.js';
17
+ import '../../client/lighter/ws.js';
18
+ import '../../client/okx/exchange-ws.js';
19
+ import '../../client/okx/ws.js';
20
+
21
+ declare class HyperliquidAccountSyncer extends BaseAccountSyncer<UserFillsByTimeResponse> {
22
+ private readonly address;
23
+ constructor(config: AccountSyncerConfig);
24
+ protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
25
+ protected isReduceOnly(fill: UserFillsByTimeResponse): boolean;
26
+ }
27
+
28
+ export { HyperliquidAccountSyncer };
@@ -0,0 +1,53 @@
1
+ import { fetchInfo } from '../../client/hyperliquid/rest';
2
+ import { BaseAccountSyncer } from '../base';
3
+
4
+ class HyperliquidAccountSyncer extends BaseAccountSyncer {
5
+ address;
6
+ constructor(config) {
7
+ super(config);
8
+ const creds = config.credentials;
9
+ this.address = creds.accountIdentifier;
10
+ }
11
+ async listExternalFills({
12
+ since,
13
+ instruments
14
+ }) {
15
+ const instrumentSymbolToIdMap = instruments.reduce((acc, instrument) => {
16
+ acc[instrument.base] = instrument.id;
17
+ return acc;
18
+ }, {});
19
+ const result = await fetchInfo({
20
+ type: "userFillsByTime",
21
+ user: this.address,
22
+ startTime: since.getTime(),
23
+ aggregateByTime: true
24
+ });
25
+ return result.reduce((acc, fill) => {
26
+ const instrumentId = instrumentSymbolToIdMap[fill.coin];
27
+ if (!instrumentId) {
28
+ console.warn(`Instrument symbol ${fill.coin} not found in instrument symbol to id map.`);
29
+ return acc;
30
+ }
31
+ acc.push({
32
+ connector: "hyperliquid",
33
+ exchangeFillId: fill.tid.toFixed(),
34
+ cloid: fill.cloid ?? null,
35
+ symbol: instrumentId,
36
+ price: fill.px,
37
+ quantity: fill.sz,
38
+ side: fill.side === "B" ? "BUY" : "SELL",
39
+ reduceOnly: this.isReduceOnly(fill),
40
+ timestamp: fill.time,
41
+ tradeFee: fill.fee,
42
+ builderFee: fill.builderFee ?? "0",
43
+ liquidation: fill.liquidation ? { mark: fill.liquidation.markPx } : null
44
+ });
45
+ return acc;
46
+ }, []);
47
+ }
48
+ isReduceOnly(fill) {
49
+ return fill.dir.includes("Close");
50
+ }
51
+ }
52
+
53
+ export { HyperliquidAccountSyncer };
@@ -1,4 +1,10 @@
1
- export { AccountPositionSyncer, AccountPositionSyncerConfig } from './base.js';
1
+ export { AccountSyncer, AccountSyncerConfig, BaseAccountSyncer, ListExternalFillsParams } from './base.js';
2
+ export { BinanceAccountSyncer } from './binance/syncer.js';
3
+ export { BybitAccountSyncer } from './bybit/syncer.js';
4
+ export { createAccountSyncer } from './factory.js';
5
+ export { HyperliquidAccountSyncer } from './hyperliquid/syncer.js';
6
+ export { LighterAccountSyncer } from './lighter/syncer.js';
7
+ export { OkxAccountSyncer } from './okx/syncer.js';
2
8
  import '@pear-protocol/core-sdk';
3
9
  import '@pear-protocol/types';
4
10
  import '../client/index.js';
@@ -16,3 +22,8 @@ import '../client/lighter/exchange-ws.js';
16
22
  import '../client/lighter/ws.js';
17
23
  import '../client/okx/exchange-ws.js';
18
24
  import '../client/okx/ws.js';
25
+ import '../client/binance/types.js';
26
+ import '../client/bybit/types.js';
27
+ import '../client/hyperliquid/types.js';
28
+ import '../client/lighter/types.js';
29
+ import '../client/okx/types.js';
@@ -1 +1,7 @@
1
1
  export * from './base';
2
+ export * from './binance/syncer';
3
+ export * from './bybit/syncer';
4
+ export * from './factory';
5
+ export * from './hyperliquid/syncer';
6
+ export * from './lighter/syncer';
7
+ export * from './okx/syncer';
@@ -0,0 +1,37 @@
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { LighterRawTrade } from '../../client/lighter/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
4
+ import '@pear-protocol/core-sdk';
5
+ import '../../client/index.js';
6
+ import '../../types.js';
7
+ import '../../client/binance/exchange-ws.js';
8
+ import '../../client/base-ws.js';
9
+ import 'partysocket';
10
+ import '../../client/exchange-ws.js';
11
+ import '../../client/binance/ws.js';
12
+ import '../../client/bybit/exchange-ws.js';
13
+ import '../../client/bybit/ws.js';
14
+ import '../../client/hyperliquid/exchange-ws.js';
15
+ import '../../client/hyperliquid/ws.js';
16
+ import '../../client/lighter/exchange-ws.js';
17
+ import '../../client/lighter/ws.js';
18
+ import '../../client/okx/exchange-ws.js';
19
+ import '../../client/okx/ws.js';
20
+
21
+ declare class LighterAccountSyncer extends BaseAccountSyncer<LighterRawTrade> {
22
+ private readonly accountIndex;
23
+ private readonly apiKeyIndex;
24
+ private readonly apiPrivateKey;
25
+ constructor(config: AccountSyncerConfig);
26
+ protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
27
+ protected isReduceOnly(trade: LighterRawTrade): boolean;
28
+ private getAccountSide;
29
+ private getClientOrderId;
30
+ private isMaker;
31
+ private getPositionSizeBefore;
32
+ private getTradeFee;
33
+ private getIntegratorFee;
34
+ private feeTickToDecimal;
35
+ }
36
+
37
+ export { LighterAccountSyncer };
@@ -0,0 +1,94 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { fetchTradesSince } from '../../client/lighter/rest';
3
+ import { BaseAccountSyncer } from '../base';
4
+
5
+ const LIGHTER_FEE_TICK_DENOMINATOR = new BigNumber(1e6);
6
+ class LighterAccountSyncer extends BaseAccountSyncer {
7
+ accountIndex;
8
+ apiKeyIndex;
9
+ apiPrivateKey;
10
+ constructor(config) {
11
+ super(config);
12
+ const creds = config.credentials;
13
+ this.accountIndex = Number(creds.accountIdentifier);
14
+ this.apiKeyIndex = creds.api_key_index;
15
+ this.apiPrivateKey = creds.api_private_key;
16
+ }
17
+ async listExternalFills({
18
+ since,
19
+ instruments
20
+ }) {
21
+ const { token } = await this.sdk.core.misc.lighter.createAuthToken({
22
+ accountIndex: this.accountIndex,
23
+ apiKeyIndex: this.apiKeyIndex,
24
+ apiPrivateKey: this.apiPrivateKey
25
+ });
26
+ const trades = await fetchTradesSince(this.accountIndex, token, since);
27
+ const instrumentIds = new Set(instruments.map((instrument) => instrument.id));
28
+ return trades.toSorted((a, b) => a.timestamp - b.timestamp).reduce((acc, trade) => {
29
+ const instrumentId = trade.market_id.toString();
30
+ if (!instrumentIds.has(instrumentId)) {
31
+ console.warn(`Lighter market id ${trade.market_id} not found in instrument id map.`);
32
+ return acc;
33
+ }
34
+ const accountSide = this.getAccountSide(trade);
35
+ if (!accountSide) return acc;
36
+ const side = accountSide === "ask" ? "SELL" : "BUY";
37
+ acc.push({
38
+ connector: "lighter",
39
+ exchangeFillId: trade.trade_id_str ?? trade.trade_id.toString(),
40
+ cloid: this.getClientOrderId(trade, accountSide),
41
+ symbol: instrumentId,
42
+ price: trade.price,
43
+ quantity: trade.size,
44
+ side,
45
+ reduceOnly: this.isReduceOnly(trade),
46
+ timestamp: trade.timestamp,
47
+ tradeFee: this.feeTickToDecimal(this.getTradeFee(trade, accountSide)),
48
+ builderFee: this.feeTickToDecimal(this.getIntegratorFee(trade, accountSide)),
49
+ liquidation: trade.type === "liquidation" ? { mark: trade.price } : null
50
+ });
51
+ return acc;
52
+ }, []);
53
+ }
54
+ isReduceOnly(trade) {
55
+ if (trade.type === "liquidation" || trade.type === "deleverage" || trade.type === "market-settlement") {
56
+ return true;
57
+ }
58
+ const accountSide = this.getAccountSide(trade);
59
+ if (!accountSide) {
60
+ return false;
61
+ }
62
+ const positionSizeBefore = this.getPositionSizeBefore(trade, accountSide);
63
+ if (positionSizeBefore.isZero()) {
64
+ return false;
65
+ }
66
+ return positionSizeBefore.isPositive() && accountSide === "ask" || positionSizeBefore.isNegative() && accountSide === "bid";
67
+ }
68
+ getAccountSide(trade) {
69
+ if (trade.ask_account_id === this.accountIndex) return "ask";
70
+ if (trade.bid_account_id === this.accountIndex) return "bid";
71
+ return null;
72
+ }
73
+ getClientOrderId(trade, side) {
74
+ return (side === "ask" ? trade.ask_client_id_str : trade.bid_client_id_str) || null;
75
+ }
76
+ isMaker(trade, side) {
77
+ return side === "ask" ? trade.is_maker_ask : !trade.is_maker_ask;
78
+ }
79
+ getPositionSizeBefore(trade, side) {
80
+ const value = this.isMaker(trade, side) ? trade.maker_position_size_before : trade.taker_position_size_before;
81
+ return new BigNumber(value ?? 0);
82
+ }
83
+ getTradeFee(trade, side) {
84
+ return this.isMaker(trade, side) ? trade.maker_fee ?? 0 : trade.taker_fee ?? 0;
85
+ }
86
+ getIntegratorFee(trade, side) {
87
+ return this.isMaker(trade, side) ? trade.integrator_maker_fee ?? 0 : trade.integrator_taker_fee ?? 0;
88
+ }
89
+ feeTickToDecimal(value) {
90
+ return new BigNumber(value).abs().div(LIGHTER_FEE_TICK_DENOMINATOR).toFixed();
91
+ }
92
+ }
93
+
94
+ export { LighterAccountSyncer };
@@ -0,0 +1,29 @@
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { OkxRawFill } from '../../client/okx/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
4
+ import '@pear-protocol/core-sdk';
5
+ import '../../client/index.js';
6
+ import '../../types.js';
7
+ import '../../client/binance/exchange-ws.js';
8
+ import '../../client/base-ws.js';
9
+ import 'partysocket';
10
+ import '../../client/exchange-ws.js';
11
+ import '../../client/binance/ws.js';
12
+ import '../../client/bybit/exchange-ws.js';
13
+ import '../../client/bybit/ws.js';
14
+ import '../../client/hyperliquid/exchange-ws.js';
15
+ import '../../client/hyperliquid/ws.js';
16
+ import '../../client/lighter/exchange-ws.js';
17
+ import '../../client/lighter/ws.js';
18
+ import '../../client/okx/exchange-ws.js';
19
+ import '../../client/okx/ws.js';
20
+
21
+ declare class OkxAccountSyncer extends BaseAccountSyncer<OkxRawFill> {
22
+ private readonly creds;
23
+ constructor(config: AccountSyncerConfig);
24
+ protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
25
+ protected isReduceOnly(fill: OkxRawFill): boolean;
26
+ private contractsToBase;
27
+ }
28
+
29
+ export { OkxAccountSyncer };
@@ -0,0 +1,48 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { fetchFillsHistorySince } from '../../client/okx/rest';
3
+ import { BaseAccountSyncer } from '../base';
4
+
5
+ class OkxAccountSyncer extends BaseAccountSyncer {
6
+ creds;
7
+ constructor(config) {
8
+ super(config);
9
+ this.creds = config.credentials;
10
+ }
11
+ async listExternalFills({
12
+ since,
13
+ instruments
14
+ }) {
15
+ const fills = await fetchFillsHistorySince(this.creds, since, this.demo);
16
+ const contractSizeByInstrumentId = new Map(
17
+ instruments.map((instrument) => [instrument.id, instrument.precision.quantity.contractSize])
18
+ );
19
+ return fills.reduce((acc, fill) => {
20
+ const contractSize = contractSizeByInstrumentId.get(fill.instId) ?? 1;
21
+ acc.push({
22
+ connector: "okx",
23
+ exchangeFillId: fill.billId || fill.tradeId,
24
+ cloid: fill.clOrdId || null,
25
+ symbol: fill.instId,
26
+ price: fill.fillPx,
27
+ quantity: this.contractsToBase(fill.fillSz, contractSize),
28
+ side: fill.side === "buy" ? "BUY" : "SELL",
29
+ reduceOnly: this.isReduceOnly(fill),
30
+ timestamp: Number(fill.fillTime || fill.ts),
31
+ tradeFee: new BigNumber(fill.fee || 0).abs().toFixed(),
32
+ builderFee: "0",
33
+ liquidation: null
34
+ });
35
+ return acc;
36
+ }, []);
37
+ }
38
+ isReduceOnly(fill) {
39
+ if (fill.posSide === "long") return fill.side === "sell";
40
+ if (fill.posSide === "short") return fill.side === "buy";
41
+ return false;
42
+ }
43
+ contractsToBase(quantity, contractSize) {
44
+ return new BigNumber(quantity).times(contractSize).toFixed();
45
+ }
46
+ }
47
+
48
+ export { OkxAccountSyncer };