@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/index.cjs
CHANGED
|
@@ -60051,6 +60051,171 @@ class BinanceExchange extends BaseExchange {
|
|
|
60051
60051
|
async forceClosePosition(symbol, options) {
|
|
60052
60052
|
return await forceClosePosition(this.client, symbol, options);
|
|
60053
60053
|
}
|
|
60054
|
+
async getTransferableAmount(options) {
|
|
60055
|
+
const { asset, maxTransferLimit } = options;
|
|
60056
|
+
try {
|
|
60057
|
+
const futuresBalance = await getWalletBalance(this.client, asset);
|
|
60058
|
+
const allPositions = await this.client.getPositionsV3();
|
|
60059
|
+
const activePositions = allPositions.filter((pos) => Math.abs(pos.positionAmt) > 0);
|
|
60060
|
+
let totalMarginUsed = 0;
|
|
60061
|
+
let totalUnrealizedPnl = 0;
|
|
60062
|
+
for (const position2 of activePositions) {
|
|
60063
|
+
const positionValue = Math.abs(position2.positionAmt) * position2.markPrice;
|
|
60064
|
+
const leverage = await getLeverage(this.client, position2.symbol);
|
|
60065
|
+
const marginForPosition = positionValue / (leverage || 1);
|
|
60066
|
+
console.log({ leverage });
|
|
60067
|
+
totalMarginUsed += marginForPosition;
|
|
60068
|
+
totalUnrealizedPnl += position2.unRealizedProfit || 0;
|
|
60069
|
+
}
|
|
60070
|
+
const safetyMarginPercent = 0.2;
|
|
60071
|
+
const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
|
|
60072
|
+
const adjustedBalance = futuresBalance + totalUnrealizedPnl;
|
|
60073
|
+
const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
|
|
60074
|
+
let maxTransferableAmount = availableForTransfer;
|
|
60075
|
+
let appliedLimit;
|
|
60076
|
+
if (maxTransferLimit && maxTransferLimit > 0) {
|
|
60077
|
+
maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
|
|
60078
|
+
appliedLimit = maxTransferLimit;
|
|
60079
|
+
}
|
|
60080
|
+
const recommendedTransferAmount = maxTransferableAmount * 0.8;
|
|
60081
|
+
const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
|
|
60082
|
+
return {
|
|
60083
|
+
asset,
|
|
60084
|
+
totalBalance: futuresBalance,
|
|
60085
|
+
availableForTransfer,
|
|
60086
|
+
reservedForMargin: requiredMargin,
|
|
60087
|
+
maxTransferableAmount,
|
|
60088
|
+
appliedLimit,
|
|
60089
|
+
recommendedTransferAmount,
|
|
60090
|
+
marginUtilization,
|
|
60091
|
+
safetyMargin: safetyMarginPercent * 100
|
|
60092
|
+
};
|
|
60093
|
+
} catch (error) {
|
|
60094
|
+
console.error(`Error analyzing transferable amount for ${asset}:`, error);
|
|
60095
|
+
throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
|
|
60096
|
+
}
|
|
60097
|
+
}
|
|
60098
|
+
async previewTransfer(options) {
|
|
60099
|
+
const { asset, amount } = options;
|
|
60100
|
+
const warnings = [];
|
|
60101
|
+
const errors = [];
|
|
60102
|
+
try {
|
|
60103
|
+
const analysis = await this.getTransferableAmount({ asset });
|
|
60104
|
+
let isValid2 = true;
|
|
60105
|
+
if (amount <= 0) {
|
|
60106
|
+
errors.push("Transfer amount must be greater than zero");
|
|
60107
|
+
isValid2 = false;
|
|
60108
|
+
}
|
|
60109
|
+
if (amount > analysis.maxTransferableAmount) {
|
|
60110
|
+
errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
|
|
60111
|
+
isValid2 = false;
|
|
60112
|
+
}
|
|
60113
|
+
if (amount > analysis.recommendedTransferAmount) {
|
|
60114
|
+
warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
|
|
60115
|
+
}
|
|
60116
|
+
if (analysis.marginUtilization > 70) {
|
|
60117
|
+
warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
|
|
60118
|
+
}
|
|
60119
|
+
const balanceAfterTransfer = analysis.totalBalance - amount;
|
|
60120
|
+
const marginRequirementAfterTransfer = analysis.reservedForMargin;
|
|
60121
|
+
if (isValid2 && balanceAfterTransfer < marginRequirementAfterTransfer) {
|
|
60122
|
+
errors.push("Transfer would result in insufficient margin for existing positions");
|
|
60123
|
+
isValid2 = false;
|
|
60124
|
+
}
|
|
60125
|
+
return {
|
|
60126
|
+
asset,
|
|
60127
|
+
requestedAmount: amount,
|
|
60128
|
+
isValid: isValid2,
|
|
60129
|
+
balanceAfterTransfer,
|
|
60130
|
+
marginRequirementAfterTransfer,
|
|
60131
|
+
warnings,
|
|
60132
|
+
errors
|
|
60133
|
+
};
|
|
60134
|
+
} catch (error) {
|
|
60135
|
+
console.error(`Error previewing transfer for ${asset}:`, error);
|
|
60136
|
+
return {
|
|
60137
|
+
asset,
|
|
60138
|
+
requestedAmount: amount,
|
|
60139
|
+
isValid: false,
|
|
60140
|
+
balanceAfterTransfer: 0,
|
|
60141
|
+
marginRequirementAfterTransfer: 0,
|
|
60142
|
+
warnings,
|
|
60143
|
+
errors: [`Failed to preview transfer: ${error instanceof Error ? error.message : error}`]
|
|
60144
|
+
};
|
|
60145
|
+
}
|
|
60146
|
+
}
|
|
60147
|
+
async executeFutureToSpotTransfer(options) {
|
|
60148
|
+
const { asset, amount, confirm, symbol = "BTCUSDT" } = options;
|
|
60149
|
+
try {
|
|
60150
|
+
if (!confirm) {
|
|
60151
|
+
return {
|
|
60152
|
+
success: false,
|
|
60153
|
+
asset,
|
|
60154
|
+
amount,
|
|
60155
|
+
fromWallet: "futures",
|
|
60156
|
+
toWallet: "spot",
|
|
60157
|
+
balanceAfterTransfer: 0,
|
|
60158
|
+
timestamp: new Date().toISOString(),
|
|
60159
|
+
error: "Transfer not confirmed. Set confirm: true to execute transfer."
|
|
60160
|
+
};
|
|
60161
|
+
}
|
|
60162
|
+
const preview = await this.previewTransfer({ asset, amount });
|
|
60163
|
+
if (!preview.isValid) {
|
|
60164
|
+
return {
|
|
60165
|
+
success: false,
|
|
60166
|
+
asset,
|
|
60167
|
+
amount,
|
|
60168
|
+
fromWallet: "futures",
|
|
60169
|
+
toWallet: "spot",
|
|
60170
|
+
balanceAfterTransfer: 0,
|
|
60171
|
+
timestamp: new Date().toISOString(),
|
|
60172
|
+
error: `Transfer validation failed: ${preview.errors.join("; ")}`
|
|
60173
|
+
};
|
|
60174
|
+
}
|
|
60175
|
+
const is_coin = !["USDT", "USDC", "BUSD"].includes(asset.toUpperCase());
|
|
60176
|
+
const transferType = is_coin ? CONSTANTS.COIN_FUTURE_TO_SPOT : CONSTANTS.USDT_FUTURE_TO_SPOT;
|
|
60177
|
+
if (!this.main_client) {
|
|
60178
|
+
throw new Error("Main client not available for transfers");
|
|
60179
|
+
}
|
|
60180
|
+
const transferClient = this.main_client;
|
|
60181
|
+
const transferResult = await transferClient.submitUniversalTransfer({
|
|
60182
|
+
asset: asset.toUpperCase(),
|
|
60183
|
+
amount,
|
|
60184
|
+
type: transferType,
|
|
60185
|
+
fromSymbol: symbol,
|
|
60186
|
+
toSymbol: symbol
|
|
60187
|
+
});
|
|
60188
|
+
const balanceAfterTransfer = await getWalletBalance(this.client, asset);
|
|
60189
|
+
return {
|
|
60190
|
+
success: true,
|
|
60191
|
+
transactionId: transferResult.tranId?.toString(),
|
|
60192
|
+
asset,
|
|
60193
|
+
amount,
|
|
60194
|
+
fromWallet: "futures",
|
|
60195
|
+
toWallet: "spot",
|
|
60196
|
+
balanceAfterTransfer,
|
|
60197
|
+
timestamp: new Date().toISOString()
|
|
60198
|
+
};
|
|
60199
|
+
} catch (error) {
|
|
60200
|
+
console.error(`Error executing transfer for ${asset}:`, error);
|
|
60201
|
+
let currentBalance = 0;
|
|
60202
|
+
try {
|
|
60203
|
+
currentBalance = await getWalletBalance(this.client, asset);
|
|
60204
|
+
} catch (balanceError) {
|
|
60205
|
+
console.warn("Could not fetch balance for error response:", balanceError);
|
|
60206
|
+
}
|
|
60207
|
+
return {
|
|
60208
|
+
success: false,
|
|
60209
|
+
asset,
|
|
60210
|
+
amount,
|
|
60211
|
+
fromWallet: "futures",
|
|
60212
|
+
toWallet: "spot",
|
|
60213
|
+
balanceAfterTransfer: currentBalance,
|
|
60214
|
+
timestamp: new Date().toISOString(),
|
|
60215
|
+
error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
|
|
60216
|
+
};
|
|
60217
|
+
}
|
|
60218
|
+
}
|
|
60054
60219
|
}
|
|
60055
60220
|
function getPricePlaces(target) {
|
|
60056
60221
|
const numStr = target.toString();
|
|
@@ -60376,6 +60541,11 @@ async function placeStopOrder2(client, payload) {
|
|
|
60376
60541
|
stop: payload.final_stop,
|
|
60377
60542
|
is_market: !payload.is_limit
|
|
60378
60543
|
};
|
|
60544
|
+
if (payload.hedge) {
|
|
60545
|
+
let reverse_kind = payload.kind === "long" ? "short" : "long";
|
|
60546
|
+
order.kind = reverse_kind;
|
|
60547
|
+
order.is_market = false;
|
|
60548
|
+
}
|
|
60379
60549
|
return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
60380
60550
|
}
|
|
60381
60551
|
async function getOpenOrders2(client, symbol, type) {
|
|
@@ -60772,6 +60942,168 @@ class BybitExchange extends BaseExchange {
|
|
|
60772
60942
|
return getOpenOrders2(this.client, payload.symbol);
|
|
60773
60943
|
}
|
|
60774
60944
|
async placeBadStopEntry(payload) {}
|
|
60945
|
+
async getTransferableAmount(options) {
|
|
60946
|
+
const { asset, maxTransferLimit } = options;
|
|
60947
|
+
try {
|
|
60948
|
+
const unifiedBalance = await getWalletBalance2(this.client, asset);
|
|
60949
|
+
const allPositions = await this.client.getPositionInfo({
|
|
60950
|
+
category: "linear",
|
|
60951
|
+
settleCoin: asset
|
|
60952
|
+
});
|
|
60953
|
+
const activePositions = (allPositions.result.list || []).filter((pos) => Math.abs(parseFloat(pos.size || "0")) > 0);
|
|
60954
|
+
let totalMarginUsed = 0;
|
|
60955
|
+
let totalUnrealizedPnl = 0;
|
|
60956
|
+
for (const position2 of activePositions) {
|
|
60957
|
+
const positionSize = Math.abs(parseFloat(position2.size || "0"));
|
|
60958
|
+
const markPrice = parseFloat(position2.markPrice || "0");
|
|
60959
|
+
const leverage = parseFloat(position2.leverage || "1");
|
|
60960
|
+
const positionValue = positionSize * markPrice;
|
|
60961
|
+
const marginForPosition = positionValue / leverage;
|
|
60962
|
+
totalMarginUsed += marginForPosition;
|
|
60963
|
+
totalUnrealizedPnl += parseFloat(position2.unrealisedPnl || "0");
|
|
60964
|
+
}
|
|
60965
|
+
const safetyMarginPercent = 0.2;
|
|
60966
|
+
const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
|
|
60967
|
+
const adjustedBalance = unifiedBalance + totalUnrealizedPnl;
|
|
60968
|
+
const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
|
|
60969
|
+
let maxTransferableAmount = availableForTransfer;
|
|
60970
|
+
let appliedLimit;
|
|
60971
|
+
if (maxTransferLimit && maxTransferLimit > 0) {
|
|
60972
|
+
maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
|
|
60973
|
+
appliedLimit = maxTransferLimit;
|
|
60974
|
+
}
|
|
60975
|
+
const recommendedTransferAmount = maxTransferableAmount * 0.8;
|
|
60976
|
+
const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
|
|
60977
|
+
return {
|
|
60978
|
+
asset,
|
|
60979
|
+
totalBalance: unifiedBalance,
|
|
60980
|
+
availableForTransfer,
|
|
60981
|
+
reservedForMargin: requiredMargin,
|
|
60982
|
+
maxTransferableAmount,
|
|
60983
|
+
appliedLimit,
|
|
60984
|
+
recommendedTransferAmount,
|
|
60985
|
+
marginUtilization,
|
|
60986
|
+
safetyMargin: safetyMarginPercent * 100
|
|
60987
|
+
};
|
|
60988
|
+
} catch (error) {
|
|
60989
|
+
console.error(`Error analyzing transferable amount for ${asset}:`, error);
|
|
60990
|
+
throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
|
|
60991
|
+
}
|
|
60992
|
+
}
|
|
60993
|
+
async previewTransfer(options) {
|
|
60994
|
+
const { asset, amount } = options;
|
|
60995
|
+
const warnings = [];
|
|
60996
|
+
const errors = [];
|
|
60997
|
+
try {
|
|
60998
|
+
const analysis = await this.getTransferableAmount({ asset });
|
|
60999
|
+
let isValid2 = true;
|
|
61000
|
+
if (amount <= 0) {
|
|
61001
|
+
errors.push("Transfer amount must be greater than zero");
|
|
61002
|
+
isValid2 = false;
|
|
61003
|
+
}
|
|
61004
|
+
if (amount > analysis.maxTransferableAmount) {
|
|
61005
|
+
errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
|
|
61006
|
+
isValid2 = false;
|
|
61007
|
+
}
|
|
61008
|
+
if (amount > analysis.recommendedTransferAmount) {
|
|
61009
|
+
warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
|
|
61010
|
+
}
|
|
61011
|
+
if (analysis.marginUtilization > 70) {
|
|
61012
|
+
warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
|
|
61013
|
+
}
|
|
61014
|
+
const balanceAfterTransfer = analysis.totalBalance - amount;
|
|
61015
|
+
const marginRequirementAfterTransfer = analysis.reservedForMargin;
|
|
61016
|
+
if (isValid2 && balanceAfterTransfer < marginRequirementAfterTransfer) {
|
|
61017
|
+
errors.push("Transfer would result in insufficient margin for existing positions");
|
|
61018
|
+
isValid2 = false;
|
|
61019
|
+
}
|
|
61020
|
+
return {
|
|
61021
|
+
asset,
|
|
61022
|
+
requestedAmount: amount,
|
|
61023
|
+
isValid: isValid2,
|
|
61024
|
+
balanceAfterTransfer,
|
|
61025
|
+
marginRequirementAfterTransfer,
|
|
61026
|
+
warnings,
|
|
61027
|
+
errors
|
|
61028
|
+
};
|
|
61029
|
+
} catch (error) {
|
|
61030
|
+
console.error(`Error previewing transfer for ${asset}:`, error);
|
|
61031
|
+
return {
|
|
61032
|
+
asset,
|
|
61033
|
+
requestedAmount: amount,
|
|
61034
|
+
isValid: false,
|
|
61035
|
+
balanceAfterTransfer: 0,
|
|
61036
|
+
marginRequirementAfterTransfer: 0,
|
|
61037
|
+
warnings,
|
|
61038
|
+
errors: [
|
|
61039
|
+
`Failed to preview transfer: ${error instanceof Error ? error.message : error}`
|
|
61040
|
+
]
|
|
61041
|
+
};
|
|
61042
|
+
}
|
|
61043
|
+
}
|
|
61044
|
+
async executeUnifiedToFundingTransfer(options) {
|
|
61045
|
+
const { asset, amount, confirm } = options;
|
|
61046
|
+
try {
|
|
61047
|
+
if (!confirm) {
|
|
61048
|
+
return {
|
|
61049
|
+
success: false,
|
|
61050
|
+
asset,
|
|
61051
|
+
amount,
|
|
61052
|
+
fromWallet: "unified",
|
|
61053
|
+
toWallet: "funding",
|
|
61054
|
+
balanceAfterTransfer: 0,
|
|
61055
|
+
timestamp: new Date().toISOString(),
|
|
61056
|
+
error: "Transfer not confirmed. Set confirm: true to execute transfer."
|
|
61057
|
+
};
|
|
61058
|
+
}
|
|
61059
|
+
const preview = await this.previewTransfer({ asset, amount });
|
|
61060
|
+
if (!preview.isValid) {
|
|
61061
|
+
return {
|
|
61062
|
+
success: false,
|
|
61063
|
+
asset,
|
|
61064
|
+
amount,
|
|
61065
|
+
fromWallet: "unified",
|
|
61066
|
+
toWallet: "funding",
|
|
61067
|
+
balanceAfterTransfer: 0,
|
|
61068
|
+
timestamp: new Date().toISOString(),
|
|
61069
|
+
error: `Transfer validation failed: ${preview.errors.join("; ")}`
|
|
61070
|
+
};
|
|
61071
|
+
}
|
|
61072
|
+
const transferResult = await this.client.createInternalTransfer(`bybit_transfer_${Date.now()}`, asset.toUpperCase(), amount.toString(), "UNIFIED", "FUND");
|
|
61073
|
+
if (transferResult.retCode !== 0) {
|
|
61074
|
+
throw new Error(`Bybit transfer failed: ${transferResult.retMsg} (code: ${transferResult.retCode})`);
|
|
61075
|
+
}
|
|
61076
|
+
const balanceAfterTransfer = await getWalletBalance2(this.client, asset);
|
|
61077
|
+
return {
|
|
61078
|
+
success: true,
|
|
61079
|
+
transactionId: transferResult.result?.transferId,
|
|
61080
|
+
asset,
|
|
61081
|
+
amount,
|
|
61082
|
+
fromWallet: "unified",
|
|
61083
|
+
toWallet: "funding",
|
|
61084
|
+
balanceAfterTransfer,
|
|
61085
|
+
timestamp: new Date().toISOString()
|
|
61086
|
+
};
|
|
61087
|
+
} catch (error) {
|
|
61088
|
+
console.error(`Error executing transfer for ${asset}:`, error);
|
|
61089
|
+
let currentBalance = 0;
|
|
61090
|
+
try {
|
|
61091
|
+
currentBalance = await getWalletBalance2(this.client, asset);
|
|
61092
|
+
} catch (balanceError) {
|
|
61093
|
+
console.warn("Could not fetch balance for error response:", balanceError);
|
|
61094
|
+
}
|
|
61095
|
+
return {
|
|
61096
|
+
success: false,
|
|
61097
|
+
asset,
|
|
61098
|
+
amount,
|
|
61099
|
+
fromWallet: "unified",
|
|
61100
|
+
toWallet: "funding",
|
|
61101
|
+
balanceAfterTransfer: currentBalance,
|
|
61102
|
+
timestamp: new Date().toISOString(),
|
|
61103
|
+
error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
|
|
61104
|
+
};
|
|
61105
|
+
}
|
|
61106
|
+
}
|
|
60775
61107
|
}
|
|
60776
61108
|
|
|
60777
61109
|
// src/helpers/accounts.ts
|
package/dist/index.js
CHANGED
|
@@ -59989,6 +59989,171 @@ class BinanceExchange extends BaseExchange {
|
|
|
59989
59989
|
async forceClosePosition(symbol, options) {
|
|
59990
59990
|
return await forceClosePosition(this.client, symbol, options);
|
|
59991
59991
|
}
|
|
59992
|
+
async getTransferableAmount(options) {
|
|
59993
|
+
const { asset, maxTransferLimit } = options;
|
|
59994
|
+
try {
|
|
59995
|
+
const futuresBalance = await getWalletBalance(this.client, asset);
|
|
59996
|
+
const allPositions = await this.client.getPositionsV3();
|
|
59997
|
+
const activePositions = allPositions.filter((pos) => Math.abs(pos.positionAmt) > 0);
|
|
59998
|
+
let totalMarginUsed = 0;
|
|
59999
|
+
let totalUnrealizedPnl = 0;
|
|
60000
|
+
for (const position2 of activePositions) {
|
|
60001
|
+
const positionValue = Math.abs(position2.positionAmt) * position2.markPrice;
|
|
60002
|
+
const leverage = await getLeverage(this.client, position2.symbol);
|
|
60003
|
+
const marginForPosition = positionValue / (leverage || 1);
|
|
60004
|
+
console.log({ leverage });
|
|
60005
|
+
totalMarginUsed += marginForPosition;
|
|
60006
|
+
totalUnrealizedPnl += position2.unRealizedProfit || 0;
|
|
60007
|
+
}
|
|
60008
|
+
const safetyMarginPercent = 0.2;
|
|
60009
|
+
const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
|
|
60010
|
+
const adjustedBalance = futuresBalance + totalUnrealizedPnl;
|
|
60011
|
+
const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
|
|
60012
|
+
let maxTransferableAmount = availableForTransfer;
|
|
60013
|
+
let appliedLimit;
|
|
60014
|
+
if (maxTransferLimit && maxTransferLimit > 0) {
|
|
60015
|
+
maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
|
|
60016
|
+
appliedLimit = maxTransferLimit;
|
|
60017
|
+
}
|
|
60018
|
+
const recommendedTransferAmount = maxTransferableAmount * 0.8;
|
|
60019
|
+
const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
|
|
60020
|
+
return {
|
|
60021
|
+
asset,
|
|
60022
|
+
totalBalance: futuresBalance,
|
|
60023
|
+
availableForTransfer,
|
|
60024
|
+
reservedForMargin: requiredMargin,
|
|
60025
|
+
maxTransferableAmount,
|
|
60026
|
+
appliedLimit,
|
|
60027
|
+
recommendedTransferAmount,
|
|
60028
|
+
marginUtilization,
|
|
60029
|
+
safetyMargin: safetyMarginPercent * 100
|
|
60030
|
+
};
|
|
60031
|
+
} catch (error) {
|
|
60032
|
+
console.error(`Error analyzing transferable amount for ${asset}:`, error);
|
|
60033
|
+
throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
|
|
60034
|
+
}
|
|
60035
|
+
}
|
|
60036
|
+
async previewTransfer(options) {
|
|
60037
|
+
const { asset, amount } = options;
|
|
60038
|
+
const warnings = [];
|
|
60039
|
+
const errors = [];
|
|
60040
|
+
try {
|
|
60041
|
+
const analysis = await this.getTransferableAmount({ asset });
|
|
60042
|
+
let isValid2 = true;
|
|
60043
|
+
if (amount <= 0) {
|
|
60044
|
+
errors.push("Transfer amount must be greater than zero");
|
|
60045
|
+
isValid2 = false;
|
|
60046
|
+
}
|
|
60047
|
+
if (amount > analysis.maxTransferableAmount) {
|
|
60048
|
+
errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
|
|
60049
|
+
isValid2 = false;
|
|
60050
|
+
}
|
|
60051
|
+
if (amount > analysis.recommendedTransferAmount) {
|
|
60052
|
+
warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
|
|
60053
|
+
}
|
|
60054
|
+
if (analysis.marginUtilization > 70) {
|
|
60055
|
+
warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
|
|
60056
|
+
}
|
|
60057
|
+
const balanceAfterTransfer = analysis.totalBalance - amount;
|
|
60058
|
+
const marginRequirementAfterTransfer = analysis.reservedForMargin;
|
|
60059
|
+
if (isValid2 && balanceAfterTransfer < marginRequirementAfterTransfer) {
|
|
60060
|
+
errors.push("Transfer would result in insufficient margin for existing positions");
|
|
60061
|
+
isValid2 = false;
|
|
60062
|
+
}
|
|
60063
|
+
return {
|
|
60064
|
+
asset,
|
|
60065
|
+
requestedAmount: amount,
|
|
60066
|
+
isValid: isValid2,
|
|
60067
|
+
balanceAfterTransfer,
|
|
60068
|
+
marginRequirementAfterTransfer,
|
|
60069
|
+
warnings,
|
|
60070
|
+
errors
|
|
60071
|
+
};
|
|
60072
|
+
} catch (error) {
|
|
60073
|
+
console.error(`Error previewing transfer for ${asset}:`, error);
|
|
60074
|
+
return {
|
|
60075
|
+
asset,
|
|
60076
|
+
requestedAmount: amount,
|
|
60077
|
+
isValid: false,
|
|
60078
|
+
balanceAfterTransfer: 0,
|
|
60079
|
+
marginRequirementAfterTransfer: 0,
|
|
60080
|
+
warnings,
|
|
60081
|
+
errors: [`Failed to preview transfer: ${error instanceof Error ? error.message : error}`]
|
|
60082
|
+
};
|
|
60083
|
+
}
|
|
60084
|
+
}
|
|
60085
|
+
async executeFutureToSpotTransfer(options) {
|
|
60086
|
+
const { asset, amount, confirm, symbol = "BTCUSDT" } = options;
|
|
60087
|
+
try {
|
|
60088
|
+
if (!confirm) {
|
|
60089
|
+
return {
|
|
60090
|
+
success: false,
|
|
60091
|
+
asset,
|
|
60092
|
+
amount,
|
|
60093
|
+
fromWallet: "futures",
|
|
60094
|
+
toWallet: "spot",
|
|
60095
|
+
balanceAfterTransfer: 0,
|
|
60096
|
+
timestamp: new Date().toISOString(),
|
|
60097
|
+
error: "Transfer not confirmed. Set confirm: true to execute transfer."
|
|
60098
|
+
};
|
|
60099
|
+
}
|
|
60100
|
+
const preview = await this.previewTransfer({ asset, amount });
|
|
60101
|
+
if (!preview.isValid) {
|
|
60102
|
+
return {
|
|
60103
|
+
success: false,
|
|
60104
|
+
asset,
|
|
60105
|
+
amount,
|
|
60106
|
+
fromWallet: "futures",
|
|
60107
|
+
toWallet: "spot",
|
|
60108
|
+
balanceAfterTransfer: 0,
|
|
60109
|
+
timestamp: new Date().toISOString(),
|
|
60110
|
+
error: `Transfer validation failed: ${preview.errors.join("; ")}`
|
|
60111
|
+
};
|
|
60112
|
+
}
|
|
60113
|
+
const is_coin = !["USDT", "USDC", "BUSD"].includes(asset.toUpperCase());
|
|
60114
|
+
const transferType = is_coin ? CONSTANTS.COIN_FUTURE_TO_SPOT : CONSTANTS.USDT_FUTURE_TO_SPOT;
|
|
60115
|
+
if (!this.main_client) {
|
|
60116
|
+
throw new Error("Main client not available for transfers");
|
|
60117
|
+
}
|
|
60118
|
+
const transferClient = this.main_client;
|
|
60119
|
+
const transferResult = await transferClient.submitUniversalTransfer({
|
|
60120
|
+
asset: asset.toUpperCase(),
|
|
60121
|
+
amount,
|
|
60122
|
+
type: transferType,
|
|
60123
|
+
fromSymbol: symbol,
|
|
60124
|
+
toSymbol: symbol
|
|
60125
|
+
});
|
|
60126
|
+
const balanceAfterTransfer = await getWalletBalance(this.client, asset);
|
|
60127
|
+
return {
|
|
60128
|
+
success: true,
|
|
60129
|
+
transactionId: transferResult.tranId?.toString(),
|
|
60130
|
+
asset,
|
|
60131
|
+
amount,
|
|
60132
|
+
fromWallet: "futures",
|
|
60133
|
+
toWallet: "spot",
|
|
60134
|
+
balanceAfterTransfer,
|
|
60135
|
+
timestamp: new Date().toISOString()
|
|
60136
|
+
};
|
|
60137
|
+
} catch (error) {
|
|
60138
|
+
console.error(`Error executing transfer for ${asset}:`, error);
|
|
60139
|
+
let currentBalance = 0;
|
|
60140
|
+
try {
|
|
60141
|
+
currentBalance = await getWalletBalance(this.client, asset);
|
|
60142
|
+
} catch (balanceError) {
|
|
60143
|
+
console.warn("Could not fetch balance for error response:", balanceError);
|
|
60144
|
+
}
|
|
60145
|
+
return {
|
|
60146
|
+
success: false,
|
|
60147
|
+
asset,
|
|
60148
|
+
amount,
|
|
60149
|
+
fromWallet: "futures",
|
|
60150
|
+
toWallet: "spot",
|
|
60151
|
+
balanceAfterTransfer: currentBalance,
|
|
60152
|
+
timestamp: new Date().toISOString(),
|
|
60153
|
+
error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
|
|
60154
|
+
};
|
|
60155
|
+
}
|
|
60156
|
+
}
|
|
59992
60157
|
}
|
|
59993
60158
|
function getPricePlaces(target) {
|
|
59994
60159
|
const numStr = target.toString();
|
|
@@ -60314,6 +60479,11 @@ async function placeStopOrder2(client, payload) {
|
|
|
60314
60479
|
stop: payload.final_stop,
|
|
60315
60480
|
is_market: !payload.is_limit
|
|
60316
60481
|
};
|
|
60482
|
+
if (payload.hedge) {
|
|
60483
|
+
let reverse_kind = payload.kind === "long" ? "short" : "long";
|
|
60484
|
+
order.kind = reverse_kind;
|
|
60485
|
+
order.is_market = false;
|
|
60486
|
+
}
|
|
60317
60487
|
return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
60318
60488
|
}
|
|
60319
60489
|
async function getOpenOrders2(client, symbol, type) {
|
|
@@ -60710,6 +60880,168 @@ class BybitExchange extends BaseExchange {
|
|
|
60710
60880
|
return getOpenOrders2(this.client, payload.symbol);
|
|
60711
60881
|
}
|
|
60712
60882
|
async placeBadStopEntry(payload) {}
|
|
60883
|
+
async getTransferableAmount(options) {
|
|
60884
|
+
const { asset, maxTransferLimit } = options;
|
|
60885
|
+
try {
|
|
60886
|
+
const unifiedBalance = await getWalletBalance2(this.client, asset);
|
|
60887
|
+
const allPositions = await this.client.getPositionInfo({
|
|
60888
|
+
category: "linear",
|
|
60889
|
+
settleCoin: asset
|
|
60890
|
+
});
|
|
60891
|
+
const activePositions = (allPositions.result.list || []).filter((pos) => Math.abs(parseFloat(pos.size || "0")) > 0);
|
|
60892
|
+
let totalMarginUsed = 0;
|
|
60893
|
+
let totalUnrealizedPnl = 0;
|
|
60894
|
+
for (const position2 of activePositions) {
|
|
60895
|
+
const positionSize = Math.abs(parseFloat(position2.size || "0"));
|
|
60896
|
+
const markPrice = parseFloat(position2.markPrice || "0");
|
|
60897
|
+
const leverage = parseFloat(position2.leverage || "1");
|
|
60898
|
+
const positionValue = positionSize * markPrice;
|
|
60899
|
+
const marginForPosition = positionValue / leverage;
|
|
60900
|
+
totalMarginUsed += marginForPosition;
|
|
60901
|
+
totalUnrealizedPnl += parseFloat(position2.unrealisedPnl || "0");
|
|
60902
|
+
}
|
|
60903
|
+
const safetyMarginPercent = 0.2;
|
|
60904
|
+
const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
|
|
60905
|
+
const adjustedBalance = unifiedBalance + totalUnrealizedPnl;
|
|
60906
|
+
const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
|
|
60907
|
+
let maxTransferableAmount = availableForTransfer;
|
|
60908
|
+
let appliedLimit;
|
|
60909
|
+
if (maxTransferLimit && maxTransferLimit > 0) {
|
|
60910
|
+
maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
|
|
60911
|
+
appliedLimit = maxTransferLimit;
|
|
60912
|
+
}
|
|
60913
|
+
const recommendedTransferAmount = maxTransferableAmount * 0.8;
|
|
60914
|
+
const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
|
|
60915
|
+
return {
|
|
60916
|
+
asset,
|
|
60917
|
+
totalBalance: unifiedBalance,
|
|
60918
|
+
availableForTransfer,
|
|
60919
|
+
reservedForMargin: requiredMargin,
|
|
60920
|
+
maxTransferableAmount,
|
|
60921
|
+
appliedLimit,
|
|
60922
|
+
recommendedTransferAmount,
|
|
60923
|
+
marginUtilization,
|
|
60924
|
+
safetyMargin: safetyMarginPercent * 100
|
|
60925
|
+
};
|
|
60926
|
+
} catch (error) {
|
|
60927
|
+
console.error(`Error analyzing transferable amount for ${asset}:`, error);
|
|
60928
|
+
throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
|
|
60929
|
+
}
|
|
60930
|
+
}
|
|
60931
|
+
async previewTransfer(options) {
|
|
60932
|
+
const { asset, amount } = options;
|
|
60933
|
+
const warnings = [];
|
|
60934
|
+
const errors = [];
|
|
60935
|
+
try {
|
|
60936
|
+
const analysis = await this.getTransferableAmount({ asset });
|
|
60937
|
+
let isValid2 = true;
|
|
60938
|
+
if (amount <= 0) {
|
|
60939
|
+
errors.push("Transfer amount must be greater than zero");
|
|
60940
|
+
isValid2 = false;
|
|
60941
|
+
}
|
|
60942
|
+
if (amount > analysis.maxTransferableAmount) {
|
|
60943
|
+
errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
|
|
60944
|
+
isValid2 = false;
|
|
60945
|
+
}
|
|
60946
|
+
if (amount > analysis.recommendedTransferAmount) {
|
|
60947
|
+
warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
|
|
60948
|
+
}
|
|
60949
|
+
if (analysis.marginUtilization > 70) {
|
|
60950
|
+
warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
|
|
60951
|
+
}
|
|
60952
|
+
const balanceAfterTransfer = analysis.totalBalance - amount;
|
|
60953
|
+
const marginRequirementAfterTransfer = analysis.reservedForMargin;
|
|
60954
|
+
if (isValid2 && balanceAfterTransfer < marginRequirementAfterTransfer) {
|
|
60955
|
+
errors.push("Transfer would result in insufficient margin for existing positions");
|
|
60956
|
+
isValid2 = false;
|
|
60957
|
+
}
|
|
60958
|
+
return {
|
|
60959
|
+
asset,
|
|
60960
|
+
requestedAmount: amount,
|
|
60961
|
+
isValid: isValid2,
|
|
60962
|
+
balanceAfterTransfer,
|
|
60963
|
+
marginRequirementAfterTransfer,
|
|
60964
|
+
warnings,
|
|
60965
|
+
errors
|
|
60966
|
+
};
|
|
60967
|
+
} catch (error) {
|
|
60968
|
+
console.error(`Error previewing transfer for ${asset}:`, error);
|
|
60969
|
+
return {
|
|
60970
|
+
asset,
|
|
60971
|
+
requestedAmount: amount,
|
|
60972
|
+
isValid: false,
|
|
60973
|
+
balanceAfterTransfer: 0,
|
|
60974
|
+
marginRequirementAfterTransfer: 0,
|
|
60975
|
+
warnings,
|
|
60976
|
+
errors: [
|
|
60977
|
+
`Failed to preview transfer: ${error instanceof Error ? error.message : error}`
|
|
60978
|
+
]
|
|
60979
|
+
};
|
|
60980
|
+
}
|
|
60981
|
+
}
|
|
60982
|
+
async executeUnifiedToFundingTransfer(options) {
|
|
60983
|
+
const { asset, amount, confirm } = options;
|
|
60984
|
+
try {
|
|
60985
|
+
if (!confirm) {
|
|
60986
|
+
return {
|
|
60987
|
+
success: false,
|
|
60988
|
+
asset,
|
|
60989
|
+
amount,
|
|
60990
|
+
fromWallet: "unified",
|
|
60991
|
+
toWallet: "funding",
|
|
60992
|
+
balanceAfterTransfer: 0,
|
|
60993
|
+
timestamp: new Date().toISOString(),
|
|
60994
|
+
error: "Transfer not confirmed. Set confirm: true to execute transfer."
|
|
60995
|
+
};
|
|
60996
|
+
}
|
|
60997
|
+
const preview = await this.previewTransfer({ asset, amount });
|
|
60998
|
+
if (!preview.isValid) {
|
|
60999
|
+
return {
|
|
61000
|
+
success: false,
|
|
61001
|
+
asset,
|
|
61002
|
+
amount,
|
|
61003
|
+
fromWallet: "unified",
|
|
61004
|
+
toWallet: "funding",
|
|
61005
|
+
balanceAfterTransfer: 0,
|
|
61006
|
+
timestamp: new Date().toISOString(),
|
|
61007
|
+
error: `Transfer validation failed: ${preview.errors.join("; ")}`
|
|
61008
|
+
};
|
|
61009
|
+
}
|
|
61010
|
+
const transferResult = await this.client.createInternalTransfer(`bybit_transfer_${Date.now()}`, asset.toUpperCase(), amount.toString(), "UNIFIED", "FUND");
|
|
61011
|
+
if (transferResult.retCode !== 0) {
|
|
61012
|
+
throw new Error(`Bybit transfer failed: ${transferResult.retMsg} (code: ${transferResult.retCode})`);
|
|
61013
|
+
}
|
|
61014
|
+
const balanceAfterTransfer = await getWalletBalance2(this.client, asset);
|
|
61015
|
+
return {
|
|
61016
|
+
success: true,
|
|
61017
|
+
transactionId: transferResult.result?.transferId,
|
|
61018
|
+
asset,
|
|
61019
|
+
amount,
|
|
61020
|
+
fromWallet: "unified",
|
|
61021
|
+
toWallet: "funding",
|
|
61022
|
+
balanceAfterTransfer,
|
|
61023
|
+
timestamp: new Date().toISOString()
|
|
61024
|
+
};
|
|
61025
|
+
} catch (error) {
|
|
61026
|
+
console.error(`Error executing transfer for ${asset}:`, error);
|
|
61027
|
+
let currentBalance = 0;
|
|
61028
|
+
try {
|
|
61029
|
+
currentBalance = await getWalletBalance2(this.client, asset);
|
|
61030
|
+
} catch (balanceError) {
|
|
61031
|
+
console.warn("Could not fetch balance for error response:", balanceError);
|
|
61032
|
+
}
|
|
61033
|
+
return {
|
|
61034
|
+
success: false,
|
|
61035
|
+
asset,
|
|
61036
|
+
amount,
|
|
61037
|
+
fromWallet: "unified",
|
|
61038
|
+
toWallet: "funding",
|
|
61039
|
+
balanceAfterTransfer: currentBalance,
|
|
61040
|
+
timestamp: new Date().toISOString(),
|
|
61041
|
+
error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
|
|
61042
|
+
};
|
|
61043
|
+
}
|
|
61044
|
+
}
|
|
60713
61045
|
}
|
|
60714
61046
|
|
|
60715
61047
|
// src/helpers/accounts.ts
|