@gbozee/ultimate 0.0.2-next.73 → 0.0.2-next.74
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 +346 -17
- package/dist/index.d.ts +71 -0
- package/dist/index.js +346 -17
- package/dist/mcp-server.cjs +346 -17
- package/dist/mcp-server.js +346 -17
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -71936,9 +71936,18 @@ class BaseExchange {
|
|
|
71936
71936
|
async previewSpotMarginHedge(_payload) {
|
|
71937
71937
|
throw new Error("Spot margin hedge preview is not supported on this exchange");
|
|
71938
71938
|
}
|
|
71939
|
+
async previewFuturesReplay(_payload) {
|
|
71940
|
+
throw new Error("Futures replay preview is not supported on this exchange");
|
|
71941
|
+
}
|
|
71939
71942
|
async placeSpotMarginHedge(_payload) {
|
|
71940
71943
|
throw new Error("Spot margin hedge placement is not supported on this exchange");
|
|
71941
71944
|
}
|
|
71945
|
+
async placeFuturesReplay(_payload) {
|
|
71946
|
+
throw new Error("Futures replay placement is not supported on this exchange");
|
|
71947
|
+
}
|
|
71948
|
+
async placeFuturesExactTrade(_payload) {
|
|
71949
|
+
throw new Error("Futures exact trade placement is not supported on this exchange");
|
|
71950
|
+
}
|
|
71942
71951
|
async placeSpotLimitOrders(_payload) {}
|
|
71943
71952
|
async buildCumulative(payload) {
|
|
71944
71953
|
const {
|
|
@@ -72347,19 +72356,198 @@ class BaseExchange {
|
|
|
72347
72356
|
// src/exchanges/binance/index.ts
|
|
72348
72357
|
var import_p_limit = __toESM(require_p_limit(), 1);
|
|
72349
72358
|
|
|
72350
|
-
// src/exchanges/binance/
|
|
72359
|
+
// src/exchanges/binance/futures-replay.ts
|
|
72351
72360
|
function roundNumber(value2, digits = 8) {
|
|
72352
72361
|
return Number(value2.toFixed(digits));
|
|
72353
72362
|
}
|
|
72354
|
-
|
|
72363
|
+
function parseNumber2(value2) {
|
|
72364
|
+
if (value2 === undefined || value2 === null || value2 === "")
|
|
72365
|
+
return;
|
|
72366
|
+
const parsed = Number(value2);
|
|
72367
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
72368
|
+
return;
|
|
72369
|
+
return roundNumber(parsed);
|
|
72370
|
+
}
|
|
72355
72371
|
function normalizeOrderInput(order) {
|
|
72372
|
+
const stop = parseNumber2(order.stop) ?? parseNumber2(order.stopPrice) ?? parseNumber2(order.triggerPrice);
|
|
72373
|
+
const type = order.type ? order.type.toUpperCase() : undefined;
|
|
72374
|
+
const quantity = order.quantity ?? order.qty ?? 0;
|
|
72375
|
+
return {
|
|
72376
|
+
price: roundNumber(Number(order.price)),
|
|
72377
|
+
quantity: roundNumber(Number(quantity)),
|
|
72378
|
+
...stop ? { stop } : {},
|
|
72379
|
+
...type && type !== "LIMIT" ? { type } : {}
|
|
72380
|
+
};
|
|
72381
|
+
}
|
|
72382
|
+
function sortReplayOrders(orders) {
|
|
72383
|
+
return [...orders].sort((left, right) => {
|
|
72384
|
+
const leftTrigger = left.stop ?? left.price;
|
|
72385
|
+
const rightTrigger = right.stop ?? right.price;
|
|
72386
|
+
if (leftTrigger !== rightTrigger)
|
|
72387
|
+
return leftTrigger - rightTrigger;
|
|
72388
|
+
if (left.price !== right.price)
|
|
72389
|
+
return left.price - right.price;
|
|
72390
|
+
return left.quantity - right.quantity;
|
|
72391
|
+
});
|
|
72392
|
+
}
|
|
72393
|
+
function buildReplayStopLimitPrice(payload) {
|
|
72394
|
+
const spread = payload.stop > 30000 ? 1.00005 : 1.0002;
|
|
72395
|
+
return roundNumber(payload.kind === "long" ? payload.stop * spread ** -1 : payload.stop * spread);
|
|
72396
|
+
}
|
|
72397
|
+
function normalizeRequestedEntryOrders(orders) {
|
|
72398
|
+
return sortReplayOrders(orders.map((order) => ({
|
|
72399
|
+
price: roundNumber(Number(order.price)),
|
|
72400
|
+
quantity: roundNumber(Number(order.quantity))
|
|
72401
|
+
})));
|
|
72402
|
+
}
|
|
72403
|
+
function normalizeRequestedStopOrders(payload) {
|
|
72404
|
+
return sortReplayOrders(payload.orders.map((order) => {
|
|
72405
|
+
const stop = parseNumber2(order.stop) ?? roundNumber(Number(order.price));
|
|
72406
|
+
return {
|
|
72407
|
+
price: order.price !== undefined ? roundNumber(Number(order.price)) : buildReplayStopLimitPrice({
|
|
72408
|
+
kind: payload.kind,
|
|
72409
|
+
stop
|
|
72410
|
+
}),
|
|
72411
|
+
quantity: roundNumber(Number(order.quantity)),
|
|
72412
|
+
stop,
|
|
72413
|
+
type: (order.type || "STOP").toUpperCase()
|
|
72414
|
+
};
|
|
72415
|
+
}));
|
|
72416
|
+
}
|
|
72417
|
+
function normalizeRequestedTakeProfitOrders(orders) {
|
|
72418
|
+
return sortReplayOrders(orders.map((order) => {
|
|
72419
|
+
const stop = parseNumber2(order.stop);
|
|
72420
|
+
const type = order.type?.toUpperCase();
|
|
72421
|
+
return {
|
|
72422
|
+
price: roundNumber(Number(order.price)),
|
|
72423
|
+
quantity: roundNumber(Number(order.quantity)),
|
|
72424
|
+
...stop ? { stop } : {},
|
|
72425
|
+
...type ? { type } : stop ? { type: "TAKE_PROFIT" } : {}
|
|
72426
|
+
};
|
|
72427
|
+
}));
|
|
72428
|
+
}
|
|
72429
|
+
function buildOrderKey(order) {
|
|
72430
|
+
return [
|
|
72431
|
+
order.type || "LIMIT",
|
|
72432
|
+
order.price,
|
|
72433
|
+
order.quantity,
|
|
72434
|
+
order.stop ?? ""
|
|
72435
|
+
].join(":");
|
|
72436
|
+
}
|
|
72437
|
+
function buildComparisonBucket(options) {
|
|
72438
|
+
const expected = sortReplayOrders(options.expected);
|
|
72439
|
+
const actual = sortReplayOrders(options.actual);
|
|
72440
|
+
const expected_keys = expected.map(buildOrderKey);
|
|
72441
|
+
const actual_keys = actual.map(buildOrderKey);
|
|
72356
72442
|
return {
|
|
72357
|
-
|
|
72358
|
-
|
|
72443
|
+
expected,
|
|
72444
|
+
actual,
|
|
72445
|
+
missing: expected_keys.filter((key) => !actual_keys.includes(key)),
|
|
72446
|
+
extra: actual_keys.filter((key) => !expected_keys.includes(key))
|
|
72447
|
+
};
|
|
72448
|
+
}
|
|
72449
|
+
function buildFuturesReplaySnapshot(payload) {
|
|
72450
|
+
const entry_side = payload.kind === "long" ? "buy" : "sell";
|
|
72451
|
+
const close_side = payload.kind === "long" ? "sell" : "buy";
|
|
72452
|
+
const entry_orders = [];
|
|
72453
|
+
const stop_orders = [];
|
|
72454
|
+
const take_profit_orders = [];
|
|
72455
|
+
for (const order of payload.open_orders) {
|
|
72456
|
+
if (order.kind !== payload.kind)
|
|
72457
|
+
continue;
|
|
72458
|
+
const normalized_order = normalizeOrderInput(order);
|
|
72459
|
+
const type = (normalized_order.type || "LIMIT").toUpperCase();
|
|
72460
|
+
if (order.side === entry_side) {
|
|
72461
|
+
entry_orders.push(normalized_order);
|
|
72462
|
+
continue;
|
|
72463
|
+
}
|
|
72464
|
+
if (order.side !== close_side)
|
|
72465
|
+
continue;
|
|
72466
|
+
if (type.includes("TAKE_PROFIT") || normalized_order.stop === undefined) {
|
|
72467
|
+
take_profit_orders.push(normalized_order);
|
|
72468
|
+
continue;
|
|
72469
|
+
}
|
|
72470
|
+
stop_orders.push(normalized_order);
|
|
72471
|
+
}
|
|
72472
|
+
return {
|
|
72473
|
+
symbol: payload.symbol,
|
|
72474
|
+
kind: payload.kind,
|
|
72475
|
+
current_price: payload.current_price,
|
|
72476
|
+
position: payload.position,
|
|
72477
|
+
open_orders: payload.open_orders.filter((order) => order.kind === payload.kind),
|
|
72478
|
+
entry_orders: sortReplayOrders(entry_orders),
|
|
72479
|
+
stop_orders: sortReplayOrders(stop_orders),
|
|
72480
|
+
take_profit_orders: sortReplayOrders(take_profit_orders)
|
|
72481
|
+
};
|
|
72482
|
+
}
|
|
72483
|
+
function inferFuturesReplayInputFromLiveOrders(payload) {
|
|
72484
|
+
const snapshot = buildFuturesReplaySnapshot(payload);
|
|
72485
|
+
return {
|
|
72486
|
+
symbol: payload.symbol,
|
|
72487
|
+
kind: payload.kind,
|
|
72488
|
+
current_price: payload.current_price,
|
|
72489
|
+
position: payload.position,
|
|
72490
|
+
entry_orders: snapshot.entry_orders,
|
|
72491
|
+
stop_orders: snapshot.stop_orders,
|
|
72492
|
+
take_profit_orders: snapshot.take_profit_orders
|
|
72493
|
+
};
|
|
72494
|
+
}
|
|
72495
|
+
function compareFuturesReplayOrders(payload) {
|
|
72496
|
+
const entry = buildComparisonBucket({
|
|
72497
|
+
expected: payload.entry_orders,
|
|
72498
|
+
actual: payload.snapshot.entry_orders
|
|
72499
|
+
});
|
|
72500
|
+
const stop = buildComparisonBucket({
|
|
72501
|
+
expected: payload.stop_orders,
|
|
72502
|
+
actual: payload.snapshot.stop_orders
|
|
72503
|
+
});
|
|
72504
|
+
const take_profit = buildComparisonBucket({
|
|
72505
|
+
expected: payload.take_profit_orders,
|
|
72506
|
+
actual: payload.snapshot.take_profit_orders
|
|
72507
|
+
});
|
|
72508
|
+
return {
|
|
72509
|
+
matches: entry.missing.length === 0 && entry.extra.length === 0 && stop.missing.length === 0 && stop.extra.length === 0 && take_profit.missing.length === 0 && take_profit.extra.length === 0,
|
|
72510
|
+
entry,
|
|
72511
|
+
stop,
|
|
72512
|
+
take_profit
|
|
72513
|
+
};
|
|
72514
|
+
}
|
|
72515
|
+
function buildFuturesReplayPlan(payload) {
|
|
72516
|
+
return {
|
|
72517
|
+
symbol: payload.symbol,
|
|
72518
|
+
kind: payload.kind,
|
|
72519
|
+
orders_to_cancel: payload.snapshot.open_orders,
|
|
72520
|
+
orders_to_create: {
|
|
72521
|
+
entry: sortReplayOrders(payload.entry_orders),
|
|
72522
|
+
stop: sortReplayOrders(payload.stop_orders),
|
|
72523
|
+
take_profit: sortReplayOrders(payload.take_profit_orders)
|
|
72524
|
+
}
|
|
72525
|
+
};
|
|
72526
|
+
}
|
|
72527
|
+
function normalizeFuturesReplayInput(payload) {
|
|
72528
|
+
return {
|
|
72529
|
+
entry_orders: normalizeRequestedEntryOrders(payload.entry_orders),
|
|
72530
|
+
stop_orders: normalizeRequestedStopOrders({
|
|
72531
|
+
kind: payload.kind,
|
|
72532
|
+
orders: payload.stop_orders
|
|
72533
|
+
}),
|
|
72534
|
+
take_profit_orders: normalizeRequestedTakeProfitOrders(payload.take_profit_orders)
|
|
72535
|
+
};
|
|
72536
|
+
}
|
|
72537
|
+
|
|
72538
|
+
// src/exchanges/binance/spot-margin-hedge.ts
|
|
72539
|
+
function roundNumber2(value2, digits = 8) {
|
|
72540
|
+
return Number(value2.toFixed(digits));
|
|
72541
|
+
}
|
|
72542
|
+
var STOP_LIMIT_SPREAD_PERCENT = 0.0005;
|
|
72543
|
+
function normalizeOrderInput2(order) {
|
|
72544
|
+
return {
|
|
72545
|
+
price: roundNumber2(order.price),
|
|
72546
|
+
quantity: roundNumber2(order.quantity)
|
|
72359
72547
|
};
|
|
72360
72548
|
}
|
|
72361
72549
|
function sortOrderInputs(orders) {
|
|
72362
|
-
return [...orders].map(
|
|
72550
|
+
return [...orders].map(normalizeOrderInput2).sort((left, right) => left.price - right.price);
|
|
72363
72551
|
}
|
|
72364
72552
|
function normalizeOrderForComparison(order) {
|
|
72365
72553
|
const type = (order.type || "limit").toLowerCase();
|
|
@@ -72368,9 +72556,9 @@ function normalizeOrderForComparison(order) {
|
|
|
72368
72556
|
return {
|
|
72369
72557
|
side: order.side,
|
|
72370
72558
|
type,
|
|
72371
|
-
price:
|
|
72372
|
-
quantity:
|
|
72373
|
-
stop: parsed_stop !== undefined && Number.isFinite(parsed_stop) && parsed_stop > 0 ?
|
|
72559
|
+
price: roundNumber2(order.price),
|
|
72560
|
+
quantity: roundNumber2(order.quantity),
|
|
72561
|
+
stop: parsed_stop !== undefined && Number.isFinite(parsed_stop) && parsed_stop > 0 ? roundNumber2(parsed_stop) : undefined
|
|
72374
72562
|
};
|
|
72375
72563
|
}
|
|
72376
72564
|
function normalizeOrders(orders) {
|
|
@@ -72393,7 +72581,7 @@ function toPlannedOrders(orders) {
|
|
|
72393
72581
|
stop: order.stop
|
|
72394
72582
|
}));
|
|
72395
72583
|
}
|
|
72396
|
-
function
|
|
72584
|
+
function buildOrderKey2(order) {
|
|
72397
72585
|
return [
|
|
72398
72586
|
order.side,
|
|
72399
72587
|
order.type,
|
|
@@ -72403,8 +72591,8 @@ function buildOrderKey(order) {
|
|
|
72403
72591
|
].join(":");
|
|
72404
72592
|
}
|
|
72405
72593
|
function buildDiff(options) {
|
|
72406
|
-
const expectedKeys = options.expected.map(
|
|
72407
|
-
const actualKeys = options.actual.map(
|
|
72594
|
+
const expectedKeys = options.expected.map(buildOrderKey2);
|
|
72595
|
+
const actualKeys = options.actual.map(buildOrderKey2);
|
|
72408
72596
|
return {
|
|
72409
72597
|
missing: expectedKeys.filter((key) => !actualKeys.includes(key)),
|
|
72410
72598
|
extra: actualKeys.filter((key) => !expectedKeys.includes(key))
|
|
@@ -72416,10 +72604,10 @@ function getQuoteAsset(symbol) {
|
|
|
72416
72604
|
return target || symbol.slice(-4);
|
|
72417
72605
|
}
|
|
72418
72606
|
function sumNotional(orders) {
|
|
72419
|
-
return
|
|
72607
|
+
return roundNumber2(orders.reduce((sum, order) => sum + order.price * order.quantity, 0), 8);
|
|
72420
72608
|
}
|
|
72421
72609
|
function sumQuantity(orders) {
|
|
72422
|
-
return
|
|
72610
|
+
return roundNumber2(orders.reduce((sum, order) => sum + order.quantity, 0), 8);
|
|
72423
72611
|
}
|
|
72424
72612
|
function buildLongOrderPlacement(options) {
|
|
72425
72613
|
const { order, current_price } = options;
|
|
@@ -72428,7 +72616,7 @@ function buildLongOrderPlacement(options) {
|
|
|
72428
72616
|
side: "buy",
|
|
72429
72617
|
type: "stop_loss_limit",
|
|
72430
72618
|
price: order.price,
|
|
72431
|
-
stop:
|
|
72619
|
+
stop: roundNumber2(order.price * (1 - STOP_LIMIT_SPREAD_PERCENT)),
|
|
72432
72620
|
quantity: order.quantity
|
|
72433
72621
|
};
|
|
72434
72622
|
}
|
|
@@ -72496,11 +72684,11 @@ function buildSpotMarginHedgePlan(options) {
|
|
|
72496
72684
|
}));
|
|
72497
72685
|
const spot_orders_to_create = options.placement_overrides?.spot || default_spot_orders_to_create;
|
|
72498
72686
|
const margin_orders_to_create = options.placement_overrides?.margin || default_margin_orders_to_create;
|
|
72499
|
-
const borrow_delta =
|
|
72687
|
+
const borrow_delta = roundNumber2(Math.max(0, options.borrow_amount - options.snapshot.borrowed_quote_amount));
|
|
72500
72688
|
const spot_long_notional = sumNotional(spot_long_orders);
|
|
72501
|
-
const transfer_to_spot_amount =
|
|
72689
|
+
const transfer_to_spot_amount = roundNumber2(Math.max(0, spot_long_notional - options.snapshot.spot_quote_free));
|
|
72502
72690
|
const short_quantity = sumQuantity(short_orders);
|
|
72503
|
-
const transfer_base_to_spot_amount =
|
|
72691
|
+
const transfer_base_to_spot_amount = roundNumber2(Math.max(0, short_quantity - options.snapshot.spot_base_free));
|
|
72504
72692
|
return {
|
|
72505
72693
|
borrow_amount: options.borrow_amount,
|
|
72506
72694
|
borrow_delta,
|
|
@@ -74159,6 +74347,30 @@ class BinanceExchange extends BaseExchange {
|
|
|
74159
74347
|
throw error;
|
|
74160
74348
|
}
|
|
74161
74349
|
}
|
|
74350
|
+
async getFuturesSymbolFormats(symbol) {
|
|
74351
|
+
if (typeof this.client.getExchangeInfo !== "function") {
|
|
74352
|
+
return {
|
|
74353
|
+
price_places: "%.8f",
|
|
74354
|
+
decimal_places: "%.8f"
|
|
74355
|
+
};
|
|
74356
|
+
}
|
|
74357
|
+
try {
|
|
74358
|
+
const exchange_info = await this.client.getExchangeInfo();
|
|
74359
|
+
const symbol_info = exchange_info?.symbols?.find((item) => item.symbol === symbol.toUpperCase());
|
|
74360
|
+
const price_filter = symbol_info?.filters?.find((filter) => filter.filterType === "PRICE_FILTER");
|
|
74361
|
+
const lot_size_filter = symbol_info?.filters?.find((filter) => filter.filterType === "LOT_SIZE");
|
|
74362
|
+
return {
|
|
74363
|
+
price_places: getPrintfFormatFromStepSize(price_filter?.tickSize, "%.8f"),
|
|
74364
|
+
decimal_places: getPrintfFormatFromStepSize(lot_size_filter?.stepSize, "%.8f")
|
|
74365
|
+
};
|
|
74366
|
+
} catch (error) {
|
|
74367
|
+
console.error("Error fetching futures symbol formats:", error);
|
|
74368
|
+
return {
|
|
74369
|
+
price_places: "%.8f",
|
|
74370
|
+
decimal_places: "%.8f"
|
|
74371
|
+
};
|
|
74372
|
+
}
|
|
74373
|
+
}
|
|
74162
74374
|
async getSpotSymbolFormats(symbol) {
|
|
74163
74375
|
if (!this.main_client || typeof this.main_client.getExchangeInfo !== "function") {
|
|
74164
74376
|
return {
|
|
@@ -74213,6 +74425,123 @@ class BinanceExchange extends BaseExchange {
|
|
|
74213
74425
|
}
|
|
74214
74426
|
return await getMarginOpenOrders(this.main_client, symbol, isIsolated);
|
|
74215
74427
|
}
|
|
74428
|
+
async getFuturesReplaySnapshot(payload) {
|
|
74429
|
+
const symbol = payload.symbol.toUpperCase();
|
|
74430
|
+
const [open_orders, position_info, current_price] = await Promise.all([
|
|
74431
|
+
this.getOpenOrders({ symbol }),
|
|
74432
|
+
this.getPositionInfo(symbol),
|
|
74433
|
+
this.getCurrentPrice(symbol)
|
|
74434
|
+
]);
|
|
74435
|
+
return buildFuturesReplaySnapshot({
|
|
74436
|
+
symbol,
|
|
74437
|
+
kind: payload.kind,
|
|
74438
|
+
current_price,
|
|
74439
|
+
position: {
|
|
74440
|
+
size: position_info[payload.kind]?.size || 0
|
|
74441
|
+
},
|
|
74442
|
+
open_orders
|
|
74443
|
+
});
|
|
74444
|
+
}
|
|
74445
|
+
async previewFuturesReplay(payload) {
|
|
74446
|
+
const snapshot = payload.snapshot ? {
|
|
74447
|
+
...payload.snapshot,
|
|
74448
|
+
current_price: payload.snapshot.current_price ?? await this.getCurrentPrice(payload.symbol)
|
|
74449
|
+
} : await this.getFuturesReplaySnapshot({
|
|
74450
|
+
symbol: payload.symbol,
|
|
74451
|
+
kind: payload.kind
|
|
74452
|
+
});
|
|
74453
|
+
const shouldInferEntryOrders = !payload.entry_orders || payload.entry_orders.length === 0;
|
|
74454
|
+
const shouldInferStopOrders = !payload.stop_orders || payload.stop_orders.length === 0;
|
|
74455
|
+
const shouldInferTakeProfitOrders = !payload.take_profit_orders || payload.take_profit_orders.length === 0;
|
|
74456
|
+
const inferred_input = shouldInferEntryOrders || shouldInferStopOrders || shouldInferTakeProfitOrders ? inferFuturesReplayInputFromLiveOrders({
|
|
74457
|
+
symbol: payload.symbol,
|
|
74458
|
+
kind: payload.kind,
|
|
74459
|
+
current_price: snapshot.current_price,
|
|
74460
|
+
position: snapshot.position,
|
|
74461
|
+
open_orders: snapshot.open_orders
|
|
74462
|
+
}) : undefined;
|
|
74463
|
+
const explicit_input = normalizeFuturesReplayInput({
|
|
74464
|
+
kind: payload.kind,
|
|
74465
|
+
entry_orders: payload.entry_orders || [],
|
|
74466
|
+
stop_orders: payload.stop_orders || [],
|
|
74467
|
+
take_profit_orders: payload.take_profit_orders || []
|
|
74468
|
+
});
|
|
74469
|
+
const entry_orders = shouldInferEntryOrders ? inferred_input?.entry_orders || [] : explicit_input.entry_orders;
|
|
74470
|
+
const stop_orders = shouldInferStopOrders ? inferred_input?.stop_orders || [] : explicit_input.stop_orders;
|
|
74471
|
+
const take_profit_orders = shouldInferTakeProfitOrders ? inferred_input?.take_profit_orders || [] : explicit_input.take_profit_orders;
|
|
74472
|
+
const requested_input = {
|
|
74473
|
+
symbol: payload.symbol,
|
|
74474
|
+
kind: payload.kind,
|
|
74475
|
+
entry_orders,
|
|
74476
|
+
stop_orders,
|
|
74477
|
+
take_profit_orders
|
|
74478
|
+
};
|
|
74479
|
+
const plan = buildFuturesReplayPlan({
|
|
74480
|
+
...requested_input,
|
|
74481
|
+
snapshot
|
|
74482
|
+
});
|
|
74483
|
+
const comparison = compareFuturesReplayOrders({
|
|
74484
|
+
...requested_input,
|
|
74485
|
+
snapshot
|
|
74486
|
+
});
|
|
74487
|
+
return {
|
|
74488
|
+
snapshot,
|
|
74489
|
+
inferred_input,
|
|
74490
|
+
requested_input,
|
|
74491
|
+
plan,
|
|
74492
|
+
comparison
|
|
74493
|
+
};
|
|
74494
|
+
}
|
|
74495
|
+
async placeFuturesReplay(payload) {
|
|
74496
|
+
const preview = await this.previewFuturesReplay(payload);
|
|
74497
|
+
if (!payload.place) {
|
|
74498
|
+
return preview;
|
|
74499
|
+
}
|
|
74500
|
+
const symbol = payload.symbol.toUpperCase();
|
|
74501
|
+
await cancelAllOrders(this.client, symbol, {
|
|
74502
|
+
kind: payload.kind
|
|
74503
|
+
});
|
|
74504
|
+
const refreshed_snapshot = await this.getFuturesReplaySnapshot({
|
|
74505
|
+
symbol,
|
|
74506
|
+
kind: payload.kind
|
|
74507
|
+
});
|
|
74508
|
+
const execution_plan = buildFuturesReplayPlan({
|
|
74509
|
+
symbol,
|
|
74510
|
+
kind: payload.kind,
|
|
74511
|
+
entry_orders: preview.requested_input.entry_orders,
|
|
74512
|
+
stop_orders: preview.requested_input.stop_orders,
|
|
74513
|
+
take_profit_orders: preview.requested_input.take_profit_orders,
|
|
74514
|
+
snapshot: refreshed_snapshot
|
|
74515
|
+
});
|
|
74516
|
+
const { price_places, decimal_places } = await this.getFuturesSymbolFormats(symbol);
|
|
74517
|
+
const entry_orders = execution_plan.orders_to_create.entry.map((order) => ({
|
|
74518
|
+
...order,
|
|
74519
|
+
side: payload.kind === "long" ? "buy" : "sell",
|
|
74520
|
+
kind: payload.kind
|
|
74521
|
+
}));
|
|
74522
|
+
const stop_orders = execution_plan.orders_to_create.stop.map((order) => ({
|
|
74523
|
+
...order,
|
|
74524
|
+
side: payload.kind === "long" ? "sell" : "buy",
|
|
74525
|
+
kind: payload.kind,
|
|
74526
|
+
type: order.type || "STOP"
|
|
74527
|
+
}));
|
|
74528
|
+
const take_profit_orders = execution_plan.orders_to_create.take_profit.map((order) => ({
|
|
74529
|
+
...order,
|
|
74530
|
+
side: payload.kind === "long" ? "sell" : "buy",
|
|
74531
|
+
kind: payload.kind,
|
|
74532
|
+
...order.stop ? { type: order.type || "TAKE_PROFIT" } : {}
|
|
74533
|
+
}));
|
|
74534
|
+
const execution = entry_orders.length > 0 || stop_orders.length > 0 || take_profit_orders.length > 0 ? await createLimitPurchaseOrdersParallel(this.client, symbol, price_places, decimal_places, [...entry_orders, ...stop_orders, ...take_profit_orders]) : [];
|
|
74535
|
+
return {
|
|
74536
|
+
...preview,
|
|
74537
|
+
execution_plan,
|
|
74538
|
+
refreshed_snapshot,
|
|
74539
|
+
execution
|
|
74540
|
+
};
|
|
74541
|
+
}
|
|
74542
|
+
async placeFuturesExactTrade(payload) {
|
|
74543
|
+
return await this.placeFuturesReplay(payload);
|
|
74544
|
+
}
|
|
74216
74545
|
async getSpotMarginHedgeSnapshot(payload) {
|
|
74217
74546
|
if (!this.main_client) {
|
|
74218
74547
|
throw new Error("Main client not available for spot and margin trading");
|