@gbozee/ultimate 0.0.2-191 → 0.0.2-193

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.
@@ -64136,7 +64136,8 @@ function determineOptimumReward(payload) {
64136
64136
  low_range = 1,
64137
64137
  high_range = 199,
64138
64138
  target_loss,
64139
- distribution
64139
+ distribution,
64140
+ max_size
64140
64141
  } = payload;
64141
64142
  const criterion = app_config.strategy || "quantity";
64142
64143
  const risk_rewards = createArray(low_range, high_range, 1);
@@ -64158,6 +64159,7 @@ function determineOptimumReward(payload) {
64158
64159
  let min = Infinity;
64159
64160
  let neg_pnl = trades[0]?.neg_pnl || 0;
64160
64161
  let entry = trades.at(-1)?.entry;
64162
+ let avg_size = trades[0]?.avg_size || 0;
64161
64163
  if (!entry) {
64162
64164
  return null;
64163
64165
  }
@@ -64174,11 +64176,15 @@ function determineOptimumReward(payload) {
64174
64176
  risk_per_trade: app_config.risk_per_trade,
64175
64177
  max,
64176
64178
  min,
64179
+ avg_size,
64177
64180
  neg_pnl,
64178
64181
  entry
64179
64182
  };
64180
64183
  });
64181
64184
  func = func.filter((r2) => Boolean(r2));
64185
+ if (max_size !== undefined && max_size > 0) {
64186
+ func = func.filter((r2) => r2.avg_size <= max_size);
64187
+ }
64182
64188
  if (target_loss === undefined) {
64183
64189
  func = func.filter((r2) => {
64184
64190
  let foundIndex = r2?.result.findIndex((e2) => e2.quantity === r2.max);
@@ -64316,7 +64322,15 @@ function determineOptimumRisk(config2, payload, params) {
64316
64322
  };
64317
64323
  }
64318
64324
  function computeRiskReward(payload) {
64319
- const { app_config, entry, stop, risk_per_trade, target_loss, distribution } = payload;
64325
+ const {
64326
+ app_config,
64327
+ entry,
64328
+ stop,
64329
+ risk_per_trade,
64330
+ target_loss,
64331
+ distribution,
64332
+ max_size
64333
+ } = payload;
64320
64334
  const kind = entry > stop ? "long" : "short";
64321
64335
  app_config.kind = kind;
64322
64336
  app_config.entry = entry;
@@ -64325,12 +64339,14 @@ function computeRiskReward(payload) {
64325
64339
  const result = determineOptimumReward({
64326
64340
  app_config,
64327
64341
  target_loss,
64328
- distribution
64342
+ distribution,
64343
+ max_size
64329
64344
  });
64330
64345
  return result;
64331
64346
  }
64332
64347
  function getRiskReward(payload) {
64333
64348
  const {
64349
+ max_size,
64334
64350
  entry,
64335
64351
  stop,
64336
64352
  risk,
@@ -64353,7 +64369,8 @@ function getRiskReward(payload) {
64353
64369
  stop,
64354
64370
  risk_per_trade: risk,
64355
64371
  target_loss,
64356
- distribution
64372
+ distribution,
64373
+ max_size
64357
64374
  });
64358
64375
  if (force_exact_risk) {
64359
64376
  const new_risk_per_trade = determineOptimumRisk(global_config, {
@@ -66583,6 +66600,171 @@ class BinanceExchange extends BaseExchange {
66583
66600
  async forceClosePosition(symbol, options) {
66584
66601
  return await forceClosePosition(this.client, symbol, options);
66585
66602
  }
66603
+ async getTransferableAmount(options) {
66604
+ const { asset, maxTransferLimit } = options;
66605
+ try {
66606
+ const futuresBalance = await getWalletBalance(this.client, asset);
66607
+ const allPositions = await this.client.getPositionsV3();
66608
+ const activePositions = allPositions.filter((pos) => Math.abs(pos.positionAmt) > 0);
66609
+ let totalMarginUsed = 0;
66610
+ let totalUnrealizedPnl = 0;
66611
+ for (const position2 of activePositions) {
66612
+ const positionValue = Math.abs(position2.positionAmt) * position2.markPrice;
66613
+ const leverage = await getLeverage(this.client, position2.symbol);
66614
+ const marginForPosition = positionValue / (leverage || 1);
66615
+ console.log({ leverage });
66616
+ totalMarginUsed += marginForPosition;
66617
+ totalUnrealizedPnl += position2.unRealizedProfit || 0;
66618
+ }
66619
+ const safetyMarginPercent = 0.2;
66620
+ const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
66621
+ const adjustedBalance = futuresBalance + totalUnrealizedPnl;
66622
+ const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
66623
+ let maxTransferableAmount = availableForTransfer;
66624
+ let appliedLimit;
66625
+ if (maxTransferLimit && maxTransferLimit > 0) {
66626
+ maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
66627
+ appliedLimit = maxTransferLimit;
66628
+ }
66629
+ const recommendedTransferAmount = maxTransferableAmount * 0.8;
66630
+ const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
66631
+ return {
66632
+ asset,
66633
+ totalBalance: futuresBalance,
66634
+ availableForTransfer,
66635
+ reservedForMargin: requiredMargin,
66636
+ maxTransferableAmount,
66637
+ appliedLimit,
66638
+ recommendedTransferAmount,
66639
+ marginUtilization,
66640
+ safetyMargin: safetyMarginPercent * 100
66641
+ };
66642
+ } catch (error) {
66643
+ console.error(`Error analyzing transferable amount for ${asset}:`, error);
66644
+ throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
66645
+ }
66646
+ }
66647
+ async previewTransfer(options) {
66648
+ const { asset, amount } = options;
66649
+ const warnings = [];
66650
+ const errors = [];
66651
+ try {
66652
+ const analysis = await this.getTransferableAmount({ asset });
66653
+ let isValid3 = true;
66654
+ if (amount <= 0) {
66655
+ errors.push("Transfer amount must be greater than zero");
66656
+ isValid3 = false;
66657
+ }
66658
+ if (amount > analysis.maxTransferableAmount) {
66659
+ errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
66660
+ isValid3 = false;
66661
+ }
66662
+ if (amount > analysis.recommendedTransferAmount) {
66663
+ warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
66664
+ }
66665
+ if (analysis.marginUtilization > 70) {
66666
+ warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
66667
+ }
66668
+ const balanceAfterTransfer = analysis.totalBalance - amount;
66669
+ const marginRequirementAfterTransfer = analysis.reservedForMargin;
66670
+ if (isValid3 && balanceAfterTransfer < marginRequirementAfterTransfer) {
66671
+ errors.push("Transfer would result in insufficient margin for existing positions");
66672
+ isValid3 = false;
66673
+ }
66674
+ return {
66675
+ asset,
66676
+ requestedAmount: amount,
66677
+ isValid: isValid3,
66678
+ balanceAfterTransfer,
66679
+ marginRequirementAfterTransfer,
66680
+ warnings,
66681
+ errors
66682
+ };
66683
+ } catch (error) {
66684
+ console.error(`Error previewing transfer for ${asset}:`, error);
66685
+ return {
66686
+ asset,
66687
+ requestedAmount: amount,
66688
+ isValid: false,
66689
+ balanceAfterTransfer: 0,
66690
+ marginRequirementAfterTransfer: 0,
66691
+ warnings,
66692
+ errors: [`Failed to preview transfer: ${error instanceof Error ? error.message : error}`]
66693
+ };
66694
+ }
66695
+ }
66696
+ async executeFutureToSpotTransfer(options) {
66697
+ const { asset, amount, confirm, symbol = "BTCUSDT" } = options;
66698
+ try {
66699
+ if (!confirm) {
66700
+ return {
66701
+ success: false,
66702
+ asset,
66703
+ amount,
66704
+ fromWallet: "futures",
66705
+ toWallet: "spot",
66706
+ balanceAfterTransfer: 0,
66707
+ timestamp: new Date().toISOString(),
66708
+ error: "Transfer not confirmed. Set confirm: true to execute transfer."
66709
+ };
66710
+ }
66711
+ const preview = await this.previewTransfer({ asset, amount });
66712
+ if (!preview.isValid) {
66713
+ return {
66714
+ success: false,
66715
+ asset,
66716
+ amount,
66717
+ fromWallet: "futures",
66718
+ toWallet: "spot",
66719
+ balanceAfterTransfer: 0,
66720
+ timestamp: new Date().toISOString(),
66721
+ error: `Transfer validation failed: ${preview.errors.join("; ")}`
66722
+ };
66723
+ }
66724
+ const is_coin = !["USDT", "USDC", "BUSD"].includes(asset.toUpperCase());
66725
+ const transferType = is_coin ? CONSTANTS.COIN_FUTURE_TO_SPOT : CONSTANTS.USDT_FUTURE_TO_SPOT;
66726
+ if (!this.main_client) {
66727
+ throw new Error("Main client not available for transfers");
66728
+ }
66729
+ const transferClient = this.main_client;
66730
+ const transferResult = await transferClient.submitUniversalTransfer({
66731
+ asset: asset.toUpperCase(),
66732
+ amount,
66733
+ type: transferType,
66734
+ fromSymbol: symbol,
66735
+ toSymbol: symbol
66736
+ });
66737
+ const balanceAfterTransfer = await getWalletBalance(this.client, asset);
66738
+ return {
66739
+ success: true,
66740
+ transactionId: transferResult.tranId?.toString(),
66741
+ asset,
66742
+ amount,
66743
+ fromWallet: "futures",
66744
+ toWallet: "spot",
66745
+ balanceAfterTransfer,
66746
+ timestamp: new Date().toISOString()
66747
+ };
66748
+ } catch (error) {
66749
+ console.error(`Error executing transfer for ${asset}:`, error);
66750
+ let currentBalance = 0;
66751
+ try {
66752
+ currentBalance = await getWalletBalance(this.client, asset);
66753
+ } catch (balanceError) {
66754
+ console.warn("Could not fetch balance for error response:", balanceError);
66755
+ }
66756
+ return {
66757
+ success: false,
66758
+ asset,
66759
+ amount,
66760
+ fromWallet: "futures",
66761
+ toWallet: "spot",
66762
+ balanceAfterTransfer: currentBalance,
66763
+ timestamp: new Date().toISOString(),
66764
+ error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
66765
+ };
66766
+ }
66767
+ }
66586
66768
  }
66587
66769
  function getPricePlaces(target) {
66588
66770
  const numStr = target.toString();
@@ -66908,6 +67090,11 @@ async function placeStopOrder2(client, payload) {
66908
67090
  stop: payload.final_stop,
66909
67091
  is_market: !payload.is_limit
66910
67092
  };
67093
+ if (payload.hedge) {
67094
+ let reverse_kind = payload.kind === "long" ? "short" : "long";
67095
+ order.kind = reverse_kind;
67096
+ order.is_market = false;
67097
+ }
66911
67098
  return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
66912
67099
  }
66913
67100
  async function getOpenOrders2(client, symbol, type) {
@@ -67304,6 +67491,168 @@ class BybitExchange extends BaseExchange {
67304
67491
  return getOpenOrders2(this.client, payload.symbol);
67305
67492
  }
67306
67493
  async placeBadStopEntry(payload) {}
67494
+ async getTransferableAmount(options) {
67495
+ const { asset, maxTransferLimit } = options;
67496
+ try {
67497
+ const unifiedBalance = await getWalletBalance2(this.client, asset);
67498
+ const allPositions = await this.client.getPositionInfo({
67499
+ category: "linear",
67500
+ settleCoin: asset
67501
+ });
67502
+ const activePositions = (allPositions.result.list || []).filter((pos) => Math.abs(parseFloat(pos.size || "0")) > 0);
67503
+ let totalMarginUsed = 0;
67504
+ let totalUnrealizedPnl = 0;
67505
+ for (const position2 of activePositions) {
67506
+ const positionSize = Math.abs(parseFloat(position2.size || "0"));
67507
+ const markPrice = parseFloat(position2.markPrice || "0");
67508
+ const leverage = parseFloat(position2.leverage || "1");
67509
+ const positionValue = positionSize * markPrice;
67510
+ const marginForPosition = positionValue / leverage;
67511
+ totalMarginUsed += marginForPosition;
67512
+ totalUnrealizedPnl += parseFloat(position2.unrealisedPnl || "0");
67513
+ }
67514
+ const safetyMarginPercent = 0.2;
67515
+ const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
67516
+ const adjustedBalance = unifiedBalance + totalUnrealizedPnl;
67517
+ const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
67518
+ let maxTransferableAmount = availableForTransfer;
67519
+ let appliedLimit;
67520
+ if (maxTransferLimit && maxTransferLimit > 0) {
67521
+ maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
67522
+ appliedLimit = maxTransferLimit;
67523
+ }
67524
+ const recommendedTransferAmount = maxTransferableAmount * 0.8;
67525
+ const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
67526
+ return {
67527
+ asset,
67528
+ totalBalance: unifiedBalance,
67529
+ availableForTransfer,
67530
+ reservedForMargin: requiredMargin,
67531
+ maxTransferableAmount,
67532
+ appliedLimit,
67533
+ recommendedTransferAmount,
67534
+ marginUtilization,
67535
+ safetyMargin: safetyMarginPercent * 100
67536
+ };
67537
+ } catch (error) {
67538
+ console.error(`Error analyzing transferable amount for ${asset}:`, error);
67539
+ throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
67540
+ }
67541
+ }
67542
+ async previewTransfer(options) {
67543
+ const { asset, amount } = options;
67544
+ const warnings = [];
67545
+ const errors = [];
67546
+ try {
67547
+ const analysis = await this.getTransferableAmount({ asset });
67548
+ let isValid3 = true;
67549
+ if (amount <= 0) {
67550
+ errors.push("Transfer amount must be greater than zero");
67551
+ isValid3 = false;
67552
+ }
67553
+ if (amount > analysis.maxTransferableAmount) {
67554
+ errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
67555
+ isValid3 = false;
67556
+ }
67557
+ if (amount > analysis.recommendedTransferAmount) {
67558
+ warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
67559
+ }
67560
+ if (analysis.marginUtilization > 70) {
67561
+ warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
67562
+ }
67563
+ const balanceAfterTransfer = analysis.totalBalance - amount;
67564
+ const marginRequirementAfterTransfer = analysis.reservedForMargin;
67565
+ if (isValid3 && balanceAfterTransfer < marginRequirementAfterTransfer) {
67566
+ errors.push("Transfer would result in insufficient margin for existing positions");
67567
+ isValid3 = false;
67568
+ }
67569
+ return {
67570
+ asset,
67571
+ requestedAmount: amount,
67572
+ isValid: isValid3,
67573
+ balanceAfterTransfer,
67574
+ marginRequirementAfterTransfer,
67575
+ warnings,
67576
+ errors
67577
+ };
67578
+ } catch (error) {
67579
+ console.error(`Error previewing transfer for ${asset}:`, error);
67580
+ return {
67581
+ asset,
67582
+ requestedAmount: amount,
67583
+ isValid: false,
67584
+ balanceAfterTransfer: 0,
67585
+ marginRequirementAfterTransfer: 0,
67586
+ warnings,
67587
+ errors: [
67588
+ `Failed to preview transfer: ${error instanceof Error ? error.message : error}`
67589
+ ]
67590
+ };
67591
+ }
67592
+ }
67593
+ async executeUnifiedToFundingTransfer(options) {
67594
+ const { asset, amount, confirm } = options;
67595
+ try {
67596
+ if (!confirm) {
67597
+ return {
67598
+ success: false,
67599
+ asset,
67600
+ amount,
67601
+ fromWallet: "unified",
67602
+ toWallet: "funding",
67603
+ balanceAfterTransfer: 0,
67604
+ timestamp: new Date().toISOString(),
67605
+ error: "Transfer not confirmed. Set confirm: true to execute transfer."
67606
+ };
67607
+ }
67608
+ const preview = await this.previewTransfer({ asset, amount });
67609
+ if (!preview.isValid) {
67610
+ return {
67611
+ success: false,
67612
+ asset,
67613
+ amount,
67614
+ fromWallet: "unified",
67615
+ toWallet: "funding",
67616
+ balanceAfterTransfer: 0,
67617
+ timestamp: new Date().toISOString(),
67618
+ error: `Transfer validation failed: ${preview.errors.join("; ")}`
67619
+ };
67620
+ }
67621
+ const transferResult = await this.client.createInternalTransfer(`bybit_transfer_${Date.now()}`, asset.toUpperCase(), amount.toString(), "UNIFIED", "FUND");
67622
+ if (transferResult.retCode !== 0) {
67623
+ throw new Error(`Bybit transfer failed: ${transferResult.retMsg} (code: ${transferResult.retCode})`);
67624
+ }
67625
+ const balanceAfterTransfer = await getWalletBalance2(this.client, asset);
67626
+ return {
67627
+ success: true,
67628
+ transactionId: transferResult.result?.transferId,
67629
+ asset,
67630
+ amount,
67631
+ fromWallet: "unified",
67632
+ toWallet: "funding",
67633
+ balanceAfterTransfer,
67634
+ timestamp: new Date().toISOString()
67635
+ };
67636
+ } catch (error) {
67637
+ console.error(`Error executing transfer for ${asset}:`, error);
67638
+ let currentBalance = 0;
67639
+ try {
67640
+ currentBalance = await getWalletBalance2(this.client, asset);
67641
+ } catch (balanceError) {
67642
+ console.warn("Could not fetch balance for error response:", balanceError);
67643
+ }
67644
+ return {
67645
+ success: false,
67646
+ asset,
67647
+ amount,
67648
+ fromWallet: "unified",
67649
+ toWallet: "funding",
67650
+ balanceAfterTransfer: currentBalance,
67651
+ timestamp: new Date().toISOString(),
67652
+ error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
67653
+ };
67654
+ }
67655
+ }
67307
67656
  }
67308
67657
 
67309
67658
  // src/helpers/accounts.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-191",
4
+ "version": "0.0.2-193",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",