@gbozee/ultimate 0.0.2-next.74 → 0.0.2-next.77
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 +313 -47
- package/dist/index.d.ts +96 -1
- package/dist/index.js +313 -47
- package/dist/mcp-server.cjs +311 -47
- package/dist/mcp-server.js +311 -47
- package/package.json +1 -1
package/dist/mcp-server.cjs
CHANGED
|
@@ -76510,7 +76510,7 @@ function buildSpotMarginHedgePlan(options) {
|
|
|
76510
76510
|
const margin_orders_to_create = options.placement_overrides?.margin || default_margin_orders_to_create;
|
|
76511
76511
|
const borrow_delta = roundNumber2(Math.max(0, options.borrow_amount - options.snapshot.borrowed_quote_amount));
|
|
76512
76512
|
const spot_long_notional = sumNotional(spot_long_orders);
|
|
76513
|
-
const transfer_to_spot_amount = roundNumber2(Math.max(0, spot_long_notional - options.snapshot.spot_quote_free));
|
|
76513
|
+
const transfer_to_spot_amount = roundNumber2(Math.max(0, options.margin_type === "cross" ? options.borrow_amount : spot_long_notional - options.snapshot.spot_quote_free));
|
|
76514
76514
|
const short_quantity = sumQuantity(short_orders);
|
|
76515
76515
|
const transfer_base_to_spot_amount = roundNumber2(Math.max(0, short_quantity - options.snapshot.spot_base_free));
|
|
76516
76516
|
return {
|
|
@@ -77014,17 +77014,17 @@ async function createMarginLimitOrdersParallel(client, symbol, priceFormat, quan
|
|
|
77014
77014
|
return Object.fromEntries(Object.entries(v).filter(([, value2]) => value2 !== undefined));
|
|
77015
77015
|
};
|
|
77016
77016
|
const newOrders = orders.map(createMarginOrder);
|
|
77017
|
-
const
|
|
77018
|
-
const
|
|
77017
|
+
const results = [];
|
|
77018
|
+
for (const orderPayload of newOrders) {
|
|
77019
77019
|
try {
|
|
77020
77020
|
const result = await client.marginAccountNewOrder(orderPayload);
|
|
77021
77021
|
console.log("Margin order result:", result);
|
|
77022
|
-
|
|
77022
|
+
results.push(result);
|
|
77023
77023
|
} catch (error) {
|
|
77024
77024
|
console.error("Error processing margin order:", error);
|
|
77025
77025
|
throw error;
|
|
77026
77026
|
}
|
|
77027
|
-
}
|
|
77027
|
+
}
|
|
77028
77028
|
return results;
|
|
77029
77029
|
}
|
|
77030
77030
|
async function getIsolatedMarginAccountInfo(client, symbol) {
|
|
@@ -78370,24 +78370,25 @@ class BinanceExchange extends BaseExchange {
|
|
|
78370
78370
|
if (!this.main_client) {
|
|
78371
78371
|
throw new Error("Main client not available for spot and margin trading");
|
|
78372
78372
|
}
|
|
78373
|
-
if (payload.margin_type !== "isolated") {
|
|
78374
|
-
throw new Error(`Unsupported margin type: ${payload.margin_type}. Only isolated is supported for replay right now.`);
|
|
78375
|
-
}
|
|
78376
78373
|
const symbol = payload.symbol.toUpperCase();
|
|
78377
78374
|
const quoteAssets = ["USDT", "USDC", "BUSD", "BTC", "ETH"];
|
|
78378
78375
|
const quoteAsset = quoteAssets.find((asset) => symbol.endsWith(asset)) || symbol.slice(-4);
|
|
78379
78376
|
const baseAsset = symbol.slice(0, symbol.length - quoteAsset.length);
|
|
78380
|
-
const
|
|
78377
|
+
const is_isolated = payload.margin_type === "isolated";
|
|
78378
|
+
const [spot_orders, margin_orders, spot_balances, margin_account] = await Promise.all([
|
|
78381
78379
|
this.getSpotOpenOrders(symbol),
|
|
78382
|
-
this.getMarginOpenOrders(symbol,
|
|
78380
|
+
this.getMarginOpenOrders(symbol, is_isolated),
|
|
78383
78381
|
this.getSpotBalances([baseAsset, quoteAsset]),
|
|
78384
|
-
this.getIsolatedMarginPosition(symbol)
|
|
78382
|
+
is_isolated ? this.getIsolatedMarginPosition(symbol) : this.getCrossMarginAccount()
|
|
78385
78383
|
]);
|
|
78386
78384
|
const current_price = await this.getSpotCurrentPrice(symbol);
|
|
78387
78385
|
const spot_quote_balance = spot_balances.find((balance) => balance.asset.toUpperCase() === quoteAsset);
|
|
78388
78386
|
const spot_base_balance = spot_balances.find((balance) => balance.asset.toUpperCase() === baseAsset);
|
|
78389
|
-
const
|
|
78390
|
-
const
|
|
78387
|
+
const isolated_margin_account = is_isolated ? margin_account : undefined;
|
|
78388
|
+
const cross_margin_account = !is_isolated ? margin_account : undefined;
|
|
78389
|
+
const isolated_asset = isolated_margin_account?.assets?.[0];
|
|
78390
|
+
const cross_quote_asset = !is_isolated ? cross_margin_account?.userAssets?.find((asset) => asset.asset?.toUpperCase?.() === quoteAsset) : undefined;
|
|
78391
|
+
const borrowed_quote_amount = parseFloat(isolated_asset?.quoteAsset?.borrowed?.toString?.() || cross_quote_asset?.borrowed?.toString?.() || "0");
|
|
78391
78392
|
return {
|
|
78392
78393
|
symbol,
|
|
78393
78394
|
margin_type: payload.margin_type,
|
|
@@ -78400,7 +78401,8 @@ class BinanceExchange extends BaseExchange {
|
|
|
78400
78401
|
margin_orders,
|
|
78401
78402
|
current_price,
|
|
78402
78403
|
spot_balances,
|
|
78403
|
-
isolated_margin_position
|
|
78404
|
+
isolated_margin_position: isolated_margin_account,
|
|
78405
|
+
cross_margin_account
|
|
78404
78406
|
};
|
|
78405
78407
|
}
|
|
78406
78408
|
async previewSpotMarginHedge(payload) {
|
|
@@ -78457,14 +78459,12 @@ class BinanceExchange extends BaseExchange {
|
|
|
78457
78459
|
if (!this.main_client) {
|
|
78458
78460
|
throw new Error("Main client not available for spot and margin trading");
|
|
78459
78461
|
}
|
|
78460
|
-
if (payload.margin_type !== "isolated") {
|
|
78461
|
-
throw new Error(`Unsupported margin type: ${payload.margin_type}. Only isolated placement is supported right now.`);
|
|
78462
|
-
}
|
|
78463
78462
|
const symbol = payload.symbol.toUpperCase();
|
|
78464
78463
|
const quoteAssets = ["USDT", "USDC", "BUSD", "BTC", "ETH"];
|
|
78465
78464
|
const quote_asset = quoteAssets.find((asset) => symbol.endsWith(asset)) || symbol.slice(-4);
|
|
78466
78465
|
const base_asset = symbol.slice(0, symbol.length - quote_asset.length);
|
|
78467
78466
|
const requested_input = preview.requested_input;
|
|
78467
|
+
const is_isolated = payload.margin_type === "isolated";
|
|
78468
78468
|
if (preview.snapshot.spot_orders.length > 0) {
|
|
78469
78469
|
await this.cancelSpotOrders(symbol, preview.snapshot.spot_orders.map((order) => ({
|
|
78470
78470
|
orderId: order.orderId || order.order_id || order.id,
|
|
@@ -78472,7 +78472,7 @@ class BinanceExchange extends BaseExchange {
|
|
|
78472
78472
|
})));
|
|
78473
78473
|
}
|
|
78474
78474
|
if (preview.snapshot.margin_orders.length > 0) {
|
|
78475
|
-
await this.cancelMarginOrders(symbol,
|
|
78475
|
+
await this.cancelMarginOrders(symbol, is_isolated, preview.snapshot.margin_orders.map((order) => ({
|
|
78476
78476
|
orderId: order.orderId || order.order_id || order.id,
|
|
78477
78477
|
origClientOrderId: order.origClientOrderId
|
|
78478
78478
|
})));
|
|
@@ -78494,50 +78494,120 @@ class BinanceExchange extends BaseExchange {
|
|
|
78494
78494
|
});
|
|
78495
78495
|
let borrow_result = null;
|
|
78496
78496
|
if (execution_plan.borrow_delta > 0) {
|
|
78497
|
-
|
|
78497
|
+
const borrow_payload = {
|
|
78498
78498
|
asset: quote_asset,
|
|
78499
78499
|
amount: execution_plan.borrow_delta,
|
|
78500
|
-
isIsolated: "TRUE",
|
|
78501
|
-
symbol,
|
|
78502
78500
|
type: "BORROW"
|
|
78501
|
+
};
|
|
78502
|
+
if (is_isolated) {
|
|
78503
|
+
borrow_payload.isIsolated = "TRUE";
|
|
78504
|
+
borrow_payload.symbol = symbol;
|
|
78505
|
+
}
|
|
78506
|
+
borrow_result = await this.main_client.submitMarginAccountBorrowRepay(borrow_payload);
|
|
78507
|
+
}
|
|
78508
|
+
async function getCrossTransferAmount(asset, amount) {
|
|
78509
|
+
if (is_isolated) {
|
|
78510
|
+
return amount;
|
|
78511
|
+
}
|
|
78512
|
+
if (!this.main_client || typeof this.main_client.queryMaxTransferOutAmount !== "function") {
|
|
78513
|
+
return amount;
|
|
78514
|
+
}
|
|
78515
|
+
const response = await this.main_client.queryMaxTransferOutAmount({
|
|
78516
|
+
asset
|
|
78503
78517
|
});
|
|
78518
|
+
const allowed_amount = parseFloat(response?.amount?.toString?.() || "0");
|
|
78519
|
+
if (!Number.isFinite(allowed_amount)) {
|
|
78520
|
+
return amount;
|
|
78521
|
+
}
|
|
78522
|
+
return Math.max(0, Math.min(amount, allowed_amount));
|
|
78504
78523
|
}
|
|
78505
78524
|
let quote_transfer_result = null;
|
|
78525
|
+
let quote_transfer_amount = execution_plan.transfer_to_spot_amount;
|
|
78506
78526
|
if (execution_plan.transfer_to_spot_amount > 0) {
|
|
78507
|
-
|
|
78508
|
-
|
|
78509
|
-
|
|
78510
|
-
|
|
78511
|
-
|
|
78512
|
-
|
|
78513
|
-
|
|
78527
|
+
quote_transfer_amount = await getCrossTransferAmount.call(this, quote_asset, execution_plan.transfer_to_spot_amount);
|
|
78528
|
+
if (quote_transfer_amount > 0) {
|
|
78529
|
+
quote_transfer_result = is_isolated ? await this.main_client.isolatedMarginAccountTransfer({
|
|
78530
|
+
asset: quote_asset,
|
|
78531
|
+
amount: quote_transfer_amount,
|
|
78532
|
+
symbol,
|
|
78533
|
+
transFrom: "ISOLATED_MARGIN",
|
|
78534
|
+
transTo: "SPOT"
|
|
78535
|
+
}) : await this.main_client.submitUniversalTransfer({
|
|
78536
|
+
type: "MARGIN_MAIN",
|
|
78537
|
+
asset: quote_asset,
|
|
78538
|
+
amount: quote_transfer_amount
|
|
78539
|
+
});
|
|
78540
|
+
}
|
|
78514
78541
|
}
|
|
78515
78542
|
let base_transfer_result = null;
|
|
78543
|
+
let base_transfer_amount = execution_plan.transfer_base_to_spot_amount;
|
|
78516
78544
|
if (execution_plan.transfer_base_to_spot_amount > 0) {
|
|
78517
|
-
|
|
78518
|
-
|
|
78519
|
-
|
|
78520
|
-
|
|
78521
|
-
|
|
78522
|
-
|
|
78523
|
-
|
|
78545
|
+
base_transfer_amount = await getCrossTransferAmount.call(this, base_asset, execution_plan.transfer_base_to_spot_amount);
|
|
78546
|
+
if (base_transfer_amount > 0) {
|
|
78547
|
+
base_transfer_result = is_isolated ? await this.main_client.isolatedMarginAccountTransfer({
|
|
78548
|
+
asset: base_asset,
|
|
78549
|
+
amount: base_transfer_amount,
|
|
78550
|
+
symbol,
|
|
78551
|
+
transFrom: "ISOLATED_MARGIN",
|
|
78552
|
+
transTo: "SPOT"
|
|
78553
|
+
}) : await this.main_client.submitUniversalTransfer({
|
|
78554
|
+
type: "MARGIN_MAIN",
|
|
78555
|
+
asset: base_asset,
|
|
78556
|
+
amount: base_transfer_amount
|
|
78557
|
+
});
|
|
78558
|
+
}
|
|
78524
78559
|
}
|
|
78525
|
-
const
|
|
78560
|
+
const spot_quote_available = refreshed_snapshot.spot_quote_free + quote_transfer_amount;
|
|
78561
|
+
const requested_max_spot_buy_orders = requested_input.max_spot_buy_orders ?? 5;
|
|
78562
|
+
const sorted_long_orders = [...requested_input.long_orders].sort((a, b) => a.price - b.price);
|
|
78563
|
+
let affordable_spot_buy_orders = 0;
|
|
78564
|
+
let affordable_spot_buy_notional = 0;
|
|
78565
|
+
for (const order of sorted_long_orders.slice(0, requested_max_spot_buy_orders)) {
|
|
78566
|
+
const next_notional = affordable_spot_buy_notional + order.price * order.quantity;
|
|
78567
|
+
if (next_notional <= spot_quote_available + 0.00000001) {
|
|
78568
|
+
affordable_spot_buy_orders += 1;
|
|
78569
|
+
affordable_spot_buy_notional = next_notional;
|
|
78570
|
+
} else {
|
|
78571
|
+
break;
|
|
78572
|
+
}
|
|
78573
|
+
}
|
|
78574
|
+
const placement_plan = buildSpotMarginHedgePlan({
|
|
78575
|
+
borrow_amount: requested_input.borrow_amount,
|
|
78576
|
+
symbol: requested_input.symbol,
|
|
78577
|
+
margin_type: requested_input.margin_type,
|
|
78578
|
+
long_orders: requested_input.long_orders,
|
|
78579
|
+
short_orders: requested_input.short_orders,
|
|
78580
|
+
current_price: refreshed_snapshot.current_price,
|
|
78581
|
+
max_spot_buy_orders: affordable_spot_buy_orders,
|
|
78582
|
+
snapshot: {
|
|
78583
|
+
...refreshed_snapshot,
|
|
78584
|
+
borrowed_quote_amount: refreshed_snapshot.borrowed_quote_amount + execution_plan.borrow_delta,
|
|
78585
|
+
spot_quote_free: spot_quote_available,
|
|
78586
|
+
spot_base_free: refreshed_snapshot.spot_base_free + base_transfer_amount
|
|
78587
|
+
}
|
|
78588
|
+
});
|
|
78589
|
+
const spot_result = placement_plan.orders_to_create.spot.length > 0 ? await this.createSpotLimitOrders({
|
|
78526
78590
|
symbol,
|
|
78527
|
-
orders:
|
|
78591
|
+
orders: placement_plan.orders_to_create.spot,
|
|
78528
78592
|
price_places: symbol_formats.price_places,
|
|
78529
78593
|
decimal_places: symbol_formats.decimal_places
|
|
78530
78594
|
}) : [];
|
|
78531
|
-
const margin_result =
|
|
78595
|
+
const margin_result = placement_plan.orders_to_create.margin.length > 0 ? await this.createMarginLimitOrders({
|
|
78532
78596
|
symbol,
|
|
78533
|
-
orders:
|
|
78534
|
-
isIsolated:
|
|
78597
|
+
orders: placement_plan.orders_to_create.margin,
|
|
78598
|
+
isIsolated: is_isolated,
|
|
78535
78599
|
price_places: symbol_formats.price_places,
|
|
78536
78600
|
decimal_places: symbol_formats.decimal_places
|
|
78537
78601
|
}) : [];
|
|
78538
78602
|
return {
|
|
78539
78603
|
...preview,
|
|
78540
|
-
execution_plan
|
|
78604
|
+
execution_plan: {
|
|
78605
|
+
...placement_plan,
|
|
78606
|
+
borrow_amount: execution_plan.borrow_amount,
|
|
78607
|
+
borrow_delta: execution_plan.borrow_delta,
|
|
78608
|
+
transfer_to_spot_amount: quote_transfer_amount,
|
|
78609
|
+
transfer_base_to_spot_amount: base_transfer_amount
|
|
78610
|
+
},
|
|
78541
78611
|
refreshed_snapshot,
|
|
78542
78612
|
execution: {
|
|
78543
78613
|
borrow: borrow_result ? {
|
|
@@ -78547,12 +78617,12 @@ class BinanceExchange extends BaseExchange {
|
|
|
78547
78617
|
} : null,
|
|
78548
78618
|
quote_transfer: quote_transfer_result ? {
|
|
78549
78619
|
asset: quote_asset,
|
|
78550
|
-
amount:
|
|
78620
|
+
amount: quote_transfer_amount,
|
|
78551
78621
|
response: quote_transfer_result
|
|
78552
78622
|
} : null,
|
|
78553
78623
|
base_transfer: base_transfer_result ? {
|
|
78554
78624
|
asset: base_asset,
|
|
78555
|
-
amount:
|
|
78625
|
+
amount: base_transfer_amount,
|
|
78556
78626
|
response: base_transfer_result
|
|
78557
78627
|
} : null,
|
|
78558
78628
|
spot_orders: spot_result,
|
|
@@ -82047,6 +82117,76 @@ async function forceClosePosition2(client, symbol, options) {
|
|
|
82047
82117
|
}
|
|
82048
82118
|
|
|
82049
82119
|
// src/exchange-account.ts
|
|
82120
|
+
function getFormatPrecision(places) {
|
|
82121
|
+
if (!places) {
|
|
82122
|
+
return 0;
|
|
82123
|
+
}
|
|
82124
|
+
const match = places.match(/%\.(\d+)f/);
|
|
82125
|
+
return match ? Number(match[1]) : 0;
|
|
82126
|
+
}
|
|
82127
|
+
function floorToFormat(value2, places) {
|
|
82128
|
+
if (!Number.isFinite(value2) || value2 <= 0) {
|
|
82129
|
+
return 0;
|
|
82130
|
+
}
|
|
82131
|
+
const precision = getFormatPrecision(places);
|
|
82132
|
+
const factor = 10 ** precision;
|
|
82133
|
+
return Math.floor((value2 + Number.EPSILON) * factor) / factor;
|
|
82134
|
+
}
|
|
82135
|
+
|
|
82136
|
+
class TakeProfitReplaceRollbackSucceededError extends Error {
|
|
82137
|
+
status = "rollback_succeeded";
|
|
82138
|
+
restored = true;
|
|
82139
|
+
symbol;
|
|
82140
|
+
kind;
|
|
82141
|
+
takeProfitPrice;
|
|
82142
|
+
quantity;
|
|
82143
|
+
previousTakeProfitPrice;
|
|
82144
|
+
previousQuantity;
|
|
82145
|
+
restoreAttempted;
|
|
82146
|
+
cause;
|
|
82147
|
+
rollbackError;
|
|
82148
|
+
constructor(metadata3) {
|
|
82149
|
+
super("Take profit replacement failed and previous take profit was restored");
|
|
82150
|
+
this.name = "TakeProfitReplaceRollbackSucceededError";
|
|
82151
|
+
this.symbol = metadata3.symbol;
|
|
82152
|
+
this.kind = metadata3.kind;
|
|
82153
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
82154
|
+
this.quantity = metadata3.quantity;
|
|
82155
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
82156
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
82157
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
82158
|
+
this.cause = metadata3.cause;
|
|
82159
|
+
this.rollbackError = metadata3.rollbackError;
|
|
82160
|
+
}
|
|
82161
|
+
}
|
|
82162
|
+
|
|
82163
|
+
class TakeProfitReplaceRollbackFailedError extends Error {
|
|
82164
|
+
status = "rollback_failed";
|
|
82165
|
+
restored = false;
|
|
82166
|
+
symbol;
|
|
82167
|
+
kind;
|
|
82168
|
+
takeProfitPrice;
|
|
82169
|
+
quantity;
|
|
82170
|
+
previousTakeProfitPrice;
|
|
82171
|
+
previousQuantity;
|
|
82172
|
+
restoreAttempted;
|
|
82173
|
+
cause;
|
|
82174
|
+
rollbackError;
|
|
82175
|
+
constructor(metadata3) {
|
|
82176
|
+
super("Take profit replacement failed and previous take profit could not be restored");
|
|
82177
|
+
this.name = "TakeProfitReplaceRollbackFailedError";
|
|
82178
|
+
this.symbol = metadata3.symbol;
|
|
82179
|
+
this.kind = metadata3.kind;
|
|
82180
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
82181
|
+
this.quantity = metadata3.quantity;
|
|
82182
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
82183
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
82184
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
82185
|
+
this.cause = metadata3.cause;
|
|
82186
|
+
this.rollbackError = metadata3.rollbackError;
|
|
82187
|
+
}
|
|
82188
|
+
}
|
|
82189
|
+
|
|
82050
82190
|
class ExchangeAccount {
|
|
82051
82191
|
instance;
|
|
82052
82192
|
exchange;
|
|
@@ -82143,8 +82283,6 @@ class ExchangeAccount {
|
|
|
82143
82283
|
refresh
|
|
82144
82284
|
});
|
|
82145
82285
|
const raw_active_account = live_exchange_instance.data;
|
|
82146
|
-
console.log("raw_active", raw_active_account);
|
|
82147
|
-
console.log("symbol_config", symbol_config);
|
|
82148
82286
|
const _all = get_active_accounts({
|
|
82149
82287
|
active_account: raw_active_account,
|
|
82150
82288
|
symbol_config
|
|
@@ -82278,6 +82416,132 @@ class ExchangeAccount {
|
|
|
82278
82416
|
});
|
|
82279
82417
|
return await focus_position.cancelOrders(payload);
|
|
82280
82418
|
}
|
|
82419
|
+
async replaceTakeProfitForPosition(payload) {
|
|
82420
|
+
const { symbol, kind, takeProfitPrice, quantity } = payload;
|
|
82421
|
+
const focusPosition = await this.getFocusPosition({
|
|
82422
|
+
symbol,
|
|
82423
|
+
kind,
|
|
82424
|
+
update: true
|
|
82425
|
+
});
|
|
82426
|
+
const position2 = focusPosition.getInstance();
|
|
82427
|
+
const symbol_config = focusPosition.symbol_config;
|
|
82428
|
+
if (!symbol_config) {
|
|
82429
|
+
throw new Error(`Missing symbol config for ${symbol}`);
|
|
82430
|
+
}
|
|
82431
|
+
const normalizedQuantity = floorToFormat(quantity, symbol_config.decimal_places);
|
|
82432
|
+
const minSize = Number(symbol_config.min_size || 0);
|
|
82433
|
+
const previousTakeProfitPrice = Number(position2?.take_profit || 0);
|
|
82434
|
+
const previousQuantity = floorToFormat(Number(position2?.tp_quantity || 0), symbol_config.decimal_places);
|
|
82435
|
+
if (normalizedQuantity <= 0) {
|
|
82436
|
+
return {
|
|
82437
|
+
status: "below_min_lot",
|
|
82438
|
+
symbol,
|
|
82439
|
+
kind,
|
|
82440
|
+
takeProfitPrice,
|
|
82441
|
+
quantity: 0,
|
|
82442
|
+
minSize,
|
|
82443
|
+
reason: "quantity_floored_to_zero"
|
|
82444
|
+
};
|
|
82445
|
+
}
|
|
82446
|
+
if (minSize > 0 && normalizedQuantity < minSize) {
|
|
82447
|
+
return {
|
|
82448
|
+
status: "below_min_lot",
|
|
82449
|
+
symbol,
|
|
82450
|
+
kind,
|
|
82451
|
+
takeProfitPrice,
|
|
82452
|
+
quantity: normalizedQuantity,
|
|
82453
|
+
minSize,
|
|
82454
|
+
reason: "below_venue_minimum"
|
|
82455
|
+
};
|
|
82456
|
+
}
|
|
82457
|
+
const exchangeSeams = this.exchange;
|
|
82458
|
+
if (exchangeSeams.replaceTakeProfitForPosition) {
|
|
82459
|
+
await exchangeSeams.replaceTakeProfitForPosition({
|
|
82460
|
+
symbol,
|
|
82461
|
+
kind,
|
|
82462
|
+
takeProfitPrice,
|
|
82463
|
+
quantity: normalizedQuantity,
|
|
82464
|
+
price_places: symbol_config.price_places,
|
|
82465
|
+
decimal_places: symbol_config.decimal_places,
|
|
82466
|
+
previousTakeProfitPrice,
|
|
82467
|
+
previousQuantity
|
|
82468
|
+
});
|
|
82469
|
+
return {
|
|
82470
|
+
status: "replaced",
|
|
82471
|
+
symbol,
|
|
82472
|
+
kind,
|
|
82473
|
+
takeProfitPrice,
|
|
82474
|
+
quantity: normalizedQuantity,
|
|
82475
|
+
previousTakeProfitPrice,
|
|
82476
|
+
previousQuantity,
|
|
82477
|
+
restoreAttempted: false,
|
|
82478
|
+
via: "native_replace"
|
|
82479
|
+
};
|
|
82480
|
+
}
|
|
82481
|
+
const placeTpWithoutCancelling = exchangeSeams._placeTpOrder;
|
|
82482
|
+
if (!placeTpWithoutCancelling) {
|
|
82483
|
+
throw new Error(`Exchange ${this.instance.exchange} does not expose a TP replace or raw TP placement path`);
|
|
82484
|
+
}
|
|
82485
|
+
if (previousTakeProfitPrice > 0) {
|
|
82486
|
+
await this.cancelOrders({
|
|
82487
|
+
symbol,
|
|
82488
|
+
kind,
|
|
82489
|
+
price: previousTakeProfitPrice
|
|
82490
|
+
});
|
|
82491
|
+
}
|
|
82492
|
+
try {
|
|
82493
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
82494
|
+
symbol,
|
|
82495
|
+
tp: takeProfitPrice,
|
|
82496
|
+
kind,
|
|
82497
|
+
quantity: normalizedQuantity,
|
|
82498
|
+
cancel: false,
|
|
82499
|
+
price_places: symbol_config.price_places,
|
|
82500
|
+
decimal_places: symbol_config.decimal_places
|
|
82501
|
+
});
|
|
82502
|
+
return {
|
|
82503
|
+
status: "replaced",
|
|
82504
|
+
symbol,
|
|
82505
|
+
kind,
|
|
82506
|
+
takeProfitPrice,
|
|
82507
|
+
quantity: normalizedQuantity,
|
|
82508
|
+
previousTakeProfitPrice,
|
|
82509
|
+
previousQuantity,
|
|
82510
|
+
restoreAttempted: false
|
|
82511
|
+
};
|
|
82512
|
+
} catch (cause) {
|
|
82513
|
+
const metadata3 = {
|
|
82514
|
+
symbol,
|
|
82515
|
+
kind,
|
|
82516
|
+
takeProfitPrice,
|
|
82517
|
+
quantity: normalizedQuantity,
|
|
82518
|
+
previousTakeProfitPrice,
|
|
82519
|
+
previousQuantity,
|
|
82520
|
+
restoreAttempted: previousTakeProfitPrice > 0 && previousQuantity > 0,
|
|
82521
|
+
cause
|
|
82522
|
+
};
|
|
82523
|
+
if (!metadata3.restoreAttempted) {
|
|
82524
|
+
throw new TakeProfitReplaceRollbackFailedError(metadata3);
|
|
82525
|
+
}
|
|
82526
|
+
try {
|
|
82527
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
82528
|
+
symbol,
|
|
82529
|
+
tp: previousTakeProfitPrice,
|
|
82530
|
+
kind,
|
|
82531
|
+
quantity: previousQuantity,
|
|
82532
|
+
cancel: false,
|
|
82533
|
+
price_places: symbol_config.price_places,
|
|
82534
|
+
decimal_places: symbol_config.decimal_places
|
|
82535
|
+
});
|
|
82536
|
+
} catch (rollbackError) {
|
|
82537
|
+
throw new TakeProfitReplaceRollbackFailedError({
|
|
82538
|
+
...metadata3,
|
|
82539
|
+
rollbackError
|
|
82540
|
+
});
|
|
82541
|
+
}
|
|
82542
|
+
throw new TakeProfitReplaceRollbackSucceededError(metadata3);
|
|
82543
|
+
}
|
|
82544
|
+
}
|
|
82281
82545
|
async cancelExchangeOrders(payload) {
|
|
82282
82546
|
return this.exchange.cancelOrders(payload);
|
|
82283
82547
|
}
|
|
@@ -82562,8 +82826,8 @@ class ExchangeAccount {
|
|
|
82562
82826
|
if (payload.trigger && !long_pause_tp && !short_pause_tp && config2) {
|
|
82563
82827
|
return await this.reduceMajorPositionEntry({
|
|
82564
82828
|
symbol,
|
|
82565
|
-
long: config2.long,
|
|
82566
|
-
short: config2.short,
|
|
82829
|
+
long: kind === "long" ? config2.long : undefined,
|
|
82830
|
+
short: kind === "short" ? config2.short : undefined,
|
|
82567
82831
|
trigger: config2.trigger
|
|
82568
82832
|
});
|
|
82569
82833
|
}
|