@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.
- package/dist/frontend-index.d.ts +7 -0
- package/dist/frontend-index.js +21 -4
- package/dist/index.cjs +353 -4
- package/dist/index.d.ts +11 -0
- package/dist/index.js +353 -4
- package/dist/mcp-server.cjs +353 -4
- package/dist/mcp-server.js +353 -4
- package/package.json +1 -1
package/dist/frontend-index.d.ts
CHANGED
|
@@ -642,6 +642,7 @@ export declare function determineOptimumReward(payload: {
|
|
|
642
642
|
high_range?: number;
|
|
643
643
|
target_loss?: number;
|
|
644
644
|
distribution?: GetEntriesParams["distribution"];
|
|
645
|
+
max_size?: number;
|
|
645
646
|
}): number | {
|
|
646
647
|
result: any[];
|
|
647
648
|
value: number;
|
|
@@ -649,6 +650,7 @@ export declare function determineOptimumReward(payload: {
|
|
|
649
650
|
risk_per_trade: number;
|
|
650
651
|
max: number;
|
|
651
652
|
min: number;
|
|
653
|
+
avg_size: any;
|
|
652
654
|
neg_pnl: any;
|
|
653
655
|
entry: any;
|
|
654
656
|
};
|
|
@@ -681,6 +683,7 @@ export declare function computeRiskReward(payload: {
|
|
|
681
683
|
risk_per_trade: number;
|
|
682
684
|
target_loss?: number;
|
|
683
685
|
distribution?: GetEntriesParams["distribution"];
|
|
686
|
+
max_size?: number;
|
|
684
687
|
}): number | {
|
|
685
688
|
result: any[];
|
|
686
689
|
value: number;
|
|
@@ -688,6 +691,7 @@ export declare function computeRiskReward(payload: {
|
|
|
688
691
|
risk_per_trade: number;
|
|
689
692
|
max: number;
|
|
690
693
|
min: number;
|
|
694
|
+
avg_size: any;
|
|
691
695
|
neg_pnl: any;
|
|
692
696
|
entry: any;
|
|
693
697
|
};
|
|
@@ -698,6 +702,7 @@ export declare function getRiskReward(payload: {
|
|
|
698
702
|
global_config: GlobalConfig;
|
|
699
703
|
force_exact_risk?: boolean;
|
|
700
704
|
target_loss?: number;
|
|
705
|
+
max_size?: number;
|
|
701
706
|
distribution?: GetEntriesParams["distribution"];
|
|
702
707
|
}): any;
|
|
703
708
|
export declare function computeProfitDetail(payload: {
|
|
@@ -913,6 +918,7 @@ export declare function generateOppositeTradeConfig(payload: {
|
|
|
913
918
|
risk_per_trade: number;
|
|
914
919
|
max: number;
|
|
915
920
|
min: number;
|
|
921
|
+
avg_size: any;
|
|
916
922
|
neg_pnl: any;
|
|
917
923
|
entry: any;
|
|
918
924
|
};
|
|
@@ -980,6 +986,7 @@ export declare function generateDangerousConfig(payload: {
|
|
|
980
986
|
risk_per_trade: number;
|
|
981
987
|
max: number;
|
|
982
988
|
min: number;
|
|
989
|
+
avg_size: any;
|
|
983
990
|
neg_pnl: any;
|
|
984
991
|
entry: any;
|
|
985
992
|
};
|
package/dist/frontend-index.js
CHANGED
|
@@ -2110,7 +2110,8 @@ function determineOptimumReward(payload) {
|
|
|
2110
2110
|
low_range = 1,
|
|
2111
2111
|
high_range = 199,
|
|
2112
2112
|
target_loss,
|
|
2113
|
-
distribution
|
|
2113
|
+
distribution,
|
|
2114
|
+
max_size
|
|
2114
2115
|
} = payload;
|
|
2115
2116
|
const criterion = app_config.strategy || "quantity";
|
|
2116
2117
|
const risk_rewards = createArray(low_range, high_range, 1);
|
|
@@ -2132,6 +2133,7 @@ function determineOptimumReward(payload) {
|
|
|
2132
2133
|
let min = Infinity;
|
|
2133
2134
|
let neg_pnl = trades[0]?.neg_pnl || 0;
|
|
2134
2135
|
let entry = trades.at(-1)?.entry;
|
|
2136
|
+
let avg_size = trades[0]?.avg_size || 0;
|
|
2135
2137
|
if (!entry) {
|
|
2136
2138
|
return null;
|
|
2137
2139
|
}
|
|
@@ -2148,11 +2150,15 @@ function determineOptimumReward(payload) {
|
|
|
2148
2150
|
risk_per_trade: app_config.risk_per_trade,
|
|
2149
2151
|
max,
|
|
2150
2152
|
min,
|
|
2153
|
+
avg_size,
|
|
2151
2154
|
neg_pnl,
|
|
2152
2155
|
entry
|
|
2153
2156
|
};
|
|
2154
2157
|
});
|
|
2155
2158
|
func = func.filter((r) => Boolean(r));
|
|
2159
|
+
if (max_size !== undefined && max_size > 0) {
|
|
2160
|
+
func = func.filter((r) => r.avg_size <= max_size);
|
|
2161
|
+
}
|
|
2156
2162
|
if (target_loss === undefined) {
|
|
2157
2163
|
func = func.filter((r) => {
|
|
2158
2164
|
let foundIndex = r?.result.findIndex((e) => e.quantity === r.max);
|
|
@@ -2290,7 +2296,15 @@ function determineOptimumRisk(config, payload, params) {
|
|
|
2290
2296
|
};
|
|
2291
2297
|
}
|
|
2292
2298
|
function computeRiskReward(payload) {
|
|
2293
|
-
const {
|
|
2299
|
+
const {
|
|
2300
|
+
app_config,
|
|
2301
|
+
entry,
|
|
2302
|
+
stop,
|
|
2303
|
+
risk_per_trade,
|
|
2304
|
+
target_loss,
|
|
2305
|
+
distribution,
|
|
2306
|
+
max_size
|
|
2307
|
+
} = payload;
|
|
2294
2308
|
const kind = entry > stop ? "long" : "short";
|
|
2295
2309
|
app_config.kind = kind;
|
|
2296
2310
|
app_config.entry = entry;
|
|
@@ -2299,12 +2313,14 @@ function computeRiskReward(payload) {
|
|
|
2299
2313
|
const result = determineOptimumReward({
|
|
2300
2314
|
app_config,
|
|
2301
2315
|
target_loss,
|
|
2302
|
-
distribution
|
|
2316
|
+
distribution,
|
|
2317
|
+
max_size
|
|
2303
2318
|
});
|
|
2304
2319
|
return result;
|
|
2305
2320
|
}
|
|
2306
2321
|
function getRiskReward(payload) {
|
|
2307
2322
|
const {
|
|
2323
|
+
max_size,
|
|
2308
2324
|
entry,
|
|
2309
2325
|
stop,
|
|
2310
2326
|
risk,
|
|
@@ -2327,7 +2343,8 @@ function getRiskReward(payload) {
|
|
|
2327
2343
|
stop,
|
|
2328
2344
|
risk_per_trade: risk,
|
|
2329
2345
|
target_loss,
|
|
2330
|
-
distribution
|
|
2346
|
+
distribution,
|
|
2347
|
+
max_size
|
|
2331
2348
|
});
|
|
2332
2349
|
if (force_exact_risk) {
|
|
2333
2350
|
const new_risk_per_trade = determineOptimumRisk(global_config, {
|
package/dist/index.cjs
CHANGED
|
@@ -57489,7 +57489,8 @@ function determineOptimumReward(payload) {
|
|
|
57489
57489
|
low_range = 1,
|
|
57490
57490
|
high_range = 199,
|
|
57491
57491
|
target_loss,
|
|
57492
|
-
distribution
|
|
57492
|
+
distribution,
|
|
57493
|
+
max_size
|
|
57493
57494
|
} = payload;
|
|
57494
57495
|
const criterion = app_config.strategy || "quantity";
|
|
57495
57496
|
const risk_rewards = createArray(low_range, high_range, 1);
|
|
@@ -57511,6 +57512,7 @@ function determineOptimumReward(payload) {
|
|
|
57511
57512
|
let min = Infinity;
|
|
57512
57513
|
let neg_pnl = trades[0]?.neg_pnl || 0;
|
|
57513
57514
|
let entry = trades.at(-1)?.entry;
|
|
57515
|
+
let avg_size = trades[0]?.avg_size || 0;
|
|
57514
57516
|
if (!entry) {
|
|
57515
57517
|
return null;
|
|
57516
57518
|
}
|
|
@@ -57527,11 +57529,15 @@ function determineOptimumReward(payload) {
|
|
|
57527
57529
|
risk_per_trade: app_config.risk_per_trade,
|
|
57528
57530
|
max,
|
|
57529
57531
|
min,
|
|
57532
|
+
avg_size,
|
|
57530
57533
|
neg_pnl,
|
|
57531
57534
|
entry
|
|
57532
57535
|
};
|
|
57533
57536
|
});
|
|
57534
57537
|
func = func.filter((r2) => Boolean(r2));
|
|
57538
|
+
if (max_size !== undefined && max_size > 0) {
|
|
57539
|
+
func = func.filter((r2) => r2.avg_size <= max_size);
|
|
57540
|
+
}
|
|
57535
57541
|
if (target_loss === undefined) {
|
|
57536
57542
|
func = func.filter((r2) => {
|
|
57537
57543
|
let foundIndex = r2?.result.findIndex((e2) => e2.quantity === r2.max);
|
|
@@ -57669,7 +57675,15 @@ function determineOptimumRisk(config2, payload, params) {
|
|
|
57669
57675
|
};
|
|
57670
57676
|
}
|
|
57671
57677
|
function computeRiskReward(payload) {
|
|
57672
|
-
const {
|
|
57678
|
+
const {
|
|
57679
|
+
app_config,
|
|
57680
|
+
entry,
|
|
57681
|
+
stop,
|
|
57682
|
+
risk_per_trade,
|
|
57683
|
+
target_loss,
|
|
57684
|
+
distribution,
|
|
57685
|
+
max_size
|
|
57686
|
+
} = payload;
|
|
57673
57687
|
const kind = entry > stop ? "long" : "short";
|
|
57674
57688
|
app_config.kind = kind;
|
|
57675
57689
|
app_config.entry = entry;
|
|
@@ -57678,12 +57692,14 @@ function computeRiskReward(payload) {
|
|
|
57678
57692
|
const result = determineOptimumReward({
|
|
57679
57693
|
app_config,
|
|
57680
57694
|
target_loss,
|
|
57681
|
-
distribution
|
|
57695
|
+
distribution,
|
|
57696
|
+
max_size
|
|
57682
57697
|
});
|
|
57683
57698
|
return result;
|
|
57684
57699
|
}
|
|
57685
57700
|
function getRiskReward(payload) {
|
|
57686
57701
|
const {
|
|
57702
|
+
max_size,
|
|
57687
57703
|
entry,
|
|
57688
57704
|
stop,
|
|
57689
57705
|
risk,
|
|
@@ -57706,7 +57722,8 @@ function getRiskReward(payload) {
|
|
|
57706
57722
|
stop,
|
|
57707
57723
|
risk_per_trade: risk,
|
|
57708
57724
|
target_loss,
|
|
57709
|
-
distribution
|
|
57725
|
+
distribution,
|
|
57726
|
+
max_size
|
|
57710
57727
|
});
|
|
57711
57728
|
if (force_exact_risk) {
|
|
57712
57729
|
const new_risk_per_trade = determineOptimumRisk(global_config, {
|
|
@@ -60034,6 +60051,171 @@ class BinanceExchange extends BaseExchange {
|
|
|
60034
60051
|
async forceClosePosition(symbol, options) {
|
|
60035
60052
|
return await forceClosePosition(this.client, symbol, options);
|
|
60036
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
|
+
}
|
|
60037
60219
|
}
|
|
60038
60220
|
function getPricePlaces(target) {
|
|
60039
60221
|
const numStr = target.toString();
|
|
@@ -60359,6 +60541,11 @@ async function placeStopOrder2(client, payload) {
|
|
|
60359
60541
|
stop: payload.final_stop,
|
|
60360
60542
|
is_market: !payload.is_limit
|
|
60361
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
|
+
}
|
|
60362
60549
|
return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
60363
60550
|
}
|
|
60364
60551
|
async function getOpenOrders2(client, symbol, type) {
|
|
@@ -60755,6 +60942,168 @@ class BybitExchange extends BaseExchange {
|
|
|
60755
60942
|
return getOpenOrders2(this.client, payload.symbol);
|
|
60756
60943
|
}
|
|
60757
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
|
+
}
|
|
60758
61107
|
}
|
|
60759
61108
|
|
|
60760
61109
|
// src/helpers/accounts.ts
|
package/dist/index.d.ts
CHANGED
|
@@ -1549,6 +1549,7 @@ export declare function determineOptimumReward(payload: {
|
|
|
1549
1549
|
high_range?: number;
|
|
1550
1550
|
target_loss?: number;
|
|
1551
1551
|
distribution?: GetEntriesParams["distribution"];
|
|
1552
|
+
max_size?: number;
|
|
1552
1553
|
}): number | {
|
|
1553
1554
|
result: any[];
|
|
1554
1555
|
value: number;
|
|
@@ -1556,6 +1557,7 @@ export declare function determineOptimumReward(payload: {
|
|
|
1556
1557
|
risk_per_trade: number;
|
|
1557
1558
|
max: number;
|
|
1558
1559
|
min: number;
|
|
1560
|
+
avg_size: any;
|
|
1559
1561
|
neg_pnl: any;
|
|
1560
1562
|
entry: any;
|
|
1561
1563
|
};
|
|
@@ -1588,6 +1590,7 @@ export declare function computeRiskReward(payload: {
|
|
|
1588
1590
|
risk_per_trade: number;
|
|
1589
1591
|
target_loss?: number;
|
|
1590
1592
|
distribution?: GetEntriesParams["distribution"];
|
|
1593
|
+
max_size?: number;
|
|
1591
1594
|
}): number | {
|
|
1592
1595
|
result: any[];
|
|
1593
1596
|
value: number;
|
|
@@ -1595,6 +1598,7 @@ export declare function computeRiskReward(payload: {
|
|
|
1595
1598
|
risk_per_trade: number;
|
|
1596
1599
|
max: number;
|
|
1597
1600
|
min: number;
|
|
1601
|
+
avg_size: any;
|
|
1598
1602
|
neg_pnl: any;
|
|
1599
1603
|
entry: any;
|
|
1600
1604
|
};
|
|
@@ -1605,6 +1609,7 @@ export declare function getRiskReward(payload: {
|
|
|
1605
1609
|
global_config: GlobalConfig;
|
|
1606
1610
|
force_exact_risk?: boolean;
|
|
1607
1611
|
target_loss?: number;
|
|
1612
|
+
max_size?: number;
|
|
1608
1613
|
distribution?: GetEntriesParams["distribution"];
|
|
1609
1614
|
}): any;
|
|
1610
1615
|
export declare function computeProfitDetail(payload: {
|
|
@@ -1820,6 +1825,7 @@ export declare function generateOppositeTradeConfig(payload: {
|
|
|
1820
1825
|
risk_per_trade: number;
|
|
1821
1826
|
max: number;
|
|
1822
1827
|
min: number;
|
|
1828
|
+
avg_size: any;
|
|
1823
1829
|
neg_pnl: any;
|
|
1824
1830
|
entry: any;
|
|
1825
1831
|
};
|
|
@@ -1887,6 +1893,7 @@ export declare function generateDangerousConfig(payload: {
|
|
|
1887
1893
|
risk_per_trade: number;
|
|
1888
1894
|
max: number;
|
|
1889
1895
|
min: number;
|
|
1896
|
+
avg_size: any;
|
|
1890
1897
|
neg_pnl: any;
|
|
1891
1898
|
entry: any;
|
|
1892
1899
|
};
|
|
@@ -2238,6 +2245,7 @@ export declare class ExchangePosition {
|
|
|
2238
2245
|
risk_per_trade: number;
|
|
2239
2246
|
max: number;
|
|
2240
2247
|
min: number;
|
|
2248
|
+
avg_size: any;
|
|
2241
2249
|
neg_pnl: any;
|
|
2242
2250
|
entry: any;
|
|
2243
2251
|
};
|
|
@@ -2249,6 +2257,7 @@ export declare class ExchangePosition {
|
|
|
2249
2257
|
risk_per_trade: number;
|
|
2250
2258
|
max: number;
|
|
2251
2259
|
min: number;
|
|
2260
|
+
avg_size: any;
|
|
2252
2261
|
neg_pnl: any;
|
|
2253
2262
|
entry: any;
|
|
2254
2263
|
}>;
|
|
@@ -2326,6 +2335,7 @@ export declare class ExchangePosition {
|
|
|
2326
2335
|
risk_per_trade: number;
|
|
2327
2336
|
max: number;
|
|
2328
2337
|
min: number;
|
|
2338
|
+
avg_size: any;
|
|
2329
2339
|
neg_pnl: any;
|
|
2330
2340
|
entry: any;
|
|
2331
2341
|
};
|
|
@@ -2902,6 +2912,7 @@ declare class ExchangeAccount$1 {
|
|
|
2902
2912
|
risk_per_trade: number;
|
|
2903
2913
|
max: number;
|
|
2904
2914
|
min: number;
|
|
2915
|
+
avg_size: any;
|
|
2905
2916
|
neg_pnl: any;
|
|
2906
2917
|
entry: any;
|
|
2907
2918
|
};
|