@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/mcp-server.cjs
CHANGED
|
@@ -75760,9 +75760,18 @@ class BaseExchange {
|
|
|
75760
75760
|
async previewSpotMarginHedge(_payload) {
|
|
75761
75761
|
throw new Error("Spot margin hedge preview is not supported on this exchange");
|
|
75762
75762
|
}
|
|
75763
|
+
async previewFuturesReplay(_payload) {
|
|
75764
|
+
throw new Error("Futures replay preview is not supported on this exchange");
|
|
75765
|
+
}
|
|
75763
75766
|
async placeSpotMarginHedge(_payload) {
|
|
75764
75767
|
throw new Error("Spot margin hedge placement is not supported on this exchange");
|
|
75765
75768
|
}
|
|
75769
|
+
async placeFuturesReplay(_payload) {
|
|
75770
|
+
throw new Error("Futures replay placement is not supported on this exchange");
|
|
75771
|
+
}
|
|
75772
|
+
async placeFuturesExactTrade(_payload) {
|
|
75773
|
+
throw new Error("Futures exact trade placement is not supported on this exchange");
|
|
75774
|
+
}
|
|
75766
75775
|
async placeSpotLimitOrders(_payload) {}
|
|
75767
75776
|
async buildCumulative(payload) {
|
|
75768
75777
|
const {
|
|
@@ -76171,19 +76180,198 @@ class BaseExchange {
|
|
|
76171
76180
|
// src/exchanges/binance/index.ts
|
|
76172
76181
|
var import_p_limit = __toESM(require_p_limit(), 1);
|
|
76173
76182
|
|
|
76174
|
-
// src/exchanges/binance/
|
|
76183
|
+
// src/exchanges/binance/futures-replay.ts
|
|
76175
76184
|
function roundNumber(value2, digits = 8) {
|
|
76176
76185
|
return Number(value2.toFixed(digits));
|
|
76177
76186
|
}
|
|
76178
|
-
|
|
76187
|
+
function parseNumber2(value2) {
|
|
76188
|
+
if (value2 === undefined || value2 === null || value2 === "")
|
|
76189
|
+
return;
|
|
76190
|
+
const parsed = Number(value2);
|
|
76191
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
76192
|
+
return;
|
|
76193
|
+
return roundNumber(parsed);
|
|
76194
|
+
}
|
|
76179
76195
|
function normalizeOrderInput(order) {
|
|
76196
|
+
const stop = parseNumber2(order.stop) ?? parseNumber2(order.stopPrice) ?? parseNumber2(order.triggerPrice);
|
|
76197
|
+
const type = order.type ? order.type.toUpperCase() : undefined;
|
|
76198
|
+
const quantity = order.quantity ?? order.qty ?? 0;
|
|
76199
|
+
return {
|
|
76200
|
+
price: roundNumber(Number(order.price)),
|
|
76201
|
+
quantity: roundNumber(Number(quantity)),
|
|
76202
|
+
...stop ? { stop } : {},
|
|
76203
|
+
...type && type !== "LIMIT" ? { type } : {}
|
|
76204
|
+
};
|
|
76205
|
+
}
|
|
76206
|
+
function sortReplayOrders(orders) {
|
|
76207
|
+
return [...orders].sort((left, right) => {
|
|
76208
|
+
const leftTrigger = left.stop ?? left.price;
|
|
76209
|
+
const rightTrigger = right.stop ?? right.price;
|
|
76210
|
+
if (leftTrigger !== rightTrigger)
|
|
76211
|
+
return leftTrigger - rightTrigger;
|
|
76212
|
+
if (left.price !== right.price)
|
|
76213
|
+
return left.price - right.price;
|
|
76214
|
+
return left.quantity - right.quantity;
|
|
76215
|
+
});
|
|
76216
|
+
}
|
|
76217
|
+
function buildReplayStopLimitPrice(payload) {
|
|
76218
|
+
const spread = payload.stop > 30000 ? 1.00005 : 1.0002;
|
|
76219
|
+
return roundNumber(payload.kind === "long" ? payload.stop * spread ** -1 : payload.stop * spread);
|
|
76220
|
+
}
|
|
76221
|
+
function normalizeRequestedEntryOrders(orders) {
|
|
76222
|
+
return sortReplayOrders(orders.map((order) => ({
|
|
76223
|
+
price: roundNumber(Number(order.price)),
|
|
76224
|
+
quantity: roundNumber(Number(order.quantity))
|
|
76225
|
+
})));
|
|
76226
|
+
}
|
|
76227
|
+
function normalizeRequestedStopOrders(payload) {
|
|
76228
|
+
return sortReplayOrders(payload.orders.map((order) => {
|
|
76229
|
+
const stop = parseNumber2(order.stop) ?? roundNumber(Number(order.price));
|
|
76230
|
+
return {
|
|
76231
|
+
price: order.price !== undefined ? roundNumber(Number(order.price)) : buildReplayStopLimitPrice({
|
|
76232
|
+
kind: payload.kind,
|
|
76233
|
+
stop
|
|
76234
|
+
}),
|
|
76235
|
+
quantity: roundNumber(Number(order.quantity)),
|
|
76236
|
+
stop,
|
|
76237
|
+
type: (order.type || "STOP").toUpperCase()
|
|
76238
|
+
};
|
|
76239
|
+
}));
|
|
76240
|
+
}
|
|
76241
|
+
function normalizeRequestedTakeProfitOrders(orders) {
|
|
76242
|
+
return sortReplayOrders(orders.map((order) => {
|
|
76243
|
+
const stop = parseNumber2(order.stop);
|
|
76244
|
+
const type = order.type?.toUpperCase();
|
|
76245
|
+
return {
|
|
76246
|
+
price: roundNumber(Number(order.price)),
|
|
76247
|
+
quantity: roundNumber(Number(order.quantity)),
|
|
76248
|
+
...stop ? { stop } : {},
|
|
76249
|
+
...type ? { type } : stop ? { type: "TAKE_PROFIT" } : {}
|
|
76250
|
+
};
|
|
76251
|
+
}));
|
|
76252
|
+
}
|
|
76253
|
+
function buildOrderKey(order) {
|
|
76254
|
+
return [
|
|
76255
|
+
order.type || "LIMIT",
|
|
76256
|
+
order.price,
|
|
76257
|
+
order.quantity,
|
|
76258
|
+
order.stop ?? ""
|
|
76259
|
+
].join(":");
|
|
76260
|
+
}
|
|
76261
|
+
function buildComparisonBucket(options) {
|
|
76262
|
+
const expected = sortReplayOrders(options.expected);
|
|
76263
|
+
const actual = sortReplayOrders(options.actual);
|
|
76264
|
+
const expected_keys = expected.map(buildOrderKey);
|
|
76265
|
+
const actual_keys = actual.map(buildOrderKey);
|
|
76180
76266
|
return {
|
|
76181
|
-
|
|
76182
|
-
|
|
76267
|
+
expected,
|
|
76268
|
+
actual,
|
|
76269
|
+
missing: expected_keys.filter((key) => !actual_keys.includes(key)),
|
|
76270
|
+
extra: actual_keys.filter((key) => !expected_keys.includes(key))
|
|
76271
|
+
};
|
|
76272
|
+
}
|
|
76273
|
+
function buildFuturesReplaySnapshot(payload) {
|
|
76274
|
+
const entry_side = payload.kind === "long" ? "buy" : "sell";
|
|
76275
|
+
const close_side = payload.kind === "long" ? "sell" : "buy";
|
|
76276
|
+
const entry_orders = [];
|
|
76277
|
+
const stop_orders = [];
|
|
76278
|
+
const take_profit_orders = [];
|
|
76279
|
+
for (const order of payload.open_orders) {
|
|
76280
|
+
if (order.kind !== payload.kind)
|
|
76281
|
+
continue;
|
|
76282
|
+
const normalized_order = normalizeOrderInput(order);
|
|
76283
|
+
const type = (normalized_order.type || "LIMIT").toUpperCase();
|
|
76284
|
+
if (order.side === entry_side) {
|
|
76285
|
+
entry_orders.push(normalized_order);
|
|
76286
|
+
continue;
|
|
76287
|
+
}
|
|
76288
|
+
if (order.side !== close_side)
|
|
76289
|
+
continue;
|
|
76290
|
+
if (type.includes("TAKE_PROFIT") || normalized_order.stop === undefined) {
|
|
76291
|
+
take_profit_orders.push(normalized_order);
|
|
76292
|
+
continue;
|
|
76293
|
+
}
|
|
76294
|
+
stop_orders.push(normalized_order);
|
|
76295
|
+
}
|
|
76296
|
+
return {
|
|
76297
|
+
symbol: payload.symbol,
|
|
76298
|
+
kind: payload.kind,
|
|
76299
|
+
current_price: payload.current_price,
|
|
76300
|
+
position: payload.position,
|
|
76301
|
+
open_orders: payload.open_orders.filter((order) => order.kind === payload.kind),
|
|
76302
|
+
entry_orders: sortReplayOrders(entry_orders),
|
|
76303
|
+
stop_orders: sortReplayOrders(stop_orders),
|
|
76304
|
+
take_profit_orders: sortReplayOrders(take_profit_orders)
|
|
76305
|
+
};
|
|
76306
|
+
}
|
|
76307
|
+
function inferFuturesReplayInputFromLiveOrders(payload) {
|
|
76308
|
+
const snapshot = buildFuturesReplaySnapshot(payload);
|
|
76309
|
+
return {
|
|
76310
|
+
symbol: payload.symbol,
|
|
76311
|
+
kind: payload.kind,
|
|
76312
|
+
current_price: payload.current_price,
|
|
76313
|
+
position: payload.position,
|
|
76314
|
+
entry_orders: snapshot.entry_orders,
|
|
76315
|
+
stop_orders: snapshot.stop_orders,
|
|
76316
|
+
take_profit_orders: snapshot.take_profit_orders
|
|
76317
|
+
};
|
|
76318
|
+
}
|
|
76319
|
+
function compareFuturesReplayOrders(payload) {
|
|
76320
|
+
const entry = buildComparisonBucket({
|
|
76321
|
+
expected: payload.entry_orders,
|
|
76322
|
+
actual: payload.snapshot.entry_orders
|
|
76323
|
+
});
|
|
76324
|
+
const stop = buildComparisonBucket({
|
|
76325
|
+
expected: payload.stop_orders,
|
|
76326
|
+
actual: payload.snapshot.stop_orders
|
|
76327
|
+
});
|
|
76328
|
+
const take_profit = buildComparisonBucket({
|
|
76329
|
+
expected: payload.take_profit_orders,
|
|
76330
|
+
actual: payload.snapshot.take_profit_orders
|
|
76331
|
+
});
|
|
76332
|
+
return {
|
|
76333
|
+
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,
|
|
76334
|
+
entry,
|
|
76335
|
+
stop,
|
|
76336
|
+
take_profit
|
|
76337
|
+
};
|
|
76338
|
+
}
|
|
76339
|
+
function buildFuturesReplayPlan(payload) {
|
|
76340
|
+
return {
|
|
76341
|
+
symbol: payload.symbol,
|
|
76342
|
+
kind: payload.kind,
|
|
76343
|
+
orders_to_cancel: payload.snapshot.open_orders,
|
|
76344
|
+
orders_to_create: {
|
|
76345
|
+
entry: sortReplayOrders(payload.entry_orders),
|
|
76346
|
+
stop: sortReplayOrders(payload.stop_orders),
|
|
76347
|
+
take_profit: sortReplayOrders(payload.take_profit_orders)
|
|
76348
|
+
}
|
|
76349
|
+
};
|
|
76350
|
+
}
|
|
76351
|
+
function normalizeFuturesReplayInput(payload) {
|
|
76352
|
+
return {
|
|
76353
|
+
entry_orders: normalizeRequestedEntryOrders(payload.entry_orders),
|
|
76354
|
+
stop_orders: normalizeRequestedStopOrders({
|
|
76355
|
+
kind: payload.kind,
|
|
76356
|
+
orders: payload.stop_orders
|
|
76357
|
+
}),
|
|
76358
|
+
take_profit_orders: normalizeRequestedTakeProfitOrders(payload.take_profit_orders)
|
|
76359
|
+
};
|
|
76360
|
+
}
|
|
76361
|
+
|
|
76362
|
+
// src/exchanges/binance/spot-margin-hedge.ts
|
|
76363
|
+
function roundNumber2(value2, digits = 8) {
|
|
76364
|
+
return Number(value2.toFixed(digits));
|
|
76365
|
+
}
|
|
76366
|
+
var STOP_LIMIT_SPREAD_PERCENT = 0.0005;
|
|
76367
|
+
function normalizeOrderInput2(order) {
|
|
76368
|
+
return {
|
|
76369
|
+
price: roundNumber2(order.price),
|
|
76370
|
+
quantity: roundNumber2(order.quantity)
|
|
76183
76371
|
};
|
|
76184
76372
|
}
|
|
76185
76373
|
function sortOrderInputs(orders) {
|
|
76186
|
-
return [...orders].map(
|
|
76374
|
+
return [...orders].map(normalizeOrderInput2).sort((left, right) => left.price - right.price);
|
|
76187
76375
|
}
|
|
76188
76376
|
function normalizeOrderForComparison(order) {
|
|
76189
76377
|
const type = (order.type || "limit").toLowerCase();
|
|
@@ -76192,9 +76380,9 @@ function normalizeOrderForComparison(order) {
|
|
|
76192
76380
|
return {
|
|
76193
76381
|
side: order.side,
|
|
76194
76382
|
type,
|
|
76195
|
-
price:
|
|
76196
|
-
quantity:
|
|
76197
|
-
stop: parsed_stop !== undefined && Number.isFinite(parsed_stop) && parsed_stop > 0 ?
|
|
76383
|
+
price: roundNumber2(order.price),
|
|
76384
|
+
quantity: roundNumber2(order.quantity),
|
|
76385
|
+
stop: parsed_stop !== undefined && Number.isFinite(parsed_stop) && parsed_stop > 0 ? roundNumber2(parsed_stop) : undefined
|
|
76198
76386
|
};
|
|
76199
76387
|
}
|
|
76200
76388
|
function normalizeOrders(orders) {
|
|
@@ -76217,7 +76405,7 @@ function toPlannedOrders(orders) {
|
|
|
76217
76405
|
stop: order.stop
|
|
76218
76406
|
}));
|
|
76219
76407
|
}
|
|
76220
|
-
function
|
|
76408
|
+
function buildOrderKey2(order) {
|
|
76221
76409
|
return [
|
|
76222
76410
|
order.side,
|
|
76223
76411
|
order.type,
|
|
@@ -76227,8 +76415,8 @@ function buildOrderKey(order) {
|
|
|
76227
76415
|
].join(":");
|
|
76228
76416
|
}
|
|
76229
76417
|
function buildDiff(options) {
|
|
76230
|
-
const expectedKeys = options.expected.map(
|
|
76231
|
-
const actualKeys = options.actual.map(
|
|
76418
|
+
const expectedKeys = options.expected.map(buildOrderKey2);
|
|
76419
|
+
const actualKeys = options.actual.map(buildOrderKey2);
|
|
76232
76420
|
return {
|
|
76233
76421
|
missing: expectedKeys.filter((key) => !actualKeys.includes(key)),
|
|
76234
76422
|
extra: actualKeys.filter((key) => !expectedKeys.includes(key))
|
|
@@ -76240,10 +76428,10 @@ function getQuoteAsset(symbol) {
|
|
|
76240
76428
|
return target || symbol.slice(-4);
|
|
76241
76429
|
}
|
|
76242
76430
|
function sumNotional(orders) {
|
|
76243
|
-
return
|
|
76431
|
+
return roundNumber2(orders.reduce((sum, order) => sum + order.price * order.quantity, 0), 8);
|
|
76244
76432
|
}
|
|
76245
76433
|
function sumQuantity(orders) {
|
|
76246
|
-
return
|
|
76434
|
+
return roundNumber2(orders.reduce((sum, order) => sum + order.quantity, 0), 8);
|
|
76247
76435
|
}
|
|
76248
76436
|
function buildLongOrderPlacement(options) {
|
|
76249
76437
|
const { order, current_price } = options;
|
|
@@ -76252,7 +76440,7 @@ function buildLongOrderPlacement(options) {
|
|
|
76252
76440
|
side: "buy",
|
|
76253
76441
|
type: "stop_loss_limit",
|
|
76254
76442
|
price: order.price,
|
|
76255
|
-
stop:
|
|
76443
|
+
stop: roundNumber2(order.price * (1 - STOP_LIMIT_SPREAD_PERCENT)),
|
|
76256
76444
|
quantity: order.quantity
|
|
76257
76445
|
};
|
|
76258
76446
|
}
|
|
@@ -76320,11 +76508,11 @@ function buildSpotMarginHedgePlan(options) {
|
|
|
76320
76508
|
}));
|
|
76321
76509
|
const spot_orders_to_create = options.placement_overrides?.spot || default_spot_orders_to_create;
|
|
76322
76510
|
const margin_orders_to_create = options.placement_overrides?.margin || default_margin_orders_to_create;
|
|
76323
|
-
const borrow_delta =
|
|
76511
|
+
const borrow_delta = roundNumber2(Math.max(0, options.borrow_amount - options.snapshot.borrowed_quote_amount));
|
|
76324
76512
|
const spot_long_notional = sumNotional(spot_long_orders);
|
|
76325
|
-
const transfer_to_spot_amount =
|
|
76513
|
+
const transfer_to_spot_amount = roundNumber2(Math.max(0, spot_long_notional - options.snapshot.spot_quote_free));
|
|
76326
76514
|
const short_quantity = sumQuantity(short_orders);
|
|
76327
|
-
const transfer_base_to_spot_amount =
|
|
76515
|
+
const transfer_base_to_spot_amount = roundNumber2(Math.max(0, short_quantity - options.snapshot.spot_base_free));
|
|
76328
76516
|
return {
|
|
76329
76517
|
borrow_amount: options.borrow_amount,
|
|
76330
76518
|
borrow_delta,
|
|
@@ -77983,6 +78171,30 @@ class BinanceExchange extends BaseExchange {
|
|
|
77983
78171
|
throw error;
|
|
77984
78172
|
}
|
|
77985
78173
|
}
|
|
78174
|
+
async getFuturesSymbolFormats(symbol) {
|
|
78175
|
+
if (typeof this.client.getExchangeInfo !== "function") {
|
|
78176
|
+
return {
|
|
78177
|
+
price_places: "%.8f",
|
|
78178
|
+
decimal_places: "%.8f"
|
|
78179
|
+
};
|
|
78180
|
+
}
|
|
78181
|
+
try {
|
|
78182
|
+
const exchange_info = await this.client.getExchangeInfo();
|
|
78183
|
+
const symbol_info = exchange_info?.symbols?.find((item) => item.symbol === symbol.toUpperCase());
|
|
78184
|
+
const price_filter = symbol_info?.filters?.find((filter) => filter.filterType === "PRICE_FILTER");
|
|
78185
|
+
const lot_size_filter = symbol_info?.filters?.find((filter) => filter.filterType === "LOT_SIZE");
|
|
78186
|
+
return {
|
|
78187
|
+
price_places: getPrintfFormatFromStepSize(price_filter?.tickSize, "%.8f"),
|
|
78188
|
+
decimal_places: getPrintfFormatFromStepSize(lot_size_filter?.stepSize, "%.8f")
|
|
78189
|
+
};
|
|
78190
|
+
} catch (error) {
|
|
78191
|
+
console.error("Error fetching futures symbol formats:", error);
|
|
78192
|
+
return {
|
|
78193
|
+
price_places: "%.8f",
|
|
78194
|
+
decimal_places: "%.8f"
|
|
78195
|
+
};
|
|
78196
|
+
}
|
|
78197
|
+
}
|
|
77986
78198
|
async getSpotSymbolFormats(symbol) {
|
|
77987
78199
|
if (!this.main_client || typeof this.main_client.getExchangeInfo !== "function") {
|
|
77988
78200
|
return {
|
|
@@ -78037,6 +78249,123 @@ class BinanceExchange extends BaseExchange {
|
|
|
78037
78249
|
}
|
|
78038
78250
|
return await getMarginOpenOrders(this.main_client, symbol, isIsolated);
|
|
78039
78251
|
}
|
|
78252
|
+
async getFuturesReplaySnapshot(payload) {
|
|
78253
|
+
const symbol = payload.symbol.toUpperCase();
|
|
78254
|
+
const [open_orders, position_info, current_price] = await Promise.all([
|
|
78255
|
+
this.getOpenOrders({ symbol }),
|
|
78256
|
+
this.getPositionInfo(symbol),
|
|
78257
|
+
this.getCurrentPrice(symbol)
|
|
78258
|
+
]);
|
|
78259
|
+
return buildFuturesReplaySnapshot({
|
|
78260
|
+
symbol,
|
|
78261
|
+
kind: payload.kind,
|
|
78262
|
+
current_price,
|
|
78263
|
+
position: {
|
|
78264
|
+
size: position_info[payload.kind]?.size || 0
|
|
78265
|
+
},
|
|
78266
|
+
open_orders
|
|
78267
|
+
});
|
|
78268
|
+
}
|
|
78269
|
+
async previewFuturesReplay(payload) {
|
|
78270
|
+
const snapshot = payload.snapshot ? {
|
|
78271
|
+
...payload.snapshot,
|
|
78272
|
+
current_price: payload.snapshot.current_price ?? await this.getCurrentPrice(payload.symbol)
|
|
78273
|
+
} : await this.getFuturesReplaySnapshot({
|
|
78274
|
+
symbol: payload.symbol,
|
|
78275
|
+
kind: payload.kind
|
|
78276
|
+
});
|
|
78277
|
+
const shouldInferEntryOrders = !payload.entry_orders || payload.entry_orders.length === 0;
|
|
78278
|
+
const shouldInferStopOrders = !payload.stop_orders || payload.stop_orders.length === 0;
|
|
78279
|
+
const shouldInferTakeProfitOrders = !payload.take_profit_orders || payload.take_profit_orders.length === 0;
|
|
78280
|
+
const inferred_input = shouldInferEntryOrders || shouldInferStopOrders || shouldInferTakeProfitOrders ? inferFuturesReplayInputFromLiveOrders({
|
|
78281
|
+
symbol: payload.symbol,
|
|
78282
|
+
kind: payload.kind,
|
|
78283
|
+
current_price: snapshot.current_price,
|
|
78284
|
+
position: snapshot.position,
|
|
78285
|
+
open_orders: snapshot.open_orders
|
|
78286
|
+
}) : undefined;
|
|
78287
|
+
const explicit_input = normalizeFuturesReplayInput({
|
|
78288
|
+
kind: payload.kind,
|
|
78289
|
+
entry_orders: payload.entry_orders || [],
|
|
78290
|
+
stop_orders: payload.stop_orders || [],
|
|
78291
|
+
take_profit_orders: payload.take_profit_orders || []
|
|
78292
|
+
});
|
|
78293
|
+
const entry_orders = shouldInferEntryOrders ? inferred_input?.entry_orders || [] : explicit_input.entry_orders;
|
|
78294
|
+
const stop_orders = shouldInferStopOrders ? inferred_input?.stop_orders || [] : explicit_input.stop_orders;
|
|
78295
|
+
const take_profit_orders = shouldInferTakeProfitOrders ? inferred_input?.take_profit_orders || [] : explicit_input.take_profit_orders;
|
|
78296
|
+
const requested_input = {
|
|
78297
|
+
symbol: payload.symbol,
|
|
78298
|
+
kind: payload.kind,
|
|
78299
|
+
entry_orders,
|
|
78300
|
+
stop_orders,
|
|
78301
|
+
take_profit_orders
|
|
78302
|
+
};
|
|
78303
|
+
const plan = buildFuturesReplayPlan({
|
|
78304
|
+
...requested_input,
|
|
78305
|
+
snapshot
|
|
78306
|
+
});
|
|
78307
|
+
const comparison = compareFuturesReplayOrders({
|
|
78308
|
+
...requested_input,
|
|
78309
|
+
snapshot
|
|
78310
|
+
});
|
|
78311
|
+
return {
|
|
78312
|
+
snapshot,
|
|
78313
|
+
inferred_input,
|
|
78314
|
+
requested_input,
|
|
78315
|
+
plan,
|
|
78316
|
+
comparison
|
|
78317
|
+
};
|
|
78318
|
+
}
|
|
78319
|
+
async placeFuturesReplay(payload) {
|
|
78320
|
+
const preview = await this.previewFuturesReplay(payload);
|
|
78321
|
+
if (!payload.place) {
|
|
78322
|
+
return preview;
|
|
78323
|
+
}
|
|
78324
|
+
const symbol = payload.symbol.toUpperCase();
|
|
78325
|
+
await cancelAllOrders(this.client, symbol, {
|
|
78326
|
+
kind: payload.kind
|
|
78327
|
+
});
|
|
78328
|
+
const refreshed_snapshot = await this.getFuturesReplaySnapshot({
|
|
78329
|
+
symbol,
|
|
78330
|
+
kind: payload.kind
|
|
78331
|
+
});
|
|
78332
|
+
const execution_plan = buildFuturesReplayPlan({
|
|
78333
|
+
symbol,
|
|
78334
|
+
kind: payload.kind,
|
|
78335
|
+
entry_orders: preview.requested_input.entry_orders,
|
|
78336
|
+
stop_orders: preview.requested_input.stop_orders,
|
|
78337
|
+
take_profit_orders: preview.requested_input.take_profit_orders,
|
|
78338
|
+
snapshot: refreshed_snapshot
|
|
78339
|
+
});
|
|
78340
|
+
const { price_places, decimal_places } = await this.getFuturesSymbolFormats(symbol);
|
|
78341
|
+
const entry_orders = execution_plan.orders_to_create.entry.map((order) => ({
|
|
78342
|
+
...order,
|
|
78343
|
+
side: payload.kind === "long" ? "buy" : "sell",
|
|
78344
|
+
kind: payload.kind
|
|
78345
|
+
}));
|
|
78346
|
+
const stop_orders = execution_plan.orders_to_create.stop.map((order) => ({
|
|
78347
|
+
...order,
|
|
78348
|
+
side: payload.kind === "long" ? "sell" : "buy",
|
|
78349
|
+
kind: payload.kind,
|
|
78350
|
+
type: order.type || "STOP"
|
|
78351
|
+
}));
|
|
78352
|
+
const take_profit_orders = execution_plan.orders_to_create.take_profit.map((order) => ({
|
|
78353
|
+
...order,
|
|
78354
|
+
side: payload.kind === "long" ? "sell" : "buy",
|
|
78355
|
+
kind: payload.kind,
|
|
78356
|
+
...order.stop ? { type: order.type || "TAKE_PROFIT" } : {}
|
|
78357
|
+
}));
|
|
78358
|
+
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]) : [];
|
|
78359
|
+
return {
|
|
78360
|
+
...preview,
|
|
78361
|
+
execution_plan,
|
|
78362
|
+
refreshed_snapshot,
|
|
78363
|
+
execution
|
|
78364
|
+
};
|
|
78365
|
+
}
|
|
78366
|
+
async placeFuturesExactTrade(payload) {
|
|
78367
|
+
return await this.placeFuturesReplay(payload);
|
|
78368
|
+
}
|
|
78040
78369
|
async getSpotMarginHedgeSnapshot(payload) {
|
|
78041
78370
|
if (!this.main_client) {
|
|
78042
78371
|
throw new Error("Main client not available for spot and margin trading");
|