perp-cli 0.7.1 → 0.7.2

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.
@@ -23,6 +23,17 @@ export class AsterAdapter {
23
23
  get isReadOnly() {
24
24
  return !this._apiKey || !this._apiSecret;
25
25
  }
26
+ /** CLI symbol → Aster API symbol (ETH → ETHUSDT) */
27
+ _toApi(symbol) {
28
+ const s = symbol.toUpperCase().replace(/-PERP$/, "");
29
+ if (s.endsWith("USDT") || s.endsWith("BUSD"))
30
+ return s;
31
+ return `${s}USDT`;
32
+ }
33
+ /** Aster API symbol → CLI symbol (ETHUSDT → ETH) */
34
+ _fromApi(symbol) {
35
+ return symbol.replace(/USDT$/, "").replace(/BUSD$/, "");
36
+ }
26
37
  async init() {
27
38
  // Verify connectivity by fetching server time
28
39
  await this._publicGet("/fapi/v1/time");
@@ -70,7 +81,7 @@ export class AsterAdapter {
70
81
  // Extract max leverage from leverage brackets if available
71
82
  const maxLev = Number(s.maxLeverage ?? 50);
72
83
  return {
73
- symbol: sym,
84
+ symbol: this._fromApi(sym),
74
85
  markPrice: String(premium?.markPrice ?? ticker?.lastPrice ?? "0"),
75
86
  indexPrice: String(premium?.indexPrice ?? "0"),
76
87
  fundingRate: String(premium?.lastFundingRate ?? "0"),
@@ -81,7 +92,7 @@ export class AsterAdapter {
81
92
  });
82
93
  }
83
94
  async getOrderbook(symbol) {
84
- const res = await this._publicGet("/fapi/v1/depth", { symbol: symbol.toUpperCase(), limit: "50" });
95
+ const res = await this._publicGet("/fapi/v1/depth", { symbol: this._toApi(symbol), limit: "50" });
85
96
  return {
86
97
  bids: res?.bids ?? [],
87
98
  asks: res?.asks ?? [],
@@ -89,12 +100,12 @@ export class AsterAdapter {
89
100
  }
90
101
  async getRecentTrades(symbol, limit = 20) {
91
102
  const trades = await this._publicGet("/fapi/v1/trades", {
92
- symbol: symbol.toUpperCase(),
103
+ symbol: this._toApi(symbol),
93
104
  limit: String(limit),
94
105
  });
95
106
  return (trades ?? []).map((t) => ({
96
107
  time: Number(t.time ?? 0),
97
- symbol: symbol.toUpperCase(),
108
+ symbol: this._fromApi(String(t.symbol ?? symbol)),
98
109
  side: t.isBuyerMaker ? "sell" : "buy",
99
110
  price: String(t.price ?? "0"),
100
111
  size: String(t.qty ?? "0"),
@@ -103,7 +114,7 @@ export class AsterAdapter {
103
114
  }
104
115
  async getFundingHistory(symbol, limit = 10) {
105
116
  const data = await this._publicGet("/fapi/v1/fundingRate", {
106
- symbol: symbol.toUpperCase(),
117
+ symbol: this._toApi(symbol),
107
118
  limit: String(limit),
108
119
  });
109
120
  return (data ?? []).map((d) => ({
@@ -114,7 +125,7 @@ export class AsterAdapter {
114
125
  }
115
126
  async getKlines(symbol, interval, startTime, endTime) {
116
127
  const data = await this._publicGet("/fapi/v1/klines", {
117
- symbol: symbol.toUpperCase(),
128
+ symbol: this._toApi(symbol),
118
129
  interval,
119
130
  startTime: String(startTime),
120
131
  endTime: String(endTime),
@@ -151,7 +162,7 @@ export class AsterAdapter {
151
162
  .map((p) => {
152
163
  const amt = Number(p.positionAmt ?? 0);
153
164
  return {
154
- symbol: String(p.symbol ?? ""),
165
+ symbol: this._fromApi(String(p.symbol ?? "")),
155
166
  side: amt > 0 ? "long" : "short",
156
167
  size: String(Math.abs(amt)),
157
168
  entryPrice: String(p.entryPrice ?? "0"),
@@ -166,7 +177,7 @@ export class AsterAdapter {
166
177
  const orders = await this._signedGet("/fapi/v1/openOrders");
167
178
  return (orders ?? []).map((o) => ({
168
179
  orderId: String(o.orderId ?? ""),
169
- symbol: String(o.symbol ?? ""),
180
+ symbol: this._fromApi(String(o.symbol ?? "")),
170
181
  side: String(o.side).toLowerCase(),
171
182
  price: String(o.price ?? "0"),
172
183
  size: String(o.origQty ?? "0"),
@@ -178,15 +189,15 @@ export class AsterAdapter {
178
189
  async getOrderHistory(limit = 30) {
179
190
  // allOrders requires symbol — get from positions or recent trades
180
191
  const positions = await this.getPositions();
181
- const symbols = new Set(positions.map(p => p.symbol));
182
- if (symbols.size === 0) {
192
+ const apiSymbols = new Set(positions.map(p => this._toApi(p.symbol)));
193
+ if (apiSymbols.size === 0) {
183
194
  // Fallback: query the most common perp symbols when no open positions exist
184
195
  for (const s of ["BTCUSDT", "ETHUSDT", "SOLUSDT", "BNBUSDT", "XRPUSDT"]) {
185
- symbols.add(s);
196
+ apiSymbols.add(s);
186
197
  }
187
198
  }
188
199
  const allOrders = [];
189
- for (const sym of symbols) {
200
+ for (const sym of apiSymbols) {
190
201
  try {
191
202
  const orders = await this._signedGet("/fapi/v1/allOrders", {
192
203
  symbol: sym,
@@ -195,7 +206,7 @@ export class AsterAdapter {
195
206
  for (const o of orders ?? []) {
196
207
  allOrders.push({
197
208
  orderId: String(o.orderId ?? ""),
198
- symbol: String(o.symbol ?? ""),
209
+ symbol: this._fromApi(String(o.symbol ?? "")),
199
210
  side: String(o.side).toLowerCase(),
200
211
  price: String(o.price ?? "0"),
201
212
  size: String(o.origQty ?? "0"),
@@ -211,11 +222,11 @@ export class AsterAdapter {
211
222
  }
212
223
  async getTradeHistory(limit = 30) {
213
224
  const positions = await this.getPositions();
214
- const symbols = new Set(positions.map(p => p.symbol));
215
- if (symbols.size === 0)
216
- symbols.add("BTCUSDT");
225
+ const apiSymbols = new Set(positions.map(p => this._toApi(p.symbol)));
226
+ if (apiSymbols.size === 0)
227
+ apiSymbols.add("BTCUSDT");
217
228
  const allTrades = [];
218
- for (const sym of symbols) {
229
+ for (const sym of apiSymbols) {
219
230
  try {
220
231
  const trades = await this._signedGet("/fapi/v1/userTrades", {
221
232
  symbol: sym,
@@ -224,7 +235,7 @@ export class AsterAdapter {
224
235
  for (const t of trades ?? []) {
225
236
  allTrades.push({
226
237
  time: Number(t.time ?? 0),
227
- symbol: String(t.symbol ?? ""),
238
+ symbol: this._fromApi(String(t.symbol ?? "")),
228
239
  side: t.buyer ? "buy" : "sell",
229
240
  price: String(t.price ?? "0"),
230
241
  size: String(t.qty ?? "0"),
@@ -243,14 +254,14 @@ export class AsterAdapter {
243
254
  });
244
255
  return (data ?? []).map((f) => ({
245
256
  time: Number(f.time ?? 0),
246
- symbol: String(f.symbol ?? ""),
257
+ symbol: this._fromApi(String(f.symbol ?? "")),
247
258
  payment: String(f.income ?? "0"),
248
259
  }));
249
260
  }
250
261
  // ── Trading ──
251
262
  async marketOrder(symbol, side, size) {
252
263
  return this._signedPost("/fapi/v1/order", {
253
- symbol: symbol.toUpperCase(),
264
+ symbol: this._toApi(symbol),
254
265
  side: side.toUpperCase(),
255
266
  type: "MARKET",
256
267
  quantity: size,
@@ -258,7 +269,7 @@ export class AsterAdapter {
258
269
  }
259
270
  async limitOrder(symbol, side, price, size, opts) {
260
271
  const params = {
261
- symbol: symbol.toUpperCase(),
272
+ symbol: this._toApi(symbol),
262
273
  side: side.toUpperCase(),
263
274
  type: "LIMIT",
264
275
  price,
@@ -279,7 +290,7 @@ export class AsterAdapter {
279
290
  }
280
291
  async cancelOrder(symbol, orderId) {
281
292
  return this._signedDelete("/fapi/v1/order", {
282
- symbol: symbol.toUpperCase(),
293
+ symbol: this._toApi(symbol),
283
294
  orderId,
284
295
  });
285
296
  }
@@ -287,14 +298,14 @@ export class AsterAdapter {
287
298
  if (!symbol) {
288
299
  // Cancel all for all symbols with open orders
289
300
  const orders = await this.getOpenOrders();
290
- const symbols = new Set(orders.map(o => o.symbol));
301
+ const apiSymbols = new Set(orders.map(o => this._toApi(o.symbol)));
291
302
  const results = [];
292
- for (const sym of symbols) {
303
+ for (const sym of apiSymbols) {
293
304
  results.push(await this._signedDelete("/fapi/v1/allOpenOrders", { symbol: sym }));
294
305
  }
295
306
  return results;
296
307
  }
297
- return this._signedDelete("/fapi/v1/allOpenOrders", { symbol: symbol.toUpperCase() });
308
+ return this._signedDelete("/fapi/v1/allOpenOrders", { symbol: this._toApi(symbol) });
298
309
  }
299
310
  // ── Risk ──
300
311
  async setLeverage(symbol, leverage, marginMode) {
@@ -302,7 +313,7 @@ export class AsterAdapter {
302
313
  if (marginMode) {
303
314
  try {
304
315
  await this._signedPost("/fapi/v1/marginType", {
305
- symbol: symbol.toUpperCase(),
316
+ symbol: this._toApi(symbol),
306
317
  marginType: marginMode === "cross" ? "CROSSED" : "ISOLATED",
307
318
  });
308
319
  }
@@ -311,13 +322,13 @@ export class AsterAdapter {
311
322
  }
312
323
  }
313
324
  return this._signedPost("/fapi/v1/leverage", {
314
- symbol: symbol.toUpperCase(),
325
+ symbol: this._toApi(symbol),
315
326
  leverage: String(leverage),
316
327
  });
317
328
  }
318
329
  async stopOrder(symbol, side, size, triggerPrice, opts) {
319
330
  const params = {
320
- symbol: symbol.toUpperCase(),
331
+ symbol: this._toApi(symbol),
321
332
  side: side.toUpperCase(),
322
333
  quantity: size,
323
334
  stopPrice: triggerPrice,
@@ -0,0 +1,62 @@
1
+ /**
2
+ * edgeX DEX adapter — StarkEx-based perpetual futures exchange.
3
+ * Base: https://pro.edgex.exchange
4
+ */
5
+ import type { ExchangeAdapter, ExchangeMarketInfo, ExchangePosition, ExchangeOrder, ExchangeBalance, ExchangeTrade, ExchangeFundingPayment, ExchangeKline } from "./interface.js";
6
+ export declare class EdgeXAdapter implements ExchangeAdapter {
7
+ readonly name = "edgex";
8
+ readonly chain = "starkex";
9
+ readonly aliases: readonly ["ex"];
10
+ private _accountId;
11
+ private _starkPrivateKey;
12
+ private _baseUrl;
13
+ private _contracts;
14
+ private _contractById;
15
+ private _marketsCache;
16
+ private static CACHE_TTL;
17
+ constructor(accountId?: string, starkPrivateKey?: string);
18
+ get isReadOnly(): boolean;
19
+ /** CLI symbol -> API symbol: ETH -> ETHUSD */
20
+ private _toApi;
21
+ /** API symbol -> CLI symbol: ETHUSD -> ETH, DOGE2USD -> DOGE2 */
22
+ private _fromApi;
23
+ private _getContract;
24
+ init(): Promise<void>;
25
+ getMarkets(): Promise<ExchangeMarketInfo[]>;
26
+ getOrderbook(symbol: string): Promise<{
27
+ bids: [string, string][];
28
+ asks: [string, string][];
29
+ }>;
30
+ getRecentTrades(symbol: string, limit?: number): Promise<ExchangeTrade[]>;
31
+ getFundingHistory(symbol: string, _limit?: number): Promise<{
32
+ time: number;
33
+ rate: string;
34
+ price: string | null;
35
+ }[]>;
36
+ getKlines(symbol: string, _interval: string, _startTime: number, _endTime: number): Promise<ExchangeKline[]>;
37
+ getBalance(): Promise<ExchangeBalance>;
38
+ getPositions(): Promise<ExchangePosition[]>;
39
+ getOpenOrders(): Promise<ExchangeOrder[]>;
40
+ getOrderHistory(_limit?: number): Promise<ExchangeOrder[]>;
41
+ getTradeHistory(_limit?: number): Promise<ExchangeTrade[]>;
42
+ getFundingPayments(_limit?: number): Promise<ExchangeFundingPayment[]>;
43
+ marketOrder(symbol: string, side: "buy" | "sell", size: string): Promise<unknown>;
44
+ limitOrder(symbol: string, side: "buy" | "sell", price: string, size: string, opts?: {
45
+ reduceOnly?: boolean;
46
+ tif?: string;
47
+ }): Promise<unknown>;
48
+ editOrder(symbol: string, orderId: string, price: string, size: string): Promise<unknown>;
49
+ cancelOrder(_symbol: string, orderId: string): Promise<unknown>;
50
+ cancelAllOrders(symbol?: string): Promise<unknown>;
51
+ setLeverage(symbol: string, leverage: number, _marginMode?: "cross" | "isolated"): Promise<unknown>;
52
+ stopOrder(symbol: string, side: "buy" | "sell", size: string, triggerPrice: string, opts?: {
53
+ limitPrice?: string;
54
+ reduceOnly?: boolean;
55
+ }): Promise<unknown>;
56
+ withdraw(_amount: string, _destination: string): Promise<unknown>;
57
+ private _computeL2OrderFields;
58
+ private _signRequest;
59
+ private _publicGet;
60
+ private _authGet;
61
+ private _authPost;
62
+ }