@pear-protocol/exchanges-sdk 0.1.3 → 0.1.5

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.
@@ -1,5 +1,5 @@
1
1
  import { BinanceCredentialsDTO } from '@pear-protocol/types';
2
- import { BinanceRawAccountStatus, BinanceRawPositionRisk } from './types.js';
2
+ import { BinanceRawAccountStatus, BinanceRawOrder, BinanceRawPositionRisk, BinanceRawUserTrade } from './types.js';
3
3
 
4
4
  declare function createListenKey(apiKey: string, demo?: boolean): Promise<string>;
5
5
  declare function keepAliveListenKey(apiKey: string, demo?: boolean): Promise<void>;
@@ -7,5 +7,7 @@ declare function fetchAccountStatus(creds: BinanceCredentialsDTO, demo: boolean)
7
7
  declare function fetchPositionRisk(creds: BinanceCredentialsDTO, symbol: string, demo: boolean): Promise<BinanceRawPositionRisk | undefined>;
8
8
  declare function fetchAllPositionRisk(creds: BinanceCredentialsDTO, demo: boolean): Promise<BinanceRawPositionRisk[]>;
9
9
  declare function fetchMultiAssetsMargin(creds: BinanceCredentialsDTO, demo: boolean): Promise<boolean>;
10
+ declare function fetchUserTradesSince(creds: BinanceCredentialsDTO, symbols: string[], since: Date, demo: boolean): Promise<BinanceRawUserTrade[]>;
11
+ declare function fetchAllOrdersSince(creds: BinanceCredentialsDTO, symbols: string[], since: Date, demo: boolean): Promise<BinanceRawOrder[]>;
10
12
 
11
- export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchMultiAssetsMargin, fetchPositionRisk, keepAliveListenKey };
13
+ export { createListenKey, fetchAccountStatus, fetchAllOrdersSince, fetchAllPositionRisk, fetchMultiAssetsMargin, fetchPositionRisk, fetchUserTradesSince, keepAliveListenKey };
@@ -54,5 +54,79 @@ async function fetchMultiAssetsMargin(creds, demo) {
54
54
  const res = await signedGet(creds, "/fapi/v1/multiAssetsMargin", {}, demo);
55
55
  return res.multiAssetsMargin;
56
56
  }
57
+ const USER_TRADES_LIMIT = 1e3;
58
+ const ALL_ORDERS_LIMIT = 1e3;
59
+ const BINANCE_MAX_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
60
+ async function fetchUserTradesSince(creds, symbols, since, demo) {
61
+ const now = Date.now();
62
+ const results = [];
63
+ for (const symbol of symbols) {
64
+ let windowStart = since.getTime();
65
+ while (windowStart <= now) {
66
+ const windowEnd = Math.min(windowStart + BINANCE_MAX_WINDOW_MS - 1, now);
67
+ let pageStart = windowStart;
68
+ while (pageStart <= windowEnd) {
69
+ const page = await signedGet(
70
+ creds,
71
+ "/fapi/v1/userTrades",
72
+ {
73
+ symbol,
74
+ startTime: pageStart.toString(),
75
+ endTime: windowEnd.toString(),
76
+ limit: USER_TRADES_LIMIT.toString()
77
+ },
78
+ demo
79
+ );
80
+ results.push(...page);
81
+ if (page.length < USER_TRADES_LIMIT) break;
82
+ const last = page[page.length - 1];
83
+ if (!last || last.time <= pageStart) break;
84
+ pageStart = last.time + 1;
85
+ }
86
+ windowStart = windowEnd + 1;
87
+ }
88
+ }
89
+ const byId = /* @__PURE__ */ new Map();
90
+ for (const trade of results) {
91
+ byId.set(`${trade.symbol}:${trade.id}`, trade);
92
+ }
93
+ return Array.from(byId.values());
94
+ }
95
+ async function fetchAllOrdersSince(creds, symbols, since, demo) {
96
+ const now = Date.now();
97
+ const results = [];
98
+ for (const symbol of symbols) {
99
+ let windowStart = since.getTime();
100
+ while (windowStart <= now) {
101
+ const windowEnd = Math.min(windowStart + BINANCE_MAX_WINDOW_MS - 1, now);
102
+ let pageStart = windowStart;
103
+ while (pageStart <= windowEnd) {
104
+ const page = await signedGet(
105
+ creds,
106
+ "/fapi/v1/allOrders",
107
+ {
108
+ symbol,
109
+ startTime: pageStart.toString(),
110
+ endTime: windowEnd.toString(),
111
+ limit: ALL_ORDERS_LIMIT.toString()
112
+ },
113
+ demo
114
+ );
115
+ results.push(...page);
116
+ if (page.length < ALL_ORDERS_LIMIT) break;
117
+ const last = page[page.length - 1];
118
+ const lastTs = last ? Math.max(last.updateTime, last.time) : pageStart;
119
+ if (lastTs <= pageStart) break;
120
+ pageStart = lastTs + 1;
121
+ }
122
+ windowStart = windowEnd + 1;
123
+ }
124
+ }
125
+ const byId = /* @__PURE__ */ new Map();
126
+ for (const order of results) {
127
+ byId.set(`${order.symbol}:${order.orderId}`, order);
128
+ }
129
+ return Array.from(byId.values());
130
+ }
57
131
 
58
- export { createListenKey, fetchAccountStatus, fetchAllPositionRisk, fetchMultiAssetsMargin, fetchPositionRisk, keepAliveListenKey };
132
+ export { createListenKey, fetchAccountStatus, fetchAllOrdersSince, fetchAllPositionRisk, fetchMultiAssetsMargin, fetchPositionRisk, fetchUserTradesSince, keepAliveListenKey };
@@ -40,6 +40,41 @@ interface BinanceRawAccountStatus {
40
40
  interface BinanceMultiAssetsMarginResponse {
41
41
  multiAssetsMargin: boolean;
42
42
  }
43
+ interface BinanceRawUserTrade {
44
+ buyer: boolean;
45
+ commission: string;
46
+ commissionAsset: string;
47
+ id: number;
48
+ maker: boolean;
49
+ orderId: number;
50
+ price: string;
51
+ qty: string;
52
+ quoteQty: string;
53
+ realizedPnl: string;
54
+ side: 'BUY' | 'SELL';
55
+ positionSide: string;
56
+ symbol: string;
57
+ time: number;
58
+ }
59
+ interface BinanceRawOrder {
60
+ avgPrice: string;
61
+ clientOrderId: string;
62
+ cumQuote: string;
63
+ executedQty: string;
64
+ orderId: number;
65
+ origQty: string;
66
+ origType: string;
67
+ price: string;
68
+ reduceOnly: boolean;
69
+ side: 'BUY' | 'SELL';
70
+ positionSide: string;
71
+ status: string;
72
+ symbol: string;
73
+ time: number;
74
+ timeInForce: string;
75
+ type: string;
76
+ updateTime: number;
77
+ }
43
78
  interface BinanceAssetIndex {
44
79
  symbol: string;
45
80
  time: number;
@@ -65,4 +100,4 @@ interface BinanceRawUserDataEvent {
65
100
  };
66
101
  }
67
102
 
68
- export type { BinanceAssetIndex, BinanceMultiAssetsMarginResponse, BinanceRawAccountStatus, BinanceRawAsset, BinanceRawPositionRisk, BinanceRawUserDataEvent };
103
+ export type { BinanceAssetIndex, BinanceMultiAssetsMarginResponse, BinanceRawAccountStatus, BinanceRawAsset, BinanceRawOrder, BinanceRawPositionRisk, BinanceRawUserDataEvent, BinanceRawUserTrade };
@@ -1,10 +1,11 @@
1
1
  import { BybitCredentialsDTO } from '@pear-protocol/types';
2
- import { BybitRawAccountInfo, BybitRawPosition, BybitRawWallet } from './types.js';
2
+ import { BybitRawAccountInfo, BybitRawExecution, BybitRawPosition, BybitRawWallet } from './types.js';
3
3
 
4
4
  declare function fetchWalletBalance(creds: BybitCredentialsDTO, demo: boolean): Promise<BybitRawWallet | undefined>;
5
5
  declare function fetchPositions(creds: BybitCredentialsDTO, settleCoin: string, demo: boolean): Promise<BybitRawPosition[]>;
6
6
  declare function fetchPositionLeverage(creds: BybitCredentialsDTO, symbol: string, demo: boolean): Promise<BybitRawPosition | undefined>;
7
7
  declare function fetchAccountInfo(creds: BybitCredentialsDTO, demo: boolean): Promise<BybitRawAccountInfo>;
8
8
  declare function fetchCollateralRatios(creds: BybitCredentialsDTO, demo: boolean): Promise<Map<string, string>>;
9
+ declare function fetchExecutionsSince(creds: BybitCredentialsDTO, since: Date, demo: boolean): Promise<BybitRawExecution[]>;
9
10
 
10
- export { fetchAccountInfo, fetchCollateralRatios, fetchPositionLeverage, fetchPositions, fetchWalletBalance };
11
+ export { fetchAccountInfo, fetchCollateralRatios, fetchExecutionsSince, fetchPositionLeverage, fetchPositions, fetchWalletBalance };
@@ -72,5 +72,38 @@ async function fetchCollateralRatios(creds, demo) {
72
72
  }
73
73
  return ratios;
74
74
  }
75
+ const EXECUTIONS_LIMIT = 100;
76
+ const BYBIT_MAX_WINDOW_MS = 7 * 24 * 60 * 60 * 1e3;
77
+ async function fetchExecutionsSince(creds, since, demo) {
78
+ const results = [];
79
+ const now = Date.now();
80
+ let windowStart = since.getTime();
81
+ while (windowStart <= now) {
82
+ const windowEnd = Math.min(windowStart + BYBIT_MAX_WINDOW_MS - 1, now);
83
+ let cursor;
84
+ do {
85
+ const result = await signedGet(
86
+ creds,
87
+ "/v5/execution/list",
88
+ {
89
+ category: "linear",
90
+ startTime: windowStart.toString(),
91
+ endTime: windowEnd.toString(),
92
+ limit: EXECUTIONS_LIMIT.toString(),
93
+ ...cursor ? { cursor } : {}
94
+ },
95
+ demo
96
+ );
97
+ results.push(...result.list ?? []);
98
+ cursor = result.nextPageCursor || void 0;
99
+ } while (cursor);
100
+ windowStart = windowEnd + 1;
101
+ }
102
+ const byId = /* @__PURE__ */ new Map();
103
+ for (const execution of results) {
104
+ byId.set(execution.execId, execution);
105
+ }
106
+ return Array.from(byId.values());
107
+ }
75
108
 
76
- export { fetchAccountInfo, fetchCollateralRatios, fetchPositionLeverage, fetchPositions, fetchWalletBalance };
109
+ export { fetchAccountInfo, fetchCollateralRatios, fetchExecutionsSince, fetchPositionLeverage, fetchPositions, fetchWalletBalance };
@@ -46,6 +46,19 @@ interface BybitRawPosition {
46
46
  tradeMode: string;
47
47
  liqPrice: string;
48
48
  }
49
+ interface BybitRawExecution {
50
+ symbol: string;
51
+ orderId: string;
52
+ orderLinkId: string;
53
+ side: 'Buy' | 'Sell';
54
+ execFee: string;
55
+ execId: string;
56
+ execPrice: string;
57
+ execQty: string;
58
+ execTime: string;
59
+ execType: string;
60
+ closedSize: string;
61
+ }
49
62
  interface BybitResponse<T> {
50
63
  retCode: number;
51
64
  retMsg: string;
@@ -59,4 +72,4 @@ type BybitWsMessage = {
59
72
  data: BybitRawPosition[];
60
73
  };
61
74
 
62
- export type { BybitRawAccountInfo, BybitRawCoin, BybitRawCollateralRatioEntry, BybitRawCollateralTier, BybitRawPosition, BybitRawWallet, BybitResponse, BybitWsMessage };
75
+ export type { BybitRawAccountInfo, BybitRawCoin, BybitRawCollateralRatioEntry, BybitRawCollateralTier, BybitRawExecution, BybitRawPosition, BybitRawWallet, BybitResponse, BybitWsMessage };
@@ -1,3 +1,5 @@
1
+ import { LighterRawTrade } from './types.js';
2
+
1
3
  type ApiKey = {
2
4
  account_index: number;
3
5
  api_key_index: number;
@@ -52,5 +54,6 @@ declare function fetchApiKeys(accountIndex: number): Promise<ApiKey[]>;
52
54
  declare function fetchAccountsByL1Address(l1Address: string): Promise<LighterAccountResponse>;
53
55
  declare function fetchAccount(accountIndex: number): Promise<DetailedAccountResponse>;
54
56
  declare function fetchOrderBookDetails(): Promise<OrderBookDetail[]>;
57
+ declare function fetchTradesSince(accountIndex: number, authToken: string, since: Date): Promise<LighterRawTrade[]>;
55
58
 
56
- export { type ApiKey, type ApprovedIntegrator, type DetailedAccountResponse, type LighterAccountResponse, type LighterSubAccount, type OrderBookDetail, type RestPosition, fetchAccount, fetchAccountsByL1Address, fetchApiKeys, fetchOrderBookDetails };
59
+ export { type ApiKey, type ApprovedIntegrator, type DetailedAccountResponse, type LighterAccountResponse, type LighterSubAccount, type OrderBookDetail, type RestPosition, fetchAccount, fetchAccountsByL1Address, fetchApiKeys, fetchOrderBookDetails, fetchTradesSince };
@@ -23,5 +23,40 @@ async function fetchOrderBookDetails() {
23
23
  const data = await res.json();
24
24
  return data.order_book_details;
25
25
  }
26
+ async function fetchTradesSince(accountIndex, authToken, since) {
27
+ const results = [];
28
+ let cursor;
29
+ do {
30
+ const params = new URLSearchParams({
31
+ market_type: "all",
32
+ account_index: accountIndex.toString(),
33
+ sort_by: "timestamp",
34
+ sort_dir: "desc",
35
+ ask_filter: "-1",
36
+ role: "all",
37
+ type: "all",
38
+ limit: "100",
39
+ aggregate: "false",
40
+ ...cursor ? { cursor } : {}
41
+ });
42
+ const res = await fetch(`${LIGHTER_BASE_URL}/api/v1/trades?${params.toString()}`, {
43
+ headers: { authorization: authToken }
44
+ });
45
+ if (!res.ok) throw new Error(`Lighter /trades returned ${res.status}`);
46
+ const data = await res.json();
47
+ if (data.code !== 200) {
48
+ throw new Error(`Lighter /trades returned ${data.code}: ${data.message ?? "unknown error"}`);
49
+ }
50
+ const page = data.trades ?? [];
51
+ results.push(...page.filter((trade) => trade.timestamp >= since.getTime()));
52
+ const reachedSince = page.some((trade) => trade.timestamp < since.getTime());
53
+ cursor = reachedSince ? void 0 : data.next_cursor || void 0;
54
+ } while (cursor);
55
+ const byId = /* @__PURE__ */ new Map();
56
+ for (const trade of results) {
57
+ byId.set(trade.trade_id_str ?? trade.trade_id.toString(), trade);
58
+ }
59
+ return Array.from(byId.values());
60
+ }
26
61
 
27
- export { fetchAccount, fetchAccountsByL1Address, fetchApiKeys, fetchOrderBookDetails };
62
+ export { fetchAccount, fetchAccountsByL1Address, fetchApiKeys, fetchOrderBookDetails, fetchTradesSince };
@@ -28,5 +28,26 @@ type UserStatsEvent = {
28
28
  margin_usage: string;
29
29
  };
30
30
  };
31
+ type LighterRawTrade = {
32
+ trade_id: number;
33
+ trade_id_str?: string;
34
+ type: 'trade' | 'liquidation' | 'deleverage' | 'market-settlement' | string;
35
+ market_id: number;
36
+ size: string;
37
+ price: string;
38
+ usd_amount: string;
39
+ ask_client_id_str?: string;
40
+ bid_client_id_str?: string;
41
+ ask_account_id: number;
42
+ bid_account_id: number;
43
+ is_maker_ask: boolean;
44
+ timestamp: number;
45
+ taker_fee?: number;
46
+ taker_position_size_before?: string;
47
+ maker_fee?: number;
48
+ maker_position_size_before?: string;
49
+ integrator_taker_fee?: number;
50
+ integrator_maker_fee?: number;
51
+ };
31
52
 
32
- export type { AccountAllEvent, RawAsset, RawPosition, UserStatsEvent };
53
+ export type { AccountAllEvent, LighterRawTrade, RawAsset, RawPosition, UserStatsEvent };
@@ -1,9 +1,10 @@
1
1
  import { OkxCredentialsDTO } from '@pear-protocol/types';
2
- import { OkxRawAccountConfig, OkxRawBalance, OkxRawLeverageInfo, OkxRawPosition } from './types.js';
2
+ import { OkxRawAccountConfig, OkxRawBalance, OkxRawFill, OkxRawLeverageInfo, OkxRawPosition } from './types.js';
3
3
 
4
4
  declare function fetchAccountConfig(creds: OkxCredentialsDTO, demo: boolean): Promise<OkxRawAccountConfig>;
5
5
  declare function fetchBalance(creds: OkxCredentialsDTO, demo: boolean): Promise<OkxRawBalance>;
6
6
  declare function fetchPositions(creds: OkxCredentialsDTO, demo: boolean): Promise<OkxRawPosition[]>;
7
7
  declare function fetchLeverageInfo(creds: OkxCredentialsDTO, instId: string, demo: boolean): Promise<OkxRawLeverageInfo | undefined>;
8
+ declare function fetchFillsHistorySince(creds: OkxCredentialsDTO, since: Date, demo: boolean): Promise<OkxRawFill[]>;
8
9
 
9
- export { fetchAccountConfig, fetchBalance, fetchLeverageInfo, fetchPositions };
10
+ export { fetchAccountConfig, fetchBalance, fetchFillsHistorySince, fetchLeverageInfo, fetchPositions };
@@ -53,5 +53,32 @@ async function fetchLeverageInfo(creds, instId, demo) {
53
53
  ).catch(() => []);
54
54
  return result[0];
55
55
  }
56
+ const FILLS_HISTORY_LIMIT = 100;
57
+ async function fetchFillsHistorySince(creds, since, demo) {
58
+ const results = [];
59
+ let after;
60
+ do {
61
+ const page = await signedGet(
62
+ creds,
63
+ "/api/v5/trade/fills-history",
64
+ {
65
+ instType: "SWAP",
66
+ begin: since.getTime().toString(),
67
+ end: Date.now().toString(),
68
+ limit: FILLS_HISTORY_LIMIT.toString(),
69
+ ...after ? { after } : {}
70
+ },
71
+ demo
72
+ );
73
+ results.push(...page);
74
+ const last = page[page.length - 1];
75
+ after = page.length === FILLS_HISTORY_LIMIT && last?.billId ? last.billId : void 0;
76
+ } while (after);
77
+ const byId = /* @__PURE__ */ new Map();
78
+ for (const fill of results) {
79
+ byId.set(fill.billId || fill.tradeId, fill);
80
+ }
81
+ return Array.from(byId.values());
82
+ }
56
83
 
57
- export { fetchAccountConfig, fetchBalance, fetchLeverageInfo, fetchPositions };
84
+ export { fetchAccountConfig, fetchBalance, fetchFillsHistorySince, fetchLeverageInfo, fetchPositions };
@@ -42,6 +42,23 @@ interface OkxRawLeverageInfo {
42
42
  lever: string;
43
43
  mgnMode: string;
44
44
  }
45
+ interface OkxRawFill {
46
+ instType: string;
47
+ instId: string;
48
+ tradeId: string;
49
+ ordId: string;
50
+ clOrdId: string;
51
+ billId: string;
52
+ fillPx: string;
53
+ fillSz: string;
54
+ side: 'buy' | 'sell';
55
+ posSide: string;
56
+ execType: string;
57
+ fee: string;
58
+ feeCcy: string;
59
+ fillTime: string;
60
+ ts: string;
61
+ }
45
62
  interface OkxWsAccountMessage {
46
63
  arg: {
47
64
  channel: 'account';
@@ -57,4 +74,4 @@ interface OkxWsPositionsMessage {
57
74
  }
58
75
  type OkxWsMessage = OkxWsAccountMessage | OkxWsPositionsMessage;
59
76
 
60
- export type { OkxRawAccountConfig, OkxRawBalance, OkxRawBalanceDetail, OkxRawLeverageInfo, OkxRawPosition, OkxWsAccountMessage, OkxWsMessage, OkxWsPositionsMessage };
77
+ export type { OkxRawAccountConfig, OkxRawBalance, OkxRawBalanceDetail, OkxRawFill, OkxRawLeverageInfo, OkxRawPosition, OkxWsAccountMessage, OkxWsMessage, OkxWsPositionsMessage };
@@ -4,6 +4,7 @@ import './lighter/types.js';
4
4
  import './lighter/ethereum/types.js';
5
5
  import 'viem';
6
6
  import '../client/lighter/rest.js';
7
+ import '../client/lighter/types.js';
7
8
 
8
9
  declare function createExchangeHelper<E extends ExchangeHelperExchange>(exchange: E, sdk: PearSDK): ExchangeHelperMap[E];
9
10
 
@@ -4,4 +4,5 @@ export { ExchangeHelperExchange, ExchangeHelperMap } from './types.js';
4
4
  export { ApiKey } from '../client/lighter/rest.js';
5
5
  export { WalletClientWithAccount } from './lighter/ethereum/types.js';
6
6
  import '@pear-protocol/core-sdk';
7
+ import '../client/lighter/types.js';
7
8
  import 'viem';
@@ -3,6 +3,7 @@ import { LighterHelper } from './types.js';
3
3
  import '../../client/lighter/rest.js';
4
4
  import './ethereum/types.js';
5
5
  import 'viem';
6
+ import '../../client/lighter/types.js';
6
7
 
7
8
  declare function createLighterHelper(sdk: PearSDK): LighterHelper;
8
9
 
@@ -26,7 +26,7 @@ function createLighterHelper(sdk) {
26
26
  },
27
27
  async connectWallet(walletClient, params) {
28
28
  const apiKeys = await fetchApiKeys(params.accountIndex);
29
- const apiKeyIndex = apiKeys.length === 0 ? 3 : apiKeys.reduce((max, k) => k.api_key_index > max ? k.api_key_index : max, 0) + 1;
29
+ const apiKeyIndex = Math.max(4, ...apiKeys.map((k) => k.api_key_index + 1));
30
30
  const { privateKey, messageToSign, txInfo } = await sdk.core.misc.lighter.createApiKey({
31
31
  accountIndex: params.accountIndex,
32
32
  apiKeyIndex
@@ -4,3 +4,4 @@ export { ApiKey } from '../../client/lighter/rest.js';
4
4
  export { WalletClientWithAccount } from './ethereum/types.js';
5
5
  import '@pear-protocol/core-sdk';
6
6
  import 'viem';
7
+ import '../../client/lighter/types.js';
@@ -1,6 +1,7 @@
1
1
  import { WalletClientWithAccount } from './ethereum/types.js';
2
2
  export { ApiKey } from '../../client/lighter/rest.js';
3
3
  import 'viem';
4
+ import '../../client/lighter/types.js';
4
5
 
5
6
  declare const AssetId: {
6
7
  readonly ETH: 1;
@@ -2,6 +2,7 @@ import { LighterHelper } from './lighter/types.js';
2
2
  import './lighter/ethereum/types.js';
3
3
  import 'viem';
4
4
  import '../client/lighter/rest.js';
5
+ import '../client/lighter/types.js';
5
6
 
6
7
  type ExchangeHelperMap = {
7
8
  lighter: LighterHelper;
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export { createLighterHelper } from './helper/lighter/helper.js';
3
3
  export { ASSET_DECIMALS, ApproveIntegratorParams, ApproveIntegratorResult, AssetId, ConnectWalletParams, ConnectWalletResult, DepositParams, LighterHelper, LighterLookupResult, RouteType, WithdrawParams, getAssetDecimals } from './helper/lighter/types.js';
4
4
  export { ExchangeHelperExchange, ExchangeHelperMap } from './helper/types.js';
5
5
  export { ExchangesSDK } from './sdk.js';
6
- export { AccountSyncer, AccountSyncerConfig, BaseAccountSyncer } from './syncer/base.js';
6
+ export { AccountSyncer, AccountSyncerConfig, BaseAccountSyncer, ListExternalFillsParams } from './syncer/base.js';
7
7
  export { BinanceAccountSyncer } from './syncer/binance/syncer.js';
8
8
  export { BybitAccountSyncer } from './syncer/bybit/syncer.js';
9
9
  export { createAccountSyncer } from './syncer/factory.js';
@@ -40,5 +40,10 @@ export { OkxWs, OkxWsConfig } from './client/okx/ws.js';
40
40
  export { WalletClientWithAccount } from './helper/lighter/ethereum/types.js';
41
41
  import '@pear-protocol/types';
42
42
  import '@pear-protocol/core-sdk';
43
+ import './client/binance/types.js';
44
+ import './client/bybit/types.js';
45
+ import './client/hyperliquid/types.js';
46
+ import './client/lighter/types.js';
47
+ import './client/okx/types.js';
43
48
  import 'partysocket';
44
49
  import 'viem';
package/dist/sdk.d.ts CHANGED
@@ -7,6 +7,7 @@ import './helper/lighter/types.js';
7
7
  import './helper/lighter/ethereum/types.js';
8
8
  import 'viem';
9
9
  import './client/lighter/rest.js';
10
+ import './client/lighter/types.js';
10
11
  import '@pear-protocol/core-sdk';
11
12
  import './client/index.js';
12
13
  import './client/binance/exchange-ws.js';
@@ -1,5 +1,5 @@
1
1
  import PearSDK from '@pear-protocol/core-sdk';
2
- import { Connector, InstrumentId, HttpTypes } 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';
@@ -26,15 +26,22 @@ interface AccountSyncerConfig {
26
26
  interface AccountSyncer {
27
27
  synchronize(): Promise<void>;
28
28
  }
29
- declare abstract class BaseAccountSyncer implements AccountSyncer {
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 {
30
36
  protected sdk: PearSDK;
31
37
  protected connector: Connector;
32
38
  protected credentials: SupportedCredentials;
33
39
  protected ws: ExchangeWsByConnector[Connector];
34
40
  protected demo: boolean;
35
41
  constructor(config: AccountSyncerConfig);
36
- protected abstract listExternalFills(since: Date, instrumentSymbolToIdMap: Record<string, InstrumentId>): Promise<HttpTypes.UnknownExternalFill[]>;
42
+ protected abstract listExternalFills(params: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
43
+ protected abstract isReduceOnly(fill: ExternalFill): boolean;
37
44
  synchronize(): Promise<void>;
38
45
  }
39
46
 
40
- export { type AccountSyncer, type AccountSyncerConfig, BaseAccountSyncer };
47
+ export { type AccountSyncer, type AccountSyncerConfig, BaseAccountSyncer, type ListExternalFillsParams };
@@ -18,23 +18,32 @@ class BaseAccountSyncer {
18
18
  this.sdk.core.positions.openLite(),
19
19
  this.sdk.core.fills.provisionals()
20
20
  ]);
21
- if (!positions.length && !provisionalFills.length) return;
22
- const [{ data: instruments }, since] = await Promise.all([
23
- this.sdk.core.instruments.symbolToIdMap({ connector: this.connector }),
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 }),
24
26
  this.sdk.core.sync.since({
25
27
  overlapMs: 6e4,
26
28
  nowMs: Date.now(),
27
29
  bootstrapLookbackMs: 30 * 24 * 60 * 60 * 1e3
28
30
  })
29
31
  ]);
30
- const externalFills = await this.listExternalFills(new Date(since.since), instruments);
32
+ const externalFills = await this.listExternalFills({
33
+ since: new Date(since.since),
34
+ instruments,
35
+ openPositions: positions,
36
+ provisionalFills
37
+ });
31
38
  const payload = await computeSyncPayload({
32
39
  openPositions: positions,
33
40
  provisionalFills,
34
41
  confirmedExchangeFillIds: since.confirmedExchangeFillIds ?? [],
35
42
  externalFills
36
43
  });
37
- if (!payload) return;
44
+ if (!payload) {
45
+ return;
46
+ }
38
47
  if (payload.reconcilables) {
39
48
  await this.sdk.core.sync.reconcile(payload.reconcilables);
40
49
  }
@@ -1,5 +1,6 @@
1
- import { InstrumentId, HttpTypes } from '@pear-protocol/types';
2
- import { BaseAccountSyncer } from '../base.js';
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { BinanceRawUserTrade } from '../../client/binance/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
3
4
  import '@pear-protocol/core-sdk';
4
5
  import '../../client/index.js';
5
6
  import '../../types.js';
@@ -17,8 +18,14 @@ import '../../client/lighter/ws.js';
17
18
  import '../../client/okx/exchange-ws.js';
18
19
  import '../../client/okx/ws.js';
19
20
 
20
- declare class BinanceAccountSyncer extends BaseAccountSyncer {
21
- protected listExternalFills(_since: Date, _instrumentSymbolToIdMap: Record<string, InstrumentId>): Promise<HttpTypes.UnknownExternalFill[]>;
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;
22
29
  }
23
30
 
24
31
  export { BinanceAccountSyncer };
@@ -1,8 +1,81 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { fetchUserTradesSince, fetchAllOrdersSince } from '../../client/binance/rest';
1
3
  import { BaseAccountSyncer } from '../base';
2
4
 
3
5
  class BinanceAccountSyncer extends BaseAccountSyncer {
4
- async listExternalFills(_since, _instrumentSymbolToIdMap) {
5
- return [];
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}`;
6
79
  }
7
80
  }
8
81
 
@@ -1,5 +1,6 @@
1
- import { InstrumentId, HttpTypes } from '@pear-protocol/types';
2
- import { BaseAccountSyncer } from '../base.js';
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { BybitRawExecution } from '../../client/bybit/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
3
4
  import '@pear-protocol/core-sdk';
4
5
  import '../../client/index.js';
5
6
  import '../../types.js';
@@ -17,8 +18,11 @@ import '../../client/lighter/ws.js';
17
18
  import '../../client/okx/exchange-ws.js';
18
19
  import '../../client/okx/ws.js';
19
20
 
20
- declare class BybitAccountSyncer extends BaseAccountSyncer {
21
- protected listExternalFills(_since: Date, _instrumentSymbolToIdMap: Record<string, InstrumentId>): Promise<HttpTypes.UnknownExternalFill[]>;
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;
22
26
  }
23
27
 
24
28
  export { BybitAccountSyncer };
@@ -1,8 +1,35 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { fetchExecutionsSince } from '../../client/bybit/rest';
1
3
  import { BaseAccountSyncer } from '../base';
2
4
 
3
5
  class BybitAccountSyncer extends BaseAccountSyncer {
4
- async listExternalFills(_since, _instrumentSymbolToIdMap) {
5
- return [];
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;
6
33
  }
7
34
  }
8
35
 
@@ -1,5 +1,6 @@
1
- import { InstrumentId, HttpTypes } from '@pear-protocol/types';
2
- import { BaseAccountSyncer, AccountSyncerConfig } from '../base.js';
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { UserFillsByTimeResponse } from '../../client/hyperliquid/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
3
4
  import '@pear-protocol/core-sdk';
4
5
  import '../../client/index.js';
5
6
  import '../../types.js';
@@ -17,10 +18,11 @@ import '../../client/lighter/ws.js';
17
18
  import '../../client/okx/exchange-ws.js';
18
19
  import '../../client/okx/ws.js';
19
20
 
20
- declare class HyperliquidAccountSyncer extends BaseAccountSyncer {
21
+ declare class HyperliquidAccountSyncer extends BaseAccountSyncer<UserFillsByTimeResponse> {
21
22
  private readonly address;
22
23
  constructor(config: AccountSyncerConfig);
23
- protected listExternalFills(since: Date, instrumentSymbolToIdMap: Record<string, InstrumentId>): Promise<HttpTypes.UnknownExternalFill[]>;
24
+ protected listExternalFills({ since, instruments, }: ListExternalFillsParams): Promise<HttpTypes.UnknownExternalFill[]>;
25
+ protected isReduceOnly(fill: UserFillsByTimeResponse): boolean;
24
26
  }
25
27
 
26
28
  export { HyperliquidAccountSyncer };
@@ -8,7 +8,14 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
8
8
  const creds = config.credentials;
9
9
  this.address = creds.accountIdentifier;
10
10
  }
11
- async listExternalFills(since, instrumentSymbolToIdMap) {
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
+ }, {});
12
19
  const result = await fetchInfo({
13
20
  type: "userFillsByTime",
14
21
  user: this.address,
@@ -29,7 +36,7 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
29
36
  price: fill.px,
30
37
  quantity: fill.sz,
31
38
  side: fill.side === "B" ? "BUY" : "SELL",
32
- reduceOnly: fill.dir.includes("Close"),
39
+ reduceOnly: this.isReduceOnly(fill),
33
40
  timestamp: fill.time,
34
41
  tradeFee: fill.fee,
35
42
  builderFee: fill.builderFee ?? "0",
@@ -38,6 +45,9 @@ class HyperliquidAccountSyncer extends BaseAccountSyncer {
38
45
  return acc;
39
46
  }, []);
40
47
  }
48
+ isReduceOnly(fill) {
49
+ return fill.dir.includes("Close");
50
+ }
41
51
  }
42
52
 
43
53
  export { HyperliquidAccountSyncer };
@@ -1,4 +1,4 @@
1
- export { AccountSyncer, AccountSyncerConfig, BaseAccountSyncer } from './base.js';
1
+ export { AccountSyncer, AccountSyncerConfig, BaseAccountSyncer, ListExternalFillsParams } from './base.js';
2
2
  export { BinanceAccountSyncer } from './binance/syncer.js';
3
3
  export { BybitAccountSyncer } from './bybit/syncer.js';
4
4
  export { createAccountSyncer } from './factory.js';
@@ -22,3 +22,8 @@ import '../client/lighter/exchange-ws.js';
22
22
  import '../client/lighter/ws.js';
23
23
  import '../client/okx/exchange-ws.js';
24
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,5 +1,6 @@
1
- import { InstrumentId, HttpTypes } from '@pear-protocol/types';
2
- import { BaseAccountSyncer } from '../base.js';
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { LighterRawTrade } from '../../client/lighter/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
3
4
  import '@pear-protocol/core-sdk';
4
5
  import '../../client/index.js';
5
6
  import '../../types.js';
@@ -17,8 +18,20 @@ import '../../client/lighter/ws.js';
17
18
  import '../../client/okx/exchange-ws.js';
18
19
  import '../../client/okx/ws.js';
19
20
 
20
- declare class LighterAccountSyncer extends BaseAccountSyncer {
21
- protected listExternalFills(_since: Date, _instrumentSymbolToIdMap: Record<string, InstrumentId>): Promise<HttpTypes.UnknownExternalFill[]>;
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;
22
35
  }
23
36
 
24
37
  export { LighterAccountSyncer };
@@ -1,8 +1,93 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { fetchTradesSince } from '../../client/lighter/rest';
1
3
  import { BaseAccountSyncer } from '../base';
2
4
 
5
+ const LIGHTER_FEE_TICK_DENOMINATOR = new BigNumber(1e6);
3
6
  class LighterAccountSyncer extends BaseAccountSyncer {
4
- async listExternalFills(_since, _instrumentSymbolToIdMap) {
5
- return [];
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();
6
91
  }
7
92
  }
8
93
 
@@ -1,5 +1,6 @@
1
- import { InstrumentId, HttpTypes } from '@pear-protocol/types';
2
- import { BaseAccountSyncer } from '../base.js';
1
+ import { HttpTypes } from '@pear-protocol/types';
2
+ import { OkxRawFill } from '../../client/okx/types.js';
3
+ import { BaseAccountSyncer, AccountSyncerConfig, ListExternalFillsParams } from '../base.js';
3
4
  import '@pear-protocol/core-sdk';
4
5
  import '../../client/index.js';
5
6
  import '../../types.js';
@@ -17,8 +18,12 @@ import '../../client/lighter/ws.js';
17
18
  import '../../client/okx/exchange-ws.js';
18
19
  import '../../client/okx/ws.js';
19
20
 
20
- declare class OkxAccountSyncer extends BaseAccountSyncer {
21
- protected listExternalFills(_since: Date, _instrumentSymbolToIdMap: Record<string, InstrumentId>): Promise<HttpTypes.UnknownExternalFill[]>;
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;
22
27
  }
23
28
 
24
29
  export { OkxAccountSyncer };
@@ -1,8 +1,47 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import { fetchFillsHistorySince } from '../../client/okx/rest';
1
3
  import { BaseAccountSyncer } from '../base';
2
4
 
3
5
  class OkxAccountSyncer extends BaseAccountSyncer {
4
- async listExternalFills(_since, _instrumentSymbolToIdMap) {
5
- return [];
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();
6
45
  }
7
46
  }
8
47
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pear-protocol/exchanges-sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Pear Protocol Exchanges SDK",
5
5
  "private": false,
6
6
  "type": "module",
@@ -25,9 +25,9 @@
25
25
  "typecheck": "tsc --noEmit"
26
26
  },
27
27
  "dependencies": {
28
- "@pear-protocol/core-sdk": "^0.0.20",
29
- "@pear-protocol/types": "^0.0.17",
30
- "@pear-protocol/utils": "^0.0.17",
28
+ "@pear-protocol/core-sdk": "^0.0.21",
29
+ "@pear-protocol/types": "^0.0.18",
30
+ "@pear-protocol/utils": "^0.0.18",
31
31
  "bignumber.js": "^11.1.1",
32
32
  "partysocket": "^1.0.3",
33
33
  "viem": "^2.48.8"