@gbozee/ultimate 0.0.2-192 → 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.
- package/dist/index.cjs +332 -0
- package/dist/index.js +332 -0
- package/dist/mcp-server.cjs +332 -0
- package/dist/mcp-server.js +332 -0
- package/package.json +1 -1
package/dist/mcp-server.cjs
CHANGED
|
@@ -66627,6 +66627,171 @@ class BinanceExchange extends BaseExchange {
|
|
|
66627
66627
|
async forceClosePosition(symbol, options) {
|
|
66628
66628
|
return await forceClosePosition(this.client, symbol, options);
|
|
66629
66629
|
}
|
|
66630
|
+
async getTransferableAmount(options) {
|
|
66631
|
+
const { asset, maxTransferLimit } = options;
|
|
66632
|
+
try {
|
|
66633
|
+
const futuresBalance = await getWalletBalance(this.client, asset);
|
|
66634
|
+
const allPositions = await this.client.getPositionsV3();
|
|
66635
|
+
const activePositions = allPositions.filter((pos) => Math.abs(pos.positionAmt) > 0);
|
|
66636
|
+
let totalMarginUsed = 0;
|
|
66637
|
+
let totalUnrealizedPnl = 0;
|
|
66638
|
+
for (const position2 of activePositions) {
|
|
66639
|
+
const positionValue = Math.abs(position2.positionAmt) * position2.markPrice;
|
|
66640
|
+
const leverage = await getLeverage(this.client, position2.symbol);
|
|
66641
|
+
const marginForPosition = positionValue / (leverage || 1);
|
|
66642
|
+
console.log({ leverage });
|
|
66643
|
+
totalMarginUsed += marginForPosition;
|
|
66644
|
+
totalUnrealizedPnl += position2.unRealizedProfit || 0;
|
|
66645
|
+
}
|
|
66646
|
+
const safetyMarginPercent = 0.2;
|
|
66647
|
+
const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
|
|
66648
|
+
const adjustedBalance = futuresBalance + totalUnrealizedPnl;
|
|
66649
|
+
const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
|
|
66650
|
+
let maxTransferableAmount = availableForTransfer;
|
|
66651
|
+
let appliedLimit;
|
|
66652
|
+
if (maxTransferLimit && maxTransferLimit > 0) {
|
|
66653
|
+
maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
|
|
66654
|
+
appliedLimit = maxTransferLimit;
|
|
66655
|
+
}
|
|
66656
|
+
const recommendedTransferAmount = maxTransferableAmount * 0.8;
|
|
66657
|
+
const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
|
|
66658
|
+
return {
|
|
66659
|
+
asset,
|
|
66660
|
+
totalBalance: futuresBalance,
|
|
66661
|
+
availableForTransfer,
|
|
66662
|
+
reservedForMargin: requiredMargin,
|
|
66663
|
+
maxTransferableAmount,
|
|
66664
|
+
appliedLimit,
|
|
66665
|
+
recommendedTransferAmount,
|
|
66666
|
+
marginUtilization,
|
|
66667
|
+
safetyMargin: safetyMarginPercent * 100
|
|
66668
|
+
};
|
|
66669
|
+
} catch (error) {
|
|
66670
|
+
console.error(`Error analyzing transferable amount for ${asset}:`, error);
|
|
66671
|
+
throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
|
|
66672
|
+
}
|
|
66673
|
+
}
|
|
66674
|
+
async previewTransfer(options) {
|
|
66675
|
+
const { asset, amount } = options;
|
|
66676
|
+
const warnings = [];
|
|
66677
|
+
const errors = [];
|
|
66678
|
+
try {
|
|
66679
|
+
const analysis = await this.getTransferableAmount({ asset });
|
|
66680
|
+
let isValid3 = true;
|
|
66681
|
+
if (amount <= 0) {
|
|
66682
|
+
errors.push("Transfer amount must be greater than zero");
|
|
66683
|
+
isValid3 = false;
|
|
66684
|
+
}
|
|
66685
|
+
if (amount > analysis.maxTransferableAmount) {
|
|
66686
|
+
errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
|
|
66687
|
+
isValid3 = false;
|
|
66688
|
+
}
|
|
66689
|
+
if (amount > analysis.recommendedTransferAmount) {
|
|
66690
|
+
warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
|
|
66691
|
+
}
|
|
66692
|
+
if (analysis.marginUtilization > 70) {
|
|
66693
|
+
warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
|
|
66694
|
+
}
|
|
66695
|
+
const balanceAfterTransfer = analysis.totalBalance - amount;
|
|
66696
|
+
const marginRequirementAfterTransfer = analysis.reservedForMargin;
|
|
66697
|
+
if (isValid3 && balanceAfterTransfer < marginRequirementAfterTransfer) {
|
|
66698
|
+
errors.push("Transfer would result in insufficient margin for existing positions");
|
|
66699
|
+
isValid3 = false;
|
|
66700
|
+
}
|
|
66701
|
+
return {
|
|
66702
|
+
asset,
|
|
66703
|
+
requestedAmount: amount,
|
|
66704
|
+
isValid: isValid3,
|
|
66705
|
+
balanceAfterTransfer,
|
|
66706
|
+
marginRequirementAfterTransfer,
|
|
66707
|
+
warnings,
|
|
66708
|
+
errors
|
|
66709
|
+
};
|
|
66710
|
+
} catch (error) {
|
|
66711
|
+
console.error(`Error previewing transfer for ${asset}:`, error);
|
|
66712
|
+
return {
|
|
66713
|
+
asset,
|
|
66714
|
+
requestedAmount: amount,
|
|
66715
|
+
isValid: false,
|
|
66716
|
+
balanceAfterTransfer: 0,
|
|
66717
|
+
marginRequirementAfterTransfer: 0,
|
|
66718
|
+
warnings,
|
|
66719
|
+
errors: [`Failed to preview transfer: ${error instanceof Error ? error.message : error}`]
|
|
66720
|
+
};
|
|
66721
|
+
}
|
|
66722
|
+
}
|
|
66723
|
+
async executeFutureToSpotTransfer(options) {
|
|
66724
|
+
const { asset, amount, confirm, symbol = "BTCUSDT" } = options;
|
|
66725
|
+
try {
|
|
66726
|
+
if (!confirm) {
|
|
66727
|
+
return {
|
|
66728
|
+
success: false,
|
|
66729
|
+
asset,
|
|
66730
|
+
amount,
|
|
66731
|
+
fromWallet: "futures",
|
|
66732
|
+
toWallet: "spot",
|
|
66733
|
+
balanceAfterTransfer: 0,
|
|
66734
|
+
timestamp: new Date().toISOString(),
|
|
66735
|
+
error: "Transfer not confirmed. Set confirm: true to execute transfer."
|
|
66736
|
+
};
|
|
66737
|
+
}
|
|
66738
|
+
const preview = await this.previewTransfer({ asset, amount });
|
|
66739
|
+
if (!preview.isValid) {
|
|
66740
|
+
return {
|
|
66741
|
+
success: false,
|
|
66742
|
+
asset,
|
|
66743
|
+
amount,
|
|
66744
|
+
fromWallet: "futures",
|
|
66745
|
+
toWallet: "spot",
|
|
66746
|
+
balanceAfterTransfer: 0,
|
|
66747
|
+
timestamp: new Date().toISOString(),
|
|
66748
|
+
error: `Transfer validation failed: ${preview.errors.join("; ")}`
|
|
66749
|
+
};
|
|
66750
|
+
}
|
|
66751
|
+
const is_coin = !["USDT", "USDC", "BUSD"].includes(asset.toUpperCase());
|
|
66752
|
+
const transferType = is_coin ? CONSTANTS.COIN_FUTURE_TO_SPOT : CONSTANTS.USDT_FUTURE_TO_SPOT;
|
|
66753
|
+
if (!this.main_client) {
|
|
66754
|
+
throw new Error("Main client not available for transfers");
|
|
66755
|
+
}
|
|
66756
|
+
const transferClient = this.main_client;
|
|
66757
|
+
const transferResult = await transferClient.submitUniversalTransfer({
|
|
66758
|
+
asset: asset.toUpperCase(),
|
|
66759
|
+
amount,
|
|
66760
|
+
type: transferType,
|
|
66761
|
+
fromSymbol: symbol,
|
|
66762
|
+
toSymbol: symbol
|
|
66763
|
+
});
|
|
66764
|
+
const balanceAfterTransfer = await getWalletBalance(this.client, asset);
|
|
66765
|
+
return {
|
|
66766
|
+
success: true,
|
|
66767
|
+
transactionId: transferResult.tranId?.toString(),
|
|
66768
|
+
asset,
|
|
66769
|
+
amount,
|
|
66770
|
+
fromWallet: "futures",
|
|
66771
|
+
toWallet: "spot",
|
|
66772
|
+
balanceAfterTransfer,
|
|
66773
|
+
timestamp: new Date().toISOString()
|
|
66774
|
+
};
|
|
66775
|
+
} catch (error) {
|
|
66776
|
+
console.error(`Error executing transfer for ${asset}:`, error);
|
|
66777
|
+
let currentBalance = 0;
|
|
66778
|
+
try {
|
|
66779
|
+
currentBalance = await getWalletBalance(this.client, asset);
|
|
66780
|
+
} catch (balanceError) {
|
|
66781
|
+
console.warn("Could not fetch balance for error response:", balanceError);
|
|
66782
|
+
}
|
|
66783
|
+
return {
|
|
66784
|
+
success: false,
|
|
66785
|
+
asset,
|
|
66786
|
+
amount,
|
|
66787
|
+
fromWallet: "futures",
|
|
66788
|
+
toWallet: "spot",
|
|
66789
|
+
balanceAfterTransfer: currentBalance,
|
|
66790
|
+
timestamp: new Date().toISOString(),
|
|
66791
|
+
error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
|
|
66792
|
+
};
|
|
66793
|
+
}
|
|
66794
|
+
}
|
|
66630
66795
|
}
|
|
66631
66796
|
function getPricePlaces(target) {
|
|
66632
66797
|
const numStr = target.toString();
|
|
@@ -66952,6 +67117,11 @@ async function placeStopOrder2(client, payload) {
|
|
|
66952
67117
|
stop: payload.final_stop,
|
|
66953
67118
|
is_market: !payload.is_limit
|
|
66954
67119
|
};
|
|
67120
|
+
if (payload.hedge) {
|
|
67121
|
+
let reverse_kind = payload.kind === "long" ? "short" : "long";
|
|
67122
|
+
order.kind = reverse_kind;
|
|
67123
|
+
order.is_market = false;
|
|
67124
|
+
}
|
|
66955
67125
|
return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
66956
67126
|
}
|
|
66957
67127
|
async function getOpenOrders2(client, symbol, type) {
|
|
@@ -67348,6 +67518,168 @@ class BybitExchange extends BaseExchange {
|
|
|
67348
67518
|
return getOpenOrders2(this.client, payload.symbol);
|
|
67349
67519
|
}
|
|
67350
67520
|
async placeBadStopEntry(payload) {}
|
|
67521
|
+
async getTransferableAmount(options) {
|
|
67522
|
+
const { asset, maxTransferLimit } = options;
|
|
67523
|
+
try {
|
|
67524
|
+
const unifiedBalance = await getWalletBalance2(this.client, asset);
|
|
67525
|
+
const allPositions = await this.client.getPositionInfo({
|
|
67526
|
+
category: "linear",
|
|
67527
|
+
settleCoin: asset
|
|
67528
|
+
});
|
|
67529
|
+
const activePositions = (allPositions.result.list || []).filter((pos) => Math.abs(parseFloat(pos.size || "0")) > 0);
|
|
67530
|
+
let totalMarginUsed = 0;
|
|
67531
|
+
let totalUnrealizedPnl = 0;
|
|
67532
|
+
for (const position2 of activePositions) {
|
|
67533
|
+
const positionSize = Math.abs(parseFloat(position2.size || "0"));
|
|
67534
|
+
const markPrice = parseFloat(position2.markPrice || "0");
|
|
67535
|
+
const leverage = parseFloat(position2.leverage || "1");
|
|
67536
|
+
const positionValue = positionSize * markPrice;
|
|
67537
|
+
const marginForPosition = positionValue / leverage;
|
|
67538
|
+
totalMarginUsed += marginForPosition;
|
|
67539
|
+
totalUnrealizedPnl += parseFloat(position2.unrealisedPnl || "0");
|
|
67540
|
+
}
|
|
67541
|
+
const safetyMarginPercent = 0.2;
|
|
67542
|
+
const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
|
|
67543
|
+
const adjustedBalance = unifiedBalance + totalUnrealizedPnl;
|
|
67544
|
+
const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
|
|
67545
|
+
let maxTransferableAmount = availableForTransfer;
|
|
67546
|
+
let appliedLimit;
|
|
67547
|
+
if (maxTransferLimit && maxTransferLimit > 0) {
|
|
67548
|
+
maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
|
|
67549
|
+
appliedLimit = maxTransferLimit;
|
|
67550
|
+
}
|
|
67551
|
+
const recommendedTransferAmount = maxTransferableAmount * 0.8;
|
|
67552
|
+
const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
|
|
67553
|
+
return {
|
|
67554
|
+
asset,
|
|
67555
|
+
totalBalance: unifiedBalance,
|
|
67556
|
+
availableForTransfer,
|
|
67557
|
+
reservedForMargin: requiredMargin,
|
|
67558
|
+
maxTransferableAmount,
|
|
67559
|
+
appliedLimit,
|
|
67560
|
+
recommendedTransferAmount,
|
|
67561
|
+
marginUtilization,
|
|
67562
|
+
safetyMargin: safetyMarginPercent * 100
|
|
67563
|
+
};
|
|
67564
|
+
} catch (error) {
|
|
67565
|
+
console.error(`Error analyzing transferable amount for ${asset}:`, error);
|
|
67566
|
+
throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
|
|
67567
|
+
}
|
|
67568
|
+
}
|
|
67569
|
+
async previewTransfer(options) {
|
|
67570
|
+
const { asset, amount } = options;
|
|
67571
|
+
const warnings = [];
|
|
67572
|
+
const errors = [];
|
|
67573
|
+
try {
|
|
67574
|
+
const analysis = await this.getTransferableAmount({ asset });
|
|
67575
|
+
let isValid3 = true;
|
|
67576
|
+
if (amount <= 0) {
|
|
67577
|
+
errors.push("Transfer amount must be greater than zero");
|
|
67578
|
+
isValid3 = false;
|
|
67579
|
+
}
|
|
67580
|
+
if (amount > analysis.maxTransferableAmount) {
|
|
67581
|
+
errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
|
|
67582
|
+
isValid3 = false;
|
|
67583
|
+
}
|
|
67584
|
+
if (amount > analysis.recommendedTransferAmount) {
|
|
67585
|
+
warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
|
|
67586
|
+
}
|
|
67587
|
+
if (analysis.marginUtilization > 70) {
|
|
67588
|
+
warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
|
|
67589
|
+
}
|
|
67590
|
+
const balanceAfterTransfer = analysis.totalBalance - amount;
|
|
67591
|
+
const marginRequirementAfterTransfer = analysis.reservedForMargin;
|
|
67592
|
+
if (isValid3 && balanceAfterTransfer < marginRequirementAfterTransfer) {
|
|
67593
|
+
errors.push("Transfer would result in insufficient margin for existing positions");
|
|
67594
|
+
isValid3 = false;
|
|
67595
|
+
}
|
|
67596
|
+
return {
|
|
67597
|
+
asset,
|
|
67598
|
+
requestedAmount: amount,
|
|
67599
|
+
isValid: isValid3,
|
|
67600
|
+
balanceAfterTransfer,
|
|
67601
|
+
marginRequirementAfterTransfer,
|
|
67602
|
+
warnings,
|
|
67603
|
+
errors
|
|
67604
|
+
};
|
|
67605
|
+
} catch (error) {
|
|
67606
|
+
console.error(`Error previewing transfer for ${asset}:`, error);
|
|
67607
|
+
return {
|
|
67608
|
+
asset,
|
|
67609
|
+
requestedAmount: amount,
|
|
67610
|
+
isValid: false,
|
|
67611
|
+
balanceAfterTransfer: 0,
|
|
67612
|
+
marginRequirementAfterTransfer: 0,
|
|
67613
|
+
warnings,
|
|
67614
|
+
errors: [
|
|
67615
|
+
`Failed to preview transfer: ${error instanceof Error ? error.message : error}`
|
|
67616
|
+
]
|
|
67617
|
+
};
|
|
67618
|
+
}
|
|
67619
|
+
}
|
|
67620
|
+
async executeUnifiedToFundingTransfer(options) {
|
|
67621
|
+
const { asset, amount, confirm } = options;
|
|
67622
|
+
try {
|
|
67623
|
+
if (!confirm) {
|
|
67624
|
+
return {
|
|
67625
|
+
success: false,
|
|
67626
|
+
asset,
|
|
67627
|
+
amount,
|
|
67628
|
+
fromWallet: "unified",
|
|
67629
|
+
toWallet: "funding",
|
|
67630
|
+
balanceAfterTransfer: 0,
|
|
67631
|
+
timestamp: new Date().toISOString(),
|
|
67632
|
+
error: "Transfer not confirmed. Set confirm: true to execute transfer."
|
|
67633
|
+
};
|
|
67634
|
+
}
|
|
67635
|
+
const preview = await this.previewTransfer({ asset, amount });
|
|
67636
|
+
if (!preview.isValid) {
|
|
67637
|
+
return {
|
|
67638
|
+
success: false,
|
|
67639
|
+
asset,
|
|
67640
|
+
amount,
|
|
67641
|
+
fromWallet: "unified",
|
|
67642
|
+
toWallet: "funding",
|
|
67643
|
+
balanceAfterTransfer: 0,
|
|
67644
|
+
timestamp: new Date().toISOString(),
|
|
67645
|
+
error: `Transfer validation failed: ${preview.errors.join("; ")}`
|
|
67646
|
+
};
|
|
67647
|
+
}
|
|
67648
|
+
const transferResult = await this.client.createInternalTransfer(`bybit_transfer_${Date.now()}`, asset.toUpperCase(), amount.toString(), "UNIFIED", "FUND");
|
|
67649
|
+
if (transferResult.retCode !== 0) {
|
|
67650
|
+
throw new Error(`Bybit transfer failed: ${transferResult.retMsg} (code: ${transferResult.retCode})`);
|
|
67651
|
+
}
|
|
67652
|
+
const balanceAfterTransfer = await getWalletBalance2(this.client, asset);
|
|
67653
|
+
return {
|
|
67654
|
+
success: true,
|
|
67655
|
+
transactionId: transferResult.result?.transferId,
|
|
67656
|
+
asset,
|
|
67657
|
+
amount,
|
|
67658
|
+
fromWallet: "unified",
|
|
67659
|
+
toWallet: "funding",
|
|
67660
|
+
balanceAfterTransfer,
|
|
67661
|
+
timestamp: new Date().toISOString()
|
|
67662
|
+
};
|
|
67663
|
+
} catch (error) {
|
|
67664
|
+
console.error(`Error executing transfer for ${asset}:`, error);
|
|
67665
|
+
let currentBalance = 0;
|
|
67666
|
+
try {
|
|
67667
|
+
currentBalance = await getWalletBalance2(this.client, asset);
|
|
67668
|
+
} catch (balanceError) {
|
|
67669
|
+
console.warn("Could not fetch balance for error response:", balanceError);
|
|
67670
|
+
}
|
|
67671
|
+
return {
|
|
67672
|
+
success: false,
|
|
67673
|
+
asset,
|
|
67674
|
+
amount,
|
|
67675
|
+
fromWallet: "unified",
|
|
67676
|
+
toWallet: "funding",
|
|
67677
|
+
balanceAfterTransfer: currentBalance,
|
|
67678
|
+
timestamp: new Date().toISOString(),
|
|
67679
|
+
error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
|
|
67680
|
+
};
|
|
67681
|
+
}
|
|
67682
|
+
}
|
|
67351
67683
|
}
|
|
67352
67684
|
|
|
67353
67685
|
// src/helpers/accounts.ts
|
package/dist/mcp-server.js
CHANGED
|
@@ -66600,6 +66600,171 @@ class BinanceExchange extends BaseExchange {
|
|
|
66600
66600
|
async forceClosePosition(symbol, options) {
|
|
66601
66601
|
return await forceClosePosition(this.client, symbol, options);
|
|
66602
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
|
+
}
|
|
66603
66768
|
}
|
|
66604
66769
|
function getPricePlaces(target) {
|
|
66605
66770
|
const numStr = target.toString();
|
|
@@ -66925,6 +67090,11 @@ async function placeStopOrder2(client, payload) {
|
|
|
66925
67090
|
stop: payload.final_stop,
|
|
66926
67091
|
is_market: !payload.is_limit
|
|
66927
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
|
+
}
|
|
66928
67098
|
return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
66929
67099
|
}
|
|
66930
67100
|
async function getOpenOrders2(client, symbol, type) {
|
|
@@ -67321,6 +67491,168 @@ class BybitExchange extends BaseExchange {
|
|
|
67321
67491
|
return getOpenOrders2(this.client, payload.symbol);
|
|
67322
67492
|
}
|
|
67323
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
|
+
}
|
|
67324
67656
|
}
|
|
67325
67657
|
|
|
67326
67658
|
// src/helpers/accounts.ts
|