@orderly.network/hooks 2.8.0 → 2.8.1

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/index.mjs CHANGED
@@ -36,9 +36,9 @@ var __export = (target, all) => {
36
36
  // src/version.ts
37
37
  if (typeof window !== "undefined") {
38
38
  window.__ORDERLY_VERSION__ = window.__ORDERLY_VERSION__ || {};
39
- window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.8.0";
39
+ window.__ORDERLY_VERSION__["@orderly.network/hooks"] = "2.8.1";
40
40
  }
41
- var version_default = "2.8.0";
41
+ var version_default = "2.8.1";
42
42
  var fetcher = (url, init2 = {}, queryOptions) => get(url, init2, queryOptions?.formatter);
43
43
  var noCacheConfig = {
44
44
  dedupingInterval: 0,
@@ -1224,7 +1224,7 @@ function checkTPSLOrderTypeIsMarket(key, values) {
1224
1224
  }
1225
1225
  function tpslCalculateHelper(key, inputs, options = {}) {
1226
1226
  const { symbol } = options;
1227
- if (key !== "quantity" && key !== "tp_trigger_price" && key !== "sl_trigger_price" && key !== "tp_pnl" && key !== "sl_pnl" && key !== "tp_offset" && key !== "sl_offset" && key !== "tp_offset_percentage" && key !== "sl_offset_percentage" && key !== "tp_order_price" && key !== "sl_order_price" && key !== "tp_order_type" && key !== "sl_order_type" && key !== "tp_enable" && key !== "sl_enable") {
1227
+ if (key !== "quantity" && key !== "tp_trigger_price" && key !== "sl_trigger_price" && key !== "tp_pnl" && key !== "sl_pnl" && key !== "tp_offset" && key !== "sl_offset" && key !== "tp_offset_percentage" && key !== "sl_offset_percentage" && key !== "tp_order_price" && key !== "sl_order_price" && key !== "tp_order_type" && key !== "sl_order_type") {
1228
1228
  return {
1229
1229
  [key]: inputs.value
1230
1230
  };
@@ -1263,19 +1263,6 @@ function tpslCalculateHelper(key, inputs, options = {}) {
1263
1263
  }
1264
1264
  break;
1265
1265
  }
1266
- case "tp_enable":
1267
- case "sl_enable": {
1268
- return {
1269
- [`${keyPrefix}enable`]: inputs.value,
1270
- [`${keyPrefix}order_type`]: OrderType.MARKET,
1271
- [`${keyPrefix}trigger_price`]: "",
1272
- [`${keyPrefix}order_price`]: "",
1273
- [`${keyPrefix}offset`]: "",
1274
- [`${keyPrefix}offset_percentage`]: "",
1275
- [`${keyPrefix}pnl`]: "",
1276
- [`${keyPrefix}ROI`]: ""
1277
- };
1278
- }
1279
1266
  case "tp_pnl":
1280
1267
  case "sl_pnl": {
1281
1268
  pnl = inputs.value;
@@ -1624,7 +1611,6 @@ var getCalculateHandler = (fieldName) => {
1624
1611
  case "total": {
1625
1612
  return totalInputHandle;
1626
1613
  }
1627
- case "tp_enable":
1628
1614
  case "tp_pnl":
1629
1615
  case "sl_pnl":
1630
1616
  case "tp_trigger_price":
@@ -1635,7 +1621,6 @@ var getCalculateHandler = (fieldName) => {
1635
1621
  case "sl_offset_percentage":
1636
1622
  case "tp_order_price":
1637
1623
  case "tp_order_type":
1638
- case "sl_enable":
1639
1624
  case "sl_order_type":
1640
1625
  case "sl_order_price":
1641
1626
  return tpslInputHandle;
@@ -2735,6 +2720,7 @@ var useAppStore = create()(
2735
2720
  );
2736
2721
  var useAccountInfo2 = () => useAppStore((state) => state.accountInfo);
2737
2722
  var usePortfolio = () => useAppStore((state) => state.portfolio);
2723
+ var useFundingRateBySymbol = (symbol) => useAppStore((state) => state.fundingRates?.[symbol]);
2738
2724
 
2739
2725
  // src/orderly/useRwaSymbolsInfo.ts
2740
2726
  var isCurrentlyTrading = (nextClose, status, currentTime = Date.now()) => {
@@ -2756,10 +2742,16 @@ var computeSymbolState = (rwaSymbol, currentTime) => {
2756
2742
  let closeTimeInterval;
2757
2743
  let openTimeInterval;
2758
2744
  if (next_close && typeof next_close === "number" && next_close > currentTime) {
2759
- closeTimeInterval = Math.max(0, Math.floor((next_close - currentTime) / 1e3));
2745
+ closeTimeInterval = Math.max(
2746
+ 0,
2747
+ Math.floor((next_close - currentTime) / 1e3)
2748
+ );
2760
2749
  }
2761
2750
  if (next_open && typeof next_open === "number" && next_open > currentTime) {
2762
- openTimeInterval = Math.max(0, Math.floor((next_open - currentTime) / 1e3));
2751
+ openTimeInterval = Math.max(
2752
+ 0,
2753
+ Math.floor((next_open - currentTime) / 1e3)
2754
+ );
2763
2755
  }
2764
2756
  return {
2765
2757
  isRwa: true,
@@ -2770,46 +2762,48 @@ var computeSymbolState = (rwaSymbol, currentTime) => {
2770
2762
  openTimeInterval
2771
2763
  };
2772
2764
  };
2773
- var useRwaSymbolsRuntimeStore = create((set, get3) => ({
2774
- computedStates: {},
2775
- currentTime: Date.now(),
2776
- timerId: void 0,
2777
- startTimer: () => {
2778
- const state = get3();
2779
- if (state.timerId) {
2780
- clearInterval(state.timerId);
2781
- }
2782
- const timerId = setInterval(() => {
2783
- const currentTime = Date.now();
2784
- const rwaSymbolsInfo = useAppStore.getState().rwaSymbolsInfo;
2785
- if (!rwaSymbolsInfo) {
2786
- set({ currentTime });
2787
- return;
2765
+ var useRwaSymbolsRuntimeStore = create(
2766
+ (set, get3) => ({
2767
+ computedStates: {},
2768
+ currentTime: Date.now(),
2769
+ timerId: void 0,
2770
+ startTimer: () => {
2771
+ const state = get3();
2772
+ if (state.timerId) {
2773
+ clearInterval(state.timerId);
2774
+ }
2775
+ const timerId = setInterval(() => {
2776
+ const currentTime = Date.now();
2777
+ const rwaSymbolsInfo = useAppStore.getState().rwaSymbolsInfo;
2778
+ if (!rwaSymbolsInfo) {
2779
+ set({ currentTime });
2780
+ return;
2781
+ }
2782
+ const computedStates = {};
2783
+ Object.entries(rwaSymbolsInfo).forEach(([symbol, rwaSymbol]) => {
2784
+ computedStates[symbol] = computeSymbolState(rwaSymbol, currentTime);
2785
+ });
2786
+ set({ computedStates, currentTime });
2787
+ }, 1e3);
2788
+ set({ timerId });
2789
+ },
2790
+ stopTimer: () => {
2791
+ const state = get3();
2792
+ if (state.timerId) {
2793
+ clearInterval(state.timerId);
2794
+ set({ timerId: void 0 });
2788
2795
  }
2796
+ },
2797
+ updateComputedStates: (rwaSymbolsInfo) => {
2798
+ const currentTime = get3().currentTime;
2789
2799
  const computedStates = {};
2790
2800
  Object.entries(rwaSymbolsInfo).forEach(([symbol, rwaSymbol]) => {
2791
2801
  computedStates[symbol] = computeSymbolState(rwaSymbol, currentTime);
2792
2802
  });
2793
- set({ computedStates, currentTime });
2794
- }, 1e3);
2795
- set({ timerId });
2796
- },
2797
- stopTimer: () => {
2798
- const state = get3();
2799
- if (state.timerId) {
2800
- clearInterval(state.timerId);
2801
- set({ timerId: void 0 });
2803
+ set({ computedStates });
2802
2804
  }
2803
- },
2804
- updateComputedStates: (rwaSymbolsInfo) => {
2805
- const currentTime = get3().currentTime;
2806
- const computedStates = {};
2807
- Object.entries(rwaSymbolsInfo).forEach(([symbol, rwaSymbol]) => {
2808
- computedStates[symbol] = computeSymbolState(rwaSymbol, currentTime);
2809
- });
2810
- set({ computedStates });
2811
- }
2812
- }));
2805
+ })
2806
+ );
2813
2807
  var useInitRwaSymbolsRuntime = () => {
2814
2808
  const rwaSymbolsInfo = useRwaSymbolsInfoStore();
2815
2809
  const { startTimer, stopTimer, updateComputedStates } = useRwaSymbolsRuntimeStore();
@@ -3285,1914 +3279,1918 @@ var useWSObserver = (calculatorService) => {
3285
3279
  };
3286
3280
  }, []);
3287
3281
  };
3288
- var useApiStatusStore = create()(
3289
- immer((set) => ({
3290
- apis: {
3291
- positions: {
3292
- loading: false
3293
- }
3294
- },
3295
- actions: {
3296
- updateStatus: (key, status) => {
3297
- set((state) => {
3298
- state.apis[key] = status;
3299
- });
3300
- },
3301
- updateApiLoading: (key, loading) => {
3302
- set((state) => {
3303
- state.apis[key].loading = loading;
3304
- });
3305
- },
3306
- updateApiError: (key, error) => {
3307
- set((state) => {
3308
- state.apis[key] = {
3309
- loading: false,
3310
- error
3311
- };
3312
- });
3313
- }
3314
- }
3315
- }))
3316
- );
3317
- var useApiStatusActions = () => useApiStatusStore((state) => state.actions);
3318
- var useTokensInfoStore = create(
3319
- (set) => ({
3320
- tokensInfo: [],
3321
- setTokensInfo(data) {
3322
- set({ tokensInfo: data });
3323
- }
3324
- })
3325
- );
3326
- var useTokensInfo = () => {
3327
- const tokensInfo = useTokensInfoStore((state) => state.tokensInfo);
3328
- return tokensInfo;
3329
- };
3330
- var useTokenInfo = (token) => {
3331
- const tokensInfo = useTokensInfo();
3332
- return useMemo(() => {
3333
- return tokensInfo?.find((item) => item.token === token);
3334
- }, [tokensInfo, token]);
3335
- };
3336
3282
 
3337
- // src/orderly/calculator/baseCalculator.ts
3338
- var BaseCalculator = class {
3339
- cache(data) {
3340
- this._cache = data;
3341
- }
3283
+ // src/orderly/orderbook.service.ts
3284
+ var defaultRawOrderBook = {
3285
+ asks: [],
3286
+ bids: [],
3287
+ ts: 0
3342
3288
  };
3343
- var useMarkPriceStore = create((set, get3) => ({
3344
- markPrices: {},
3345
- // orderBook: {},
3346
- // ask_bid: [],
3347
- actions: {
3348
- updateMarkPrice: (markPrice) => {
3349
- set({
3350
- markPrices: markPrice
3351
- });
3352
- },
3353
- getMarkPriceBySymbol: (symbol) => {
3354
- return get3().markPrices[symbol];
3355
- }
3356
- }
3357
- }));
3358
- var useMarkPriceBySymbol = (symbol) => useMarkPriceStore((state) => state.actions.getMarkPriceBySymbol(symbol));
3359
- var useMarkPriceActions = () => useMarkPriceStore((state) => state.actions);
3360
-
3361
- // src/orderly/calculator/markPrice.ts
3362
- var MarketCalculatorName = "markPriceCalculator";
3363
- var MarkPriceCalculator = class extends BaseCalculator {
3289
+ var OrderbookService = class _OrderbookService {
3364
3290
  constructor() {
3365
- super(...arguments);
3366
- this.name = MarketCalculatorName;
3367
- }
3368
- calc(scope, data, ctx) {
3369
- return data;
3291
+ this.bufferedOrderBookUpdates = {};
3292
+ this.rawOrderBook = {};
3370
3293
  }
3371
- update(data, scope) {
3372
- useMarkPriceStore.getState().actions.updateMarkPrice(data);
3294
+ static getInstance() {
3295
+ if (!this.instance) {
3296
+ this.instance = new _OrderbookService();
3297
+ }
3298
+ return this.instance;
3373
3299
  }
3374
- };
3375
-
3376
- // src/orderly/calculator/calculatorContext.ts
3377
- var CalculatorContext = class _CalculatorContext {
3378
- static get instance() {
3379
- return this._instance;
3300
+ sortBufferedOrderBookUpdates(symbol) {
3301
+ this.bufferedOrderBookUpdates[symbol]?.sort((a, b) => a.ts - b.ts);
3380
3302
  }
3381
- static create(scope, data) {
3382
- if (!this._instance) {
3383
- this._instance = new _CalculatorContext(scope, data);
3303
+ applyUpdateToRawOrderBook(symbol, update) {
3304
+ const rawOrderBook = this.rawOrderBook[symbol];
3305
+ if (!rawOrderBook || rawOrderBook.ts > update.prevTs) {
3306
+ return;
3384
3307
  }
3385
- return this._instance.update(scope, data);
3386
- }
3387
- constructor(scope, data) {
3388
- this.setCtxData();
3389
- this.output = {
3390
- // rows: positions,
3391
- };
3308
+ const askMap = /* @__PURE__ */ new Map();
3309
+ const bidMap = /* @__PURE__ */ new Map();
3310
+ rawOrderBook.asks.forEach((ask) => {
3311
+ askMap.set(ask[0], ask[1]);
3312
+ });
3313
+ rawOrderBook.bids.forEach((bid) => {
3314
+ bidMap.set(bid[0], bid[1]);
3315
+ });
3316
+ update.asks.forEach(
3317
+ (ask) => ask[1] === 0 ? askMap.delete(ask[0]) : askMap.set(ask[0], ask[1])
3318
+ );
3319
+ update.bids.forEach(
3320
+ (bid) => bid[1] === 0 ? bidMap.delete(bid[0]) : bidMap.set(bid[0], bid[1])
3321
+ );
3322
+ rawOrderBook.asks = Array.from(askMap.entries()).sort(
3323
+ (a, b) => a[0] - b[0]
3324
+ );
3325
+ rawOrderBook.bids = Array.from(bidMap.entries()).sort(
3326
+ (a, b) => b[0] - a[0]
3327
+ );
3328
+ rawOrderBook.ts = update.ts;
3392
3329
  }
3393
- update(scope, data) {
3394
- this.setCtxData();
3395
- this.markPrices = scope === "markPrice" /* MARK_PRICE */ ? data : this.output[MarketCalculatorName];
3396
- this.portfolio = this.output["portfolio"] || useAppStore.getState().portfolio;
3397
- return this;
3330
+ applyBufferedUpdatesToRawOrderBooks(symbol) {
3331
+ this.bufferedOrderBookUpdates[symbol]?.forEach((update) => {
3332
+ this.applyUpdateToRawOrderBook(symbol, update);
3333
+ });
3398
3334
  }
3399
- setCtxData() {
3400
- this.accountInfo = useAppStore.getState().accountInfo;
3401
- this.symbolsInfo = useAppStore.getState().symbolsInfo;
3402
- this.fundingRates = useAppStore.getState().fundingRates;
3403
- this.tokensInfo = useTokensInfoStore.getState().tokensInfo;
3335
+ deleteBufferedOrderBookUpdates(symbol) {
3336
+ delete this.bufferedOrderBookUpdates[symbol];
3404
3337
  }
3405
- get(fn) {
3406
- return fn(this.output);
3338
+ commitOrderBook(symbol) {
3339
+ const rawOrderBook = this.rawOrderBook[symbol];
3340
+ if (!rawOrderBook) {
3341
+ return;
3342
+ }
3407
3343
  }
3408
- getCacheValue(name, fallback) {
3409
- return this.output[name] || fallback();
3344
+ pushUpdateToBuffer(symbol, update) {
3345
+ if (this.bufferedOrderBookUpdates[symbol] === void 0) {
3346
+ this.bufferedOrderBookUpdates[symbol] = [];
3347
+ }
3348
+ const buffer = this.bufferedOrderBookUpdates[symbol];
3349
+ if (buffer.length > 0) {
3350
+ const lastUpdate = buffer[buffer.length - 1];
3351
+ if (lastUpdate.ts !== update.prevTs) {
3352
+ this.bufferedOrderBookUpdates[symbol] = [];
3353
+ }
3354
+ }
3355
+ this.bufferedOrderBookUpdates[symbol].push(update);
3410
3356
  }
3411
- clearCache() {
3412
- this.output = {};
3413
- this.accountInfo = void 0;
3414
- this.portfolio = void 0;
3357
+ isValidFullOrderBook(symbol, currentTs) {
3358
+ if ((this.bufferedOrderBookUpdates[symbol]?.length ?? 0) !== 0) {
3359
+ const earliestUpdates = this.bufferedOrderBookUpdates[symbol][0];
3360
+ return earliestUpdates.prevTs <= currentTs;
3361
+ }
3362
+ return true;
3415
3363
  }
3416
- deleteByName(name) {
3417
- delete this.output[name];
3364
+ setFullOrderbook(symbol, rawOrderbook) {
3365
+ const { ts } = rawOrderbook;
3366
+ this.rawOrderBook[symbol] = rawOrderbook;
3367
+ this.sortBufferedOrderBookUpdates(symbol);
3368
+ if (this.isValidFullOrderBook(symbol, ts)) {
3369
+ this.applyBufferedUpdatesToRawOrderBooks(symbol);
3370
+ }
3418
3371
  }
3419
- // get positions(): API.PositionTPSLExt[] {
3420
- // if (this.output.positionCalculator) return this.output.positionCalculator;
3421
- // return usePositionStore.getState().positions;
3422
- // }
3423
- get isReady() {
3424
- return !!this.accountInfo;
3372
+ updateOrderbook(symbol, update, callback) {
3373
+ const { asks, bids, prevTs, ts } = update;
3374
+ const rawOrderBook = this.rawOrderBook[symbol];
3375
+ if (!rawOrderBook) {
3376
+ return;
3377
+ }
3378
+ const currentTs = rawOrderBook.ts;
3379
+ if (currentTs === 0) {
3380
+ this.pushUpdateToBuffer(symbol, { asks, bids, prevTs, ts });
3381
+ return;
3382
+ }
3383
+ if (prevTs !== currentTs) {
3384
+ this.pushUpdateToBuffer(symbol, { asks, bids, prevTs, ts });
3385
+ if (callback) {
3386
+ callback();
3387
+ }
3388
+ return;
3389
+ }
3390
+ this.applyUpdateToRawOrderBook(symbol, update);
3391
+ this.deleteBufferedOrderBookUpdates(symbol);
3425
3392
  }
3426
- saveOutput(name, data) {
3427
- this.output[name] = data;
3393
+ getRawOrderbook(symbol) {
3394
+ return this.rawOrderBook[symbol];
3428
3395
  }
3429
- outputToValue() {
3430
- return this.output;
3396
+ resetOrderBook(symbol) {
3397
+ this.rawOrderBook[symbol] = defaultRawOrderBook;
3431
3398
  }
3432
3399
  };
3433
-
3434
- // src/orderly/calculator/calculatorService.ts
3435
- var CalculatorService = class {
3436
- constructor(scheduler, calculators) {
3437
- this.scheduler = scheduler;
3438
- this.pendingCalc = [];
3439
- this.calcQueue = [];
3440
- /**
3441
- * Reference count for each calculator, used to determine if a calculator is still in use.
3442
- */
3443
- this.referenceCount = /* @__PURE__ */ new Map();
3444
- this.isPaused = false;
3445
- this.calculators = new Map(calculators);
3446
- }
3447
- register(scope, calculator) {
3448
- const ref_count_name = `${scope}_${calculator.name}`;
3449
- const count = this.referenceCount.get(ref_count_name);
3450
- if (typeof count !== "undefined" && count > 0) {
3451
- this.referenceCount.set(ref_count_name, count + 1);
3452
- return;
3400
+ var orderBookService = OrderbookService.getInstance();
3401
+ var orderbook_service_default = orderBookService;
3402
+ var useMarkPrice = (symbol) => {
3403
+ const ws = useWS();
3404
+ const [price, setPrice] = useState(0);
3405
+ useEffect(() => {
3406
+ const unsubscribe = ws.subscribe(`${symbol}@markprice`, {
3407
+ onMessage: (message) => {
3408
+ setPrice(message.price);
3409
+ }
3410
+ });
3411
+ return () => {
3412
+ unsubscribe?.();
3413
+ };
3414
+ }, [symbol]);
3415
+ return { data: price };
3416
+ };
3417
+ var useIndexPrice = (symbol) => {
3418
+ symbol = symbol.replace("PERP", "SPOT");
3419
+ const ws = useWS();
3420
+ return useSWRSubscription(`${symbol}@indexprice`, (key, { next }) => {
3421
+ const unsubscribe = ws.subscribe(`${symbol}@indexprice`, {
3422
+ onMessage: (message) => {
3423
+ next(null, message.price);
3424
+ }
3425
+ });
3426
+ return () => {
3427
+ unsubscribe?.();
3428
+ };
3429
+ });
3430
+ };
3431
+ var useOpenInterest = (symbol) => {
3432
+ const ws = useWS();
3433
+ return useSWRSubscription(`${symbol}@openinterest`, (key, { next }) => {
3434
+ const unsubscribe = ws.subscribe(`${symbol}@openinterest`, {
3435
+ onMessage: (message) => {
3436
+ next(null, message.openInterest);
3437
+ }
3438
+ });
3439
+ return () => {
3440
+ unsubscribe?.();
3441
+ };
3442
+ });
3443
+ };
3444
+ var useFutures = () => {
3445
+ const { data, isLoading, error } = useQuery(
3446
+ `/v1/public/futures`,
3447
+ {
3448
+ revalidateOnFocus: false
3453
3449
  }
3454
- const calculators = this.calculators.get(scope);
3455
- if (Array.isArray(calculators)) {
3456
- calculators.push(calculator);
3457
- } else {
3458
- this.calculators.set(scope, [calculator]);
3450
+ );
3451
+ const [sortedData, setSortedData] = useState(data);
3452
+ useWS();
3453
+ useEffect(() => {
3454
+ }, []);
3455
+ useEffect(() => {
3456
+ if (data) {
3457
+ const sortedData2 = data.sort((a, b) => {
3458
+ return 0;
3459
+ });
3460
+ setSortedData(sortedData2);
3459
3461
  }
3460
- this.referenceCount.set(ref_count_name, 1);
3462
+ }, [data]);
3463
+ const sortBy = useCallback((key) => {
3464
+ }, [data]);
3465
+ const filterBy = useCallback((key) => {
3466
+ }, [data]);
3467
+ return {
3468
+ data: sortedData,
3469
+ sortBy,
3470
+ filterBy,
3471
+ isLoading,
3472
+ error
3473
+ };
3474
+ };
3475
+
3476
+ // src/orderly/useTickerStream.ts
3477
+ var useTickerStream = (symbol) => {
3478
+ if (!symbol) {
3479
+ throw new SDKError("Symbol is required");
3461
3480
  }
3462
- unregister(scope, calculator) {
3463
- const ref_count_name = `${scope}_${calculator.name}`;
3464
- const count = this.referenceCount.get(ref_count_name);
3465
- if (typeof count !== "undefined" && count > 1) {
3466
- this.referenceCount.set(ref_count_name, count - 1);
3467
- return;
3481
+ const { data: info } = useQuery(
3482
+ `/v1/public/futures/${symbol}`,
3483
+ {
3484
+ revalidateOnFocus: false
3468
3485
  }
3469
- const calculators = this.calculators.get(scope);
3470
- if (Array.isArray(calculators)) {
3471
- const index = calculators.findIndex((c) => c.name === calculator.name);
3472
- if (index > -1) {
3473
- calculators[index].destroy?.();
3474
- calculators.splice(index, 1);
3486
+ );
3487
+ const [ticker, setTicker] = useState();
3488
+ const ws = useWS();
3489
+ useEffect(() => {
3490
+ const unsubscribe = ws.subscribe(
3491
+ // { event: "subscribe", topic: "markprices" },
3492
+ `${symbol}@ticker`,
3493
+ {
3494
+ onMessage: (message) => {
3495
+ if (message.symbol !== symbol)
3496
+ return;
3497
+ setTicker(message);
3498
+ }
3499
+ // onUnsubscribe: () => {
3500
+ // return "markprices";
3501
+ // },
3502
+ // onError: (error: any) => {
3503
+ //
3504
+ // },
3475
3505
  }
3506
+ );
3507
+ return () => {
3508
+ setTicker(void 0);
3509
+ unsubscribe?.();
3510
+ };
3511
+ }, [symbol]);
3512
+ const { data: markPrice } = useMarkPrice(symbol);
3513
+ const { data: indexPrice } = useIndexPrice(symbol);
3514
+ const { data: openInterest } = useOpenInterest(symbol);
3515
+ const { data: futures } = useFutures();
3516
+ const value = useMemo(() => {
3517
+ if (!info)
3518
+ return null;
3519
+ if (!ticker || ticker.symbol !== symbol)
3520
+ return info;
3521
+ const futureIndex = futures?.findIndex(
3522
+ (item) => item.symbol === symbol
3523
+ );
3524
+ let _oi = openInterest;
3525
+ if (!_oi && futureIndex !== -1 && futures) {
3526
+ _oi = futures[futureIndex].open_interest;
3476
3527
  }
3477
- this.referenceCount.delete(ref_count_name);
3478
- }
3479
- async calc(scope, data, options) {
3480
- if (scope !== "position" /* POSITION */) {
3481
- if (!options?.skipWhenOnPause) ;
3528
+ const config = {
3529
+ ...info,
3530
+ mark_price: markPrice,
3531
+ index_price: indexPrice,
3532
+ open_interest: _oi
3533
+ };
3534
+ if (ticker.open !== void 0) {
3535
+ config["24h_open"] = ticker.open;
3482
3536
  }
3483
- const ctx = CalculatorContext.create(scope, data);
3484
- if (!ctx.isReady && options?.skipPending) {
3485
- return;
3537
+ if (ticker.close !== void 0) {
3538
+ config["24h_close"] = ticker.close;
3486
3539
  }
3487
- if (options?.skipWhenOnPause && !this.windowIsVisible)
3488
- return;
3489
- this.calcQueue.push({ scope, data, options });
3490
- await this.handleCalcQueue(ctx);
3491
- this.ctx = ctx;
3492
- }
3493
- // private async handlePendingCalc() {
3494
- // // console.log("[handlePendingCalc]:", this.pendingCalc);
3495
- // if (this.pendingCalc.length === 0) return;
3496
- // this.calcQueue = [...this.pendingCalc, ...this.calcQueue];
3497
- // this.pendingCalc = [];
3498
- // }
3499
- async handleCalcQueue(context) {
3500
- const first = this.calcQueue.shift();
3501
- if (first) {
3502
- const { scope, data, options } = first;
3503
- const ctx = context || CalculatorContext.create(scope, data);
3504
- const calculators = this.calculators.get(scope);
3505
- if (Array.isArray(calculators) && calculators.length) {
3506
- try {
3507
- await this.scheduler.calc(scope, calculators, data, ctx);
3508
- } catch (e) {
3509
- }
3510
- if (!options?.skipUpdate) {
3511
- this.scheduler.update(scope, calculators, ctx.outputToValue());
3512
- }
3513
- }
3514
- if (this.calcQueue.length) {
3515
- this.handleCalcQueue(ctx);
3516
- }
3540
+ if (ticker.high !== void 0) {
3541
+ config["24h_high"] = ticker.high;
3517
3542
  }
3518
- }
3519
- stop() {
3520
- this.calcQueue = [];
3521
- this.ctx?.clearCache();
3522
- }
3523
- get windowIsVisible() {
3524
- if (typeof document === "undefined") {
3525
- return true;
3543
+ if (ticker.low !== void 0) {
3544
+ config["24h_low"] = ticker.low;
3526
3545
  }
3527
- return document.visibilityState === "visible";
3528
- }
3546
+ if (ticker.volume !== void 0) {
3547
+ config["24h_volumn"] = ticker.volume;
3548
+ config["24h_volume"] = ticker.volume;
3549
+ }
3550
+ if (ticker.close !== void 0 && ticker.open !== void 0) {
3551
+ config["change"] = new Decimal(ticker.close).minus(ticker.open).div(ticker.open).toNumber();
3552
+ config["24h_change"] = new Decimal(ticker.close).minus(ticker.open).toNumber();
3553
+ }
3554
+ return config;
3555
+ }, [info, symbol, ticker, futures, openInterest]);
3556
+ return value;
3529
3557
  };
3530
- var CalculatorServiceID = "CalculatorService";
3531
3558
 
3532
- // src/orderly/calculator/shardedScheduler.ts
3533
- var requestIdleCallbackPolyfill = (callback, options) => {
3534
- const startTime = Date.now();
3535
- return setTimeout(() => {
3536
- callback({
3537
- didTimeout: false,
3538
- timeRemaining: () => Math.max(0, 50 - (Date.now() - startTime))
3539
- });
3540
- }, 1);
3559
+ // src/orderly/useOrderbookStream.ts
3560
+ var paddingFn = (len) => Array(len).fill([Number.NaN, Number.NaN, Number.NaN, Number.NaN]);
3561
+ var isNumber = (val) => {
3562
+ return typeof val === "number" && !Number.isNaN(val);
3541
3563
  };
3542
- var cancelIdleCallbackPolyfill = (id) => {
3543
- clearTimeout(id);
3564
+ var getPriceKey = (rawPrice, depth, isAsks) => {
3565
+ return new Decimal(rawPrice).div(depth).toDecimalPlaces(0, isAsks ? Decimal.ROUND_CEIL : Decimal.ROUND_FLOOR).mul(depth).toNumber();
3544
3566
  };
3545
- var safeRequestIdleCallback = typeof window !== "undefined" && window.requestIdleCallback ? window.requestIdleCallback.bind(window) : requestIdleCallbackPolyfill;
3546
- typeof window !== "undefined" && window.cancelIdleCallback ? window.cancelIdleCallback.bind(window) : cancelIdleCallbackPolyfill;
3547
- var ShardingScheduler = class {
3548
- // run(calculators: Calculator[]) {}
3549
- calc(scope, calculators, data, ctx) {
3550
- return new Promise((resolve, reject) => {
3551
- try {
3552
- this.computation(
3553
- calculators,
3554
- (shard) => {
3555
- const results = [];
3556
- for (let index = 0; index < shard.length; index++) {
3557
- const calculator = shard[index];
3558
- const result = calculator.calc(scope, data, ctx);
3559
- if (result) {
3560
- ctx.saveOutput(calculator.name, result);
3561
- results.push(result);
3562
- }
3563
- }
3564
- return results;
3565
- },
3566
- (results) => {
3567
- resolve(results);
3568
- }
3569
- );
3570
- } catch (error) {
3571
- reject(error);
3572
- }
3573
- });
3567
+ var reduceItems = (depth, data, isAsks) => {
3568
+ if (!Array.isArray(data) || data.length === 0) {
3569
+ return [];
3574
3570
  }
3575
- update(scope, calculators, data) {
3576
- for (let index = 0; index < calculators.length; index++) {
3577
- const calculator = calculators[index];
3578
- const item = data[calculator.name];
3579
- if (!!item) {
3580
- calculator.update(item, scope);
3571
+ let newData = [...data];
3572
+ const result = [];
3573
+ if (typeof depth !== "undefined") {
3574
+ const pricesMap = /* @__PURE__ */ new Map();
3575
+ const len = data.length;
3576
+ for (let i = 0; i < len; i++) {
3577
+ const [rawPrice, quantity] = data[i];
3578
+ if (!isNumber(rawPrice) || !isNumber(quantity)) {
3579
+ continue;
3580
+ }
3581
+ const priceKey = getPriceKey(rawPrice, depth, isAsks);
3582
+ const amtByRaw = new Decimal(rawPrice).mul(quantity).toNumber();
3583
+ if (pricesMap.has(priceKey)) {
3584
+ const item = pricesMap.get(priceKey);
3585
+ const sumQty = new Decimal(item[1]).add(quantity).toNumber();
3586
+ const sumAmtByRaw = new Decimal(item[2] ?? 0).add(amtByRaw).toNumber();
3587
+ pricesMap.set(priceKey, [priceKey, sumQty, sumAmtByRaw]);
3588
+ } else {
3589
+ pricesMap.set(priceKey, [priceKey, quantity, amtByRaw]);
3581
3590
  }
3582
3591
  }
3583
- return Promise.resolve();
3592
+ newData = Array.from(pricesMap.values());
3584
3593
  }
3585
- computation(data, processor, onComplete) {
3586
- let index = 0;
3587
- const results = [];
3588
- const estimatedShardSize = Math.min(data.length, 2);
3589
- function processNextShard(deadline) {
3590
- let shardSize = estimatedShardSize;
3591
- while (index + shardSize <= data.length && deadline.timeRemaining() > 0) {
3592
- const shard = data.slice(index, index + shardSize);
3593
- const result = processor(shard);
3594
- results.push(result);
3595
- index += shardSize;
3596
- if (deadline.timeRemaining() < 1) {
3597
- shardSize = Math.max(1, Math.floor(shardSize / 2));
3594
+ for (let i = 0; i < newData.length; i++) {
3595
+ const [price, quantity, sumAmtByRaw] = newData[i];
3596
+ if (!isNumber(price) || !isNumber(quantity)) {
3597
+ continue;
3598
+ }
3599
+ const resLen = result.length;
3600
+ const newQuantity = new Decimal(quantity).add(resLen ? result[resLen - 1][2] : 0).toNumber();
3601
+ const pieceAmount = isNumber(sumAmtByRaw) ? sumAmtByRaw : new Decimal(quantity).mul(price).toNumber();
3602
+ const newAmount = new Decimal(pieceAmount).add(resLen ? result[resLen - 1][3] : 0).toNumber();
3603
+ result.push([price, quantity, newQuantity, newAmount]);
3604
+ }
3605
+ return result;
3606
+ };
3607
+ var reduceOrderbook = (depth, level, padding, data) => {
3608
+ let asks = reduceItems(depth, data.asks, true);
3609
+ let bids = reduceItems(depth, data.bids, false);
3610
+ if (asks.length !== 0 && bids.length !== 0 && asks[0][0] <= bids[0][0]) {
3611
+ if (asks.length === 1) {
3612
+ const [price, qty, newQuantity, newAmount] = asks[0];
3613
+ asks.shift();
3614
+ asks.push([
3615
+ price + (depth === void 0 ? 0 : Number(depth)),
3616
+ qty,
3617
+ newQuantity,
3618
+ newAmount
3619
+ ]);
3620
+ } else {
3621
+ const [bidPrice] = bids[0];
3622
+ while (asks.length > 0) {
3623
+ const [askPrice, askQty, newQuantity, newAmount] = asks[0];
3624
+ if (askPrice <= bidPrice) {
3625
+ asks.shift();
3626
+ for (let i = 0; i < asks.length; i++) {
3627
+ if (i === 0) {
3628
+ const quantity = new Decimal(asks[i][1]).add(askQty);
3629
+ asks[i][1] = quantity.toNumber();
3630
+ asks[i][2] = quantity.toNumber();
3631
+ asks[i][3] = quantity.toDecimalPlaces(0, Decimal.ROUND_CEIL).mul(asks[i][0]).toNumber();
3632
+ } else {
3633
+ asks[i][3] = new Decimal(asks[i][0]).mul(asks[i][1]).add(asks[i - 1][3]).toNumber();
3634
+ }
3635
+ }
3598
3636
  } else {
3599
- shardSize = Math.min(data.length - index, shardSize * 2);
3637
+ break;
3600
3638
  }
3601
3639
  }
3602
- if (index < data.length) {
3603
- safeRequestIdleCallback(processNextShard, {
3604
- timeout: 1e3
3605
- });
3606
- } else {
3607
- onComplete(results.flat());
3608
- }
3609
3640
  }
3610
- safeRequestIdleCallback(processNextShard, {
3611
- timeout: 1e3
3612
- });
3613
3641
  }
3642
+ asks = asks.reverse();
3643
+ if (padding) {
3644
+ asks = asks.length < level ? paddingFn(level - asks.length).concat(asks) : asks;
3645
+ bids = bids.length < level ? bids.concat(paddingFn(level - bids.length)) : bids;
3646
+ }
3647
+ return {
3648
+ asks,
3649
+ bids
3650
+ };
3614
3651
  };
3615
- var POSITION_EMPTY = {
3616
- rows: null,
3617
- margin_ratio: 0,
3618
- initial_margin_ratio: 0,
3619
- maintenance_margin_ratio: 0,
3620
- open_margin_ratio: 0,
3621
- current_margin_ratio_with_orders: 0,
3622
- initial_margin_ratio_with_orders: 0,
3623
- maintenance_margin_ratio_with_orders: 0,
3624
- total_collateral_value: 0,
3625
- free_collateral: 0,
3626
- total_pnl_24_h: 0,
3627
- unrealPnL: 0,
3628
- total_unreal_pnl: 0,
3629
- unsettledPnL: 0,
3630
- total_unsettled_pnl: 0,
3631
- notional: 0,
3632
- unrealPnlROI: 0
3652
+ var ORDERLY_ORDERBOOK_DEPTH_KEY = "orderly_orderbook_depth_key";
3653
+ var INIT_DATA = {
3654
+ asks: [],
3655
+ bids: []
3633
3656
  };
3634
- var usePositionStore = create()(
3635
- immer((set) => ({
3636
- positions: {
3637
- all: POSITION_EMPTY
3638
- },
3639
- actions: {
3640
- setPositions: (key, positions3) => {
3641
- set((state) => {
3642
- state.positions[key] = positions3;
3643
- });
3644
- },
3645
- closePosition: (symbol) => {
3646
- set((state) => {
3647
- delete state.positions[symbol];
3648
- });
3649
- },
3650
- clearAll: () => {
3651
- set((state) => {
3652
- state.positions = {
3653
- all: POSITION_EMPTY
3654
- };
3655
- });
3656
- }
3657
- }
3658
- }))
3659
- );
3660
- var usePositions = (symbol = "all") => usePositionStore((state) => (state.positions[symbol] ?? POSITION_EMPTY).rows);
3661
- var usePositionActions = () => usePositionStore((state) => state.actions);
3662
-
3663
- // src/orderly/calculator/positions.ts
3664
- var NAME_PREFIX = "positionCalculator";
3665
- var AllPositions = "all";
3666
- var PositionCalculator = class extends BaseCalculator {
3667
- // private id: string;
3668
- constructor(symbol = AllPositions) {
3669
- super();
3670
- this.name = `${NAME_PREFIX}_${symbol}`;
3671
- this.symbol = symbol;
3657
+ var useOrderbookStream = (symbol, initial = INIT_DATA, options) => {
3658
+ if (!symbol) {
3659
+ throw new SDKError("Symbol is required");
3672
3660
  }
3673
- calc(scope, data, ctx) {
3674
- if (scope === "markPrice" /* MARK_PRICE */) {
3675
- return this.calcByMarkPrice(data, ctx);
3661
+ const level = options?.level ?? 10;
3662
+ const padding = options?.padding ?? true;
3663
+ const symbolRef = useRef(symbol);
3664
+ symbolRef.current = symbol;
3665
+ const {
3666
+ defaultOrderbookTickSizes: DEFAULT_TICK_SIZES2 = {},
3667
+ defaultOrderbookSymbolDepths: DEFAULT_SYMBOL_DEPTHS2 = {}
3668
+ } = useContext(OrderlyContext);
3669
+ const [data, setData] = useState(initial);
3670
+ const [isLoading, setIsLoading] = useState(true);
3671
+ const config = useSymbolsInfo()[symbol];
3672
+ const [depthObject, setDepthObject] = useLocalStorage(
3673
+ ORDERLY_ORDERBOOK_DEPTH_KEY,
3674
+ {}
3675
+ );
3676
+ const prevMiddlePrice = useRef(0);
3677
+ const tick = config("quote_tick");
3678
+ const depths = useMemo(() => {
3679
+ if (DEFAULT_SYMBOL_DEPTHS2[symbol]) {
3680
+ return DEFAULT_SYMBOL_DEPTHS2[symbol];
3676
3681
  }
3677
- if (scope === "indexPrice" /* INDEX_PRICE */) {
3678
- return this.calcByIndexPrice(data, ctx);
3682
+ if (typeof tick === "undefined") {
3683
+ return [];
3679
3684
  }
3680
- if (scope === "position" /* POSITION */) {
3681
- return this.calcByPosition(
3682
- this.preprocess(data),
3683
- ctx
3684
- );
3685
+ try {
3686
+ const base = new Decimal(tick);
3687
+ return [
3688
+ base.toNumber(),
3689
+ base.mul(10).toNumber(),
3690
+ base.mul(100).toNumber(),
3691
+ base.mul(1e3).toNumber()
3692
+ ];
3693
+ } catch {
3685
3694
  }
3686
- return data;
3687
- }
3688
- update(data, scope) {
3689
- if (!data || !Array.isArray(data.rows))
3695
+ return [tick];
3696
+ }, [symbol, tick]);
3697
+ useEffect(() => {
3698
+ if (depthObject[symbol]) {
3690
3699
  return;
3691
- usePositionStore.getState().actions.setPositions(this.symbol, data);
3692
- if (Array.isArray(data.rows) && useApiStatusStore.getState().apis.positions.loading) {
3693
- useApiStatusStore.getState().actions.updateApiLoading("positions", false);
3694
3700
  }
3695
- }
3696
- calcByMarkPrice(markPrice, ctx) {
3697
- let positions3 = this.getPosition(markPrice, ctx);
3698
- useAppStore.getState().fundingRates;
3699
- if (!positions3 || !Array.isArray(positions3.rows) || !positions3.rows.length)
3700
- return positions3;
3701
- positions3 = {
3702
- ...positions3,
3703
- rows: positions3.rows.map((item) => {
3704
- return {
3705
- ...item,
3706
- mark_price: markPrice[item.symbol] || item.mark_price
3707
- };
3708
- })
3709
- };
3710
- return this.format(positions3, ctx);
3711
- }
3712
- calcByIndexPrice(indexPrice, ctx) {
3713
- let positions3 = this.getPosition(indexPrice, ctx);
3714
- if (!positions3) {
3715
- return positions3;
3716
- }
3717
- if (!Array.isArray(positions3.rows) || !positions3.rows.length)
3718
- return positions3;
3719
- positions3 = {
3720
- ...positions3,
3721
- rows: positions3.rows.map((item) => ({
3722
- ...item,
3723
- index_price: indexPrice[item.symbol] || item.index_price || item.mark_price
3724
- }))
3725
- };
3726
- return this.format(positions3, ctx);
3727
- }
3728
- calcByPosition(positions3, ctx) {
3729
- if (positions3.rows.length === 0)
3730
- return positions3;
3731
- return this.format(positions3, ctx);
3732
- }
3733
- format(data, ctx) {
3734
- const { accountInfo, symbolsInfo, fundingRates, portfolio } = ctx;
3735
- if (!accountInfo || !fundingRates || !symbolsInfo) {
3736
- return data;
3737
- }
3738
- let unrealPnL_total = zero, unrealPnL_total_index = zero, notional_total = zero, unsettlementPnL_total = zero;
3739
- let rows = data.rows.map((item) => {
3740
- const info = symbolsInfo[item.symbol];
3741
- const sum_unitary_funding = fundingRates?.[item.symbol]?.["sum_unitary_funding"] ?? 0;
3742
- const notional = positions.notional(item.position_qty, item.mark_price);
3743
- const unrealPnl = positions.unrealizedPnL({
3744
- qty: item.position_qty,
3745
- openPrice: item?.average_open_price,
3746
- // markPrice: unRealizedPrice,
3747
- markPrice: item.mark_price
3748
- });
3749
- let unrealPnl_index = 0, unrealPnlROI_index = 0;
3750
- const maxLeverage = item.leverage || 1;
3751
- const imr = account.IMR({
3752
- maxLeverage,
3753
- baseIMR: info?.["base_imr"],
3754
- IMR_Factor: accountInfo.imr_factor[item.symbol],
3755
- positionNotional: notional,
3756
- ordersNotional: 0,
3757
- IMR_factor_power: 4 / 5
3758
- });
3759
- const unrealPnlROI = positions.unrealizedPnLROI({
3760
- positionQty: item.position_qty,
3761
- openPrice: item.average_open_price,
3762
- IMR: imr,
3763
- unrealizedPnL: unrealPnl
3764
- });
3765
- if (item.index_price) {
3766
- unrealPnl_index = positions.unrealizedPnL({
3767
- qty: item.position_qty,
3768
- openPrice: item?.average_open_price,
3769
- // markPrice: unRealizedPrice,
3770
- markPrice: item.index_price
3771
- });
3772
- unrealPnlROI_index = positions.unrealizedPnLROI({
3773
- positionQty: item.position_qty,
3774
- openPrice: item.average_open_price,
3775
- IMR: imr,
3776
- unrealizedPnL: unrealPnl_index
3777
- });
3778
- }
3779
- const unsettlementPnL2 = positions.unsettlementPnL({
3780
- positionQty: item.position_qty,
3781
- markPrice: item.mark_price,
3782
- costPosition: item.cost_position,
3783
- sumUnitaryFunding: propOr(
3784
- 0,
3785
- "sum_unitary_funding",
3786
- fundingRates[item.symbol]
3787
- ),
3788
- lastSumUnitaryFunding: item.last_sum_unitary_funding
3789
- });
3790
- const MMR = positions.MMR({
3791
- baseMMR: info?.["base_mmr"],
3792
- baseIMR: info?.["base_imr"],
3793
- IMRFactor: accountInfo.imr_factor[item.symbol],
3794
- positionNotional: notional,
3795
- IMR_factor_power: 4 / 5
3796
- });
3797
- unrealPnL_total = unrealPnL_total.add(unrealPnl);
3798
- unrealPnL_total_index = unrealPnL_total_index.add(unrealPnl_index);
3799
- notional_total = notional_total.add(notional);
3800
- unsettlementPnL_total = unsettlementPnL_total.add(unsettlementPnL2);
3801
- const fundingFee = new Decimal(sum_unitary_funding).sub(item.last_sum_unitary_funding).mul(item.position_qty).negated().toNumber();
3802
- return {
3803
- ...item,
3804
- fundingFee,
3805
- mm: positions.maintenanceMargin({
3806
- positionQty: item.position_qty,
3807
- markPrice: item.mark_price,
3808
- MMR
3809
- }),
3810
- mmr: MMR,
3811
- notional,
3812
- unsettlement_pnl: unsettlementPnL2,
3813
- unrealized_pnl: unrealPnl,
3814
- unrealized_pnl_index: unrealPnl_index,
3815
- unrealized_pnl_ROI: unrealPnlROI,
3816
- unrealized_pnl_ROI_index: unrealPnlROI_index
3817
- };
3818
- });
3819
- const totalUnrealPnl = unrealPnL_total.toNumber();
3820
- const totalUnrealPnl_index = unrealPnL_total_index.toNumber();
3821
- const unsettlementPnL = unsettlementPnL_total.toNumber();
3822
- let totalUnrealizedROI = 0, totalUnrealizedROI_index = 0;
3823
- if (portfolio) {
3824
- const { totalValue, totalCollateral } = portfolio;
3825
- rows = rows.map((item) => {
3826
- const est_liq_price = positions.liqPrice({
3827
- markPrice: item.mark_price,
3828
- totalCollateral: totalCollateral.toNumber(),
3829
- positionQty: item.position_qty,
3830
- positions: rows,
3831
- MMR: item.mmr
3832
- });
3833
- return {
3834
- ...item,
3835
- est_liq_price
3836
- };
3837
- });
3838
- if (totalValue !== null && !totalValue.eq(zero)) {
3839
- totalUnrealizedROI = account.totalUnrealizedROI({
3840
- totalUnrealizedPnL: totalUnrealPnl,
3841
- totalValue: totalValue.toNumber()
3842
- });
3843
- totalUnrealizedROI_index = account.totalUnrealizedROI({
3844
- totalUnrealizedPnL: totalUnrealPnl_index,
3845
- totalValue: totalValue.toNumber()
3846
- });
3847
- }
3848
- }
3849
- return {
3850
- ...data,
3851
- unrealPnL: totalUnrealPnl,
3852
- total_unreal_pnl: totalUnrealPnl,
3853
- total_unreal_pnl_index: totalUnrealPnl_index,
3854
- notional: notional_total.toNumber(),
3855
- unsettledPnL: unsettlementPnL,
3856
- total_unsettled_pnl: unsettlementPnL,
3857
- unrealPnlROI: totalUnrealizedROI,
3858
- unrealPnlROI_index: totalUnrealizedROI_index,
3859
- rows
3860
- };
3861
- }
3862
- preprocess(data) {
3863
- let rows = data.rows;
3864
- if (this.symbol !== AllPositions && Array.isArray(rows)) {
3865
- rows = rows.filter((item) => item.symbol === this.symbol);
3866
- }
3867
- return {
3868
- ...data,
3869
- rows
3870
- };
3871
- }
3872
- getPosition(_, ctx) {
3873
- const positions3 = ctx.get((output) => output[this.name]) || usePositionStore.getState().positions[this.symbol];
3874
- if (this.symbol === AllPositions) {
3875
- return positions3;
3876
- }
3877
- if (positions3 && Array.isArray(positions3.rows)) {
3878
- return positions3;
3879
- }
3880
- return this.preprocess(this.getAllPositions(ctx));
3881
- }
3882
- destroy() {
3883
- usePositionStore.getState().actions.closePosition(this.symbol);
3884
- CalculatorContext.instance?.deleteByName(this.name);
3885
- }
3886
- getAllPositions(ctx) {
3887
- return ctx.get((output) => output[AllPositions]) || usePositionStore.getState().positions[AllPositions];
3888
- }
3889
- };
3890
- PositionCalculator.logPosition = (symbol = "all") => {
3891
- return usePositionStore.getState().positions[symbol];
3892
- };
3893
- var parseHolding = (holding, indexPrices, tokensInfo) => {
3894
- const nonUSDC = [];
3895
- let USDC_holding = 0;
3896
- holding.forEach((item) => {
3897
- if (item.token === "USDC") {
3898
- USDC_holding = item.holding;
3899
- } else {
3900
- const tokenInfo = tokensInfo.find(({ token }) => token === item.token);
3901
- const {
3902
- base_weight = 0,
3903
- discount_factor = 0,
3904
- user_max_qty = 0
3905
- } = tokenInfo || {};
3906
- const holdingQty = item?.holding ?? 0;
3907
- const indexPrice = indexPrices[`PERP_${item.token}_USDC`] ?? 0;
3908
- const collateralRatio4 = account.collateralRatio({
3909
- baseWeight: base_weight,
3910
- discountFactor: discount_factor,
3911
- collateralQty: holdingQty,
3912
- collateralCap: user_max_qty,
3913
- indexPrice
3914
- });
3915
- nonUSDC.push({
3916
- holding: holdingQty,
3917
- indexPrice,
3918
- collateralCap: user_max_qty,
3919
- collateralRatio: collateralRatio4
3920
- });
3921
- }
3922
- });
3923
- return [USDC_holding, nonUSDC];
3924
- };
3925
- var useIndexPriceStore = create((set) => ({
3926
- indexPrices: {},
3927
- actions: {
3928
- updateIndexPrice: (indexPrice) => {
3929
- set({
3930
- indexPrices: indexPrice
3931
- });
3932
- }
3933
- }
3934
- }));
3935
-
3936
- // src/orderly/calculator/indexPrice.ts
3937
- var IndexPriceCalculatorName = "indexPriceCalculator";
3938
- var IndexPriceCalculator = class extends BaseCalculator {
3939
- constructor() {
3940
- super(...arguments);
3941
- this.name = IndexPriceCalculatorName;
3942
- }
3943
- calc(scope, data, ctx) {
3944
- return data;
3945
- }
3946
- update(data) {
3947
- if (!data)
3948
- return;
3949
- useIndexPriceStore.getState().actions.updateIndexPrice(data);
3950
- }
3951
- static getValue() {
3952
- return useIndexPriceStore.getState().indexPrices;
3953
- }
3954
- };
3955
-
3956
- // src/orderly/calculator/portfolio.ts
3957
- var PortfolioCalculatorName = "portfolio";
3958
- var PortfolioCalculator = class extends BaseCalculator {
3959
- constructor() {
3960
- super(...arguments);
3961
- this.name = PortfolioCalculatorName;
3962
- }
3963
- calc(scope, data, ctx) {
3964
- let markPrices;
3965
- let indexPrices;
3966
- const portfolio = this.getPortfolio(ctx);
3967
- if (scope === "markPrice" /* MARK_PRICE */) {
3968
- markPrices = data;
3969
- } else {
3970
- markPrices = ctx.get(
3971
- (cache) => cache[MarketCalculatorName]
3972
- );
3973
- }
3974
- if (scope === "indexPrice" /* INDEX_PRICE */) {
3975
- indexPrices = data;
3701
+ if (DEFAULT_TICK_SIZES2[symbol]) {
3702
+ setDepthObject((prev) => ({
3703
+ ...prev,
3704
+ [symbol]: Number(DEFAULT_TICK_SIZES2[symbol])
3705
+ }));
3976
3706
  } else {
3977
- indexPrices = ctx.get(
3978
- (cache) => cache[IndexPriceCalculatorName]
3979
- );
3707
+ setDepthObject((prev) => ({
3708
+ ...prev,
3709
+ [symbol]: tick
3710
+ }));
3980
3711
  }
3981
- const positions3 = ctx.get(
3982
- (output) => output.positionCalculator_all
3983
- );
3984
- let holding = portfolio.holding;
3985
- if (scope === "portfolio" /* PORTFOLIO */ && data.holding && Array.isArray(holding)) {
3986
- if (Array.isArray(data.holding)) {
3987
- holding = data.holding;
3988
- } else {
3989
- holding = holding.map((item) => {
3990
- if (data.holding[item.token]) {
3991
- return {
3992
- ...item,
3993
- holding: data.holding[item.token].holding,
3994
- frozen: data.holding[item.token].frozen
3995
- };
3712
+ }, [depthObject, tick, symbol, DEFAULT_TICK_SIZES2]);
3713
+ const onDepthChange = useCallback(
3714
+ (val) => {
3715
+ setDepthObject((prev) => ({ ...prev, [symbol]: val }));
3716
+ },
3717
+ [symbol]
3718
+ );
3719
+ const ws = useWS();
3720
+ const ticker = useTickerStream(symbol);
3721
+ const eventEmitter = useEventEmitter();
3722
+ useEffect(() => {
3723
+ let needRequestFullOrderbook = true;
3724
+ setIsLoading(true);
3725
+ let fullOrderBookUpdateSub;
3726
+ const orderBookUpdateSub = ws.subscribe(
3727
+ {
3728
+ event: "subscribe",
3729
+ topic: `${symbol}@orderbookupdate`
3730
+ },
3731
+ {
3732
+ formatter: (message) => message,
3733
+ onMessage: (message) => {
3734
+ const { data: wsData, ts } = message;
3735
+ const { symbol: symbol2, asks, bids, prevTs } = wsData;
3736
+ if (symbolRef.current !== symbol2) {
3737
+ orderBookUpdateSub?.();
3738
+ return;
3996
3739
  }
3997
- return item;
3998
- });
3740
+ orderbook_service_default.updateOrderbook(
3741
+ symbol2,
3742
+ { asks, bids, ts, prevTs },
3743
+ () => {
3744
+ needRequestFullOrderbook = true;
3745
+ }
3746
+ );
3747
+ const data2 = orderbook_service_default.getRawOrderbook(symbol2);
3748
+ setData({ bids: data2.bids, asks: data2.asks });
3749
+ }
3999
3750
  }
4000
- }
4001
- const accountInfo = ctx.accountInfo;
4002
- const symbolsInfo = ctx.symbolsInfo;
4003
- const tokensInfo = ctx.tokensInfo;
4004
- return this.format({
4005
- holding,
4006
- positions: positions3,
4007
- markPrices,
4008
- accountInfo,
4009
- symbolsInfo,
4010
- indexPrices,
4011
- tokensInfo: tokensInfo ?? EMPTY_LIST
4012
- });
4013
- }
4014
- getPortfolio(ctx) {
4015
- return ctx.get((output) => output[this.name]) || useAppStore.getState().portfolio;
4016
- }
4017
- format(inputs) {
4018
- const {
4019
- holding,
4020
- positions: positions3,
4021
- markPrices,
4022
- indexPrices,
4023
- accountInfo,
4024
- symbolsInfo,
4025
- tokensInfo
4026
- } = inputs;
4027
- if (!holding || !positions3 || !Array.isArray(positions3.rows) || !markPrices || !indexPrices || !accountInfo) {
4028
- return null;
4029
- }
4030
- const unsettledPnL = pathOr(0, ["total_unsettled_pnl"])(positions3);
4031
- const unrealizedPnL = pathOr(0, ["total_unreal_pnl"])(positions3);
4032
- const [USDC_holding, nonUSDC] = parseHolding(
4033
- holding,
4034
- indexPrices,
4035
- tokensInfo
4036
3751
  );
4037
- const usdc = holding.find((item) => item.token === "USDC");
4038
- const totalCollateral = account.totalCollateral({
4039
- USDCHolding: USDC_holding,
4040
- nonUSDCHolding: nonUSDC,
4041
- unsettlementPnL: unsettledPnL
4042
- });
4043
- const totalValue = account.totalValue({
4044
- totalUnsettlementPnL: unsettledPnL,
4045
- USDCHolding: USDC_holding,
4046
- nonUSDCHolding: nonUSDC
4047
- });
4048
- const totalUnrealizedROI = account.totalUnrealizedROI({
4049
- totalUnrealizedPnL: unrealizedPnL,
4050
- totalValue: totalValue.toNumber()
4051
- });
4052
- const totalInitialMarginWithOrders = account.totalInitialMarginWithQty({
4053
- positions: positions3.rows,
4054
- markPrices,
4055
- IMR_Factors: accountInfo.imr_factor,
4056
- maxLeverage: accountInfo.max_leverage,
4057
- symbolInfo: createGetter({ ...symbolsInfo })
4058
- });
4059
- const freeCollateral = account.freeCollateral({
4060
- totalCollateral,
4061
- totalInitialMarginWithOrders
4062
- });
4063
- const availableBalance = account.availableBalance({
4064
- USDCHolding: usdc?.holding ?? 0,
4065
- unsettlementPnL: positions3.total_unsettled_pnl ?? 0
4066
- });
4067
- return {
4068
- totalCollateral,
4069
- totalValue,
4070
- totalUnrealizedROI,
4071
- freeCollateral,
4072
- availableBalance,
4073
- unsettledPnL,
4074
- holding
3752
+ if (needRequestFullOrderbook) {
3753
+ setIsLoading(true);
3754
+ fullOrderBookUpdateSub = ws.onceSubscribe(
3755
+ {
3756
+ event: "request",
3757
+ id: `${symbol}@orderbook`,
3758
+ params: {
3759
+ type: "orderbook",
3760
+ symbol
3761
+ }
3762
+ },
3763
+ {
3764
+ formatter: (message) => message,
3765
+ onMessage: (message) => {
3766
+ const { symbol: symbol2, asks, bids, ts } = message.data;
3767
+ if (symbolRef.current !== symbol2) {
3768
+ return;
3769
+ }
3770
+ orderbook_service_default.setFullOrderbook(symbol2, { asks, bids, ts });
3771
+ const data2 = orderbook_service_default.getRawOrderbook(symbol2);
3772
+ setData({ bids: data2.bids, asks: data2.asks });
3773
+ setIsLoading(false);
3774
+ }
3775
+ }
3776
+ );
3777
+ needRequestFullOrderbook = false;
3778
+ }
3779
+ return () => {
3780
+ orderBookUpdateSub?.();
3781
+ fullOrderBookUpdateSub?.();
3782
+ orderbook_service_default.resetOrderBook(symbol);
3783
+ setData(INIT_DATA);
4075
3784
  };
4076
- }
4077
- update(data, scope) {
4078
- if (data) {
4079
- useAppStore.getState().actions.batchUpdateForPortfolio({
4080
- totalCollateral: data.totalCollateral,
4081
- totalValue: data.totalValue,
4082
- freeCollateral: data.freeCollateral,
4083
- availableBalance: data.availableBalance,
4084
- totalUnrealizedROI: data.totalUnrealizedROI,
4085
- unsettledPnL: data.unsettledPnL,
4086
- holding: Array.isArray(data.holding) ? data.holding : []
4087
- });
3785
+ }, [symbol]);
3786
+ const { data: markPrice } = useMarkPrice(symbol);
3787
+ const onItemClick = useCallback((item) => {
3788
+ eventEmitter.emit("orderbook:item:click", item);
3789
+ }, []);
3790
+ const reducedData = reduceOrderbook(depthObject[symbol], level, padding, {
3791
+ asks: data.asks,
3792
+ bids: data.bids
3793
+ });
3794
+ useEffect(() => {
3795
+ eventEmitter.emit("orderbook:update", reducedData);
3796
+ }, [reducedData]);
3797
+ const middlePrice = useMemo(() => {
3798
+ let asksFrist = 0;
3799
+ let bidsFirst = 0;
3800
+ if (data.asks.length > 0) {
3801
+ asksFrist = reducedData.asks?.[reducedData.asks.length - 1]?.[0];
4088
3802
  }
4089
- }
4090
- };
4091
-
4092
- // src/useCalculatorService.ts
4093
- var useCalculatorService = () => {
4094
- const { get: get3 } = useSimpleDI();
4095
- const calculatorService = useConstant(() => {
4096
- let calculatorService2 = get3(CalculatorServiceID);
4097
- if (!calculatorService2) {
4098
- const positionCalculator = new PositionCalculator();
4099
- const portfolioCalculator = new PortfolioCalculator();
4100
- const markPriceCalculator = new MarkPriceCalculator();
4101
- const indexPriceCalculator = new IndexPriceCalculator();
4102
- calculatorService2 = new CalculatorService(new ShardingScheduler(), [
4103
- [
4104
- "markPrice" /* MARK_PRICE */,
4105
- [
4106
- markPriceCalculator,
4107
- positionCalculator,
4108
- portfolioCalculator,
4109
- positionCalculator
4110
- ]
4111
- ],
4112
- ["position" /* POSITION */, [positionCalculator, portfolioCalculator]],
4113
- ["portfolio" /* PORTFOLIO */, [portfolioCalculator]],
4114
- // indexPrice
4115
- [
4116
- "indexPrice" /* INDEX_PRICE */,
4117
- [indexPriceCalculator, positionCalculator]
4118
- ]
4119
- ]);
4120
- SimpleDI.registerByName(CalculatorServiceID, calculatorService2);
3803
+ if (data.bids.length > 0) {
3804
+ bidsFirst = data.bids[0][0];
4121
3805
  }
4122
- return calculatorService2;
4123
- });
4124
- return calculatorService;
4125
- };
4126
-
4127
- // src/orderly/orderbook.service.ts
4128
- var defaultRawOrderBook = {
4129
- asks: [],
4130
- bids: [],
4131
- ts: 0
4132
- };
4133
- var OrderbookService = class _OrderbookService {
4134
- constructor() {
4135
- this.bufferedOrderBookUpdates = {};
4136
- this.rawOrderBook = {};
4137
- }
4138
- static getInstance() {
4139
- if (!this.instance) {
4140
- this.instance = new _OrderbookService();
3806
+ if (!isNumber(asksFrist) || !isNumber(bidsFirst) || !ticker) {
3807
+ return 0;
4141
3808
  }
4142
- return this.instance;
4143
- }
4144
- sortBufferedOrderBookUpdates(symbol) {
4145
- this.bufferedOrderBookUpdates[symbol]?.sort((a, b) => a.ts - b.ts);
4146
- }
4147
- applyUpdateToRawOrderBook(symbol, update) {
4148
- const rawOrderBook = this.rawOrderBook[symbol];
4149
- if (!rawOrderBook || rawOrderBook.ts > update.prevTs) {
4150
- return;
3809
+ return [asksFrist, bidsFirst, ticker["24h_close"]].sort()[1];
3810
+ }, [ticker?.["24h_close"], data]);
3811
+ useEffect(() => {
3812
+ prevMiddlePrice.current = middlePrice;
3813
+ }, [middlePrice]);
3814
+ return [
3815
+ {
3816
+ asks: reducedData.asks.slice(-level),
3817
+ bids: reducedData.bids.slice(0, level),
3818
+ markPrice,
3819
+ middlePrice: [prevMiddlePrice.current, middlePrice]
3820
+ },
3821
+ {
3822
+ onDepthChange,
3823
+ depth: depthObject[symbol],
3824
+ allDepths: depths,
3825
+ isLoading,
3826
+ onItemClick
4151
3827
  }
4152
- const askMap = /* @__PURE__ */ new Map();
4153
- const bidMap = /* @__PURE__ */ new Map();
4154
- rawOrderBook.asks.forEach((ask) => {
4155
- askMap.set(ask[0], ask[1]);
4156
- });
4157
- rawOrderBook.bids.forEach((bid) => {
4158
- bidMap.set(bid[0], bid[1]);
4159
- });
4160
- update.asks.forEach(
4161
- (ask) => ask[1] === 0 ? askMap.delete(ask[0]) : askMap.set(ask[0], ask[1])
4162
- );
4163
- update.bids.forEach(
4164
- (bid) => bid[1] === 0 ? bidMap.delete(bid[0]) : bidMap.set(bid[0], bid[1])
4165
- );
4166
- rawOrderBook.asks = Array.from(askMap.entries()).sort(
4167
- (a, b) => a[0] - b[0]
4168
- );
4169
- rawOrderBook.bids = Array.from(bidMap.entries()).sort(
4170
- (a, b) => b[0] - a[0]
4171
- );
4172
- rawOrderBook.ts = update.ts;
4173
- }
4174
- applyBufferedUpdatesToRawOrderBooks(symbol) {
4175
- this.bufferedOrderBookUpdates[symbol]?.forEach((update) => {
4176
- this.applyUpdateToRawOrderBook(symbol, update);
3828
+ ];
3829
+ };
3830
+ var useSymbolInfo = (symbol) => {
3831
+ const infos = useSymbolsInfo();
3832
+ return useMemo(() => {
3833
+ return !symbol || infos.isNil ? null : infos[symbol];
3834
+ }, [infos, symbol]);
3835
+ };
3836
+ var useFundingRates = () => {
3837
+ const data = useAppStore((state) => state.fundingRates);
3838
+ return createGetter({ ...data });
3839
+ };
3840
+ var useFundingRatesStore = () => {
3841
+ const data = useAppStore((state) => state.fundingRates);
3842
+ return data;
3843
+ };
3844
+
3845
+ // src/orderly/useMarket.ts
3846
+ var DefaultTab = { name: "Popular", id: 1 };
3847
+ var marketsKey = "markets";
3848
+ var useMarket = (type) => {
3849
+ const { configStore } = useContext(OrderlyContext);
3850
+ const symbolsInfo = useSymbolsInfo();
3851
+ const fundingRates = useFundingRates();
3852
+ const { data: futures } = useMarketsStream();
3853
+ const updateStore = (key, data) => {
3854
+ configStore.set(marketsKey, {
3855
+ ...configStore.getOr(marketsKey, {}),
3856
+ [key]: data
4177
3857
  });
4178
- }
4179
- deleteBufferedOrderBookUpdates(symbol) {
4180
- delete this.bufferedOrderBookUpdates[symbol];
4181
- }
4182
- commitOrderBook(symbol) {
4183
- const rawOrderBook = this.rawOrderBook[symbol];
4184
- if (!rawOrderBook) {
4185
- return;
3858
+ };
3859
+ const getStore = (key, defaultValue) => {
3860
+ return configStore.get(marketsKey)[key] || defaultValue;
3861
+ };
3862
+ if (!configStore.get(marketsKey)) {
3863
+ const jsonStr = localStorage.getItem(marketsKey);
3864
+ if (jsonStr) {
3865
+ configStore.set(marketsKey, JSON.parse(jsonStr));
3866
+ } else {
3867
+ configStore.set(marketsKey, {
3868
+ recent: [],
3869
+ favorites: [
3870
+ { name: "PERP_ETH_USDC", tabs: [{ ...DefaultTab }] },
3871
+ { name: "PERP_BTC_USDC", tabs: [{ ...DefaultTab }] }
3872
+ ],
3873
+ favoriteTabs: [{ ...DefaultTab }],
3874
+ lastSelectedFavoriteTab: { ...DefaultTab }
3875
+ });
4186
3876
  }
4187
3877
  }
4188
- pushUpdateToBuffer(symbol, update) {
4189
- if (this.bufferedOrderBookUpdates[symbol] === void 0) {
4190
- this.bufferedOrderBookUpdates[symbol] = [];
4191
- }
4192
- const buffer = this.bufferedOrderBookUpdates[symbol];
4193
- if (buffer.length > 0) {
4194
- const lastUpdate = buffer[buffer.length - 1];
4195
- if (lastUpdate.ts !== update.prevTs) {
4196
- this.bufferedOrderBookUpdates[symbol] = [];
3878
+ const getFavoriteTabs = useMemo(() => {
3879
+ return getStore("favoriteTabs", [{ ...DefaultTab }]);
3880
+ }, []);
3881
+ const getFavorites = useMemo(() => {
3882
+ const curData = getStore("favorites", []);
3883
+ const tabs = getFavoriteTabs;
3884
+ const result = [];
3885
+ const len = curData.length;
3886
+ for (let index = 0; index < len; index++) {
3887
+ const favData = curData[index];
3888
+ const favTabs = favData.tabs.filter(
3889
+ (tab) => tabs.findIndex((item) => tab.id === item.id) !== -1
3890
+ );
3891
+ if (favTabs.length) {
3892
+ result.push({ ...favData, tabs: favTabs });
4197
3893
  }
4198
3894
  }
4199
- this.bufferedOrderBookUpdates[symbol].push(update);
4200
- }
4201
- isValidFullOrderBook(symbol, currentTs) {
4202
- if ((this.bufferedOrderBookUpdates[symbol]?.length ?? 0) !== 0) {
4203
- const earliestUpdates = this.bufferedOrderBookUpdates[symbol][0];
4204
- return earliestUpdates.prevTs <= currentTs;
4205
- }
4206
- return true;
4207
- }
4208
- setFullOrderbook(symbol, rawOrderbook) {
4209
- const { ts } = rawOrderbook;
4210
- this.rawOrderBook[symbol] = rawOrderbook;
4211
- this.sortBufferedOrderBookUpdates(symbol);
4212
- if (this.isValidFullOrderBook(symbol, ts)) {
4213
- this.applyBufferedUpdatesToRawOrderBooks(symbol);
4214
- }
4215
- }
4216
- updateOrderbook(symbol, update, callback) {
4217
- const { asks, bids, prevTs, ts } = update;
4218
- const rawOrderBook = this.rawOrderBook[symbol];
4219
- if (!rawOrderBook) {
4220
- return;
4221
- }
4222
- const currentTs = rawOrderBook.ts;
4223
- if (currentTs === 0) {
4224
- this.pushUpdateToBuffer(symbol, { asks, bids, prevTs, ts });
3895
+ updateStore("favorites", result);
3896
+ return result;
3897
+ }, [configStore]);
3898
+ const [favoriteTabs, setFavoriteTabs] = useState(getFavoriteTabs);
3899
+ const [favorites, setFavorites] = useState(getFavorites);
3900
+ const [recent, setRecent] = useState(
3901
+ getStore("recent", []).filter((e) => e)
3902
+ );
3903
+ const [tabSort, setTabSort] = useState(
3904
+ getStore("tabSort", {})
3905
+ );
3906
+ const updateFavoriteTabs = (tab, operator) => {
3907
+ const saveTabs = (tabs2) => {
3908
+ setFavoriteTabs(tabs2);
3909
+ updateStore("favoriteTabs", tabs2);
3910
+ };
3911
+ if (Array.isArray(tab)) {
3912
+ saveTabs(tab);
4225
3913
  return;
4226
3914
  }
4227
- if (prevTs !== currentTs) {
4228
- this.pushUpdateToBuffer(symbol, { asks, bids, prevTs, ts });
4229
- if (callback) {
4230
- callback();
3915
+ const tabs = [...favoriteTabs];
3916
+ const index = tabs.findIndex((item) => item.id === tab.id);
3917
+ if (operator?.add) {
3918
+ tabs.push(tab);
3919
+ } else if (operator?.update) {
3920
+ if (index !== -1) {
3921
+ tabs[index] = tab;
3922
+ }
3923
+ } else if (operator?.delete) {
3924
+ if (index !== -1) {
3925
+ tabs.splice(index, 1);
4231
3926
  }
4232
- return;
4233
3927
  }
4234
- this.applyUpdateToRawOrderBook(symbol, update);
4235
- this.deleteBufferedOrderBookUpdates(symbol);
4236
- }
4237
- getRawOrderbook(symbol) {
4238
- return this.rawOrderBook[symbol];
4239
- }
4240
- resetOrderBook(symbol) {
4241
- this.rawOrderBook[symbol] = defaultRawOrderBook;
4242
- }
4243
- };
4244
- var orderBookService = OrderbookService.getInstance();
4245
- var orderbook_service_default = orderBookService;
4246
- var useMarkPrice = (symbol) => {
4247
- const ws = useWS();
4248
- const [price, setPrice] = useState(0);
4249
- useEffect(() => {
4250
- const unsubscribe = ws.subscribe(`${symbol}@markprice`, {
4251
- onMessage: (message) => {
4252
- setPrice(message.price);
3928
+ saveTabs(tabs);
3929
+ };
3930
+ const updateFavorites = (favorites2) => {
3931
+ updateStore("favorites", favorites2);
3932
+ setFavorites(favorites2);
3933
+ };
3934
+ const addToHistory = (symbol) => {
3935
+ const curData = [...recent];
3936
+ const index = curData.findIndex((item) => item.name == symbol.symbol);
3937
+ if (index !== -1) {
3938
+ curData.splice(index, 1);
3939
+ }
3940
+ curData.unshift({ name: symbol.symbol });
3941
+ updateStore("recent", curData);
3942
+ setRecent(curData);
3943
+ };
3944
+ const updateSymbolFavoriteState = (symbol, tab, remove = false) => {
3945
+ const curData = [...favorites];
3946
+ const index = curData.findIndex((item) => item.name == symbol.symbol);
3947
+ if (index === -1) {
3948
+ if (Array.isArray(tab)) {
3949
+ if (tab.length > 0) {
3950
+ curData.unshift({ name: symbol.symbol, tabs: tab });
3951
+ }
3952
+ } else {
3953
+ if (!remove) {
3954
+ curData.unshift({ name: symbol.symbol, tabs: [tab] });
3955
+ }
4253
3956
  }
4254
- });
4255
- return () => {
4256
- unsubscribe?.();
4257
- };
4258
- }, [symbol]);
4259
- return { data: price };
4260
- };
4261
- var useIndexPrice = (symbol) => {
4262
- symbol = symbol.replace("PERP", "SPOT");
4263
- const ws = useWS();
4264
- return useSWRSubscription(`${symbol}@indexprice`, (key, { next }) => {
4265
- const unsubscribe = ws.subscribe(`${symbol}@indexprice`, {
4266
- onMessage: (message) => {
4267
- next(null, message.price);
3957
+ } else {
3958
+ const favorite = curData[index];
3959
+ if (Array.isArray(tab)) {
3960
+ if (tab.length === 0) {
3961
+ curData.splice(index, 1);
3962
+ } else {
3963
+ curData[index] = { ...favorite, tabs: tab };
3964
+ }
3965
+ } else {
3966
+ if (remove) {
3967
+ const tabs = favorite.tabs.filter((item) => item.id != tab.id);
3968
+ if (tabs.length === 0) {
3969
+ curData.splice(index, 1);
3970
+ } else {
3971
+ curData[index] = { ...favorite, tabs };
3972
+ }
3973
+ } else {
3974
+ const tabs = favorite.tabs;
3975
+ tabs.push(tab);
3976
+ curData[index] = { ...favorite, tabs };
3977
+ }
4268
3978
  }
3979
+ }
3980
+ updateStore("favorites", curData);
3981
+ setFavorites(() => curData);
3982
+ };
3983
+ const marketsList = useMemo(() => {
3984
+ const list = futures?.map((item) => {
3985
+ const { open_interest = 0, index_price = 0 } = item;
3986
+ const info = symbolsInfo[item.symbol];
3987
+ const rate = fundingRates[item.symbol];
3988
+ const est_funding_rate = rate("est_funding_rate");
3989
+ const funding_period = info("funding_period");
3990
+ const change = item.change === void 0 ? get24hChange2(item["24h_close"], item["24h_open"]) : item.change;
3991
+ return {
3992
+ ...item,
3993
+ change,
3994
+ "8h_funding": get8hFunding2(est_funding_rate, funding_period),
3995
+ quote_dp: info("quote_dp"),
3996
+ created_time: info("created_time"),
3997
+ openInterest: new Decimal(open_interest || 0).mul(index_price || 0).toNumber()
3998
+ };
4269
3999
  });
4270
- return () => {
4271
- unsubscribe?.();
4272
- };
4273
- });
4274
- };
4275
- var useOpenInterest = (symbol) => {
4276
- const ws = useWS();
4277
- return useSWRSubscription(`${symbol}@openinterest`, (key, { next }) => {
4278
- const unsubscribe = ws.subscribe(`${symbol}@openinterest`, {
4279
- onMessage: (message) => {
4280
- next(null, message.openInterest);
4000
+ return list || [];
4001
+ }, [symbolsInfo, futures, fundingRates]);
4002
+ const getData = (type2) => {
4003
+ const localData = type2 === 0 /* FAVORITES */ ? [...favorites] : [...recent];
4004
+ const keys = localData.map((item) => item.name);
4005
+ const filter = type2 == 2 /* ALL */ ? marketsList : marketsList?.filter((item) => keys.includes(item.symbol));
4006
+ const favoritesData = [...favorites];
4007
+ const favoriteKeys = favoritesData.map((item) => item.name);
4008
+ if (filter) {
4009
+ for (let index = 0; index < filter.length; index++) {
4010
+ const element = filter[index];
4011
+ const isFavorite = type2 == 0 /* FAVORITES */ ? true : favoriteKeys.includes(element.symbol);
4012
+ const fIndex = favoritesData.findIndex(
4013
+ (item) => item.name === element.symbol
4014
+ );
4015
+ const tabs = fIndex === -1 ? [] : favoritesData[fIndex].tabs;
4016
+ let imr = void 0;
4017
+ if (symbolsInfo) {
4018
+ imr = symbolsInfo?.[element.symbol]("base_imr");
4019
+ }
4020
+ filter[index] = {
4021
+ ...filter[index],
4022
+ isFavorite,
4023
+ tabs,
4024
+ leverage: imr ? 1 / imr : void 0
4025
+ };
4281
4026
  }
4282
- });
4283
- return () => {
4284
- unsubscribe?.();
4027
+ }
4028
+ return filter;
4029
+ };
4030
+ const pinToTop = (symbol) => {
4031
+ const index = favorites.findIndex((item) => item.name === symbol.symbol);
4032
+ if (index !== -1) {
4033
+ const element = favorites[index];
4034
+ const list = [...favorites];
4035
+ list.splice(index, 1);
4036
+ list.unshift(element);
4037
+ updateStore("favorites", list);
4038
+ setFavorites(list);
4039
+ }
4040
+ };
4041
+ const getLastSelFavTab = () => {
4042
+ return getStore("lastSelectedFavoriteTab", { ...DefaultTab });
4043
+ };
4044
+ const updateSelectedFavoriteTab = (tab) => {
4045
+ updateStore("lastSelectedFavoriteTab", tab);
4046
+ };
4047
+ const updateTabsSortState = (tabId, sortKey, sortOrder) => {
4048
+ const map = getStore("tabSort", {});
4049
+ map[tabId] = {
4050
+ sortKey,
4051
+ sortOrder
4285
4052
  };
4286
- });
4287
- };
4288
- var useFutures = () => {
4289
- const { data, isLoading, error } = useQuery(
4290
- `/v1/public/futures`,
4053
+ updateStore("tabSort", map);
4054
+ setTabSort(map);
4055
+ };
4056
+ const markets = getData(type);
4057
+ return [
4058
+ markets || EMPTY_LIST,
4291
4059
  {
4292
- revalidateOnFocus: false
4060
+ favoriteTabs,
4061
+ favorites,
4062
+ recent,
4063
+ tabSort,
4064
+ addToHistory,
4065
+ updateFavorites,
4066
+ updateFavoriteTabs,
4067
+ updateSymbolFavoriteState,
4068
+ pinToTop,
4069
+ getLastSelFavTab,
4070
+ updateSelectedFavoriteTab,
4071
+ updateTabsSortState
4293
4072
  }
4294
- );
4295
- const [sortedData, setSortedData] = useState(data);
4296
- useWS();
4297
- useEffect(() => {
4298
- }, []);
4299
- useEffect(() => {
4300
- if (data) {
4301
- const sortedData2 = data.sort((a, b) => {
4302
- return 0;
4073
+ ];
4074
+ };
4075
+ function get8hFunding2(est_funding_rate, funding_period) {
4076
+ let funding8h = 0;
4077
+ if (est_funding_rate === void 0 || est_funding_rate === null) {
4078
+ return null;
4079
+ }
4080
+ if (funding_period) {
4081
+ funding8h = new Decimal(est_funding_rate || 0).mul(funding_period).div(8).toNumber();
4082
+ }
4083
+ return funding8h;
4084
+ }
4085
+ function get24hChange2(close, open) {
4086
+ if (close !== void 0 && open !== void 0) {
4087
+ if (open === 0) {
4088
+ return 0;
4089
+ }
4090
+ return new Decimal(close).minus(open).div(open).toNumber();
4091
+ }
4092
+ }
4093
+ var useMarkPriceStore = create((set, get3) => ({
4094
+ markPrices: {},
4095
+ // orderBook: {},
4096
+ // ask_bid: [],
4097
+ actions: {
4098
+ updateMarkPrice: (markPrice) => {
4099
+ set({
4100
+ markPrices: markPrice
4101
+ });
4102
+ },
4103
+ getMarkPriceBySymbol: (symbol) => {
4104
+ return get3().markPrices[symbol];
4105
+ }
4106
+ }
4107
+ }));
4108
+ var useMarkPriceBySymbol = (symbol) => useMarkPriceStore((state) => state.actions.getMarkPriceBySymbol(symbol));
4109
+ var useMarkPriceActions = () => useMarkPriceStore((state) => state.actions);
4110
+
4111
+ // src/orderly/useMarkPricesStream.ts
4112
+ var useMarkPricesStream = () => {
4113
+ const data = useMarkPriceStore((state) => state.markPrices);
4114
+ return { data };
4115
+ };
4116
+ var useIndexPriceStore = create((set) => ({
4117
+ indexPrices: {},
4118
+ actions: {
4119
+ updateIndexPrice: (indexPrice) => {
4120
+ set({
4121
+ indexPrices: indexPrice
4303
4122
  });
4304
- setSortedData(sortedData2);
4305
4123
  }
4306
- }, [data]);
4307
- const sortBy = useCallback((key) => {
4308
- }, [data]);
4309
- const filterBy = useCallback((key) => {
4310
- }, [data]);
4124
+ }
4125
+ }));
4126
+
4127
+ // src/orderly/useIndexPricesStream.ts
4128
+ var useIndexPricesStream = () => {
4129
+ const indexPrices = useIndexPriceStore((state) => state.indexPrices);
4130
+ const getIndexPrice = (token) => {
4131
+ if (token === "USDC") {
4132
+ return 1;
4133
+ }
4134
+ return indexPrices[`PERP_${token}_USDC`] ?? 0;
4135
+ };
4311
4136
  return {
4312
- data: sortedData,
4313
- sortBy,
4314
- filterBy,
4315
- isLoading,
4316
- error
4137
+ data: indexPrices,
4138
+ getIndexPrice: useMemoizedFn(getIndexPrice)
4317
4139
  };
4318
4140
  };
4319
-
4320
- // src/orderly/useTickerStream.ts
4321
- var useTickerStream = (symbol) => {
4322
- if (!symbol) {
4323
- throw new SDKError("Symbol is required");
4141
+ var generateLeverageLevers = (max2) => {
4142
+ const min2 = 1;
4143
+ const parts = 5;
4144
+ const step = (max2 - min2) / (parts - 1);
4145
+ const result = [];
4146
+ for (let i = 0; i < parts; i++) {
4147
+ result.push(Math.floor(min2 + step * i));
4324
4148
  }
4325
- const { data: info } = useQuery(
4326
- `/v1/public/futures/${symbol}`,
4149
+ return result;
4150
+ };
4151
+ var useLeverage = () => {
4152
+ const { data, mutate: mutate6 } = usePrivateQuery(
4153
+ "/v1/client/info",
4327
4154
  {
4328
4155
  revalidateOnFocus: false
4329
4156
  }
4330
4157
  );
4331
- const [ticker, setTicker] = useState();
4332
- const ws = useWS();
4333
- useEffect(() => {
4334
- const unsubscribe = ws.subscribe(
4335
- // { event: "subscribe", topic: "markprices" },
4336
- `${symbol}@ticker`,
4337
- {
4338
- onMessage: (message) => {
4339
- if (message.symbol !== symbol)
4340
- return;
4341
- setTicker(message);
4342
- }
4343
- // onUnsubscribe: () => {
4344
- // return "markprices";
4345
- // },
4346
- // onError: (error: any) => {
4347
- //
4348
- // },
4158
+ const [update, { isMutating }] = useMutation("/v1/client/leverage");
4159
+ const { data: leverageConfig, isLoading } = useQuery("/v1/public/leverage", {
4160
+ revalidateOnFocus: false,
4161
+ errorRetryCount: 3
4162
+ // formatter: (data) => data,
4163
+ });
4164
+ const updateLeverage = useCallback(
4165
+ async (data2) => {
4166
+ const res = await update(data2);
4167
+ if (res.success) {
4168
+ return mutate6();
4169
+ } else {
4170
+ throw new Error(res.message);
4349
4171
  }
4350
- );
4351
- return () => {
4352
- setTicker(void 0);
4353
- unsubscribe?.();
4354
- };
4355
- }, [symbol]);
4356
- const { data: markPrice } = useMarkPrice(symbol);
4357
- const { data: indexPrice } = useIndexPrice(symbol);
4358
- const { data: openInterest } = useOpenInterest(symbol);
4359
- const { data: futures } = useFutures();
4360
- const value = useMemo(() => {
4361
- if (!info)
4362
- return null;
4363
- if (!ticker || ticker.symbol !== symbol)
4364
- return info;
4365
- const futureIndex = futures?.findIndex(
4366
- (item) => item.symbol === symbol
4367
- );
4368
- let _oi = openInterest;
4369
- if (!_oi && futureIndex !== -1 && futures) {
4370
- _oi = futures[futureIndex].open_interest;
4371
- }
4372
- const config = {
4373
- ...info,
4374
- mark_price: markPrice,
4375
- index_price: indexPrice,
4376
- open_interest: _oi
4377
- };
4378
- if (ticker.open !== void 0) {
4379
- config["24h_open"] = ticker.open;
4380
- }
4381
- if (ticker.close !== void 0) {
4382
- config["24h_close"] = ticker.close;
4383
- }
4384
- if (ticker.high !== void 0) {
4385
- config["24h_high"] = ticker.high;
4386
- }
4387
- if (ticker.low !== void 0) {
4388
- config["24h_low"] = ticker.low;
4389
- }
4390
- if (ticker.volume !== void 0) {
4391
- config["24h_volumn"] = ticker.volume;
4392
- config["24h_volume"] = ticker.volume;
4172
+ },
4173
+ [update, mutate6]
4174
+ );
4175
+ const memoizedCurLeverage = useMemo(() => {
4176
+ if (data?.max_leverage !== void 0) {
4177
+ return Number(data.max_leverage);
4393
4178
  }
4394
- if (ticker.close !== void 0 && ticker.open !== void 0) {
4395
- config["change"] = new Decimal(ticker.close).minus(ticker.open).div(ticker.open).toNumber();
4396
- config["24h_change"] = new Decimal(ticker.close).minus(ticker.open).toNumber();
4179
+ return 1;
4180
+ }, [data?.max_leverage]);
4181
+ const memoizedMaxLeverage = useMemo(() => {
4182
+ if (leverageConfig?.max_futures_leverage !== void 0) {
4183
+ return Number(leverageConfig.max_futures_leverage);
4397
4184
  }
4398
- return config;
4399
- }, [info, symbol, ticker, futures, openInterest]);
4400
- return value;
4185
+ return 1;
4186
+ }, [leverageConfig?.max_futures_leverage]);
4187
+ const memoizedLeverageLevers = useMemo(() => {
4188
+ return generateLeverageLevers(memoizedMaxLeverage);
4189
+ }, [memoizedMaxLeverage]);
4190
+ return {
4191
+ update: updateLeverage,
4192
+ isLoading: isLoading || isMutating,
4193
+ leverageLevers: memoizedLeverageLevers,
4194
+ curLeverage: memoizedCurLeverage,
4195
+ maxLeverage: memoizedMaxLeverage
4196
+ };
4401
4197
  };
4402
4198
 
4403
- // src/orderly/useOrderbookStream.ts
4404
- var paddingFn = (len) => Array(len).fill([Number.NaN, Number.NaN, Number.NaN, Number.NaN]);
4405
- var isNumber = (val) => {
4406
- return typeof val === "number" && !Number.isNaN(val);
4407
- };
4408
- var getPriceKey = (rawPrice, depth, isAsks) => {
4409
- return new Decimal(rawPrice).div(depth).toDecimalPlaces(0, isAsks ? Decimal.ROUND_CEIL : Decimal.ROUND_FLOOR).mul(depth).toNumber();
4199
+ // src/orderly/useOdosQuote.ts
4200
+ var useOdosQuote = () => {
4201
+ return useMutation(`https://api.odos.xyz/sor/quote/v2`);
4410
4202
  };
4411
- var reduceItems = (depth, data, isAsks) => {
4412
- if (!Array.isArray(data) || data.length === 0) {
4413
- return [];
4414
- }
4415
- let newData = [...data];
4416
- const result = [];
4417
- if (typeof depth !== "undefined") {
4418
- const pricesMap = /* @__PURE__ */ new Map();
4419
- const len = data.length;
4420
- for (let i = 0; i < len; i++) {
4421
- const [rawPrice, quantity] = data[i];
4422
- if (!isNumber(rawPrice) || !isNumber(quantity)) {
4423
- continue;
4424
- }
4425
- const priceKey = getPriceKey(rawPrice, depth, isAsks);
4426
- const amtByRaw = new Decimal(rawPrice).mul(quantity).toNumber();
4427
- if (pricesMap.has(priceKey)) {
4428
- const item = pricesMap.get(priceKey);
4429
- const sumQty = new Decimal(item[1]).add(quantity).toNumber();
4430
- const sumAmtByRaw = new Decimal(item[2] ?? 0).add(amtByRaw).toNumber();
4431
- pricesMap.set(priceKey, [priceKey, sumQty, sumAmtByRaw]);
4432
- } else {
4433
- pricesMap.set(priceKey, [priceKey, quantity, amtByRaw]);
4434
- }
4435
- }
4436
- newData = Array.from(pricesMap.values());
4437
- }
4438
- for (let i = 0; i < newData.length; i++) {
4439
- const [price, quantity, sumAmtByRaw] = newData[i];
4440
- if (!isNumber(price) || !isNumber(quantity)) {
4441
- continue;
4203
+ var useTokensInfoStore = create(
4204
+ (set) => ({
4205
+ tokensInfo: [],
4206
+ setTokensInfo(data) {
4207
+ set({ tokensInfo: data });
4442
4208
  }
4443
- const resLen = result.length;
4444
- const newQuantity = new Decimal(quantity).add(resLen ? result[resLen - 1][2] : 0).toNumber();
4445
- const pieceAmount = isNumber(sumAmtByRaw) ? sumAmtByRaw : new Decimal(quantity).mul(price).toNumber();
4446
- const newAmount = new Decimal(pieceAmount).add(resLen ? result[resLen - 1][3] : 0).toNumber();
4447
- result.push([price, quantity, newQuantity, newAmount]);
4448
- }
4449
- return result;
4209
+ })
4210
+ );
4211
+ var useTokensInfo = () => {
4212
+ const tokensInfo = useTokensInfoStore((state) => state.tokensInfo);
4213
+ return tokensInfo;
4450
4214
  };
4451
- var reduceOrderbook = (depth, level, padding, data) => {
4452
- let asks = reduceItems(depth, data.asks, true);
4453
- let bids = reduceItems(depth, data.bids, false);
4454
- if (asks.length !== 0 && bids.length !== 0 && asks[0][0] <= bids[0][0]) {
4455
- if (asks.length === 1) {
4456
- const [price, qty, newQuantity, newAmount] = asks[0];
4457
- asks.shift();
4458
- asks.push([
4459
- price + (depth === void 0 ? 0 : Number(depth)),
4460
- qty,
4461
- newQuantity,
4462
- newAmount
4463
- ]);
4464
- } else {
4465
- const [bidPrice] = bids[0];
4466
- while (asks.length > 0) {
4467
- const [askPrice, askQty, newQuantity, newAmount] = asks[0];
4468
- if (askPrice <= bidPrice) {
4469
- asks.shift();
4470
- for (let i = 0; i < asks.length; i++) {
4471
- if (i === 0) {
4472
- const quantity = new Decimal(asks[i][1]).add(askQty);
4473
- asks[i][1] = quantity.toNumber();
4474
- asks[i][2] = quantity.toNumber();
4475
- asks[i][3] = quantity.toDecimalPlaces(0, Decimal.ROUND_CEIL).mul(asks[i][0]).toNumber();
4476
- } else {
4477
- asks[i][3] = new Decimal(asks[i][0]).mul(asks[i][1]).add(asks[i - 1][3]).toNumber();
4478
- }
4479
- }
4480
- } else {
4481
- break;
4482
- }
4483
- }
4215
+ var useTokenInfo = (token) => {
4216
+ const tokensInfo = useTokensInfo();
4217
+ return useMemo(() => {
4218
+ return tokensInfo?.find((item) => item.token === token);
4219
+ }, [tokensInfo, token]);
4220
+ };
4221
+
4222
+ // src/orderly/useComputedLTV.ts
4223
+ var { LTV, collateralRatio } = account;
4224
+ var useComputedLTV = (options = {}) => {
4225
+ const { input, token } = options;
4226
+ const isUSDC = token?.toUpperCase() === "USDC";
4227
+ const tokensInfo = useTokensInfo();
4228
+ const { usdc, data: holdingList = [] } = useHoldingStream();
4229
+ const { getIndexPrice } = useIndexPricesStream();
4230
+ const { unsettledPnL } = useCollateral();
4231
+ const usdcBalance = useMemo(() => {
4232
+ if (isUSDC && input) {
4233
+ return new Decimal(usdc?.holding ?? 0).add(input).toNumber();
4484
4234
  }
4235
+ return usdc?.holding ?? 0;
4236
+ }, [usdc?.holding, input, isUSDC]);
4237
+ const getAdjustedQty = useCallback(
4238
+ (item) => {
4239
+ if (input && item.token === token) {
4240
+ return new Decimal(item?.holding ?? 0).add(input).toNumber();
4241
+ }
4242
+ return item?.holding ?? 0;
4243
+ },
4244
+ [input, token]
4245
+ );
4246
+ const memoizedLTV = useMemo(() => {
4247
+ return LTV({
4248
+ usdcBalance,
4249
+ upnl: unsettledPnL,
4250
+ assets: holdingList.filter((h) => h.token.toUpperCase() !== "USDC").map((item) => {
4251
+ const indexPrice = getIndexPrice(item.token);
4252
+ const findToken = tokensInfo?.find((i) => i.token === item.token);
4253
+ const qty = getAdjustedQty(item);
4254
+ const weight = collateralRatio({
4255
+ baseWeight: findToken?.base_weight ?? 0,
4256
+ discountFactor: findToken?.discount_factor ?? 0,
4257
+ collateralCap: findToken?.user_max_qty ?? qty,
4258
+ collateralQty: qty,
4259
+ indexPrice
4260
+ });
4261
+ return {
4262
+ qty,
4263
+ indexPrice,
4264
+ weight: weight.toNumber()
4265
+ };
4266
+ })
4267
+ });
4268
+ }, [
4269
+ usdcBalance,
4270
+ unsettledPnL,
4271
+ holdingList,
4272
+ tokensInfo,
4273
+ getIndexPrice,
4274
+ getAdjustedQty
4275
+ ]);
4276
+ if (new Decimal(usdcBalance).add(new Decimal(unsettledPnL)).gte(zero)) {
4277
+ return 0;
4485
4278
  }
4486
- asks = asks.reverse();
4487
- if (padding) {
4488
- asks = asks.length < level ? paddingFn(level - asks.length).concat(asks) : asks;
4489
- bids = bids.length < level ? bids.concat(paddingFn(level - bids.length)) : bids;
4490
- }
4491
- return {
4492
- asks,
4493
- bids
4494
- };
4495
- };
4496
- var ORDERLY_ORDERBOOK_DEPTH_KEY = "orderly_orderbook_depth_key";
4497
- var INIT_DATA = {
4498
- asks: [],
4499
- bids: []
4279
+ return new Decimal(memoizedLTV).mul(100).toDecimalPlaces(2, Decimal.ROUND_DOWN).toNumber();
4500
4280
  };
4501
- var useOrderbookStream = (symbol, initial = INIT_DATA, options) => {
4281
+ var useFundingRate = (symbol) => {
4502
4282
  if (!symbol) {
4503
4283
  throw new SDKError("Symbol is required");
4504
4284
  }
4505
- const level = options?.level ?? 10;
4506
- const padding = options?.padding ?? true;
4507
- const symbolRef = useRef(symbol);
4508
- symbolRef.current = symbol;
4509
- const {
4510
- defaultOrderbookTickSizes: DEFAULT_TICK_SIZES2 = {},
4511
- defaultOrderbookSymbolDepths: DEFAULT_SYMBOL_DEPTHS2 = {}
4512
- } = useContext(OrderlyContext);
4513
- const [data, setData] = useState(initial);
4514
- const [isLoading, setIsLoading] = useState(true);
4515
- const config = useSymbolsInfo()[symbol];
4516
- const [depthObject, setDepthObject] = useLocalStorage(
4517
- ORDERLY_ORDERBOOK_DEPTH_KEY,
4518
- {}
4519
- );
4520
- const prevMiddlePrice = useRef(0);
4521
- const tick = config("quote_tick");
4522
- const depths = useMemo(() => {
4523
- if (DEFAULT_SYMBOL_DEPTHS2[symbol]) {
4524
- return DEFAULT_SYMBOL_DEPTHS2[symbol];
4525
- }
4526
- if (typeof tick === "undefined") {
4527
- return [];
4528
- }
4529
- try {
4530
- const base = new Decimal(tick);
4531
- return [
4532
- base.toNumber(),
4533
- base.mul(10).toNumber(),
4534
- base.mul(100).toNumber(),
4535
- base.mul(1e3).toNumber()
4536
- ];
4537
- } catch {
4285
+ const [countDown, setCountDown] = useState("00:00:00");
4286
+ const timerRef = useRef(null);
4287
+ const { data, isLoading } = useQuery(
4288
+ `/v1/public/funding_rate/${symbol}`,
4289
+ {
4290
+ fallbackData: {
4291
+ est_funding_rate: 0,
4292
+ next_funing_time: 0
4293
+ }
4538
4294
  }
4539
- return [tick];
4540
- }, [symbol, tick]);
4295
+ );
4541
4296
  useEffect(() => {
4542
- if (depthObject[symbol]) {
4297
+ if (!data || isLoading) {
4543
4298
  return;
4544
4299
  }
4545
- if (DEFAULT_TICK_SIZES2[symbol]) {
4546
- setDepthObject((prev) => ({
4547
- ...prev,
4548
- [symbol]: Number(DEFAULT_TICK_SIZES2[symbol])
4549
- }));
4550
- } else {
4551
- setDepthObject((prev) => ({
4552
- ...prev,
4553
- [symbol]: tick
4554
- }));
4300
+ const { next_funding_time } = data;
4301
+ if (!next_funding_time || next_funding_time <= 0) {
4302
+ return;
4555
4303
  }
4556
- }, [depthObject, tick, symbol, DEFAULT_TICK_SIZES2]);
4557
- const onDepthChange = useCallback(
4558
- (val) => {
4559
- setDepthObject((prev) => ({ ...prev, [symbol]: val }));
4560
- },
4561
- [symbol]
4562
- );
4563
- const ws = useWS();
4564
- const ticker = useTickerStream(symbol);
4565
- const eventEmitter = useEventEmitter();
4566
- useEffect(() => {
4567
- let needRequestFullOrderbook = true;
4568
- setIsLoading(true);
4569
- let fullOrderBookUpdateSub;
4570
- const orderBookUpdateSub = ws.subscribe(
4571
- {
4572
- event: "subscribe",
4573
- topic: `${symbol}@orderbookupdate`
4574
- },
4575
- {
4576
- formatter: (message) => message,
4577
- onMessage: (message) => {
4578
- const { data: wsData, ts } = message;
4579
- const { symbol: symbol2, asks, bids, prevTs } = wsData;
4580
- if (symbolRef.current !== symbol2) {
4581
- orderBookUpdateSub?.();
4582
- return;
4583
- }
4584
- orderbook_service_default.updateOrderbook(
4585
- symbol2,
4586
- { asks, bids, ts, prevTs },
4587
- () => {
4588
- needRequestFullOrderbook = true;
4589
- }
4590
- );
4591
- const data2 = orderbook_service_default.getRawOrderbook(symbol2);
4592
- setData({ bids: data2.bids, asks: data2.asks });
4304
+ timerRef.current = setInterval(() => {
4305
+ const diff = new Date(next_funding_time).getTime() - getTimestamp();
4306
+ if (diff <= 0) {
4307
+ setCountDown("00:00:00");
4308
+ if (timerRef.current) {
4309
+ clearInterval(timerRef.current);
4593
4310
  }
4311
+ return;
4312
+ }
4313
+ const result = timeConvertString(diff);
4314
+ if (result.length === 3) {
4315
+ setCountDown(
4316
+ `${result[0].toString().padStart(2, "0")}:${result[1].toString().padStart(2, "0")}:${result[2].toString().padStart(2, "0")}`
4317
+ );
4318
+ }
4319
+ }, 1e3);
4320
+ return () => {
4321
+ if (timerRef.current) {
4322
+ clearInterval(timerRef.current);
4594
4323
  }
4324
+ };
4325
+ }, [data, isLoading]);
4326
+ const est_funding_rate = useMemo(() => {
4327
+ if (!data) {
4328
+ return;
4329
+ }
4330
+ const { next_funding_time, est_funding_rate: est_funding_rate2 = 0 } = data;
4331
+ if (getTimestamp() > next_funding_time) {
4332
+ return null;
4333
+ }
4334
+ return new Decimal(Number(est_funding_rate2) * 100).toFixed(
4335
+ 4,
4336
+ Decimal.ROUND_DOWN
4595
4337
  );
4596
- if (needRequestFullOrderbook) {
4597
- setIsLoading(true);
4598
- fullOrderBookUpdateSub = ws.onceSubscribe(
4599
- {
4600
- event: "request",
4601
- id: `${symbol}@orderbook`,
4602
- params: {
4603
- type: "orderbook",
4604
- symbol
4605
- }
4338
+ }, [data]);
4339
+ return {
4340
+ ...data,
4341
+ est_funding_rate,
4342
+ countDown
4343
+ };
4344
+ };
4345
+ var useFundingDetails = (symbol) => {
4346
+ if (!symbol) {
4347
+ throw new SDKError("symbol is required");
4348
+ }
4349
+ return useQuery(`/v1/public/info/${symbol}`, {
4350
+ errorRetryCount: 3,
4351
+ revalidateOnFocus: false
4352
+ });
4353
+ };
4354
+ var calculatePositiveRate = (periodData, period) => {
4355
+ if (!periodData || !period) {
4356
+ return 0;
4357
+ }
4358
+ const daysMap = {
4359
+ "1d": 1,
4360
+ "3d": 3,
4361
+ "7d": 7,
4362
+ "14d": 14,
4363
+ "30d": 30,
4364
+ "90d": 90
4365
+ };
4366
+ const totalTimes = daysMap[period] * 3;
4367
+ return periodData.positive / totalTimes;
4368
+ };
4369
+ var useFundingRateHistory = () => {
4370
+ const { data: historyData, isLoading } = useQuery(
4371
+ "/v1/public/market_info/funding_history"
4372
+ );
4373
+ const getPositiveRates = useCallback(
4374
+ (data, period) => {
4375
+ if (!data?.length) {
4376
+ return {};
4377
+ }
4378
+ return data.reduce(
4379
+ (acc, item) => {
4380
+ acc[item.symbol] = calculatePositiveRate(
4381
+ item.funding[period],
4382
+ period
4383
+ );
4384
+ return acc;
4606
4385
  },
4607
- {
4608
- formatter: (message) => message,
4609
- onMessage: (message) => {
4610
- const { symbol: symbol2, asks, bids, ts } = message.data;
4611
- if (symbolRef.current !== symbol2) {
4612
- return;
4613
- }
4614
- orderbook_service_default.setFullOrderbook(symbol2, { asks, bids, ts });
4615
- const data2 = orderbook_service_default.getRawOrderbook(symbol2);
4616
- setData({ bids: data2.bids, asks: data2.asks });
4617
- setIsLoading(false);
4618
- }
4619
- }
4386
+ {}
4620
4387
  );
4621
- needRequestFullOrderbook = false;
4622
- }
4623
- return () => {
4624
- orderBookUpdateSub?.();
4625
- fullOrderBookUpdateSub?.();
4626
- orderbook_service_default.resetOrderBook(symbol);
4627
- setData(INIT_DATA);
4628
- };
4629
- }, [symbol]);
4630
- const { data: markPrice } = useMarkPrice(symbol);
4631
- const onItemClick = useCallback((item) => {
4632
- eventEmitter.emit("orderbook:item:click", item);
4633
- }, []);
4634
- const reducedData = reduceOrderbook(depthObject[symbol], level, padding, {
4635
- asks: data.asks,
4636
- bids: data.bids
4637
- });
4638
- useEffect(() => {
4639
- eventEmitter.emit("orderbook:update", reducedData);
4640
- }, [reducedData]);
4641
- const middlePrice = useMemo(() => {
4642
- let asksFrist = 0;
4643
- let bidsFirst = 0;
4644
- if (data.asks.length > 0) {
4645
- asksFrist = reducedData.asks?.[reducedData.asks.length - 1]?.[0];
4646
- }
4647
- if (data.bids.length > 0) {
4648
- bidsFirst = data.bids[0][0];
4649
- }
4650
- if (!isNumber(asksFrist) || !isNumber(bidsFirst) || !ticker) {
4651
- return 0;
4652
- }
4653
- return [asksFrist, bidsFirst, ticker["24h_close"]].sort()[1];
4654
- }, [ticker?.["24h_close"], data]);
4655
- useEffect(() => {
4656
- prevMiddlePrice.current = middlePrice;
4657
- }, [middlePrice]);
4658
- return [
4659
- {
4660
- asks: reducedData.asks.slice(-level),
4661
- bids: reducedData.bids.slice(0, level),
4662
- markPrice,
4663
- middlePrice: [prevMiddlePrice.current, middlePrice]
4664
4388
  },
4665
- {
4666
- onDepthChange,
4667
- depth: depthObject[symbol],
4668
- allDepths: depths,
4389
+ []
4390
+ );
4391
+ return useMemo(() => {
4392
+ return {
4393
+ data: historyData ?? EMPTY_LIST,
4669
4394
  isLoading,
4670
- onItemClick
4671
- }
4672
- ];
4395
+ getPositiveRates
4396
+ };
4397
+ }, [historyData, isLoading, getPositiveRates]);
4673
4398
  };
4674
- var useSymbolInfo = (symbol) => {
4675
- const infos = useSymbolsInfo();
4676
- return useMemo(() => {
4677
- return !symbol || infos.isNil ? null : infos[symbol];
4678
- }, [infos, symbol]);
4399
+ var useApiStatusStore = create()(
4400
+ immer((set) => ({
4401
+ apis: {
4402
+ positions: {
4403
+ loading: false
4404
+ }
4405
+ },
4406
+ actions: {
4407
+ updateStatus: (key, status) => {
4408
+ set((state) => {
4409
+ state.apis[key] = status;
4410
+ });
4411
+ },
4412
+ updateApiLoading: (key, loading) => {
4413
+ set((state) => {
4414
+ state.apis[key].loading = loading;
4415
+ });
4416
+ },
4417
+ updateApiError: (key, error) => {
4418
+ set((state) => {
4419
+ state.apis[key] = {
4420
+ loading: false,
4421
+ error
4422
+ };
4423
+ });
4424
+ }
4425
+ }
4426
+ }))
4427
+ );
4428
+ var useApiStatusActions = () => useApiStatusStore((state) => state.actions);
4429
+
4430
+ // src/orderly/calculator/baseCalculator.ts
4431
+ var BaseCalculator = class {
4432
+ cache(data) {
4433
+ this._cache = data;
4434
+ }
4679
4435
  };
4680
- var useFundingRates = () => {
4681
- const data = useAppStore((state) => state.fundingRates);
4682
- return createGetter({ ...data });
4436
+
4437
+ // src/orderly/calculator/markPrice.ts
4438
+ var MarketCalculatorName = "markPriceCalculator";
4439
+ var MarkPriceCalculator = class extends BaseCalculator {
4440
+ constructor() {
4441
+ super(...arguments);
4442
+ this.name = MarketCalculatorName;
4443
+ }
4444
+ calc(scope, data, ctx) {
4445
+ return data;
4446
+ }
4447
+ update(data, scope) {
4448
+ useMarkPriceStore.getState().actions.updateMarkPrice(data);
4449
+ }
4683
4450
  };
4684
- var useFundingRatesStore = () => {
4685
- const data = useAppStore((state) => state.fundingRates);
4686
- return data;
4451
+
4452
+ // src/orderly/calculator/calculatorContext.ts
4453
+ var CalculatorContext = class _CalculatorContext {
4454
+ static get instance() {
4455
+ return this._instance;
4456
+ }
4457
+ static create(scope, data) {
4458
+ if (!this._instance) {
4459
+ this._instance = new _CalculatorContext(scope, data);
4460
+ }
4461
+ return this._instance.update(scope, data);
4462
+ }
4463
+ constructor(scope, data) {
4464
+ this.setCtxData();
4465
+ this.output = {
4466
+ // rows: positions,
4467
+ };
4468
+ }
4469
+ update(scope, data) {
4470
+ this.setCtxData();
4471
+ this.markPrices = scope === "markPrice" /* MARK_PRICE */ ? data : this.output[MarketCalculatorName];
4472
+ this.portfolio = this.output["portfolio"] || useAppStore.getState().portfolio;
4473
+ return this;
4474
+ }
4475
+ setCtxData() {
4476
+ this.accountInfo = useAppStore.getState().accountInfo;
4477
+ this.symbolsInfo = useAppStore.getState().symbolsInfo;
4478
+ this.fundingRates = useAppStore.getState().fundingRates;
4479
+ this.tokensInfo = useTokensInfoStore.getState().tokensInfo;
4480
+ }
4481
+ get(fn) {
4482
+ return fn(this.output);
4483
+ }
4484
+ getCacheValue(name, fallback) {
4485
+ return this.output[name] || fallback();
4486
+ }
4487
+ clearCache() {
4488
+ this.output = {};
4489
+ this.accountInfo = void 0;
4490
+ this.portfolio = void 0;
4491
+ }
4492
+ deleteByName(name) {
4493
+ delete this.output[name];
4494
+ }
4495
+ // get positions(): API.PositionTPSLExt[] {
4496
+ // if (this.output.positionCalculator) return this.output.positionCalculator;
4497
+ // return usePositionStore.getState().positions;
4498
+ // }
4499
+ get isReady() {
4500
+ return !!this.accountInfo;
4501
+ }
4502
+ saveOutput(name, data) {
4503
+ this.output[name] = data;
4504
+ }
4505
+ outputToValue() {
4506
+ return this.output;
4507
+ }
4687
4508
  };
4688
4509
 
4689
- // src/orderly/useMarket.ts
4690
- var DefaultTab = { name: "Popular", id: 1 };
4691
- var marketsKey = "markets";
4692
- var useMarket = (type) => {
4693
- const { configStore } = useContext(OrderlyContext);
4694
- const symbolsInfo = useSymbolsInfo();
4695
- const fundingRates = useFundingRates();
4696
- const { data: futures } = useMarketsStream();
4697
- const updateStore = (key, data) => {
4698
- configStore.set(marketsKey, {
4699
- ...configStore.getOr(marketsKey, {}),
4700
- [key]: data
4701
- });
4702
- };
4703
- const getStore = (key, defaultValue) => {
4704
- return configStore.get(marketsKey)[key] || defaultValue;
4705
- };
4706
- if (!configStore.get(marketsKey)) {
4707
- const jsonStr = localStorage.getItem(marketsKey);
4708
- if (jsonStr) {
4709
- configStore.set(marketsKey, JSON.parse(jsonStr));
4510
+ // src/orderly/calculator/calculatorService.ts
4511
+ var CalculatorService = class {
4512
+ constructor(scheduler, calculators) {
4513
+ this.scheduler = scheduler;
4514
+ this.pendingCalc = [];
4515
+ this.calcQueue = [];
4516
+ /**
4517
+ * Reference count for each calculator, used to determine if a calculator is still in use.
4518
+ */
4519
+ this.referenceCount = /* @__PURE__ */ new Map();
4520
+ this.isPaused = false;
4521
+ this.calculators = new Map(calculators);
4522
+ }
4523
+ register(scope, calculator) {
4524
+ const ref_count_name = `${scope}_${calculator.name}`;
4525
+ const count = this.referenceCount.get(ref_count_name);
4526
+ if (typeof count !== "undefined" && count > 0) {
4527
+ this.referenceCount.set(ref_count_name, count + 1);
4528
+ return;
4529
+ }
4530
+ const calculators = this.calculators.get(scope);
4531
+ if (Array.isArray(calculators)) {
4532
+ calculators.push(calculator);
4710
4533
  } else {
4711
- configStore.set(marketsKey, {
4712
- recent: [],
4713
- favorites: [
4714
- { name: "PERP_ETH_USDC", tabs: [{ ...DefaultTab }] },
4715
- { name: "PERP_BTC_USDC", tabs: [{ ...DefaultTab }] }
4716
- ],
4717
- favoriteTabs: [{ ...DefaultTab }],
4718
- lastSelectedFavoriteTab: { ...DefaultTab }
4719
- });
4534
+ this.calculators.set(scope, [calculator]);
4535
+ }
4536
+ this.referenceCount.set(ref_count_name, 1);
4537
+ }
4538
+ unregister(scope, calculator) {
4539
+ const ref_count_name = `${scope}_${calculator.name}`;
4540
+ const count = this.referenceCount.get(ref_count_name);
4541
+ if (typeof count !== "undefined" && count > 1) {
4542
+ this.referenceCount.set(ref_count_name, count - 1);
4543
+ return;
4544
+ }
4545
+ const calculators = this.calculators.get(scope);
4546
+ if (Array.isArray(calculators)) {
4547
+ const index = calculators.findIndex((c) => c.name === calculator.name);
4548
+ if (index > -1) {
4549
+ calculators[index].destroy?.();
4550
+ calculators.splice(index, 1);
4551
+ }
4720
4552
  }
4553
+ this.referenceCount.delete(ref_count_name);
4721
4554
  }
4722
- const getFavoriteTabs = useMemo(() => {
4723
- return getStore("favoriteTabs", [{ ...DefaultTab }]);
4724
- }, []);
4725
- const getFavorites = useMemo(() => {
4726
- const curData = getStore("favorites", []);
4727
- const tabs = getFavoriteTabs;
4728
- const result = [];
4729
- const len = curData.length;
4730
- for (let index = 0; index < len; index++) {
4731
- const favData = curData[index];
4732
- const favTabs = favData.tabs.filter(
4733
- (tab) => tabs.findIndex((item) => tab.id === item.id) !== -1
4734
- );
4735
- if (favTabs.length) {
4736
- result.push({ ...favData, tabs: favTabs });
4737
- }
4555
+ async calc(scope, data, options) {
4556
+ if (scope !== "position" /* POSITION */) {
4557
+ if (!options?.skipWhenOnPause) ;
4738
4558
  }
4739
- updateStore("favorites", result);
4740
- return result;
4741
- }, [configStore]);
4742
- const [favoriteTabs, setFavoriteTabs] = useState(getFavoriteTabs);
4743
- const [favorites, setFavorites] = useState(getFavorites);
4744
- const [recent, setRecent] = useState(
4745
- getStore("recent", []).filter((e) => e)
4746
- );
4747
- const [tabSort, setTabSort] = useState(
4748
- getStore("tabSort", {})
4749
- );
4750
- const updateFavoriteTabs = (tab, operator) => {
4751
- const saveTabs = (tabs2) => {
4752
- setFavoriteTabs(tabs2);
4753
- updateStore("favoriteTabs", tabs2);
4754
- };
4755
- if (Array.isArray(tab)) {
4756
- saveTabs(tab);
4559
+ const ctx = CalculatorContext.create(scope, data);
4560
+ if (!ctx.isReady && options?.skipPending) {
4757
4561
  return;
4758
4562
  }
4759
- const tabs = [...favoriteTabs];
4760
- const index = tabs.findIndex((item) => item.id === tab.id);
4761
- if (operator?.add) {
4762
- tabs.push(tab);
4763
- } else if (operator?.update) {
4764
- if (index !== -1) {
4765
- tabs[index] = tab;
4563
+ if (options?.skipWhenOnPause && !this.windowIsVisible)
4564
+ return;
4565
+ this.calcQueue.push({ scope, data, options });
4566
+ await this.handleCalcQueue(ctx);
4567
+ this.ctx = ctx;
4568
+ }
4569
+ // private async handlePendingCalc() {
4570
+ // // console.log("[handlePendingCalc]:", this.pendingCalc);
4571
+ // if (this.pendingCalc.length === 0) return;
4572
+ // this.calcQueue = [...this.pendingCalc, ...this.calcQueue];
4573
+ // this.pendingCalc = [];
4574
+ // }
4575
+ async handleCalcQueue(context) {
4576
+ const first = this.calcQueue.shift();
4577
+ if (first) {
4578
+ const { scope, data, options } = first;
4579
+ const ctx = context || CalculatorContext.create(scope, data);
4580
+ const calculators = this.calculators.get(scope);
4581
+ if (Array.isArray(calculators) && calculators.length) {
4582
+ try {
4583
+ await this.scheduler.calc(scope, calculators, data, ctx);
4584
+ } catch (e) {
4585
+ }
4586
+ if (!options?.skipUpdate) {
4587
+ this.scheduler.update(scope, calculators, ctx.outputToValue());
4588
+ }
4766
4589
  }
4767
- } else if (operator?.delete) {
4768
- if (index !== -1) {
4769
- tabs.splice(index, 1);
4590
+ if (this.calcQueue.length) {
4591
+ this.handleCalcQueue(ctx);
4770
4592
  }
4771
4593
  }
4772
- saveTabs(tabs);
4773
- };
4774
- const updateFavorites = (favorites2) => {
4775
- updateStore("favorites", favorites2);
4776
- setFavorites(favorites2);
4777
- };
4778
- const addToHistory = (symbol) => {
4779
- const curData = [...recent];
4780
- const index = curData.findIndex((item) => item.name == symbol.symbol);
4781
- if (index !== -1) {
4782
- curData.splice(index, 1);
4594
+ }
4595
+ stop() {
4596
+ this.calcQueue = [];
4597
+ this.ctx?.clearCache();
4598
+ }
4599
+ get windowIsVisible() {
4600
+ if (typeof document === "undefined") {
4601
+ return true;
4783
4602
  }
4784
- curData.unshift({ name: symbol.symbol });
4785
- updateStore("recent", curData);
4786
- setRecent(curData);
4787
- };
4788
- const updateSymbolFavoriteState = (symbol, tab, remove = false) => {
4789
- const curData = [...favorites];
4790
- const index = curData.findIndex((item) => item.name == symbol.symbol);
4791
- if (index === -1) {
4792
- if (Array.isArray(tab)) {
4793
- if (tab.length > 0) {
4794
- curData.unshift({ name: symbol.symbol, tabs: tab });
4795
- }
4796
- } else {
4797
- if (!remove) {
4798
- curData.unshift({ name: symbol.symbol, tabs: [tab] });
4799
- }
4603
+ return document.visibilityState === "visible";
4604
+ }
4605
+ };
4606
+ var CalculatorServiceID = "CalculatorService";
4607
+
4608
+ // src/orderly/calculator/shardedScheduler.ts
4609
+ var requestIdleCallbackPolyfill = (callback, options) => {
4610
+ const startTime = Date.now();
4611
+ return setTimeout(() => {
4612
+ callback({
4613
+ didTimeout: false,
4614
+ timeRemaining: () => Math.max(0, 50 - (Date.now() - startTime))
4615
+ });
4616
+ }, 1);
4617
+ };
4618
+ var cancelIdleCallbackPolyfill = (id) => {
4619
+ clearTimeout(id);
4620
+ };
4621
+ var safeRequestIdleCallback = typeof window !== "undefined" && window.requestIdleCallback ? window.requestIdleCallback.bind(window) : requestIdleCallbackPolyfill;
4622
+ typeof window !== "undefined" && window.cancelIdleCallback ? window.cancelIdleCallback.bind(window) : cancelIdleCallbackPolyfill;
4623
+ var ShardingScheduler = class {
4624
+ // run(calculators: Calculator[]) {}
4625
+ calc(scope, calculators, data, ctx) {
4626
+ return new Promise((resolve, reject) => {
4627
+ try {
4628
+ this.computation(
4629
+ calculators,
4630
+ (shard) => {
4631
+ const results = [];
4632
+ for (let index = 0; index < shard.length; index++) {
4633
+ const calculator = shard[index];
4634
+ const result = calculator.calc(scope, data, ctx);
4635
+ if (result) {
4636
+ ctx.saveOutput(calculator.name, result);
4637
+ results.push(result);
4638
+ }
4639
+ }
4640
+ return results;
4641
+ },
4642
+ (results) => {
4643
+ resolve(results);
4644
+ }
4645
+ );
4646
+ } catch (error) {
4647
+ reject(error);
4800
4648
  }
4801
- } else {
4802
- const favorite = curData[index];
4803
- if (Array.isArray(tab)) {
4804
- if (tab.length === 0) {
4805
- curData.splice(index, 1);
4649
+ });
4650
+ }
4651
+ update(scope, calculators, data) {
4652
+ for (let index = 0; index < calculators.length; index++) {
4653
+ const calculator = calculators[index];
4654
+ const item = data[calculator.name];
4655
+ if (!!item) {
4656
+ calculator.update(item, scope);
4657
+ }
4658
+ }
4659
+ return Promise.resolve();
4660
+ }
4661
+ computation(data, processor, onComplete) {
4662
+ let index = 0;
4663
+ const results = [];
4664
+ const estimatedShardSize = Math.min(data.length, 2);
4665
+ function processNextShard(deadline) {
4666
+ let shardSize = estimatedShardSize;
4667
+ while (index + shardSize <= data.length && deadline.timeRemaining() > 0) {
4668
+ const shard = data.slice(index, index + shardSize);
4669
+ const result = processor(shard);
4670
+ results.push(result);
4671
+ index += shardSize;
4672
+ if (deadline.timeRemaining() < 1) {
4673
+ shardSize = Math.max(1, Math.floor(shardSize / 2));
4806
4674
  } else {
4807
- curData[index] = { ...favorite, tabs: tab };
4675
+ shardSize = Math.min(data.length - index, shardSize * 2);
4808
4676
  }
4677
+ }
4678
+ if (index < data.length) {
4679
+ safeRequestIdleCallback(processNextShard, {
4680
+ timeout: 1e3
4681
+ });
4809
4682
  } else {
4810
- if (remove) {
4811
- const tabs = favorite.tabs.filter((item) => item.id != tab.id);
4812
- if (tabs.length === 0) {
4813
- curData.splice(index, 1);
4814
- } else {
4815
- curData[index] = { ...favorite, tabs };
4816
- }
4817
- } else {
4818
- const tabs = favorite.tabs;
4819
- tabs.push(tab);
4820
- curData[index] = { ...favorite, tabs };
4821
- }
4683
+ onComplete(results.flat());
4684
+ }
4685
+ }
4686
+ safeRequestIdleCallback(processNextShard, {
4687
+ timeout: 1e3
4688
+ });
4689
+ }
4690
+ };
4691
+ var POSITION_EMPTY = {
4692
+ rows: null,
4693
+ margin_ratio: 0,
4694
+ initial_margin_ratio: 0,
4695
+ maintenance_margin_ratio: 0,
4696
+ open_margin_ratio: 0,
4697
+ current_margin_ratio_with_orders: 0,
4698
+ initial_margin_ratio_with_orders: 0,
4699
+ maintenance_margin_ratio_with_orders: 0,
4700
+ total_collateral_value: 0,
4701
+ free_collateral: 0,
4702
+ total_pnl_24_h: 0,
4703
+ unrealPnL: 0,
4704
+ total_unreal_pnl: 0,
4705
+ unsettledPnL: 0,
4706
+ total_unsettled_pnl: 0,
4707
+ notional: 0,
4708
+ unrealPnlROI: 0
4709
+ };
4710
+ var usePositionStore = create()(
4711
+ immer((set) => ({
4712
+ positions: {
4713
+ all: POSITION_EMPTY
4714
+ },
4715
+ actions: {
4716
+ setPositions: (key, positions3) => {
4717
+ set((state) => {
4718
+ state.positions[key] = positions3;
4719
+ });
4720
+ },
4721
+ closePosition: (symbol) => {
4722
+ set((state) => {
4723
+ delete state.positions[symbol];
4724
+ });
4725
+ },
4726
+ clearAll: () => {
4727
+ set((state) => {
4728
+ state.positions = {
4729
+ all: POSITION_EMPTY
4730
+ };
4731
+ });
4822
4732
  }
4823
4733
  }
4824
- updateStore("favorites", curData);
4825
- setFavorites(() => curData);
4826
- };
4827
- const marketsList = useMemo(() => {
4828
- const list = futures?.map((item) => {
4829
- const { open_interest = 0, index_price = 0 } = item;
4734
+ }))
4735
+ );
4736
+ var usePositions = (symbol = "all") => usePositionStore((state) => (state.positions[symbol] ?? POSITION_EMPTY).rows);
4737
+ var usePositionActions = () => usePositionStore((state) => state.actions);
4738
+
4739
+ // src/orderly/calculator/positions.ts
4740
+ var NAME_PREFIX = "positionCalculator";
4741
+ var AllPositions = "all";
4742
+ var PositionCalculator = class extends BaseCalculator {
4743
+ // private id: string;
4744
+ constructor(symbol = AllPositions) {
4745
+ super();
4746
+ this.name = `${NAME_PREFIX}_${symbol}`;
4747
+ this.symbol = symbol;
4748
+ }
4749
+ calc(scope, data, ctx) {
4750
+ if (scope === "markPrice" /* MARK_PRICE */) {
4751
+ return this.calcByMarkPrice(data, ctx);
4752
+ }
4753
+ if (scope === "indexPrice" /* INDEX_PRICE */) {
4754
+ return this.calcByIndexPrice(data, ctx);
4755
+ }
4756
+ if (scope === "position" /* POSITION */) {
4757
+ return this.calcByPosition(
4758
+ this.preprocess(data),
4759
+ ctx
4760
+ );
4761
+ }
4762
+ return data;
4763
+ }
4764
+ update(data, scope) {
4765
+ if (!data || !Array.isArray(data.rows))
4766
+ return;
4767
+ usePositionStore.getState().actions.setPositions(this.symbol, data);
4768
+ if (Array.isArray(data.rows) && useApiStatusStore.getState().apis.positions.loading) {
4769
+ useApiStatusStore.getState().actions.updateApiLoading("positions", false);
4770
+ }
4771
+ }
4772
+ calcByMarkPrice(markPrice, ctx) {
4773
+ let positions3 = this.getPosition(markPrice, ctx);
4774
+ useAppStore.getState().fundingRates;
4775
+ if (!positions3 || !Array.isArray(positions3.rows) || !positions3.rows.length)
4776
+ return positions3;
4777
+ positions3 = {
4778
+ ...positions3,
4779
+ rows: positions3.rows.map((item) => {
4780
+ return {
4781
+ ...item,
4782
+ mark_price: markPrice[item.symbol] || item.mark_price
4783
+ };
4784
+ })
4785
+ };
4786
+ return this.format(positions3, ctx);
4787
+ }
4788
+ calcByIndexPrice(indexPrice, ctx) {
4789
+ let positions3 = this.getPosition(indexPrice, ctx);
4790
+ if (!positions3) {
4791
+ return positions3;
4792
+ }
4793
+ if (!Array.isArray(positions3.rows) || !positions3.rows.length)
4794
+ return positions3;
4795
+ positions3 = {
4796
+ ...positions3,
4797
+ rows: positions3.rows.map((item) => ({
4798
+ ...item,
4799
+ index_price: indexPrice[item.symbol] || item.index_price || item.mark_price
4800
+ }))
4801
+ };
4802
+ return this.format(positions3, ctx);
4803
+ }
4804
+ calcByPosition(positions3, ctx) {
4805
+ if (positions3.rows.length === 0)
4806
+ return positions3;
4807
+ return this.format(positions3, ctx);
4808
+ }
4809
+ format(data, ctx) {
4810
+ const { accountInfo, symbolsInfo, fundingRates, portfolio } = ctx;
4811
+ if (!accountInfo || !fundingRates || !symbolsInfo) {
4812
+ return data;
4813
+ }
4814
+ let unrealPnL_total = zero, unrealPnL_total_index = zero, notional_total = zero, unsettlementPnL_total = zero;
4815
+ let rows = data.rows.map((item) => {
4830
4816
  const info = symbolsInfo[item.symbol];
4831
- const rate = fundingRates[item.symbol];
4832
- const est_funding_rate = rate("est_funding_rate");
4833
- const funding_period = info("funding_period");
4834
- const change = item.change === void 0 ? get24hChange2(item["24h_close"], item["24h_open"]) : item.change;
4817
+ const sum_unitary_funding = fundingRates?.[item.symbol]?.["sum_unitary_funding"] ?? 0;
4818
+ const notional = positions.notional(item.position_qty, item.mark_price);
4819
+ const unrealPnl = positions.unrealizedPnL({
4820
+ qty: item.position_qty,
4821
+ openPrice: item?.average_open_price,
4822
+ // markPrice: unRealizedPrice,
4823
+ markPrice: item.mark_price
4824
+ });
4825
+ let unrealPnl_index = 0, unrealPnlROI_index = 0;
4826
+ const maxLeverage = item.leverage || 1;
4827
+ const imr = account.IMR({
4828
+ maxLeverage,
4829
+ baseIMR: info?.["base_imr"],
4830
+ IMR_Factor: accountInfo.imr_factor[item.symbol],
4831
+ positionNotional: notional,
4832
+ ordersNotional: 0,
4833
+ IMR_factor_power: 4 / 5
4834
+ });
4835
+ const unrealPnlROI = positions.unrealizedPnLROI({
4836
+ positionQty: item.position_qty,
4837
+ openPrice: item.average_open_price,
4838
+ IMR: imr,
4839
+ unrealizedPnL: unrealPnl
4840
+ });
4841
+ if (item.index_price) {
4842
+ unrealPnl_index = positions.unrealizedPnL({
4843
+ qty: item.position_qty,
4844
+ openPrice: item?.average_open_price,
4845
+ // markPrice: unRealizedPrice,
4846
+ markPrice: item.index_price
4847
+ });
4848
+ unrealPnlROI_index = positions.unrealizedPnLROI({
4849
+ positionQty: item.position_qty,
4850
+ openPrice: item.average_open_price,
4851
+ IMR: imr,
4852
+ unrealizedPnL: unrealPnl_index
4853
+ });
4854
+ }
4855
+ const unsettlementPnL2 = positions.unsettlementPnL({
4856
+ positionQty: item.position_qty,
4857
+ markPrice: item.mark_price,
4858
+ costPosition: item.cost_position,
4859
+ sumUnitaryFunding: propOr(
4860
+ 0,
4861
+ "sum_unitary_funding",
4862
+ fundingRates[item.symbol]
4863
+ ),
4864
+ lastSumUnitaryFunding: item.last_sum_unitary_funding
4865
+ });
4866
+ const MMR = positions.MMR({
4867
+ baseMMR: info?.["base_mmr"],
4868
+ baseIMR: info?.["base_imr"],
4869
+ IMRFactor: accountInfo.imr_factor[item.symbol],
4870
+ positionNotional: notional,
4871
+ IMR_factor_power: 4 / 5
4872
+ });
4873
+ unrealPnL_total = unrealPnL_total.add(unrealPnl);
4874
+ unrealPnL_total_index = unrealPnL_total_index.add(unrealPnl_index);
4875
+ notional_total = notional_total.add(notional);
4876
+ unsettlementPnL_total = unsettlementPnL_total.add(unsettlementPnL2);
4877
+ const fundingFee = new Decimal(sum_unitary_funding).sub(item.last_sum_unitary_funding).mul(item.position_qty).negated().toNumber();
4835
4878
  return {
4836
4879
  ...item,
4837
- change,
4838
- "8h_funding": get8hFunding2(est_funding_rate, funding_period),
4839
- quote_dp: info("quote_dp"),
4840
- created_time: info("created_time"),
4841
- openInterest: new Decimal(open_interest || 0).mul(index_price || 0).toNumber()
4880
+ fundingFee,
4881
+ mm: positions.maintenanceMargin({
4882
+ positionQty: item.position_qty,
4883
+ markPrice: item.mark_price,
4884
+ MMR
4885
+ }),
4886
+ mmr: MMR,
4887
+ notional,
4888
+ unsettlement_pnl: unsettlementPnL2,
4889
+ unrealized_pnl: unrealPnl,
4890
+ unrealized_pnl_index: unrealPnl_index,
4891
+ unrealized_pnl_ROI: unrealPnlROI,
4892
+ unrealized_pnl_ROI_index: unrealPnlROI_index
4842
4893
  };
4843
4894
  });
4844
- return list || [];
4845
- }, [symbolsInfo, futures, fundingRates]);
4846
- const getData = (type2) => {
4847
- const localData = type2 === 0 /* FAVORITES */ ? [...favorites] : [...recent];
4848
- const keys = localData.map((item) => item.name);
4849
- const filter = type2 == 2 /* ALL */ ? marketsList : marketsList?.filter((item) => keys.includes(item.symbol));
4850
- const favoritesData = [...favorites];
4851
- const favoriteKeys = favoritesData.map((item) => item.name);
4852
- if (filter) {
4853
- for (let index = 0; index < filter.length; index++) {
4854
- const element = filter[index];
4855
- const isFavorite = type2 == 0 /* FAVORITES */ ? true : favoriteKeys.includes(element.symbol);
4856
- const fIndex = favoritesData.findIndex(
4857
- (item) => item.name === element.symbol
4858
- );
4859
- const tabs = fIndex === -1 ? [] : favoritesData[fIndex].tabs;
4860
- let imr = void 0;
4861
- if (symbolsInfo) {
4862
- imr = symbolsInfo?.[element.symbol]("base_imr");
4863
- }
4864
- filter[index] = {
4865
- ...filter[index],
4866
- isFavorite,
4867
- tabs,
4868
- leverage: imr ? 1 / imr : void 0
4895
+ const totalUnrealPnl = unrealPnL_total.toNumber();
4896
+ const totalUnrealPnl_index = unrealPnL_total_index.toNumber();
4897
+ const unsettlementPnL = unsettlementPnL_total.toNumber();
4898
+ let totalUnrealizedROI = 0, totalUnrealizedROI_index = 0;
4899
+ if (portfolio) {
4900
+ const { totalValue, totalCollateral } = portfolio;
4901
+ rows = rows.map((item) => {
4902
+ const est_liq_price = positions.liqPrice({
4903
+ markPrice: item.mark_price,
4904
+ totalCollateral: totalCollateral.toNumber(),
4905
+ positionQty: item.position_qty,
4906
+ positions: rows,
4907
+ MMR: item.mmr
4908
+ });
4909
+ return {
4910
+ ...item,
4911
+ est_liq_price
4869
4912
  };
4913
+ });
4914
+ if (totalValue !== null && !totalValue.eq(zero)) {
4915
+ totalUnrealizedROI = account.totalUnrealizedROI({
4916
+ totalUnrealizedPnL: totalUnrealPnl,
4917
+ totalValue: totalValue.toNumber()
4918
+ });
4919
+ totalUnrealizedROI_index = account.totalUnrealizedROI({
4920
+ totalUnrealizedPnL: totalUnrealPnl_index,
4921
+ totalValue: totalValue.toNumber()
4922
+ });
4870
4923
  }
4871
4924
  }
4872
- return filter;
4873
- };
4874
- const pinToTop = (symbol) => {
4875
- const index = favorites.findIndex((item) => item.name === symbol.symbol);
4876
- if (index !== -1) {
4877
- const element = favorites[index];
4878
- const list = [...favorites];
4879
- list.splice(index, 1);
4880
- list.unshift(element);
4881
- updateStore("favorites", list);
4882
- setFavorites(list);
4925
+ return {
4926
+ ...data,
4927
+ unrealPnL: totalUnrealPnl,
4928
+ total_unreal_pnl: totalUnrealPnl,
4929
+ total_unreal_pnl_index: totalUnrealPnl_index,
4930
+ notional: notional_total.toNumber(),
4931
+ unsettledPnL: unsettlementPnL,
4932
+ total_unsettled_pnl: unsettlementPnL,
4933
+ unrealPnlROI: totalUnrealizedROI,
4934
+ unrealPnlROI_index: totalUnrealizedROI_index,
4935
+ rows
4936
+ };
4937
+ }
4938
+ preprocess(data) {
4939
+ let rows = data.rows;
4940
+ if (this.symbol !== AllPositions && Array.isArray(rows)) {
4941
+ rows = rows.filter((item) => item.symbol === this.symbol);
4883
4942
  }
4884
- };
4885
- const getLastSelFavTab = () => {
4886
- return getStore("lastSelectedFavoriteTab", { ...DefaultTab });
4887
- };
4888
- const updateSelectedFavoriteTab = (tab) => {
4889
- updateStore("lastSelectedFavoriteTab", tab);
4890
- };
4891
- const updateTabsSortState = (tabId, sortKey, sortOrder) => {
4892
- const map = getStore("tabSort", {});
4893
- map[tabId] = {
4894
- sortKey,
4895
- sortOrder
4943
+ return {
4944
+ ...data,
4945
+ rows
4896
4946
  };
4897
- updateStore("tabSort", map);
4898
- setTabSort(map);
4899
- };
4900
- const markets = getData(type);
4901
- return [
4902
- markets || EMPTY_LIST,
4903
- {
4904
- favoriteTabs,
4905
- favorites,
4906
- recent,
4907
- tabSort,
4908
- addToHistory,
4909
- updateFavorites,
4910
- updateFavoriteTabs,
4911
- updateSymbolFavoriteState,
4912
- pinToTop,
4913
- getLastSelFavTab,
4914
- updateSelectedFavoriteTab,
4915
- updateTabsSortState
4947
+ }
4948
+ getPosition(_, ctx) {
4949
+ const positions3 = ctx.get((output) => output[this.name]) || usePositionStore.getState().positions[this.symbol];
4950
+ if (this.symbol === AllPositions) {
4951
+ return positions3;
4916
4952
  }
4917
- ];
4918
- };
4919
- function get8hFunding2(est_funding_rate, funding_period) {
4920
- let funding8h = 0;
4921
- if (est_funding_rate === void 0 || est_funding_rate === null) {
4922
- return null;
4953
+ if (positions3 && Array.isArray(positions3.rows)) {
4954
+ return positions3;
4955
+ }
4956
+ return this.preprocess(this.getAllPositions(ctx));
4923
4957
  }
4924
- if (funding_period) {
4925
- funding8h = new Decimal(est_funding_rate || 0).mul(funding_period).div(8).toNumber();
4958
+ destroy() {
4959
+ usePositionStore.getState().actions.closePosition(this.symbol);
4960
+ CalculatorContext.instance?.deleteByName(this.name);
4926
4961
  }
4927
- return funding8h;
4928
- }
4929
- function get24hChange2(close, open) {
4930
- if (close !== void 0 && open !== void 0) {
4931
- if (open === 0) {
4932
- return 0;
4933
- }
4934
- return new Decimal(close).minus(open).div(open).toNumber();
4962
+ getAllPositions(ctx) {
4963
+ return ctx.get((output) => output[AllPositions]) || usePositionStore.getState().positions[AllPositions];
4935
4964
  }
4936
- }
4937
-
4938
- // src/orderly/useMarkPricesStream.ts
4939
- var useMarkPricesStream = () => {
4940
- const data = useMarkPriceStore((state) => state.markPrices);
4941
- return { data };
4942
- };
4943
-
4944
- // src/orderly/useIndexPricesStream.ts
4945
- var useIndexPricesStream = () => {
4946
- const indexPrices = useIndexPriceStore((state) => state.indexPrices);
4947
- const getIndexPrice = (token) => {
4948
- if (token === "USDC") {
4949
- return 1;
4950
- }
4951
- return indexPrices[`PERP_${token}_USDC`] ?? 0;
4952
- };
4953
- return {
4954
- data: indexPrices,
4955
- getIndexPrice: useMemoizedFn(getIndexPrice)
4956
- };
4957
4965
  };
4958
- var generateLeverageLevers = (max2) => {
4959
- const min2 = 1;
4960
- const parts = 5;
4961
- const step = (max2 - min2) / (parts - 1);
4962
- const result = [];
4963
- for (let i = 0; i < parts; i++) {
4964
- result.push(Math.floor(min2 + step * i));
4965
- }
4966
- return result;
4966
+ PositionCalculator.logPosition = (symbol = "all") => {
4967
+ return usePositionStore.getState().positions[symbol];
4967
4968
  };
4968
- var useLeverage = () => {
4969
- const { data, mutate: mutate6 } = usePrivateQuery(
4970
- "/v1/client/info",
4971
- {
4972
- revalidateOnFocus: false
4969
+ var parseHolding = (holding, indexPrices, tokensInfo) => {
4970
+ const nonUSDC = [];
4971
+ let USDC_holding = 0;
4972
+ holding.forEach((item) => {
4973
+ if (item.token === "USDC") {
4974
+ USDC_holding = item.holding;
4975
+ } else {
4976
+ const tokenInfo = tokensInfo.find(({ token }) => token === item.token);
4977
+ const {
4978
+ base_weight = 0,
4979
+ discount_factor = 0,
4980
+ user_max_qty = 0
4981
+ } = tokenInfo || {};
4982
+ const holdingQty = item?.holding ?? 0;
4983
+ const indexPrice = indexPrices[`PERP_${item.token}_USDC`] ?? 0;
4984
+ const collateralRatio4 = account.collateralRatio({
4985
+ baseWeight: base_weight,
4986
+ discountFactor: discount_factor,
4987
+ collateralQty: holdingQty,
4988
+ collateralCap: user_max_qty,
4989
+ indexPrice
4990
+ });
4991
+ nonUSDC.push({
4992
+ holding: holdingQty,
4993
+ indexPrice,
4994
+ collateralCap: user_max_qty,
4995
+ collateralRatio: collateralRatio4
4996
+ });
4973
4997
  }
4974
- );
4975
- const [update, { isMutating }] = useMutation("/v1/client/leverage");
4976
- const { data: leverageConfig, isLoading } = useQuery("/v1/public/leverage", {
4977
- revalidateOnFocus: false,
4978
- errorRetryCount: 3
4979
- // formatter: (data) => data,
4980
4998
  });
4981
- const updateLeverage = useCallback(
4982
- async (data2) => {
4983
- const res = await update(data2);
4984
- if (res.success) {
4985
- return mutate6();
4986
- } else {
4987
- throw new Error(res.message);
4988
- }
4989
- },
4990
- [update, mutate6]
4991
- );
4992
- const memoizedCurLeverage = useMemo(() => {
4993
- if (data?.max_leverage !== void 0) {
4994
- return Number(data.max_leverage);
4995
- }
4996
- return 1;
4997
- }, [data?.max_leverage]);
4998
- const memoizedMaxLeverage = useMemo(() => {
4999
- if (leverageConfig?.max_futures_leverage !== void 0) {
5000
- return Number(leverageConfig.max_futures_leverage);
5001
- }
5002
- return 1;
5003
- }, [leverageConfig?.max_futures_leverage]);
5004
- const memoizedLeverageLevers = useMemo(() => {
5005
- return generateLeverageLevers(memoizedMaxLeverage);
5006
- }, [memoizedMaxLeverage]);
5007
- return {
5008
- update: updateLeverage,
5009
- isLoading: isLoading || isMutating,
5010
- leverageLevers: memoizedLeverageLevers,
5011
- curLeverage: memoizedCurLeverage,
5012
- maxLeverage: memoizedMaxLeverage
5013
- };
4999
+ return [USDC_holding, nonUSDC];
5014
5000
  };
5015
5001
 
5016
- // src/orderly/useOdosQuote.ts
5017
- var useOdosQuote = () => {
5018
- return useMutation(`https://api.odos.xyz/sor/quote/v2`);
5019
- };
5020
- var { LTV, collateralRatio } = account;
5021
- var useComputedLTV = (options = {}) => {
5022
- const { input, token } = options;
5023
- const isUSDC = token?.toUpperCase() === "USDC";
5024
- const tokensInfo = useTokensInfo();
5025
- const { usdc, data: holdingList = [] } = useHoldingStream();
5026
- const { getIndexPrice } = useIndexPricesStream();
5027
- const { unsettledPnL } = useCollateral();
5028
- const usdcBalance = useMemo(() => {
5029
- if (isUSDC && input) {
5030
- return new Decimal(usdc?.holding ?? 0).add(input).toNumber();
5031
- }
5032
- return usdc?.holding ?? 0;
5033
- }, [usdc?.holding, input, isUSDC]);
5034
- const getAdjustedQty = useCallback(
5035
- (item) => {
5036
- if (input && item.token === token) {
5037
- return new Decimal(item?.holding ?? 0).add(input).toNumber();
5038
- }
5039
- return item?.holding ?? 0;
5040
- },
5041
- [input, token]
5042
- );
5043
- const memoizedLTV = useMemo(() => {
5044
- return LTV({
5045
- usdcBalance,
5046
- upnl: unsettledPnL,
5047
- assets: holdingList.filter((h) => h.token.toUpperCase() !== "USDC").map((item) => {
5048
- const indexPrice = getIndexPrice(item.token);
5049
- const findToken = tokensInfo?.find((i) => i.token === item.token);
5050
- const qty = getAdjustedQty(item);
5051
- const weight = collateralRatio({
5052
- baseWeight: findToken?.base_weight ?? 0,
5053
- discountFactor: findToken?.discount_factor ?? 0,
5054
- collateralCap: findToken?.user_max_qty ?? qty,
5055
- collateralQty: qty,
5056
- indexPrice
5057
- });
5058
- return {
5059
- qty,
5060
- indexPrice,
5061
- weight: weight.toNumber()
5062
- };
5063
- })
5064
- });
5065
- }, [
5066
- usdcBalance,
5067
- unsettledPnL,
5068
- holdingList,
5069
- tokensInfo,
5070
- getIndexPrice,
5071
- getAdjustedQty
5072
- ]);
5073
- if (new Decimal(usdcBalance).add(new Decimal(unsettledPnL)).gte(zero)) {
5074
- return 0;
5075
- }
5076
- return new Decimal(memoizedLTV).mul(100).toDecimalPlaces(2, Decimal.ROUND_DOWN).toNumber();
5077
- };
5078
- var useFundingRate = (symbol) => {
5079
- if (!symbol) {
5080
- throw new SDKError("Symbol is required");
5002
+ // src/orderly/calculator/indexPrice.ts
5003
+ var IndexPriceCalculatorName = "indexPriceCalculator";
5004
+ var IndexPriceCalculator = class extends BaseCalculator {
5005
+ constructor() {
5006
+ super(...arguments);
5007
+ this.name = IndexPriceCalculatorName;
5081
5008
  }
5082
- const [countDown, setCountDown] = useState("00:00:00");
5083
- const timerRef = useRef(null);
5084
- const { data, isLoading } = useQuery(
5085
- `/v1/public/funding_rate/${symbol}`,
5086
- {
5087
- fallbackData: {
5088
- est_funding_rate: 0,
5089
- next_funing_time: 0
5090
- }
5091
- }
5092
- );
5093
- useEffect(() => {
5094
- if (!data || isLoading) {
5009
+ calc(scope, data, ctx) {
5010
+ return data;
5011
+ }
5012
+ update(data) {
5013
+ if (!data)
5095
5014
  return;
5015
+ useIndexPriceStore.getState().actions.updateIndexPrice(data);
5016
+ }
5017
+ static getValue() {
5018
+ return useIndexPriceStore.getState().indexPrices;
5019
+ }
5020
+ };
5021
+
5022
+ // src/orderly/calculator/portfolio.ts
5023
+ var PortfolioCalculatorName = "portfolio";
5024
+ var PortfolioCalculator = class extends BaseCalculator {
5025
+ constructor() {
5026
+ super(...arguments);
5027
+ this.name = PortfolioCalculatorName;
5028
+ }
5029
+ calc(scope, data, ctx) {
5030
+ let markPrices;
5031
+ let indexPrices;
5032
+ const portfolio = this.getPortfolio(ctx);
5033
+ if (scope === "markPrice" /* MARK_PRICE */) {
5034
+ markPrices = data;
5035
+ } else {
5036
+ markPrices = ctx.get(
5037
+ (cache) => cache[MarketCalculatorName]
5038
+ );
5096
5039
  }
5097
- const { next_funding_time } = data;
5098
- if (!next_funding_time || next_funding_time <= 0) {
5099
- return;
5040
+ if (scope === "indexPrice" /* INDEX_PRICE */) {
5041
+ indexPrices = data;
5042
+ } else {
5043
+ indexPrices = ctx.get(
5044
+ (cache) => cache[IndexPriceCalculatorName]
5045
+ );
5100
5046
  }
5101
- timerRef.current = setInterval(() => {
5102
- const diff = new Date(next_funding_time).getTime() - getTimestamp();
5103
- if (diff <= 0) {
5104
- setCountDown("00:00:00");
5105
- if (timerRef.current) {
5106
- clearInterval(timerRef.current);
5107
- }
5108
- return;
5109
- }
5110
- const result = timeConvertString(diff);
5111
- if (result.length === 3) {
5112
- setCountDown(
5113
- `${result[0].toString().padStart(2, "0")}:${result[1].toString().padStart(2, "0")}:${result[2].toString().padStart(2, "0")}`
5114
- );
5115
- }
5116
- }, 1e3);
5117
- return () => {
5118
- if (timerRef.current) {
5119
- clearInterval(timerRef.current);
5047
+ const positions3 = ctx.get(
5048
+ (output) => output.positionCalculator_all
5049
+ );
5050
+ let holding = portfolio.holding;
5051
+ if (scope === "portfolio" /* PORTFOLIO */ && data.holding && Array.isArray(holding)) {
5052
+ if (Array.isArray(data.holding)) {
5053
+ holding = data.holding;
5054
+ } else {
5055
+ holding = holding.map((item) => {
5056
+ if (data.holding[item.token]) {
5057
+ return {
5058
+ ...item,
5059
+ holding: data.holding[item.token].holding,
5060
+ frozen: data.holding[item.token].frozen
5061
+ };
5062
+ }
5063
+ return item;
5064
+ });
5120
5065
  }
5121
- };
5122
- }, [data, isLoading]);
5123
- const est_funding_rate = useMemo(() => {
5124
- if (!data) {
5125
- return;
5126
5066
  }
5127
- const { next_funding_time, est_funding_rate: est_funding_rate2 = 0 } = data;
5128
- if (getTimestamp() > next_funding_time) {
5067
+ const accountInfo = ctx.accountInfo;
5068
+ const symbolsInfo = ctx.symbolsInfo;
5069
+ const tokensInfo = ctx.tokensInfo;
5070
+ return this.format({
5071
+ holding,
5072
+ positions: positions3,
5073
+ markPrices,
5074
+ accountInfo,
5075
+ symbolsInfo,
5076
+ indexPrices,
5077
+ tokensInfo: tokensInfo ?? EMPTY_LIST
5078
+ });
5079
+ }
5080
+ getPortfolio(ctx) {
5081
+ return ctx.get((output) => output[this.name]) || useAppStore.getState().portfolio;
5082
+ }
5083
+ format(inputs) {
5084
+ const {
5085
+ holding,
5086
+ positions: positions3,
5087
+ markPrices,
5088
+ indexPrices,
5089
+ accountInfo,
5090
+ symbolsInfo,
5091
+ tokensInfo
5092
+ } = inputs;
5093
+ if (!holding || !positions3 || !Array.isArray(positions3.rows) || !markPrices || !indexPrices || !accountInfo) {
5129
5094
  return null;
5130
5095
  }
5131
- return new Decimal(Number(est_funding_rate2) * 100).toFixed(
5132
- 4,
5133
- Decimal.ROUND_DOWN
5096
+ const unsettledPnL = pathOr(0, ["total_unsettled_pnl"])(positions3);
5097
+ const unrealizedPnL = pathOr(0, ["total_unreal_pnl"])(positions3);
5098
+ const [USDC_holding, nonUSDC] = parseHolding(
5099
+ holding,
5100
+ indexPrices,
5101
+ tokensInfo
5134
5102
  );
5135
- }, [data]);
5136
- return {
5137
- ...data,
5138
- est_funding_rate,
5139
- countDown
5140
- };
5141
- };
5142
- var useFundingDetails = (symbol) => {
5143
- if (!symbol) {
5144
- throw new SDKError("symbol is required");
5103
+ const usdc = holding.find((item) => item.token === "USDC");
5104
+ const totalCollateral = account.totalCollateral({
5105
+ USDCHolding: USDC_holding,
5106
+ nonUSDCHolding: nonUSDC,
5107
+ unsettlementPnL: unsettledPnL
5108
+ });
5109
+ const totalValue = account.totalValue({
5110
+ totalUnsettlementPnL: unsettledPnL,
5111
+ USDCHolding: USDC_holding,
5112
+ nonUSDCHolding: nonUSDC
5113
+ });
5114
+ const totalUnrealizedROI = account.totalUnrealizedROI({
5115
+ totalUnrealizedPnL: unrealizedPnL,
5116
+ totalValue: totalValue.toNumber()
5117
+ });
5118
+ const totalInitialMarginWithOrders = account.totalInitialMarginWithQty({
5119
+ positions: positions3.rows,
5120
+ markPrices,
5121
+ IMR_Factors: accountInfo.imr_factor,
5122
+ maxLeverage: accountInfo.max_leverage,
5123
+ symbolInfo: createGetter({ ...symbolsInfo })
5124
+ });
5125
+ const freeCollateral = account.freeCollateral({
5126
+ totalCollateral,
5127
+ totalInitialMarginWithOrders
5128
+ });
5129
+ const availableBalance = account.availableBalance({
5130
+ USDCHolding: usdc?.holding ?? 0,
5131
+ unsettlementPnL: positions3.total_unsettled_pnl ?? 0
5132
+ });
5133
+ return {
5134
+ totalCollateral,
5135
+ totalValue,
5136
+ totalUnrealizedROI,
5137
+ freeCollateral,
5138
+ availableBalance,
5139
+ unsettledPnL,
5140
+ holding
5141
+ };
5145
5142
  }
5146
- return useQuery(`/v1/public/info/${symbol}`, {
5147
- errorRetryCount: 3,
5148
- revalidateOnFocus: false
5149
- });
5150
- };
5151
- var calculatePositiveRate = (periodData, period) => {
5152
- if (!periodData || !period) {
5153
- return 0;
5143
+ update(data, scope) {
5144
+ if (data) {
5145
+ useAppStore.getState().actions.batchUpdateForPortfolio({
5146
+ totalCollateral: data.totalCollateral,
5147
+ totalValue: data.totalValue,
5148
+ freeCollateral: data.freeCollateral,
5149
+ availableBalance: data.availableBalance,
5150
+ totalUnrealizedROI: data.totalUnrealizedROI,
5151
+ unsettledPnL: data.unsettledPnL,
5152
+ holding: Array.isArray(data.holding) ? data.holding : []
5153
+ });
5154
+ }
5154
5155
  }
5155
- const daysMap = {
5156
- "1d": 1,
5157
- "3d": 3,
5158
- "7d": 7,
5159
- "14d": 14,
5160
- "30d": 30,
5161
- "90d": 90
5162
- };
5163
- const totalTimes = daysMap[period] * 3;
5164
- return periodData.positive / totalTimes;
5165
5156
  };
5166
- var useFundingRateHistory = () => {
5167
- const { data: historyData, isLoading } = useQuery(
5168
- "/v1/public/market_info/funding_history"
5169
- );
5170
- const getPositiveRates = useCallback(
5171
- (data, period) => {
5172
- if (!data?.length) {
5173
- return {};
5174
- }
5175
- return data.reduce(
5176
- (acc, item) => {
5177
- acc[item.symbol] = calculatePositiveRate(
5178
- item.funding[period],
5179
- period
5180
- );
5181
- return acc;
5182
- },
5183
- {}
5184
- );
5185
- },
5186
- []
5187
- );
5188
- return useMemo(() => {
5189
- return {
5190
- data: historyData ?? EMPTY_LIST,
5191
- isLoading,
5192
- getPositiveRates
5193
- };
5194
- }, [historyData, isLoading, getPositiveRates]);
5157
+
5158
+ // src/useCalculatorService.ts
5159
+ var useCalculatorService = () => {
5160
+ const { get: get3 } = useSimpleDI();
5161
+ const calculatorService = useConstant(() => {
5162
+ let calculatorService2 = get3(CalculatorServiceID);
5163
+ if (!calculatorService2) {
5164
+ const positionCalculator = new PositionCalculator();
5165
+ const portfolioCalculator = new PortfolioCalculator();
5166
+ const markPriceCalculator = new MarkPriceCalculator();
5167
+ const indexPriceCalculator = new IndexPriceCalculator();
5168
+ calculatorService2 = new CalculatorService(new ShardingScheduler(), [
5169
+ [
5170
+ "markPrice" /* MARK_PRICE */,
5171
+ [
5172
+ markPriceCalculator,
5173
+ positionCalculator,
5174
+ portfolioCalculator,
5175
+ positionCalculator
5176
+ ]
5177
+ ],
5178
+ ["position" /* POSITION */, [positionCalculator, portfolioCalculator]],
5179
+ ["portfolio" /* PORTFOLIO */, [portfolioCalculator]],
5180
+ // indexPrice
5181
+ [
5182
+ "indexPrice" /* INDEX_PRICE */,
5183
+ [indexPriceCalculator, positionCalculator]
5184
+ ]
5185
+ ]);
5186
+ SimpleDI.registerByName(CalculatorServiceID, calculatorService2);
5187
+ }
5188
+ return calculatorService2;
5189
+ });
5190
+ return calculatorService;
5195
5191
  };
5192
+
5193
+ // src/orderly/usePositionStream/usePositionStream.ts
5196
5194
  var scopes = [
5197
5195
  "position" /* POSITION */,
5198
5196
  "markPrice" /* MARK_PRICE */,
@@ -7118,6 +7116,252 @@ var useSettleSubscription = (options) => {
7118
7116
  }
7119
7117
  );
7120
7118
  };
7119
+ var usePrivateDataObserver = (options) => {
7120
+ const ws = useWS();
7121
+ const ee = useEventEmitter();
7122
+ const { state, account: account9 } = useAccount();
7123
+ const { setAccountInfo, restoreHolding, cleanAll } = useAppStore(
7124
+ (state2) => state2.actions
7125
+ );
7126
+ const statusActions = useApiStatusActions();
7127
+ const calculatorService = useCalculatorService();
7128
+ const positionsActions = usePositionActions();
7129
+ const { data: clientInfo } = usePrivateQuery(
7130
+ "/v1/client/info",
7131
+ {
7132
+ revalidateOnFocus: false
7133
+ }
7134
+ );
7135
+ useEffect(() => {
7136
+ if (clientInfo) {
7137
+ setAccountInfo(clientInfo);
7138
+ }
7139
+ }, [clientInfo, setAccountInfo]);
7140
+ const { data: positions3, isLoading: isPositionLoading } = usePrivateQuery("/v1/positions", {
7141
+ formatter: (data) => data,
7142
+ onError: (error) => {
7143
+ statusActions.updateApiError("positions", error.message);
7144
+ }
7145
+ // revalidateOnFocus: false,
7146
+ });
7147
+ useEffect(() => {
7148
+ const handler = (state2) => {
7149
+ if (!state2.accountId) {
7150
+ calculatorService.stop();
7151
+ cleanAll();
7152
+ positionsActions.clearAll();
7153
+ }
7154
+ };
7155
+ account9.on(EVENT_NAMES.statusChanged, handler);
7156
+ return () => {
7157
+ account9.off(EVENT_NAMES.statusChanged, handler);
7158
+ };
7159
+ }, []);
7160
+ useEffect(() => {
7161
+ if (isPositionLoading) {
7162
+ statusActions.updateApiLoading("positions", isPositionLoading);
7163
+ }
7164
+ }, [isPositionLoading, statusActions]);
7165
+ useEffect(() => {
7166
+ if (positions3 && Array.isArray(positions3.rows)) {
7167
+ calculatorService.calc("position" /* POSITION */, positions3);
7168
+ }
7169
+ }, [calculatorService, positions3]);
7170
+ const { data: holding } = usePrivateQuery(
7171
+ "/v1/client/holding",
7172
+ {
7173
+ formatter: (data) => data.holding
7174
+ // revalidateOnFocus: false,
7175
+ }
7176
+ );
7177
+ useEffect(() => {
7178
+ if (!account9.accountId)
7179
+ return;
7180
+ const unsubscribe = ws.privateSubscribe(
7181
+ {
7182
+ id: "balance",
7183
+ event: "subscribe",
7184
+ topic: "balance",
7185
+ ts: Date.now()
7186
+ },
7187
+ {
7188
+ onMessage: (data) => {
7189
+ const holding2 = data?.balances ?? {};
7190
+ if (holding2) {
7191
+ calculatorService.calc("portfolio" /* PORTFOLIO */, { holding: holding2 });
7192
+ }
7193
+ }
7194
+ }
7195
+ );
7196
+ return () => unsubscribe?.();
7197
+ }, [account9.accountId]);
7198
+ const isHoldingInit = useRef(false);
7199
+ useEffect(() => {
7200
+ isHoldingInit.current = false;
7201
+ }, [state.address]);
7202
+ useEffect(() => {
7203
+ if (!holding) {
7204
+ return;
7205
+ }
7206
+ if (isHoldingInit.current) {
7207
+ calculatorService.calc("portfolio" /* PORTFOLIO */, { holding });
7208
+ } else {
7209
+ restoreHolding(holding);
7210
+ }
7211
+ isHoldingInit.current = true;
7212
+ }, [holding]);
7213
+ const [subOrder] = useLocalStorage("orderly_subscribe_order", true);
7214
+ const updateOrders = (data, isAlgoOrder) => {
7215
+ const keysMap = options.getKeysMap("orders");
7216
+ const filteredKeys = /* @__PURE__ */ new Map();
7217
+ const keyStartWith = isAlgoOrder ? "algoOrders" : "orders";
7218
+ const keys = keysMap.keys();
7219
+ for (const key of keys) {
7220
+ if (key.startsWith(keyStartWith)) {
7221
+ filteredKeys.set(key, keysMap.get(key));
7222
+ }
7223
+ }
7224
+ let fieldChanges = {};
7225
+ filteredKeys.forEach((getKey, key) => {
7226
+ mutate(
7227
+ unstable_serialize((index, prevData) => [
7228
+ getKey(index, prevData),
7229
+ state.accountId
7230
+ ]),
7231
+ (prevData) => {
7232
+ try {
7233
+ if (isAlgoOrder) {
7234
+ const res = updateAlgoOrdersHandler(
7235
+ key,
7236
+ data,
7237
+ prevData
7238
+ );
7239
+ fieldChanges = res?.fieldChanges || {};
7240
+ return res?.mergedOrders;
7241
+ }
7242
+ return updateOrdersHandler(key, data, prevData);
7243
+ } catch (error) {
7244
+ return prevData;
7245
+ }
7246
+ },
7247
+ {
7248
+ revalidate: false
7249
+ }
7250
+ );
7251
+ });
7252
+ const formattedData = isAlgoOrder ? AlgoOrderMergeHandler.groupOrders(data) : object2underscore(data);
7253
+ ee.emit("orders:changed", {
7254
+ ...formattedData,
7255
+ status: isAlgoOrder ? formattedData.algo_status : data.status,
7256
+ // custom field name
7257
+ fieldChanges
7258
+ });
7259
+ };
7260
+ useEffect(() => {
7261
+ if (!state.accountId) {
7262
+ return;
7263
+ }
7264
+ if (subOrder !== true) {
7265
+ return;
7266
+ }
7267
+ const unsubscribe = ws.privateSubscribe("executionreport", {
7268
+ onMessage: (data) => {
7269
+ updateOrders(data, false);
7270
+ }
7271
+ });
7272
+ return () => unsubscribe?.();
7273
+ }, [state.accountId, subOrder]);
7274
+ useEffect(() => {
7275
+ if (!state.accountId)
7276
+ return;
7277
+ if (subOrder !== true)
7278
+ return;
7279
+ const unsubscribe = ws.privateSubscribe("algoexecutionreport", {
7280
+ onMessage: (data) => {
7281
+ updateOrders(data, true);
7282
+ }
7283
+ });
7284
+ return () => unsubscribe?.();
7285
+ }, [state.accountId, subOrder]);
7286
+ useEffect(() => {
7287
+ if (!state.accountId)
7288
+ return;
7289
+ const key = ["/v1/positions", state.accountId];
7290
+ const unsubscribe = ws.privateSubscribe("account", {
7291
+ onMessage: (data) => {
7292
+ const { symbol, leverage } = data?.accountDetail?.symbolLeverage || {};
7293
+ if (symbol && leverage) {
7294
+ mutate(
7295
+ key,
7296
+ (prevPositions) => {
7297
+ if (prevPositions?.rows?.length) {
7298
+ return {
7299
+ ...prevPositions,
7300
+ rows: prevPositions.rows.map((row) => {
7301
+ return row.symbol === symbol ? { ...row, leverage } : row;
7302
+ })
7303
+ };
7304
+ }
7305
+ return prevPositions;
7306
+ },
7307
+ {
7308
+ revalidate: false
7309
+ }
7310
+ );
7311
+ }
7312
+ }
7313
+ });
7314
+ return () => unsubscribe?.();
7315
+ }, [state.accountId]);
7316
+ useEffect(() => {
7317
+ if (!state.accountId) {
7318
+ return;
7319
+ }
7320
+ const key = ["/v1/positions", state.accountId];
7321
+ const unsubscribe = ws.privateSubscribe("position", {
7322
+ onMessage: (data) => {
7323
+ const { positions: nextPositions } = data;
7324
+ mutate(
7325
+ key,
7326
+ (prevPositions) => {
7327
+ if (!!prevPositions) {
7328
+ const newPositions = {
7329
+ ...prevPositions,
7330
+ rows: prevPositions.rows.map((row) => {
7331
+ const itemIndex = nextPositions.findIndex(
7332
+ (item) => item.symbol === row.symbol
7333
+ );
7334
+ if (itemIndex >= 0) {
7335
+ const itemArr = nextPositions.splice(itemIndex, 1);
7336
+ const item = itemArr[0];
7337
+ if (item.averageOpenPrice === 0 && item.positionQty !== 0) {
7338
+ return row;
7339
+ }
7340
+ return object2underscore(item);
7341
+ }
7342
+ return row;
7343
+ })
7344
+ };
7345
+ if (nextPositions.length > 0) {
7346
+ newPositions.rows = [
7347
+ ...newPositions.rows,
7348
+ ...nextPositions.map(object2underscore)
7349
+ ];
7350
+ }
7351
+ return newPositions;
7352
+ }
7353
+ },
7354
+ {
7355
+ revalidate: false
7356
+ }
7357
+ );
7358
+ }
7359
+ });
7360
+ return () => {
7361
+ unsubscribe?.();
7362
+ };
7363
+ }, [state.accountId]);
7364
+ };
7121
7365
  var useSymbolPriceRange = (symbol, side, price) => {
7122
7366
  const config = useSymbolsInfo();
7123
7367
  const priceRange = config?.[symbol]("price_range");
@@ -7570,12 +7814,12 @@ async function bracketOrderValidator(values, config) {
7570
7814
  const result = /* @__PURE__ */ Object.create(null);
7571
7815
  await Promise.resolve();
7572
7816
  const {
7573
- tp_enable,
7817
+ // tp_enable,
7818
+ // sl_enable,
7574
7819
  tp_trigger_price,
7575
7820
  tp_order_price,
7576
7821
  tp_order_type,
7577
7822
  sl_trigger_price,
7578
- sl_enable,
7579
7823
  sl_order_price,
7580
7824
  sl_order_type,
7581
7825
  side
@@ -7595,12 +7839,6 @@ async function bracketOrderValidator(values, config) {
7595
7839
  if (Number(sl_trigger_price) < 0) {
7596
7840
  result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
7597
7841
  }
7598
- if (tp_enable && !tp_trigger_price) {
7599
- result.tp_trigger_price = OrderValidation.required("tp_trigger_price");
7600
- }
7601
- if (sl_enable && !sl_trigger_price) {
7602
- result.sl_trigger_price = OrderValidation.required("sl_trigger_price");
7603
- }
7604
7842
  if (tp_order_type === OrderType.LIMIT && !tp_order_price) {
7605
7843
  result.tp_order_price = OrderValidation.required("tp_order_price");
7606
7844
  }
@@ -8420,8 +8658,8 @@ var BaseAlgoOrderCreator = class {
8420
8658
  tp_trigger_price,
8421
8659
  sl_trigger_price,
8422
8660
  side,
8423
- tp_enable,
8424
- sl_enable,
8661
+ // tp_enable,
8662
+ // sl_enable,
8425
8663
  tp_order_type,
8426
8664
  sl_order_type,
8427
8665
  tp_order_price,
@@ -8450,12 +8688,6 @@ var BaseAlgoOrderCreator = class {
8450
8688
  if (Number(sl_trigger_price) < 0) {
8451
8689
  result.sl_trigger_price = OrderValidation.min("sl_trigger_price", 0);
8452
8690
  }
8453
- if (tp_enable && !tp_trigger_price) {
8454
- result.tp_trigger_price = OrderValidation.required("tp_trigger_price");
8455
- }
8456
- if (sl_enable && !sl_trigger_price) {
8457
- result.sl_trigger_price = OrderValidation.required("sl_trigger_price");
8458
- }
8459
8691
  if (tp_order_type === OrderType.LIMIT && !tp_order_price) {
8460
8692
  result.tp_order_price = OrderValidation.required("tp_order_price");
8461
8693
  }
@@ -8966,9 +9198,6 @@ var tpslFields = [
8966
9198
  "sl_offset_percentage"
8967
9199
  ];
8968
9200
  var isBracketOrder = (order) => {
8969
- if (order.sl_enable || order.tp_enable) {
8970
- return true;
8971
- }
8972
9201
  return !!order.tp_trigger_price || !!order.sl_trigger_price;
8973
9202
  };
8974
9203
  var hasTPSL = (order) => {
@@ -9498,28 +9727,6 @@ function useSubAccountMaxWithdrawal(options) {
9498
9727
  }
9499
9728
 
9500
9729
  // src/orderly/useTakeProfitAndStopLoss/useTPSL.ts
9501
- var checkIsEnableTpSL = (order) => {
9502
- const result = {
9503
- tp_enable: true,
9504
- sl_enable: true
9505
- };
9506
- if (!order) {
9507
- return result;
9508
- }
9509
- const tp = order.child_orders.find(
9510
- (o) => o.algo_type === AlgoOrderType.TAKE_PROFIT && o.is_activated
9511
- );
9512
- const sl = order.child_orders.find(
9513
- (o) => o.algo_type === AlgoOrderType.STOP_LOSS && o.is_activated
9514
- );
9515
- if (!tp) {
9516
- result.tp_enable = false;
9517
- }
9518
- if (!sl) {
9519
- result.sl_enable = false;
9520
- }
9521
- return result;
9522
- };
9523
9730
  var useTaskProfitAndStopLossInternal = (position, options) => {
9524
9731
  const isEditing = typeof options?.isEditing !== "undefined" ? options.isEditing : !!options?.defaultOrder;
9525
9732
  const [order, setOrder] = useState({
@@ -9534,8 +9741,12 @@ var useTaskProfitAndStopLossInternal = (position, options) => {
9534
9741
  // quantity:
9535
9742
  // options?.defaultOrder?.quantity || Math.abs(position.position_qty),
9536
9743
  algo_type: options?.defaultOrder?.algo_type,
9537
- tp_enable: isEditing ? checkIsEnableTpSL(options?.defaultOrder).tp_enable : options?.tpslEnable?.tp_enable,
9538
- sl_enable: isEditing ? checkIsEnableTpSL(options?.defaultOrder).sl_enable : options?.tpslEnable?.sl_enable,
9744
+ // tp_enable: isEditing
9745
+ // ? checkIsEnableTpSL(options?.defaultOrder).tp_enable
9746
+ // : options?.tpslEnable?.tp_enable,
9747
+ // sl_enable: isEditing
9748
+ // ? checkIsEnableTpSL(options?.defaultOrder).sl_enable
9749
+ // : options?.tpslEnable?.sl_enable,
9539
9750
  position_type: options?.positionType
9540
9751
  });
9541
9752
  const symbolInfo = useSymbolsInfo()[position.symbol]();
@@ -10187,254 +10398,6 @@ var useStorageLedgerAddress = () => {
10187
10398
  ledgerWallet
10188
10399
  };
10189
10400
  };
10190
-
10191
- // src/orderly/usePrivateDataObserver.ts
10192
- var usePrivateDataObserver = (options) => {
10193
- const ws = useWS();
10194
- const ee = useEventEmitter();
10195
- const { state, account: account9 } = useAccount();
10196
- const { setAccountInfo, restoreHolding, cleanAll } = useAppStore(
10197
- (state2) => state2.actions
10198
- );
10199
- const statusActions = useApiStatusActions();
10200
- const calculatorService = useCalculatorService();
10201
- const positionsActions = usePositionActions();
10202
- const { data: clientInfo } = usePrivateQuery(
10203
- "/v1/client/info",
10204
- {
10205
- revalidateOnFocus: false
10206
- }
10207
- );
10208
- useEffect(() => {
10209
- if (clientInfo) {
10210
- setAccountInfo(clientInfo);
10211
- }
10212
- }, [clientInfo, setAccountInfo]);
10213
- const { data: positions3, isLoading: isPositionLoading } = usePrivateQuery("/v1/positions", {
10214
- formatter: (data) => data,
10215
- onError: (error) => {
10216
- statusActions.updateApiError("positions", error.message);
10217
- }
10218
- // revalidateOnFocus: false,
10219
- });
10220
- useEffect(() => {
10221
- const handler = (state2) => {
10222
- if (!state2.accountId) {
10223
- calculatorService.stop();
10224
- cleanAll();
10225
- positionsActions.clearAll();
10226
- }
10227
- };
10228
- account9.on(EVENT_NAMES.statusChanged, handler);
10229
- return () => {
10230
- account9.off(EVENT_NAMES.statusChanged, handler);
10231
- };
10232
- }, []);
10233
- useEffect(() => {
10234
- if (isPositionLoading) {
10235
- statusActions.updateApiLoading("positions", isPositionLoading);
10236
- }
10237
- }, [isPositionLoading, statusActions]);
10238
- useEffect(() => {
10239
- if (positions3 && Array.isArray(positions3.rows)) {
10240
- calculatorService.calc("position" /* POSITION */, positions3);
10241
- }
10242
- }, [calculatorService, positions3]);
10243
- const { data: holding } = usePrivateQuery(
10244
- "/v1/client/holding",
10245
- {
10246
- formatter: (data) => data.holding
10247
- // revalidateOnFocus: false,
10248
- }
10249
- );
10250
- useEffect(() => {
10251
- if (!account9.accountId)
10252
- return;
10253
- const unsubscribe = ws.privateSubscribe(
10254
- {
10255
- id: "balance",
10256
- event: "subscribe",
10257
- topic: "balance",
10258
- ts: Date.now()
10259
- },
10260
- {
10261
- onMessage: (data) => {
10262
- const holding2 = data?.balances ?? {};
10263
- if (holding2) {
10264
- calculatorService.calc("portfolio" /* PORTFOLIO */, { holding: holding2 });
10265
- }
10266
- }
10267
- }
10268
- );
10269
- return () => unsubscribe?.();
10270
- }, [account9.accountId]);
10271
- const isHoldingInit = useRef(false);
10272
- useEffect(() => {
10273
- isHoldingInit.current = false;
10274
- }, [state.address]);
10275
- useEffect(() => {
10276
- if (!holding) {
10277
- return;
10278
- }
10279
- if (isHoldingInit.current) {
10280
- calculatorService.calc("portfolio" /* PORTFOLIO */, { holding });
10281
- } else {
10282
- restoreHolding(holding);
10283
- }
10284
- isHoldingInit.current = true;
10285
- }, [holding]);
10286
- const [subOrder] = useLocalStorage("orderly_subscribe_order", true);
10287
- const updateOrders = (data, isAlgoOrder) => {
10288
- const keysMap = options.getKeysMap("orders");
10289
- const filteredKeys = /* @__PURE__ */ new Map();
10290
- const keyStartWith = isAlgoOrder ? "algoOrders" : "orders";
10291
- const keys = keysMap.keys();
10292
- for (const key of keys) {
10293
- if (key.startsWith(keyStartWith)) {
10294
- filteredKeys.set(key, keysMap.get(key));
10295
- }
10296
- }
10297
- let fieldChanges = {};
10298
- filteredKeys.forEach((getKey, key) => {
10299
- mutate(
10300
- unstable_serialize((index, prevData) => [
10301
- getKey(index, prevData),
10302
- state.accountId
10303
- ]),
10304
- (prevData) => {
10305
- try {
10306
- if (isAlgoOrder) {
10307
- const res = updateAlgoOrdersHandler(
10308
- key,
10309
- data,
10310
- prevData
10311
- );
10312
- fieldChanges = res?.fieldChanges || {};
10313
- return res?.mergedOrders;
10314
- }
10315
- return updateOrdersHandler(key, data, prevData);
10316
- } catch (error) {
10317
- return prevData;
10318
- }
10319
- },
10320
- {
10321
- revalidate: false
10322
- }
10323
- );
10324
- });
10325
- const formattedData = isAlgoOrder ? AlgoOrderMergeHandler.groupOrders(data) : object2underscore(data);
10326
- ee.emit("orders:changed", {
10327
- ...formattedData,
10328
- status: isAlgoOrder ? formattedData.algo_status : data.status,
10329
- // custom field name
10330
- fieldChanges
10331
- });
10332
- };
10333
- useEffect(() => {
10334
- if (!state.accountId) {
10335
- return;
10336
- }
10337
- if (subOrder !== true) {
10338
- return;
10339
- }
10340
- const unsubscribe = ws.privateSubscribe("executionreport", {
10341
- onMessage: (data) => {
10342
- updateOrders(data, false);
10343
- }
10344
- });
10345
- return () => unsubscribe?.();
10346
- }, [state.accountId, subOrder]);
10347
- useEffect(() => {
10348
- if (!state.accountId)
10349
- return;
10350
- if (subOrder !== true)
10351
- return;
10352
- const unsubscribe = ws.privateSubscribe("algoexecutionreport", {
10353
- onMessage: (data) => {
10354
- updateOrders(data, true);
10355
- }
10356
- });
10357
- return () => unsubscribe?.();
10358
- }, [state.accountId, subOrder]);
10359
- useEffect(() => {
10360
- if (!state.accountId)
10361
- return;
10362
- const key = ["/v1/positions", state.accountId];
10363
- const unsubscribe = ws.privateSubscribe("account", {
10364
- onMessage: (data) => {
10365
- const { symbol, leverage } = data?.accountDetail?.symbolLeverage || {};
10366
- if (symbol && leverage) {
10367
- mutate(
10368
- key,
10369
- (prevPositions) => {
10370
- if (prevPositions?.rows?.length) {
10371
- return {
10372
- ...prevPositions,
10373
- rows: prevPositions.rows.map((row) => {
10374
- return row.symbol === symbol ? { ...row, leverage } : row;
10375
- })
10376
- };
10377
- }
10378
- return prevPositions;
10379
- },
10380
- {
10381
- revalidate: false
10382
- }
10383
- );
10384
- }
10385
- }
10386
- });
10387
- return () => unsubscribe?.();
10388
- }, [state.accountId]);
10389
- useEffect(() => {
10390
- if (!state.accountId) {
10391
- return;
10392
- }
10393
- const key = ["/v1/positions", state.accountId];
10394
- const unsubscribe = ws.privateSubscribe("position", {
10395
- onMessage: (data) => {
10396
- const { positions: nextPositions } = data;
10397
- mutate(
10398
- key,
10399
- (prevPositions) => {
10400
- if (!!prevPositions) {
10401
- const newPositions = {
10402
- ...prevPositions,
10403
- rows: prevPositions.rows.map((row) => {
10404
- const itemIndex = nextPositions.findIndex(
10405
- (item) => item.symbol === row.symbol
10406
- );
10407
- if (itemIndex >= 0) {
10408
- const itemArr = nextPositions.splice(itemIndex, 1);
10409
- const item = itemArr[0];
10410
- if (item.averageOpenPrice === 0 && item.positionQty !== 0) {
10411
- return row;
10412
- }
10413
- return object2underscore(item);
10414
- }
10415
- return row;
10416
- })
10417
- };
10418
- if (nextPositions.length > 0) {
10419
- newPositions.rows = [
10420
- ...newPositions.rows,
10421
- ...nextPositions.map(object2underscore)
10422
- ];
10423
- }
10424
- return newPositions;
10425
- }
10426
- },
10427
- {
10428
- revalidate: false
10429
- }
10430
- );
10431
- }
10432
- });
10433
- return () => {
10434
- unsubscribe?.();
10435
- };
10436
- }, [state.accountId]);
10437
- };
10438
10401
  var useMarketStore = create(
10439
10402
  (set, get3) => ({
10440
10403
  market: [],
@@ -18048,6 +18011,6 @@ var usePositionClose = (options) => {
18048
18011
  };
18049
18012
  };
18050
18013
 
18051
- export { DefaultLayoutConfig, DistributionId, ENVType2 as ENVType, EpochStatus, ExtendedConfigStore, MaintenanceStatus, MarketsStorageKey, MarketsType, ORDERLY_ORDERBOOK_DEPTH_KEY, OrderlyConfigProvider, OrderlyContext, OrderlyProvider, StatusProvider, TWType, WalletConnectorContext, WsNetworkStatus, checkNotional, cleanStringStyle, fetcher, findPositionTPSLFromOrders, findTPSLFromOrder, findTPSLOrderPriceFromOrder, getMinNotional, getPriceKey, isCurrentlyClosed, isCurrentlyTrading, noCacheConfig, parseJSON, useAccount, useAccountInfo, useAccountInstance, useAccountRewardsHistory, useAllBrokers, useApiKeyManager, useAssetsHistory, useAudioPlayer, useBalanceSubscription, useBalanceTopic, useBoolean, useChain, useChainInfo, useChains, useCheckReferralCode, useCollateral, useCommission, useComputedLTV, useConfig, useConvert, useCurEpochEstimate, useDaily, useDeposit, useDistribution, useDistributionHistory, useEpochInfo, useEventEmitter, useFeeState, useFundingDetails, useFundingFeeHistory, useFundingRate, useFundingRateHistory, useFundingRates, useFundingRatesStore, useGetClaimed, useGetEnv, useGetReferralCode, useGetRwaSymbolCloseTimeInterval, useGetRwaSymbolInfo, useGetRwaSymbolOpenStatus, useGetRwaSymbolOpenTimeInterval, useHoldingStream, useIndexPrice, useIndexPricesStream, useInfiniteQuery, useInitRwaSymbolsRuntime, useInternalTransfer, useKeyStore, useLazyQuery, useLeverage, useLeverageBySymbol, useLocalStorage, useMaintenanceStatus, useMarginRatio, useMarkPrice, useMarkPriceBySymbol, useMarkPricesStream, useMarket, useMarketList, useMarketMap, useMarketTradeStream, useMarkets, useMarketsStore, useMarketsStream, useMaxLeverage, useMaxQty, useMaxWithdrawal, useMediaQuery, useMemoizedFn, useMutation, useNetworkInfo, useOdosQuote, useOrderEntity, useOrderEntry2 as useOrderEntry, useOrderEntry as useOrderEntry_deprecated, useOrderStore2 as useOrderStore, useOrderStream, useOrderbookStream, useOrderlyContext, usePortfolio, usePositionActions, usePositionClose, usePositionStream, usePoster, usePreLoadData, usePrivateDataObserver, usePrivateInfiniteQuery, usePrivateQuery, useQuery, useRefereeHistory, useRefereeInfo, useRefereeRebateSummary, useReferralInfo, useReferralRebateSummary, useRestrictedInfo, useRwaSymbolsInfo, useRwaSymbolsInfoStore, useSessionStorage, useSettleSubscription, useSimpleDI, useStatisticsDaily, useStorageChain, useStorageLedgerAddress, useSubAccountDataObserver, useSubAccountMaxWithdrawal, useSubAccountMutation, useSubAccountQuery, useSubAccountWS, useSymbolInfo, useSymbolLeverage, useSymbolPriceRange, useSymbolsInfo, useSymbolsInfoStore, useTPSLOrder, useTickerStream, useTokenInfo, useTokensInfo, useTrack, useTrackingInstance, useTradingRewardsStatus, useTransfer, useTransferHistory, useUpdatedRef, useVaultsHistory, useWS, useWalletConnector, useWalletRewardsHistory, useWalletSubscription, useWalletTopic, useWithdraw, useWsStatus, utils_exports as utils, version_default as version };
18014
+ export { DefaultLayoutConfig, DistributionId, ENVType2 as ENVType, EpochStatus, ExtendedConfigStore, MaintenanceStatus, MarketsStorageKey, MarketsType, ORDERLY_ORDERBOOK_DEPTH_KEY, OrderlyConfigProvider, OrderlyContext, OrderlyProvider, StatusProvider, TWType, WalletConnectorContext, WsNetworkStatus, checkNotional, cleanStringStyle, fetcher, findPositionTPSLFromOrders, findTPSLFromOrder, findTPSLOrderPriceFromOrder, getMinNotional, getPriceKey, isCurrentlyClosed, isCurrentlyTrading, noCacheConfig, parseJSON, useAccount, useAccountInfo, useAccountInstance, useAccountRewardsHistory, useAllBrokers, useApiKeyManager, useAssetsHistory, useAudioPlayer, useBalanceSubscription, useBalanceTopic, useBoolean, useChain, useChainInfo, useChains, useCheckReferralCode, useCollateral, useCommission, useComputedLTV, useConfig, useConvert, useCurEpochEstimate, useDaily, useDeposit, useDistribution, useDistributionHistory, useEpochInfo, useEventEmitter, useFeeState, useFundingDetails, useFundingFeeHistory, useFundingRate, useFundingRateBySymbol, useFundingRateHistory, useFundingRates, useFundingRatesStore, useGetClaimed, useGetEnv, useGetReferralCode, useGetRwaSymbolCloseTimeInterval, useGetRwaSymbolInfo, useGetRwaSymbolOpenStatus, useGetRwaSymbolOpenTimeInterval, useHoldingStream, useIndexPrice, useIndexPricesStream, useInfiniteQuery, useInitRwaSymbolsRuntime, useInternalTransfer, useKeyStore, useLazyQuery, useLeverage, useLeverageBySymbol, useLocalStorage, useMaintenanceStatus, useMarginRatio, useMarkPrice, useMarkPriceBySymbol, useMarkPricesStream, useMarket, useMarketList, useMarketMap, useMarketTradeStream, useMarkets, useMarketsStore, useMarketsStream, useMaxLeverage, useMaxQty, useMaxWithdrawal, useMediaQuery, useMemoizedFn, useMutation, useNetworkInfo, useOdosQuote, useOrderEntity, useOrderEntry2 as useOrderEntry, useOrderEntry as useOrderEntry_deprecated, useOrderStore2 as useOrderStore, useOrderStream, useOrderbookStream, useOrderlyContext, usePortfolio, usePositionActions, usePositionClose, usePositionStream, usePoster, usePreLoadData, usePrivateDataObserver, usePrivateInfiniteQuery, usePrivateQuery, useQuery, useRefereeHistory, useRefereeInfo, useRefereeRebateSummary, useReferralInfo, useReferralRebateSummary, useRestrictedInfo, useRwaSymbolsInfo, useRwaSymbolsInfoStore, useSessionStorage, useSettleSubscription, useSimpleDI, useStatisticsDaily, useStorageChain, useStorageLedgerAddress, useSubAccountDataObserver, useSubAccountMaxWithdrawal, useSubAccountMutation, useSubAccountQuery, useSubAccountWS, useSymbolInfo, useSymbolLeverage, useSymbolPriceRange, useSymbolsInfo, useSymbolsInfoStore, useTPSLOrder, useTickerStream, useTokenInfo, useTokensInfo, useTrack, useTrackingInstance, useTradingRewardsStatus, useTransfer, useTransferHistory, useUpdatedRef, useVaultsHistory, useWS, useWalletConnector, useWalletRewardsHistory, useWalletSubscription, useWalletTopic, useWithdraw, useWsStatus, utils_exports as utils, version_default as version };
18052
18015
  //# sourceMappingURL=out.js.map
18053
18016
  //# sourceMappingURL=index.mjs.map