@gbozee/ultimate 0.0.2-192 → 0.0.2-194
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 +5 -0
- package/dist/frontend-index.js +3 -0
- package/dist/index.cjs +373 -185
- package/dist/index.d.ts +3 -98
- package/dist/index.js +373 -185
- package/dist/mcp-server.cjs +332 -147
- package/dist/mcp-server.js +332 -147
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38677,20 +38677,20 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
38677
38677
|
var reduceDescriptors = (obj, reducer) => {
|
|
38678
38678
|
const descriptors2 = Object.getOwnPropertyDescriptors(obj);
|
|
38679
38679
|
const reducedDescriptors = {};
|
|
38680
|
-
forEach2(descriptors2, (descriptor,
|
|
38680
|
+
forEach2(descriptors2, (descriptor, name3) => {
|
|
38681
38681
|
let ret;
|
|
38682
|
-
if ((ret = reducer(descriptor,
|
|
38683
|
-
reducedDescriptors[
|
|
38682
|
+
if ((ret = reducer(descriptor, name3, obj)) !== false) {
|
|
38683
|
+
reducedDescriptors[name3] = ret || descriptor;
|
|
38684
38684
|
}
|
|
38685
38685
|
});
|
|
38686
38686
|
Object.defineProperties(obj, reducedDescriptors);
|
|
38687
38687
|
};
|
|
38688
38688
|
var freezeMethods = (obj) => {
|
|
38689
|
-
reduceDescriptors(obj, (descriptor,
|
|
38690
|
-
if (isFunction(obj) && ["arguments", "caller", "callee"].indexOf(
|
|
38689
|
+
reduceDescriptors(obj, (descriptor, name3) => {
|
|
38690
|
+
if (isFunction(obj) && ["arguments", "caller", "callee"].indexOf(name3) !== -1) {
|
|
38691
38691
|
return false;
|
|
38692
38692
|
}
|
|
38693
|
-
const value2 = obj[
|
|
38693
|
+
const value2 = obj[name3];
|
|
38694
38694
|
if (!isFunction(value2))
|
|
38695
38695
|
return;
|
|
38696
38696
|
descriptor.enumerable = false;
|
|
@@ -38700,7 +38700,7 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
38700
38700
|
}
|
|
38701
38701
|
if (!descriptor.set) {
|
|
38702
38702
|
descriptor.set = () => {
|
|
38703
|
-
throw Error("Can not rewrite read-only method '" +
|
|
38703
|
+
throw Error("Can not rewrite read-only method '" + name3 + "'");
|
|
38704
38704
|
};
|
|
38705
38705
|
}
|
|
38706
38706
|
});
|
|
@@ -39008,8 +39008,8 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
39008
39008
|
params && toFormData(params, this, options);
|
|
39009
39009
|
}
|
|
39010
39010
|
var prototype = AxiosURLSearchParams.prototype;
|
|
39011
|
-
prototype.append = function append(
|
|
39012
|
-
this._pairs.push([
|
|
39011
|
+
prototype.append = function append(name3, value2) {
|
|
39012
|
+
this._pairs.push([name3, value2]);
|
|
39013
39013
|
};
|
|
39014
39014
|
prototype.toString = function toString(encoder2) {
|
|
39015
39015
|
const _encode = encoder2 ? function(value2) {
|
|
@@ -39145,8 +39145,8 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
39145
39145
|
}
|
|
39146
39146
|
}, options));
|
|
39147
39147
|
}
|
|
39148
|
-
function parsePropPath(
|
|
39149
|
-
return utils$1.matchAll(/\w+|\[(\w*)]/g,
|
|
39148
|
+
function parsePropPath(name3) {
|
|
39149
|
+
return utils$1.matchAll(/\w+|\[(\w*)]/g, name3).map((match) => {
|
|
39150
39150
|
return match[0] === "[]" ? "" : match[1] || match[0];
|
|
39151
39151
|
});
|
|
39152
39152
|
}
|
|
@@ -39164,33 +39164,33 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
39164
39164
|
}
|
|
39165
39165
|
function formDataToJSON(formData) {
|
|
39166
39166
|
function buildPath(path, value2, target, index) {
|
|
39167
|
-
let
|
|
39168
|
-
if (
|
|
39167
|
+
let name3 = path[index++];
|
|
39168
|
+
if (name3 === "__proto__")
|
|
39169
39169
|
return true;
|
|
39170
|
-
const isNumericKey = Number.isFinite(+
|
|
39170
|
+
const isNumericKey = Number.isFinite(+name3);
|
|
39171
39171
|
const isLast = index >= path.length;
|
|
39172
|
-
|
|
39172
|
+
name3 = !name3 && utils$1.isArray(target) ? target.length : name3;
|
|
39173
39173
|
if (isLast) {
|
|
39174
|
-
if (utils$1.hasOwnProp(target,
|
|
39175
|
-
target[
|
|
39174
|
+
if (utils$1.hasOwnProp(target, name3)) {
|
|
39175
|
+
target[name3] = [target[name3], value2];
|
|
39176
39176
|
} else {
|
|
39177
|
-
target[
|
|
39177
|
+
target[name3] = value2;
|
|
39178
39178
|
}
|
|
39179
39179
|
return !isNumericKey;
|
|
39180
39180
|
}
|
|
39181
|
-
if (!target[
|
|
39182
|
-
target[
|
|
39181
|
+
if (!target[name3] || !utils$1.isObject(target[name3])) {
|
|
39182
|
+
target[name3] = [];
|
|
39183
39183
|
}
|
|
39184
|
-
const result = buildPath(path, value2, target[
|
|
39185
|
-
if (result && utils$1.isArray(target[
|
|
39186
|
-
target[
|
|
39184
|
+
const result = buildPath(path, value2, target[name3], index);
|
|
39185
|
+
if (result && utils$1.isArray(target[name3])) {
|
|
39186
|
+
target[name3] = arrayToObject(target[name3]);
|
|
39187
39187
|
}
|
|
39188
39188
|
return !isNumericKey;
|
|
39189
39189
|
}
|
|
39190
39190
|
if (utils$1.isFormData(formData) && utils$1.isFunction(formData.entries)) {
|
|
39191
39191
|
const obj = {};
|
|
39192
|
-
utils$1.forEachEntry(formData, (
|
|
39193
|
-
buildPath(parsePropPath(
|
|
39192
|
+
utils$1.forEachEntry(formData, (name3, value2) => {
|
|
39193
|
+
buildPath(parsePropPath(name3), value2, obj, 0);
|
|
39194
39194
|
});
|
|
39195
39195
|
return obj;
|
|
39196
39196
|
}
|
|
@@ -39769,10 +39769,10 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
39769
39769
|
var CRLF_BYTES_COUNT = 2;
|
|
39770
39770
|
|
|
39771
39771
|
class FormDataPart {
|
|
39772
|
-
constructor(
|
|
39772
|
+
constructor(name3, value2) {
|
|
39773
39773
|
const { escapeName } = this.constructor;
|
|
39774
39774
|
const isStringValue = utils$1.isString(value2);
|
|
39775
|
-
let headers = `Content-Disposition: form-data; name="${escapeName(
|
|
39775
|
+
let headers = `Content-Disposition: form-data; name="${escapeName(name3)}"${!isStringValue && value2.name ? `; filename="${escapeName(value2.name)}"` : ""}${CRLF}`;
|
|
39776
39776
|
if (isStringValue) {
|
|
39777
39777
|
value2 = textEncoder.encode(String(value2).replace(/\r?\n|\r\n?/g, CRLF));
|
|
39778
39778
|
} else {
|
|
@@ -39781,7 +39781,7 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
39781
39781
|
this.headers = textEncoder.encode(headers + CRLF);
|
|
39782
39782
|
this.contentLength = isStringValue ? value2.byteLength : value2.size;
|
|
39783
39783
|
this.size = this.headers.byteLength + this.contentLength + CRLF_BYTES_COUNT;
|
|
39784
|
-
this.name =
|
|
39784
|
+
this.name = name3;
|
|
39785
39785
|
this.value = value2;
|
|
39786
39786
|
}
|
|
39787
39787
|
async* encode() {
|
|
@@ -39794,8 +39794,8 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
39794
39794
|
}
|
|
39795
39795
|
yield CRLF_BYTES;
|
|
39796
39796
|
}
|
|
39797
|
-
static escapeName(
|
|
39798
|
-
return String(
|
|
39797
|
+
static escapeName(name3) {
|
|
39798
|
+
return String(name3).replace(/[\r\n"]/g, (match) => ({
|
|
39799
39799
|
"\r": "%0D",
|
|
39800
39800
|
"\n": "%0A",
|
|
39801
39801
|
'"': "%22"
|
|
@@ -39817,8 +39817,8 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
39817
39817
|
const boundaryBytes = textEncoder.encode("--" + boundary + CRLF);
|
|
39818
39818
|
const footerBytes = textEncoder.encode("--" + boundary + "--" + CRLF + CRLF);
|
|
39819
39819
|
let contentLength = footerBytes.byteLength;
|
|
39820
|
-
const parts = Array.from(form.entries()).map(([
|
|
39821
|
-
const part = new FormDataPart(
|
|
39820
|
+
const parts = Array.from(form.entries()).map(([name3, value2]) => {
|
|
39821
|
+
const part = new FormDataPart(name3, value2);
|
|
39822
39822
|
contentLength += part.size;
|
|
39823
39823
|
return part;
|
|
39824
39824
|
});
|
|
@@ -40426,20 +40426,20 @@ var require_axios2 = __commonJS((exports2, module2) => {
|
|
|
40426
40426
|
return origin2.protocol === url2.protocol && origin2.host === url2.host && (isMSIE || origin2.port === url2.port);
|
|
40427
40427
|
})(new URL(platform.origin), platform.navigator && /(msie|trident)/i.test(platform.navigator.userAgent)) : () => true;
|
|
40428
40428
|
var cookies = platform.hasStandardBrowserEnv ? {
|
|
40429
|
-
write(
|
|
40430
|
-
const cookie = [
|
|
40429
|
+
write(name3, value2, expires, path, domain, secure) {
|
|
40430
|
+
const cookie = [name3 + "=" + encodeURIComponent(value2)];
|
|
40431
40431
|
utils$1.isNumber(expires) && cookie.push("expires=" + new Date(expires).toGMTString());
|
|
40432
40432
|
utils$1.isString(path) && cookie.push("path=" + path);
|
|
40433
40433
|
utils$1.isString(domain) && cookie.push("domain=" + domain);
|
|
40434
40434
|
secure === true && cookie.push("secure");
|
|
40435
40435
|
document.cookie = cookie.join("; ");
|
|
40436
40436
|
},
|
|
40437
|
-
read(
|
|
40438
|
-
const match = document.cookie.match(new RegExp("(^|;\\s*)(" +
|
|
40437
|
+
read(name3) {
|
|
40438
|
+
const match = document.cookie.match(new RegExp("(^|;\\s*)(" + name3 + ")=([^;]*)"));
|
|
40439
40439
|
return match ? decodeURIComponent(match[3]) : null;
|
|
40440
40440
|
},
|
|
40441
|
-
remove(
|
|
40442
|
-
this.write(
|
|
40441
|
+
remove(name3) {
|
|
40442
|
+
this.write(name3, "", Date.now() - 86400000);
|
|
40443
40443
|
}
|
|
40444
40444
|
} : {
|
|
40445
40445
|
write() {},
|
|
@@ -44876,6 +44876,7 @@ var require_lib3 = __commonJS((exports2) => {
|
|
|
44876
44876
|
var exports_src = {};
|
|
44877
44877
|
__export(exports_src, {
|
|
44878
44878
|
sortedBuildConfig: () => sortedBuildConfig,
|
|
44879
|
+
name: () => name2,
|
|
44879
44880
|
initialize: () => initialize,
|
|
44880
44881
|
initApp: () => initApp,
|
|
44881
44882
|
get_app_config_and_max_size: () => get_app_config_and_max_size,
|
|
@@ -54801,35 +54802,6 @@ class AppDatabase {
|
|
|
54801
54802
|
}
|
|
54802
54803
|
return null;
|
|
54803
54804
|
}
|
|
54804
|
-
async getRunningInstanceFromDB(account, symbol, options) {
|
|
54805
|
-
const { delay = 60 * 1000 } = options || {
|
|
54806
|
-
delay: 60 * 1000
|
|
54807
|
-
};
|
|
54808
|
-
const running_instance = await this.pb.collection("trade_block_tracking").getFirstListItem(`account.owner = "${account.owner}" && account.exchange = "${account.exchange}" && symbol = "${symbol}"`, {
|
|
54809
|
-
expand: "account"
|
|
54810
|
-
});
|
|
54811
|
-
if (!running_instance) {
|
|
54812
|
-
let account_instance = await this.pb.collection("exchange_accounts").getFirstListItem(`owner = "${account.owner}" && exchange = "${account.exchange}"`);
|
|
54813
|
-
return await this.pb.collection("trade_block_tracking").create({
|
|
54814
|
-
account: account_instance.id,
|
|
54815
|
-
symbol,
|
|
54816
|
-
running: false
|
|
54817
|
-
});
|
|
54818
|
-
}
|
|
54819
|
-
const updatedAt = new Date(running_instance.updated);
|
|
54820
|
-
const now = new Date;
|
|
54821
|
-
const diffInMinutes = (now.getTime() - updatedAt.getTime()) / delay;
|
|
54822
|
-
if (diffInMinutes >= 1) {
|
|
54823
|
-
await this.updateRunningInstance(running_instance.id, false);
|
|
54824
|
-
running_instance.running = false;
|
|
54825
|
-
}
|
|
54826
|
-
return running_instance;
|
|
54827
|
-
}
|
|
54828
|
-
async updateRunningInstance(id, running) {
|
|
54829
|
-
return await this.pb.collection("trade_block_tracking").update(id, {
|
|
54830
|
-
running
|
|
54831
|
-
});
|
|
54832
|
-
}
|
|
54833
54805
|
async getOrders(account, options) {
|
|
54834
54806
|
const { symbol, kind } = options;
|
|
54835
54807
|
const db_orders = await this.pb.collection("orders").getFullList({
|
|
@@ -55140,110 +55112,6 @@ class AppDatabase {
|
|
|
55140
55112
|
}
|
|
55141
55113
|
return null;
|
|
55142
55114
|
}
|
|
55143
|
-
async getBotViewInstance(payload) {
|
|
55144
|
-
const { asset, main_account } = payload;
|
|
55145
|
-
const bot_instances = await this.pb.collection("bot_view").getFullList({
|
|
55146
|
-
filter: `asset:lower="${asset.toLowerCase()}" && main_account.owner:lower="${main_account.owner.toLowerCase()}" && main_account.exchange:lower="${main_account.exchange.toLowerCase()}"`,
|
|
55147
|
-
expand: "main_account,secondary_account,main_long_strategy,main_short_strategy,secondary_long_strategy,secondary_short_strategy"
|
|
55148
|
-
});
|
|
55149
|
-
if (bot_instances.length > 0) {
|
|
55150
|
-
const instance = bot_instances[0];
|
|
55151
|
-
const {
|
|
55152
|
-
main_account: main_account2,
|
|
55153
|
-
secondary_account,
|
|
55154
|
-
main_long_strategy,
|
|
55155
|
-
main_short_strategy,
|
|
55156
|
-
secondary_long_strategy,
|
|
55157
|
-
secondary_short_strategy
|
|
55158
|
-
} = instance.expand;
|
|
55159
|
-
const update_boolean = (value) => {
|
|
55160
|
-
if (!value) {
|
|
55161
|
-
return value;
|
|
55162
|
-
}
|
|
55163
|
-
return {
|
|
55164
|
-
...value,
|
|
55165
|
-
follow: Boolean(value.follow),
|
|
55166
|
-
place_tp: Boolean(value.place_tp),
|
|
55167
|
-
pause_tp: Boolean(value.pause_tp)
|
|
55168
|
-
};
|
|
55169
|
-
};
|
|
55170
|
-
return {
|
|
55171
|
-
...instance,
|
|
55172
|
-
main: {
|
|
55173
|
-
account: main_account2,
|
|
55174
|
-
symbol: instance.main_symbol,
|
|
55175
|
-
strategy: {
|
|
55176
|
-
long: main_long_strategy,
|
|
55177
|
-
short: main_short_strategy
|
|
55178
|
-
},
|
|
55179
|
-
position: {
|
|
55180
|
-
long: instance.main_long_position,
|
|
55181
|
-
short: instance.main_short_position
|
|
55182
|
-
},
|
|
55183
|
-
config: {
|
|
55184
|
-
long: update_boolean(instance.main_long_config),
|
|
55185
|
-
short: update_boolean(instance.main_short_config)
|
|
55186
|
-
}
|
|
55187
|
-
},
|
|
55188
|
-
secondary: {
|
|
55189
|
-
account: secondary_account,
|
|
55190
|
-
symbol: instance.secondary_symbol,
|
|
55191
|
-
strategy: {
|
|
55192
|
-
long: secondary_long_strategy,
|
|
55193
|
-
short: secondary_short_strategy
|
|
55194
|
-
},
|
|
55195
|
-
position: {
|
|
55196
|
-
long: instance.secondary_long_position,
|
|
55197
|
-
short: instance.secondary_short_position
|
|
55198
|
-
},
|
|
55199
|
-
config: {
|
|
55200
|
-
long: update_boolean(instance.secondary_long_config),
|
|
55201
|
-
short: update_boolean(instance.secondary_short_config)
|
|
55202
|
-
}
|
|
55203
|
-
}
|
|
55204
|
-
};
|
|
55205
|
-
}
|
|
55206
|
-
return null;
|
|
55207
|
-
}
|
|
55208
|
-
async getBotInstance(payload) {
|
|
55209
|
-
const { asset, main_account } = payload;
|
|
55210
|
-
const bot_instances = await this.pb.collection("bot_instances").getFullList({
|
|
55211
|
-
filter: `asset:lower="${asset.toLowerCase()}" && main_account.owner:lower="${main_account.owner.toLowerCase()}" && main_account.exchange:lower="${main_account.exchange.toLowerCase()}"`
|
|
55212
|
-
});
|
|
55213
|
-
if (bot_instances.length > 0) {
|
|
55214
|
-
return bot_instances[0];
|
|
55215
|
-
}
|
|
55216
|
-
return null;
|
|
55217
|
-
}
|
|
55218
|
-
async getBotState(payload) {
|
|
55219
|
-
const { asset, main_account, running } = payload;
|
|
55220
|
-
let filter = `bot.asset:lower="${asset.toLowerCase()}" && bot.main_account.owner:lower="${main_account.owner.toLowerCase()}" && bot.main_account.exchange:lower="${main_account.exchange.toLowerCase()}"`;
|
|
55221
|
-
if (running !== undefined) {
|
|
55222
|
-
filter += ` && running=${running}`;
|
|
55223
|
-
}
|
|
55224
|
-
const bot_states = await this.pb.collection("bot_states").getFullList({
|
|
55225
|
-
filter
|
|
55226
|
-
});
|
|
55227
|
-
return bot_states;
|
|
55228
|
-
}
|
|
55229
|
-
async getBotOrderHistories(payload) {
|
|
55230
|
-
const { asset, main_account, symbol, kind, type } = payload;
|
|
55231
|
-
let filter = `field.bot.asset:lower="${asset.toLowerCase()}" && field.bot.main_account.owner:lower="${main_account.owner.toLowerCase()}" && field.bot.main_account.exchange:lower="${main_account.exchange.toLowerCase()}"`;
|
|
55232
|
-
if (symbol) {
|
|
55233
|
-
filter += ` && symbol:lower="${symbol.toLowerCase()}"`;
|
|
55234
|
-
}
|
|
55235
|
-
if (kind) {
|
|
55236
|
-
filter += ` && kind="${kind}"`;
|
|
55237
|
-
}
|
|
55238
|
-
if (type) {
|
|
55239
|
-
filter += ` && type="${type}"`;
|
|
55240
|
-
}
|
|
55241
|
-
const bot_order_histories = await this.pb.collection("bot_order_history").getFullList({
|
|
55242
|
-
filter,
|
|
55243
|
-
sort: "-created"
|
|
55244
|
-
});
|
|
55245
|
-
return bot_order_histories;
|
|
55246
|
-
}
|
|
55247
55115
|
async createOrUpdateWindingDownMarket(payload) {
|
|
55248
55116
|
const { symbol, risk_reward = 30 } = payload;
|
|
55249
55117
|
const existing_winding_down_market = await this.pb.collection("winding_down_markets").getFullList({
|
|
@@ -58714,6 +58582,8 @@ class Strategy {
|
|
|
58714
58582
|
};
|
|
58715
58583
|
}
|
|
58716
58584
|
}
|
|
58585
|
+
// src/helpers/compound.ts
|
|
58586
|
+
var name2 = "";
|
|
58717
58587
|
// src/types/index.ts
|
|
58718
58588
|
class BaseExchange {
|
|
58719
58589
|
client;
|
|
@@ -60051,6 +59921,171 @@ class BinanceExchange extends BaseExchange {
|
|
|
60051
59921
|
async forceClosePosition(symbol, options) {
|
|
60052
59922
|
return await forceClosePosition(this.client, symbol, options);
|
|
60053
59923
|
}
|
|
59924
|
+
async getTransferableAmount(options) {
|
|
59925
|
+
const { asset, maxTransferLimit } = options;
|
|
59926
|
+
try {
|
|
59927
|
+
const futuresBalance = await getWalletBalance(this.client, asset);
|
|
59928
|
+
const allPositions = await this.client.getPositionsV3();
|
|
59929
|
+
const activePositions = allPositions.filter((pos) => Math.abs(pos.positionAmt) > 0);
|
|
59930
|
+
let totalMarginUsed = 0;
|
|
59931
|
+
let totalUnrealizedPnl = 0;
|
|
59932
|
+
for (const position2 of activePositions) {
|
|
59933
|
+
const positionValue = Math.abs(position2.positionAmt) * position2.markPrice;
|
|
59934
|
+
const leverage = await getLeverage(this.client, position2.symbol);
|
|
59935
|
+
const marginForPosition = positionValue / (leverage || 1);
|
|
59936
|
+
console.log({ leverage });
|
|
59937
|
+
totalMarginUsed += marginForPosition;
|
|
59938
|
+
totalUnrealizedPnl += position2.unRealizedProfit || 0;
|
|
59939
|
+
}
|
|
59940
|
+
const safetyMarginPercent = 0.2;
|
|
59941
|
+
const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
|
|
59942
|
+
const adjustedBalance = futuresBalance + totalUnrealizedPnl;
|
|
59943
|
+
const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
|
|
59944
|
+
let maxTransferableAmount = availableForTransfer;
|
|
59945
|
+
let appliedLimit;
|
|
59946
|
+
if (maxTransferLimit && maxTransferLimit > 0) {
|
|
59947
|
+
maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
|
|
59948
|
+
appliedLimit = maxTransferLimit;
|
|
59949
|
+
}
|
|
59950
|
+
const recommendedTransferAmount = maxTransferableAmount * 0.8;
|
|
59951
|
+
const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
|
|
59952
|
+
return {
|
|
59953
|
+
asset,
|
|
59954
|
+
totalBalance: futuresBalance,
|
|
59955
|
+
availableForTransfer,
|
|
59956
|
+
reservedForMargin: requiredMargin,
|
|
59957
|
+
maxTransferableAmount,
|
|
59958
|
+
appliedLimit,
|
|
59959
|
+
recommendedTransferAmount,
|
|
59960
|
+
marginUtilization,
|
|
59961
|
+
safetyMargin: safetyMarginPercent * 100
|
|
59962
|
+
};
|
|
59963
|
+
} catch (error) {
|
|
59964
|
+
console.error(`Error analyzing transferable amount for ${asset}:`, error);
|
|
59965
|
+
throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
|
|
59966
|
+
}
|
|
59967
|
+
}
|
|
59968
|
+
async previewTransfer(options) {
|
|
59969
|
+
const { asset, amount } = options;
|
|
59970
|
+
const warnings = [];
|
|
59971
|
+
const errors = [];
|
|
59972
|
+
try {
|
|
59973
|
+
const analysis = await this.getTransferableAmount({ asset });
|
|
59974
|
+
let isValid2 = true;
|
|
59975
|
+
if (amount <= 0) {
|
|
59976
|
+
errors.push("Transfer amount must be greater than zero");
|
|
59977
|
+
isValid2 = false;
|
|
59978
|
+
}
|
|
59979
|
+
if (amount > analysis.maxTransferableAmount) {
|
|
59980
|
+
errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
|
|
59981
|
+
isValid2 = false;
|
|
59982
|
+
}
|
|
59983
|
+
if (amount > analysis.recommendedTransferAmount) {
|
|
59984
|
+
warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
|
|
59985
|
+
}
|
|
59986
|
+
if (analysis.marginUtilization > 70) {
|
|
59987
|
+
warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
|
|
59988
|
+
}
|
|
59989
|
+
const balanceAfterTransfer = analysis.totalBalance - amount;
|
|
59990
|
+
const marginRequirementAfterTransfer = analysis.reservedForMargin;
|
|
59991
|
+
if (isValid2 && balanceAfterTransfer < marginRequirementAfterTransfer) {
|
|
59992
|
+
errors.push("Transfer would result in insufficient margin for existing positions");
|
|
59993
|
+
isValid2 = false;
|
|
59994
|
+
}
|
|
59995
|
+
return {
|
|
59996
|
+
asset,
|
|
59997
|
+
requestedAmount: amount,
|
|
59998
|
+
isValid: isValid2,
|
|
59999
|
+
balanceAfterTransfer,
|
|
60000
|
+
marginRequirementAfterTransfer,
|
|
60001
|
+
warnings,
|
|
60002
|
+
errors
|
|
60003
|
+
};
|
|
60004
|
+
} catch (error) {
|
|
60005
|
+
console.error(`Error previewing transfer for ${asset}:`, error);
|
|
60006
|
+
return {
|
|
60007
|
+
asset,
|
|
60008
|
+
requestedAmount: amount,
|
|
60009
|
+
isValid: false,
|
|
60010
|
+
balanceAfterTransfer: 0,
|
|
60011
|
+
marginRequirementAfterTransfer: 0,
|
|
60012
|
+
warnings,
|
|
60013
|
+
errors: [`Failed to preview transfer: ${error instanceof Error ? error.message : error}`]
|
|
60014
|
+
};
|
|
60015
|
+
}
|
|
60016
|
+
}
|
|
60017
|
+
async executeFutureToSpotTransfer(options) {
|
|
60018
|
+
const { asset, amount, confirm, symbol = "BTCUSDT" } = options;
|
|
60019
|
+
try {
|
|
60020
|
+
if (!confirm) {
|
|
60021
|
+
return {
|
|
60022
|
+
success: false,
|
|
60023
|
+
asset,
|
|
60024
|
+
amount,
|
|
60025
|
+
fromWallet: "futures",
|
|
60026
|
+
toWallet: "spot",
|
|
60027
|
+
balanceAfterTransfer: 0,
|
|
60028
|
+
timestamp: new Date().toISOString(),
|
|
60029
|
+
error: "Transfer not confirmed. Set confirm: true to execute transfer."
|
|
60030
|
+
};
|
|
60031
|
+
}
|
|
60032
|
+
const preview = await this.previewTransfer({ asset, amount });
|
|
60033
|
+
if (!preview.isValid) {
|
|
60034
|
+
return {
|
|
60035
|
+
success: false,
|
|
60036
|
+
asset,
|
|
60037
|
+
amount,
|
|
60038
|
+
fromWallet: "futures",
|
|
60039
|
+
toWallet: "spot",
|
|
60040
|
+
balanceAfterTransfer: 0,
|
|
60041
|
+
timestamp: new Date().toISOString(),
|
|
60042
|
+
error: `Transfer validation failed: ${preview.errors.join("; ")}`
|
|
60043
|
+
};
|
|
60044
|
+
}
|
|
60045
|
+
const is_coin = !["USDT", "USDC", "BUSD"].includes(asset.toUpperCase());
|
|
60046
|
+
const transferType = is_coin ? CONSTANTS.COIN_FUTURE_TO_SPOT : CONSTANTS.USDT_FUTURE_TO_SPOT;
|
|
60047
|
+
if (!this.main_client) {
|
|
60048
|
+
throw new Error("Main client not available for transfers");
|
|
60049
|
+
}
|
|
60050
|
+
const transferClient = this.main_client;
|
|
60051
|
+
const transferResult = await transferClient.submitUniversalTransfer({
|
|
60052
|
+
asset: asset.toUpperCase(),
|
|
60053
|
+
amount,
|
|
60054
|
+
type: transferType,
|
|
60055
|
+
fromSymbol: symbol,
|
|
60056
|
+
toSymbol: symbol
|
|
60057
|
+
});
|
|
60058
|
+
const balanceAfterTransfer = await getWalletBalance(this.client, asset);
|
|
60059
|
+
return {
|
|
60060
|
+
success: true,
|
|
60061
|
+
transactionId: transferResult.tranId?.toString(),
|
|
60062
|
+
asset,
|
|
60063
|
+
amount,
|
|
60064
|
+
fromWallet: "futures",
|
|
60065
|
+
toWallet: "spot",
|
|
60066
|
+
balanceAfterTransfer,
|
|
60067
|
+
timestamp: new Date().toISOString()
|
|
60068
|
+
};
|
|
60069
|
+
} catch (error) {
|
|
60070
|
+
console.error(`Error executing transfer for ${asset}:`, error);
|
|
60071
|
+
let currentBalance = 0;
|
|
60072
|
+
try {
|
|
60073
|
+
currentBalance = await getWalletBalance(this.client, asset);
|
|
60074
|
+
} catch (balanceError) {
|
|
60075
|
+
console.warn("Could not fetch balance for error response:", balanceError);
|
|
60076
|
+
}
|
|
60077
|
+
return {
|
|
60078
|
+
success: false,
|
|
60079
|
+
asset,
|
|
60080
|
+
amount,
|
|
60081
|
+
fromWallet: "futures",
|
|
60082
|
+
toWallet: "spot",
|
|
60083
|
+
balanceAfterTransfer: currentBalance,
|
|
60084
|
+
timestamp: new Date().toISOString(),
|
|
60085
|
+
error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
|
|
60086
|
+
};
|
|
60087
|
+
}
|
|
60088
|
+
}
|
|
60054
60089
|
}
|
|
60055
60090
|
function getPricePlaces(target) {
|
|
60056
60091
|
const numStr = target.toString();
|
|
@@ -60376,6 +60411,11 @@ async function placeStopOrder2(client, payload) {
|
|
|
60376
60411
|
stop: payload.final_stop,
|
|
60377
60412
|
is_market: !payload.is_limit
|
|
60378
60413
|
};
|
|
60414
|
+
if (payload.hedge) {
|
|
60415
|
+
let reverse_kind = payload.kind === "long" ? "short" : "long";
|
|
60416
|
+
order.kind = reverse_kind;
|
|
60417
|
+
order.is_market = false;
|
|
60418
|
+
}
|
|
60379
60419
|
return createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
60380
60420
|
}
|
|
60381
60421
|
async function getOpenOrders2(client, symbol, type) {
|
|
@@ -60772,6 +60812,168 @@ class BybitExchange extends BaseExchange {
|
|
|
60772
60812
|
return getOpenOrders2(this.client, payload.symbol);
|
|
60773
60813
|
}
|
|
60774
60814
|
async placeBadStopEntry(payload) {}
|
|
60815
|
+
async getTransferableAmount(options) {
|
|
60816
|
+
const { asset, maxTransferLimit } = options;
|
|
60817
|
+
try {
|
|
60818
|
+
const unifiedBalance = await getWalletBalance2(this.client, asset);
|
|
60819
|
+
const allPositions = await this.client.getPositionInfo({
|
|
60820
|
+
category: "linear",
|
|
60821
|
+
settleCoin: asset
|
|
60822
|
+
});
|
|
60823
|
+
const activePositions = (allPositions.result.list || []).filter((pos) => Math.abs(parseFloat(pos.size || "0")) > 0);
|
|
60824
|
+
let totalMarginUsed = 0;
|
|
60825
|
+
let totalUnrealizedPnl = 0;
|
|
60826
|
+
for (const position2 of activePositions) {
|
|
60827
|
+
const positionSize = Math.abs(parseFloat(position2.size || "0"));
|
|
60828
|
+
const markPrice = parseFloat(position2.markPrice || "0");
|
|
60829
|
+
const leverage = parseFloat(position2.leverage || "1");
|
|
60830
|
+
const positionValue = positionSize * markPrice;
|
|
60831
|
+
const marginForPosition = positionValue / leverage;
|
|
60832
|
+
totalMarginUsed += marginForPosition;
|
|
60833
|
+
totalUnrealizedPnl += parseFloat(position2.unrealisedPnl || "0");
|
|
60834
|
+
}
|
|
60835
|
+
const safetyMarginPercent = 0.2;
|
|
60836
|
+
const requiredMargin = totalMarginUsed * (1 + safetyMarginPercent);
|
|
60837
|
+
const adjustedBalance = unifiedBalance + totalUnrealizedPnl;
|
|
60838
|
+
const availableForTransfer = Math.max(0, adjustedBalance - requiredMargin);
|
|
60839
|
+
let maxTransferableAmount = availableForTransfer;
|
|
60840
|
+
let appliedLimit;
|
|
60841
|
+
if (maxTransferLimit && maxTransferLimit > 0) {
|
|
60842
|
+
maxTransferableAmount = Math.min(availableForTransfer, maxTransferLimit);
|
|
60843
|
+
appliedLimit = maxTransferLimit;
|
|
60844
|
+
}
|
|
60845
|
+
const recommendedTransferAmount = maxTransferableAmount * 0.8;
|
|
60846
|
+
const marginUtilization = adjustedBalance > 0 ? requiredMargin / adjustedBalance * 100 : 0;
|
|
60847
|
+
return {
|
|
60848
|
+
asset,
|
|
60849
|
+
totalBalance: unifiedBalance,
|
|
60850
|
+
availableForTransfer,
|
|
60851
|
+
reservedForMargin: requiredMargin,
|
|
60852
|
+
maxTransferableAmount,
|
|
60853
|
+
appliedLimit,
|
|
60854
|
+
recommendedTransferAmount,
|
|
60855
|
+
marginUtilization,
|
|
60856
|
+
safetyMargin: safetyMarginPercent * 100
|
|
60857
|
+
};
|
|
60858
|
+
} catch (error) {
|
|
60859
|
+
console.error(`Error analyzing transferable amount for ${asset}:`, error);
|
|
60860
|
+
throw new Error(`Failed to analyze transferable funds: ${error instanceof Error ? error.message : error}`);
|
|
60861
|
+
}
|
|
60862
|
+
}
|
|
60863
|
+
async previewTransfer(options) {
|
|
60864
|
+
const { asset, amount } = options;
|
|
60865
|
+
const warnings = [];
|
|
60866
|
+
const errors = [];
|
|
60867
|
+
try {
|
|
60868
|
+
const analysis = await this.getTransferableAmount({ asset });
|
|
60869
|
+
let isValid2 = true;
|
|
60870
|
+
if (amount <= 0) {
|
|
60871
|
+
errors.push("Transfer amount must be greater than zero");
|
|
60872
|
+
isValid2 = false;
|
|
60873
|
+
}
|
|
60874
|
+
if (amount > analysis.maxTransferableAmount) {
|
|
60875
|
+
errors.push(`Transfer amount (${amount}) exceeds maximum transferable amount (${analysis.maxTransferableAmount})`);
|
|
60876
|
+
isValid2 = false;
|
|
60877
|
+
}
|
|
60878
|
+
if (amount > analysis.recommendedTransferAmount) {
|
|
60879
|
+
warnings.push(`Transfer amount exceeds recommended amount (${analysis.recommendedTransferAmount.toFixed(4)}). Consider transferring a smaller amount for safety.`);
|
|
60880
|
+
}
|
|
60881
|
+
if (analysis.marginUtilization > 70) {
|
|
60882
|
+
warnings.push(`High margin utilization (${analysis.marginUtilization.toFixed(1)}%). Transferring funds may increase liquidation risk.`);
|
|
60883
|
+
}
|
|
60884
|
+
const balanceAfterTransfer = analysis.totalBalance - amount;
|
|
60885
|
+
const marginRequirementAfterTransfer = analysis.reservedForMargin;
|
|
60886
|
+
if (isValid2 && balanceAfterTransfer < marginRequirementAfterTransfer) {
|
|
60887
|
+
errors.push("Transfer would result in insufficient margin for existing positions");
|
|
60888
|
+
isValid2 = false;
|
|
60889
|
+
}
|
|
60890
|
+
return {
|
|
60891
|
+
asset,
|
|
60892
|
+
requestedAmount: amount,
|
|
60893
|
+
isValid: isValid2,
|
|
60894
|
+
balanceAfterTransfer,
|
|
60895
|
+
marginRequirementAfterTransfer,
|
|
60896
|
+
warnings,
|
|
60897
|
+
errors
|
|
60898
|
+
};
|
|
60899
|
+
} catch (error) {
|
|
60900
|
+
console.error(`Error previewing transfer for ${asset}:`, error);
|
|
60901
|
+
return {
|
|
60902
|
+
asset,
|
|
60903
|
+
requestedAmount: amount,
|
|
60904
|
+
isValid: false,
|
|
60905
|
+
balanceAfterTransfer: 0,
|
|
60906
|
+
marginRequirementAfterTransfer: 0,
|
|
60907
|
+
warnings,
|
|
60908
|
+
errors: [
|
|
60909
|
+
`Failed to preview transfer: ${error instanceof Error ? error.message : error}`
|
|
60910
|
+
]
|
|
60911
|
+
};
|
|
60912
|
+
}
|
|
60913
|
+
}
|
|
60914
|
+
async executeUnifiedToFundingTransfer(options) {
|
|
60915
|
+
const { asset, amount, confirm } = options;
|
|
60916
|
+
try {
|
|
60917
|
+
if (!confirm) {
|
|
60918
|
+
return {
|
|
60919
|
+
success: false,
|
|
60920
|
+
asset,
|
|
60921
|
+
amount,
|
|
60922
|
+
fromWallet: "unified",
|
|
60923
|
+
toWallet: "funding",
|
|
60924
|
+
balanceAfterTransfer: 0,
|
|
60925
|
+
timestamp: new Date().toISOString(),
|
|
60926
|
+
error: "Transfer not confirmed. Set confirm: true to execute transfer."
|
|
60927
|
+
};
|
|
60928
|
+
}
|
|
60929
|
+
const preview = await this.previewTransfer({ asset, amount });
|
|
60930
|
+
if (!preview.isValid) {
|
|
60931
|
+
return {
|
|
60932
|
+
success: false,
|
|
60933
|
+
asset,
|
|
60934
|
+
amount,
|
|
60935
|
+
fromWallet: "unified",
|
|
60936
|
+
toWallet: "funding",
|
|
60937
|
+
balanceAfterTransfer: 0,
|
|
60938
|
+
timestamp: new Date().toISOString(),
|
|
60939
|
+
error: `Transfer validation failed: ${preview.errors.join("; ")}`
|
|
60940
|
+
};
|
|
60941
|
+
}
|
|
60942
|
+
const transferResult = await this.client.createInternalTransfer(`bybit_transfer_${Date.now()}`, asset.toUpperCase(), amount.toString(), "UNIFIED", "FUND");
|
|
60943
|
+
if (transferResult.retCode !== 0) {
|
|
60944
|
+
throw new Error(`Bybit transfer failed: ${transferResult.retMsg} (code: ${transferResult.retCode})`);
|
|
60945
|
+
}
|
|
60946
|
+
const balanceAfterTransfer = await getWalletBalance2(this.client, asset);
|
|
60947
|
+
return {
|
|
60948
|
+
success: true,
|
|
60949
|
+
transactionId: transferResult.result?.transferId,
|
|
60950
|
+
asset,
|
|
60951
|
+
amount,
|
|
60952
|
+
fromWallet: "unified",
|
|
60953
|
+
toWallet: "funding",
|
|
60954
|
+
balanceAfterTransfer,
|
|
60955
|
+
timestamp: new Date().toISOString()
|
|
60956
|
+
};
|
|
60957
|
+
} catch (error) {
|
|
60958
|
+
console.error(`Error executing transfer for ${asset}:`, error);
|
|
60959
|
+
let currentBalance = 0;
|
|
60960
|
+
try {
|
|
60961
|
+
currentBalance = await getWalletBalance2(this.client, asset);
|
|
60962
|
+
} catch (balanceError) {
|
|
60963
|
+
console.warn("Could not fetch balance for error response:", balanceError);
|
|
60964
|
+
}
|
|
60965
|
+
return {
|
|
60966
|
+
success: false,
|
|
60967
|
+
asset,
|
|
60968
|
+
amount,
|
|
60969
|
+
fromWallet: "unified",
|
|
60970
|
+
toWallet: "funding",
|
|
60971
|
+
balanceAfterTransfer: currentBalance,
|
|
60972
|
+
timestamp: new Date().toISOString(),
|
|
60973
|
+
error: `Transfer execution failed: ${error instanceof Error ? error.message : error}`
|
|
60974
|
+
};
|
|
60975
|
+
}
|
|
60976
|
+
}
|
|
60775
60977
|
}
|
|
60776
60978
|
|
|
60777
60979
|
// src/helpers/accounts.ts
|
|
@@ -62480,9 +62682,6 @@ class ExchangeAccount {
|
|
|
62480
62682
|
}
|
|
62481
62683
|
return db_positions;
|
|
62482
62684
|
}
|
|
62483
|
-
async getRunningInstanceFromDB(symbol) {
|
|
62484
|
-
return await this.app_db.getRunningInstanceFromDB(this.instance, symbol);
|
|
62485
|
-
}
|
|
62486
62685
|
async syncOrders(options) {
|
|
62487
62686
|
const { symbol, update = false, kind } = options;
|
|
62488
62687
|
if (!update && kind) {
|
|
@@ -64131,22 +64330,11 @@ class App {
|
|
|
64131
64330
|
}
|
|
64132
64331
|
async syncOrders(payload) {
|
|
64133
64332
|
const exchange_account = await this.getExchangeAccount(payload.account);
|
|
64134
|
-
const db_running_instance = await exchange_account.getRunningInstanceFromDB(payload.symbol);
|
|
64135
|
-
if (db_running_instance.running) {
|
|
64136
|
-
return {
|
|
64137
|
-
new_config: null,
|
|
64138
|
-
position: null,
|
|
64139
|
-
config: null,
|
|
64140
|
-
error: "Already running"
|
|
64141
|
-
};
|
|
64142
|
-
}
|
|
64143
|
-
await this.app_db.updateRunningInstance(db_running_instance.id, true);
|
|
64144
64333
|
await exchange_account.syncAccount({
|
|
64145
64334
|
symbol: payload.symbol,
|
|
64146
64335
|
kind: payload.kind,
|
|
64147
64336
|
update: true
|
|
64148
64337
|
});
|
|
64149
|
-
await this.app_db.updateRunningInstance(db_running_instance.id, false);
|
|
64150
64338
|
return true;
|
|
64151
64339
|
}
|
|
64152
64340
|
async cancelOrders(payload) {
|