@gbozee/ultimate 0.0.2-next.71 → 0.0.2-next.73

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.cjs CHANGED
@@ -72035,15 +72035,20 @@ class BaseExchange {
72035
72035
  });
72036
72036
  }
72037
72037
  }
72038
+ async previewSpotMarginHedge(_payload) {
72039
+ throw new Error("Spot margin hedge preview is not supported on this exchange");
72040
+ }
72041
+ async placeSpotMarginHedge(_payload) {
72042
+ throw new Error("Spot margin hedge placement is not supported on this exchange");
72043
+ }
72038
72044
  async placeSpotLimitOrders(_payload) {}
72039
- async bulkPlaceLimitOrders(payload) {
72045
+ async buildCumulative(payload) {
72040
72046
  const {
72041
72047
  orders,
72042
72048
  kind,
72043
72049
  decimal_places = "%.3f",
72044
- price_places = "%.1f",
72045
72050
  symbol,
72046
- place = false
72051
+ is_stop = false
72047
72052
  } = payload;
72048
72053
  const totalQuantity = orders.reduce((sum, order) => sum + (order.quantity || 0), 0);
72049
72054
  let runningTotal = to_f(totalQuantity, decimal_places);
@@ -72051,6 +72056,9 @@ class BaseExchange {
72051
72056
  if (kind === "short") {
72052
72057
  sortedOrders.reverse();
72053
72058
  }
72059
+ if (is_stop) {
72060
+ sortedOrders.reverse();
72061
+ }
72054
72062
  const withCumulative = [];
72055
72063
  for (const order of sortedOrders) {
72056
72064
  withCumulative.push({
@@ -72073,6 +72081,17 @@ class BaseExchange {
72073
72081
  kind,
72074
72082
  side: kind.toLowerCase() === "long" ? "buy" : "sell"
72075
72083
  }));
72084
+ return filteredOrders;
72085
+ }
72086
+ async bulkPlaceLimitOrders(payload) {
72087
+ const {
72088
+ kind,
72089
+ decimal_places = "%.3f",
72090
+ price_places = "%.1f",
72091
+ symbol,
72092
+ place = false
72093
+ } = payload;
72094
+ const filteredOrders = await this.buildCumulative(payload);
72076
72095
  if (filteredOrders.length > 0 && place) {
72077
72096
  await this.cancelAllOrders(symbol, {
72078
72097
  type: "limit",
@@ -72217,9 +72236,13 @@ class BaseExchange {
72217
72236
  });
72218
72237
  }
72219
72238
  async entryStopLimitOrders(payload) {
72220
- const { symbol, kind, orders, price_places, decimal_places, place } = payload;
72239
+ const { symbol, kind, price_places, decimal_places, place } = payload;
72240
+ const cummulative = await this.buildCumulative({
72241
+ ...payload,
72242
+ is_stop: true
72243
+ });
72221
72244
  const price = await this.get_current_price(symbol);
72222
- const orders_to_place = orders.map((order) => {
72245
+ const orders_to_place = cummulative.map((order) => {
72223
72246
  const { entry } = order;
72224
72247
  let spread = 0.005;
72225
72248
  if (price < 5000) {
@@ -72237,7 +72260,10 @@ class BaseExchange {
72237
72260
  is_market: false
72238
72261
  };
72239
72262
  });
72240
- if (place) {
72263
+ if (place && orders_to_place.length > 0) {
72264
+ await this.cancelAllOrders(symbol, {
72265
+ kind
72266
+ });
72241
72267
  return this._createLimitPurchaseOrders({
72242
72268
  symbol,
72243
72269
  price_places,
@@ -72422,6 +72448,210 @@ class BaseExchange {
72422
72448
 
72423
72449
  // src/exchanges/binance/index.ts
72424
72450
  var import_p_limit = __toESM(require_p_limit(), 1);
72451
+
72452
+ // src/exchanges/binance/spot-margin-hedge.ts
72453
+ function roundNumber(value2, digits = 8) {
72454
+ return Number(value2.toFixed(digits));
72455
+ }
72456
+ var STOP_LIMIT_SPREAD_PERCENT = 0.0005;
72457
+ function normalizeOrderInput(order) {
72458
+ return {
72459
+ price: roundNumber(order.price),
72460
+ quantity: roundNumber(order.quantity)
72461
+ };
72462
+ }
72463
+ function sortOrderInputs(orders) {
72464
+ return [...orders].map(normalizeOrderInput).sort((left, right) => left.price - right.price);
72465
+ }
72466
+ function normalizeOrderForComparison(order) {
72467
+ const type = (order.type || "limit").toLowerCase();
72468
+ const raw_stop = "stop" in order && order.stop !== undefined ? order.stop : ("stopPrice" in order) ? order.stopPrice : undefined;
72469
+ const parsed_stop = raw_stop === undefined || raw_stop === null || raw_stop === "" ? undefined : Number(raw_stop);
72470
+ return {
72471
+ side: order.side,
72472
+ type,
72473
+ price: roundNumber(order.price),
72474
+ quantity: roundNumber(order.quantity),
72475
+ stop: parsed_stop !== undefined && Number.isFinite(parsed_stop) && parsed_stop > 0 ? roundNumber(parsed_stop) : undefined
72476
+ };
72477
+ }
72478
+ function normalizeOrders(orders) {
72479
+ return [...orders].map(normalizeOrderForComparison).sort((left, right) => {
72480
+ if (left.side !== right.side)
72481
+ return left.side.localeCompare(right.side);
72482
+ if (left.type !== right.type)
72483
+ return left.type.localeCompare(right.type);
72484
+ if (left.price !== right.price)
72485
+ return left.price - right.price;
72486
+ return left.quantity - right.quantity;
72487
+ });
72488
+ }
72489
+ function toPlannedOrders(orders) {
72490
+ return normalizeOrders(orders).map((order) => ({
72491
+ side: order.side,
72492
+ type: order.type,
72493
+ price: order.price,
72494
+ quantity: order.quantity,
72495
+ stop: order.stop
72496
+ }));
72497
+ }
72498
+ function buildOrderKey(order) {
72499
+ return [
72500
+ order.side,
72501
+ order.type,
72502
+ order.price,
72503
+ order.quantity,
72504
+ order.stop ?? ""
72505
+ ].join(":");
72506
+ }
72507
+ function buildDiff(options) {
72508
+ const expectedKeys = options.expected.map(buildOrderKey);
72509
+ const actualKeys = options.actual.map(buildOrderKey);
72510
+ return {
72511
+ missing: expectedKeys.filter((key) => !actualKeys.includes(key)),
72512
+ extra: actualKeys.filter((key) => !expectedKeys.includes(key))
72513
+ };
72514
+ }
72515
+ function getQuoteAsset(symbol) {
72516
+ const quoteAssets = ["USDT", "USDC", "BUSD", "BTC", "ETH"];
72517
+ const target = quoteAssets.find((asset) => symbol.endsWith(asset));
72518
+ return target || symbol.slice(-4);
72519
+ }
72520
+ function sumNotional(orders) {
72521
+ return roundNumber(orders.reduce((sum, order) => sum + order.price * order.quantity, 0), 8);
72522
+ }
72523
+ function sumQuantity(orders) {
72524
+ return roundNumber(orders.reduce((sum, order) => sum + order.quantity, 0), 8);
72525
+ }
72526
+ function buildLongOrderPlacement(options) {
72527
+ const { order, current_price } = options;
72528
+ if (order.price > current_price) {
72529
+ return {
72530
+ side: "buy",
72531
+ type: "stop_loss_limit",
72532
+ price: order.price,
72533
+ stop: roundNumber(order.price * (1 - STOP_LIMIT_SPREAD_PERCENT)),
72534
+ quantity: order.quantity
72535
+ };
72536
+ }
72537
+ return {
72538
+ side: "buy",
72539
+ type: "limit",
72540
+ price: order.price,
72541
+ quantity: order.quantity
72542
+ };
72543
+ }
72544
+ function inferSpotMarginHedgeInputFromLiveOrders(options) {
72545
+ const long_orders = sortOrderInputs([
72546
+ ...options.spot_orders.filter((order) => order.side === "buy").map((order) => ({
72547
+ price: order.price,
72548
+ quantity: order.quantity
72549
+ })),
72550
+ ...options.margin_orders.filter((order) => order.side === "buy").map((order) => ({
72551
+ price: order.price,
72552
+ quantity: order.quantity
72553
+ }))
72554
+ ]);
72555
+ const short_orders = sortOrderInputs([
72556
+ ...options.spot_orders.filter((order) => order.side === "sell").map((order) => ({
72557
+ price: order.price,
72558
+ quantity: order.quantity
72559
+ })),
72560
+ ...options.margin_orders.filter((order) => order.side === "sell").map((order) => ({
72561
+ price: order.price,
72562
+ quantity: order.quantity
72563
+ }))
72564
+ ]);
72565
+ return {
72566
+ symbol: options.symbol,
72567
+ margin_type: options.margin_type,
72568
+ borrow_amount: sumNotional(long_orders),
72569
+ long_orders,
72570
+ short_orders,
72571
+ placement_overrides: {
72572
+ spot: toPlannedOrders(options.spot_orders),
72573
+ margin: toPlannedOrders(options.margin_orders)
72574
+ }
72575
+ };
72576
+ }
72577
+ function buildSpotMarginHedgePlan(options) {
72578
+ const max_spot_buy_orders = options.max_spot_buy_orders ?? 5;
72579
+ const long_orders = sortOrderInputs(options.long_orders);
72580
+ const short_orders = sortOrderInputs(options.short_orders);
72581
+ const spot_long_orders = long_orders.slice(0, max_spot_buy_orders);
72582
+ const margin_long_orders = long_orders.slice(max_spot_buy_orders);
72583
+ const default_spot_orders_to_create = [
72584
+ ...spot_long_orders.map((order) => buildLongOrderPlacement({
72585
+ order,
72586
+ current_price: options.current_price
72587
+ })),
72588
+ ...short_orders.map((order) => ({
72589
+ side: "sell",
72590
+ type: "limit",
72591
+ price: order.price,
72592
+ quantity: order.quantity
72593
+ }))
72594
+ ];
72595
+ const default_margin_orders_to_create = margin_long_orders.map((order) => buildLongOrderPlacement({
72596
+ order,
72597
+ current_price: options.current_price
72598
+ }));
72599
+ const spot_orders_to_create = options.placement_overrides?.spot || default_spot_orders_to_create;
72600
+ const margin_orders_to_create = options.placement_overrides?.margin || default_margin_orders_to_create;
72601
+ const borrow_delta = roundNumber(Math.max(0, options.borrow_amount - options.snapshot.borrowed_quote_amount));
72602
+ const spot_long_notional = sumNotional(spot_long_orders);
72603
+ const transfer_to_spot_amount = roundNumber(Math.max(0, spot_long_notional - options.snapshot.spot_quote_free));
72604
+ const short_quantity = sumQuantity(short_orders);
72605
+ const transfer_base_to_spot_amount = roundNumber(Math.max(0, short_quantity - options.snapshot.spot_base_free));
72606
+ return {
72607
+ borrow_amount: options.borrow_amount,
72608
+ borrow_delta,
72609
+ transfer_to_spot_amount,
72610
+ transfer_to_spot_asset: getQuoteAsset(options.symbol),
72611
+ transfer_base_to_spot_amount,
72612
+ orders_to_cancel: {
72613
+ spot: options.snapshot.spot_orders,
72614
+ margin: options.snapshot.margin_orders
72615
+ },
72616
+ orders_to_create: {
72617
+ spot: spot_orders_to_create,
72618
+ margin: margin_orders_to_create
72619
+ },
72620
+ normalized: {
72621
+ spot: normalizeOrders(spot_orders_to_create),
72622
+ margin: normalizeOrders(margin_orders_to_create)
72623
+ }
72624
+ };
72625
+ }
72626
+ function compareSpotMarginHedgeOrders(options) {
72627
+ const actualSpot = normalizeOrders(options.spot_orders);
72628
+ const actualMargin = normalizeOrders(options.margin_orders);
72629
+ const spotDiff = buildDiff({
72630
+ expected: options.plan.normalized.spot,
72631
+ actual: actualSpot
72632
+ });
72633
+ const marginDiff = buildDiff({
72634
+ expected: options.plan.normalized.margin,
72635
+ actual: actualMargin
72636
+ });
72637
+ return {
72638
+ matches: spotDiff.missing.length === 0 && spotDiff.extra.length === 0 && marginDiff.missing.length === 0 && marginDiff.extra.length === 0,
72639
+ spot: {
72640
+ expected: options.plan.normalized.spot,
72641
+ actual: actualSpot,
72642
+ missing: spotDiff.missing,
72643
+ extra: spotDiff.extra
72644
+ },
72645
+ margin: {
72646
+ expected: options.plan.normalized.margin,
72647
+ actual: actualMargin,
72648
+ missing: marginDiff.missing,
72649
+ extra: marginDiff.extra
72650
+ }
72651
+ };
72652
+ }
72653
+
72654
+ // src/exchanges/binance/index.ts
72425
72655
  var CONSTANTS = {
72426
72656
  SPOT_TO_FIAT: "MAIN_C2C",
72427
72657
  SPOT_TO_USDT_FUTURE: "MAIN_UMFUTURE",
@@ -72910,12 +73140,20 @@ async function getCrossMarginAccountDetails(client) {
72910
73140
  async function cancelMarginOrders(client, symbol, isIsolated = false, orders) {
72911
73141
  try {
72912
73142
  if (orders && orders.length > 0) {
72913
- const cancelPromises = orders.map((order) => client.marginAccountCancelOrder({
72914
- symbol,
72915
- orderId: order.orderId,
72916
- origClientOrderId: order.origClientOrderId,
72917
- isIsolated: isIsolated ? "TRUE" : "FALSE"
72918
- }));
73143
+ const cancelPromises = orders.map((order) => {
73144
+ const payload = {
73145
+ symbol,
73146
+ isIsolated: isIsolated ? "TRUE" : "FALSE"
73147
+ };
73148
+ if (order.orderId !== undefined) {
73149
+ payload.orderId = order.orderId;
73150
+ }
73151
+ const origClientOrderId = order.origClientOrderId ?? order.clientOrderId;
73152
+ if (origClientOrderId !== undefined) {
73153
+ payload.origClientOrderId = origClientOrderId;
73154
+ }
73155
+ return client.marginAccountCancelOrder(payload);
73156
+ });
72919
73157
  return await Promise.all(cancelPromises);
72920
73158
  } else {
72921
73159
  return await client.marginAccountCancelOpenOrders({
@@ -73170,7 +73408,7 @@ async function placeStopOrder(client, payload) {
73170
73408
  });
73171
73409
  }
73172
73410
  }
73173
- const spread = 1.00005;
73411
+ const spread = payload.stop > 30000 ? 1.00005 : 1.0002;
73174
73412
  const order = {
73175
73413
  kind: payload.kind,
73176
73414
  side: payload.kind === "long" ? "sell" : "buy",
@@ -73577,6 +73815,16 @@ async function getAllOpenOrders(payload) {
73577
73815
  const response = await client.getAllOpenOrders();
73578
73816
  return response;
73579
73817
  }
73818
+ function getPrintfFormatFromStepSize(stepSize, fallback) {
73819
+ if (stepSize === undefined || stepSize === null) {
73820
+ return fallback;
73821
+ }
73822
+ const normalized = String(stepSize);
73823
+ const [, decimalPart = ""] = normalized.split(".");
73824
+ const trimmed = decimalPart.replace(/0+$/, "");
73825
+ const digits = trimmed.length;
73826
+ return `%.${digits}f`;
73827
+ }
73580
73828
 
73581
73829
  class BinanceExchange extends BaseExchange {
73582
73830
  main_client;
@@ -74013,6 +74261,30 @@ class BinanceExchange extends BaseExchange {
74013
74261
  throw error;
74014
74262
  }
74015
74263
  }
74264
+ async getSpotSymbolFormats(symbol) {
74265
+ if (!this.main_client || typeof this.main_client.getExchangeInfo !== "function") {
74266
+ return {
74267
+ price_places: "%.8f",
74268
+ decimal_places: "%.8f"
74269
+ };
74270
+ }
74271
+ try {
74272
+ const exchange_info = await this.main_client.getExchangeInfo();
74273
+ const symbol_info = exchange_info?.symbols?.find((item) => item.symbol === symbol.toUpperCase());
74274
+ const price_filter = symbol_info?.filters?.find((filter) => filter.filterType === "PRICE_FILTER");
74275
+ const lot_size_filter = symbol_info?.filters?.find((filter) => filter.filterType === "LOT_SIZE");
74276
+ return {
74277
+ price_places: getPrintfFormatFromStepSize(price_filter?.tickSize, "%.8f"),
74278
+ decimal_places: getPrintfFormatFromStepSize(lot_size_filter?.stepSize, "%.8f")
74279
+ };
74280
+ } catch (error) {
74281
+ console.error("Error fetching spot symbol formats:", error);
74282
+ return {
74283
+ price_places: "%.8f",
74284
+ decimal_places: "%.8f"
74285
+ };
74286
+ }
74287
+ }
74016
74288
  async createMarginLimitOrders(payload) {
74017
74289
  if (!this.main_client) {
74018
74290
  throw new Error("Main client not available for margin trading");
@@ -74043,6 +74315,200 @@ class BinanceExchange extends BaseExchange {
74043
74315
  }
74044
74316
  return await getMarginOpenOrders(this.main_client, symbol, isIsolated);
74045
74317
  }
74318
+ async getSpotMarginHedgeSnapshot(payload) {
74319
+ if (!this.main_client) {
74320
+ throw new Error("Main client not available for spot and margin trading");
74321
+ }
74322
+ if (payload.margin_type !== "isolated") {
74323
+ throw new Error(`Unsupported margin type: ${payload.margin_type}. Only isolated is supported for replay right now.`);
74324
+ }
74325
+ const symbol = payload.symbol.toUpperCase();
74326
+ const quoteAssets = ["USDT", "USDC", "BUSD", "BTC", "ETH"];
74327
+ const quoteAsset = quoteAssets.find((asset) => symbol.endsWith(asset)) || symbol.slice(-4);
74328
+ const baseAsset = symbol.slice(0, symbol.length - quoteAsset.length);
74329
+ const [spot_orders, margin_orders, spot_balances, isolated_margin_position] = await Promise.all([
74330
+ this.getSpotOpenOrders(symbol),
74331
+ this.getMarginOpenOrders(symbol, true),
74332
+ this.getSpotBalances([baseAsset, quoteAsset]),
74333
+ this.getIsolatedMarginPosition(symbol)
74334
+ ]);
74335
+ const current_price = await this.getSpotCurrentPrice(symbol);
74336
+ const spot_quote_balance = spot_balances.find((balance) => balance.asset.toUpperCase() === quoteAsset);
74337
+ const spot_base_balance = spot_balances.find((balance) => balance.asset.toUpperCase() === baseAsset);
74338
+ const isolated_asset = isolated_margin_position?.assets?.[0];
74339
+ const borrowed_quote_amount = parseFloat(isolated_asset?.quoteAsset?.borrowed?.toString?.() || "0");
74340
+ return {
74341
+ symbol,
74342
+ margin_type: payload.margin_type,
74343
+ quote_asset: quoteAsset,
74344
+ base_asset: baseAsset,
74345
+ borrowed_quote_amount,
74346
+ spot_quote_free: parseFloat(spot_quote_balance?.free?.toString?.() || "0"),
74347
+ spot_base_free: parseFloat(spot_base_balance?.free?.toString?.() || "0"),
74348
+ spot_orders,
74349
+ margin_orders,
74350
+ current_price,
74351
+ spot_balances,
74352
+ isolated_margin_position
74353
+ };
74354
+ }
74355
+ async previewSpotMarginHedge(payload) {
74356
+ const snapshot = payload.snapshot ? {
74357
+ ...payload.snapshot,
74358
+ current_price: payload.snapshot.current_price ?? await this.getSpotCurrentPrice(payload.symbol)
74359
+ } : await this.getSpotMarginHedgeSnapshot({
74360
+ symbol: payload.symbol,
74361
+ margin_type: payload.margin_type
74362
+ });
74363
+ const shouldInferLongOrders = !payload.long_orders || payload.long_orders.length === 0;
74364
+ const shouldInferShortOrders = !payload.short_orders || payload.short_orders.length === 0;
74365
+ const inferred_input = shouldInferLongOrders || shouldInferShortOrders ? inferSpotMarginHedgeInputFromLiveOrders({
74366
+ symbol: payload.symbol,
74367
+ margin_type: payload.margin_type,
74368
+ spot_orders: snapshot.spot_orders,
74369
+ margin_orders: snapshot.margin_orders
74370
+ }) : undefined;
74371
+ const long_orders = shouldInferLongOrders ? inferred_input?.long_orders || [] : payload.long_orders || [];
74372
+ const short_orders = shouldInferShortOrders ? inferred_input?.short_orders || [] : payload.short_orders || [];
74373
+ const borrow_amount = payload.borrow_amount ?? (long_orders.length > 0 ? sumNotional(long_orders) : inferred_input?.borrow_amount ?? 0);
74374
+ const requested_input = {
74375
+ borrow_amount,
74376
+ symbol: payload.symbol,
74377
+ margin_type: payload.margin_type,
74378
+ long_orders,
74379
+ short_orders,
74380
+ current_price: snapshot.current_price,
74381
+ max_spot_buy_orders: payload.max_spot_buy_orders,
74382
+ placement_overrides: inferred_input?.placement_overrides
74383
+ };
74384
+ const plan = buildSpotMarginHedgePlan({
74385
+ ...requested_input,
74386
+ snapshot
74387
+ });
74388
+ const comparison = compareSpotMarginHedgeOrders({
74389
+ plan,
74390
+ spot_orders: snapshot.spot_orders,
74391
+ margin_orders: snapshot.margin_orders
74392
+ });
74393
+ return {
74394
+ snapshot,
74395
+ inferred_input,
74396
+ requested_input,
74397
+ plan,
74398
+ comparison
74399
+ };
74400
+ }
74401
+ async placeSpotMarginHedge(payload) {
74402
+ const preview = await this.previewSpotMarginHedge(payload);
74403
+ if (!payload.place) {
74404
+ return preview;
74405
+ }
74406
+ if (!this.main_client) {
74407
+ throw new Error("Main client not available for spot and margin trading");
74408
+ }
74409
+ if (payload.margin_type !== "isolated") {
74410
+ throw new Error(`Unsupported margin type: ${payload.margin_type}. Only isolated placement is supported right now.`);
74411
+ }
74412
+ const symbol = payload.symbol.toUpperCase();
74413
+ const quoteAssets = ["USDT", "USDC", "BUSD", "BTC", "ETH"];
74414
+ const quote_asset = quoteAssets.find((asset) => symbol.endsWith(asset)) || symbol.slice(-4);
74415
+ const base_asset = symbol.slice(0, symbol.length - quote_asset.length);
74416
+ const requested_input = preview.requested_input;
74417
+ if (preview.snapshot.spot_orders.length > 0) {
74418
+ await this.cancelSpotOrders(symbol, preview.snapshot.spot_orders.map((order) => ({
74419
+ orderId: order.orderId || order.order_id || order.id,
74420
+ origClientOrderId: order.origClientOrderId
74421
+ })));
74422
+ }
74423
+ if (preview.snapshot.margin_orders.length > 0) {
74424
+ await this.cancelMarginOrders(symbol, true, preview.snapshot.margin_orders.map((order) => ({
74425
+ orderId: order.orderId || order.order_id || order.id,
74426
+ origClientOrderId: order.origClientOrderId
74427
+ })));
74428
+ }
74429
+ const refreshed_snapshot = await this.getSpotMarginHedgeSnapshot({
74430
+ symbol,
74431
+ margin_type: payload.margin_type
74432
+ });
74433
+ const symbol_formats = await this.getSpotSymbolFormats(symbol);
74434
+ const execution_plan = buildSpotMarginHedgePlan({
74435
+ borrow_amount: requested_input.borrow_amount,
74436
+ symbol: requested_input.symbol,
74437
+ margin_type: requested_input.margin_type,
74438
+ long_orders: requested_input.long_orders,
74439
+ short_orders: requested_input.short_orders,
74440
+ current_price: refreshed_snapshot.current_price,
74441
+ max_spot_buy_orders: requested_input.max_spot_buy_orders,
74442
+ snapshot: refreshed_snapshot
74443
+ });
74444
+ let borrow_result = null;
74445
+ if (execution_plan.borrow_delta > 0) {
74446
+ borrow_result = await this.main_client.submitMarginAccountBorrowRepay({
74447
+ asset: quote_asset,
74448
+ amount: execution_plan.borrow_delta,
74449
+ isIsolated: "TRUE",
74450
+ symbol,
74451
+ type: "BORROW"
74452
+ });
74453
+ }
74454
+ let quote_transfer_result = null;
74455
+ if (execution_plan.transfer_to_spot_amount > 0) {
74456
+ quote_transfer_result = await this.main_client.isolatedMarginAccountTransfer({
74457
+ asset: quote_asset,
74458
+ amount: execution_plan.transfer_to_spot_amount,
74459
+ symbol,
74460
+ transFrom: "ISOLATED_MARGIN",
74461
+ transTo: "SPOT"
74462
+ });
74463
+ }
74464
+ let base_transfer_result = null;
74465
+ if (execution_plan.transfer_base_to_spot_amount > 0) {
74466
+ base_transfer_result = await this.main_client.isolatedMarginAccountTransfer({
74467
+ asset: base_asset,
74468
+ amount: execution_plan.transfer_base_to_spot_amount,
74469
+ symbol,
74470
+ transFrom: "ISOLATED_MARGIN",
74471
+ transTo: "SPOT"
74472
+ });
74473
+ }
74474
+ const spot_result = execution_plan.orders_to_create.spot.length > 0 ? await this.createSpotLimitOrders({
74475
+ symbol,
74476
+ orders: execution_plan.orders_to_create.spot,
74477
+ price_places: symbol_formats.price_places,
74478
+ decimal_places: symbol_formats.decimal_places
74479
+ }) : [];
74480
+ const margin_result = execution_plan.orders_to_create.margin.length > 0 ? await this.createMarginLimitOrders({
74481
+ symbol,
74482
+ orders: execution_plan.orders_to_create.margin,
74483
+ isIsolated: true,
74484
+ price_places: symbol_formats.price_places,
74485
+ decimal_places: symbol_formats.decimal_places
74486
+ }) : [];
74487
+ return {
74488
+ ...preview,
74489
+ execution_plan,
74490
+ refreshed_snapshot,
74491
+ execution: {
74492
+ borrow: borrow_result ? {
74493
+ asset: quote_asset,
74494
+ amount: execution_plan.borrow_delta,
74495
+ response: borrow_result
74496
+ } : null,
74497
+ quote_transfer: quote_transfer_result ? {
74498
+ asset: quote_asset,
74499
+ amount: execution_plan.transfer_to_spot_amount,
74500
+ response: quote_transfer_result
74501
+ } : null,
74502
+ base_transfer: base_transfer_result ? {
74503
+ asset: base_asset,
74504
+ amount: execution_plan.transfer_base_to_spot_amount,
74505
+ response: base_transfer_result
74506
+ } : null,
74507
+ spot_orders: spot_result,
74508
+ margin_orders: margin_result
74509
+ }
74510
+ };
74511
+ }
74046
74512
  async getLastUserTrade(payload) {
74047
74513
  return await getLastUserTrade(this.client, payload.symbol);
74048
74514
  }
package/dist/index.d.ts CHANGED
@@ -372,7 +372,47 @@ declare abstract class BaseExchange {
372
372
  place?: boolean;
373
373
  cancel?: boolean;
374
374
  }): Promise<any>;
375
+ previewSpotMarginHedge(_payload: {
376
+ borrow_amount?: number;
377
+ symbol: string;
378
+ margin_type: "isolated" | "cross";
379
+ long_orders?: Array<{
380
+ price: number;
381
+ quantity: number;
382
+ }>;
383
+ short_orders?: Array<{
384
+ price: number;
385
+ quantity: number;
386
+ }>;
387
+ max_spot_buy_orders?: number;
388
+ snapshot?: any;
389
+ }): Promise<any>;
390
+ placeSpotMarginHedge(_payload: {
391
+ borrow_amount?: number;
392
+ symbol: string;
393
+ margin_type: "isolated" | "cross";
394
+ long_orders?: Array<{
395
+ price: number;
396
+ quantity: number;
397
+ }>;
398
+ short_orders?: Array<{
399
+ price: number;
400
+ quantity: number;
401
+ }>;
402
+ max_spot_buy_orders?: number;
403
+ snapshot?: any;
404
+ place?: boolean;
405
+ }): Promise<any>;
375
406
  placeSpotLimitOrders(_payload: any): Promise<void>;
407
+ buildCumulative(payload: {
408
+ orders: Order$1[];
409
+ kind: "long" | "short";
410
+ decimal_places?: string;
411
+ price_places?: string;
412
+ symbol: string;
413
+ place?: boolean;
414
+ is_stop?: boolean;
415
+ }): Promise<any[]>;
376
416
  bulkPlaceLimitOrders(payload: {
377
417
  orders: Order$1[];
378
418
  kind: "long" | "short";