@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.js
CHANGED
|
@@ -75719,9 +75719,18 @@ class BaseExchange {
|
|
|
75719
75719
|
async previewSpotMarginHedge(_payload) {
|
|
75720
75720
|
throw new Error("Spot margin hedge preview is not supported on this exchange");
|
|
75721
75721
|
}
|
|
75722
|
+
async previewFuturesReplay(_payload) {
|
|
75723
|
+
throw new Error("Futures replay preview is not supported on this exchange");
|
|
75724
|
+
}
|
|
75722
75725
|
async placeSpotMarginHedge(_payload) {
|
|
75723
75726
|
throw new Error("Spot margin hedge placement is not supported on this exchange");
|
|
75724
75727
|
}
|
|
75728
|
+
async placeFuturesReplay(_payload) {
|
|
75729
|
+
throw new Error("Futures replay placement is not supported on this exchange");
|
|
75730
|
+
}
|
|
75731
|
+
async placeFuturesExactTrade(_payload) {
|
|
75732
|
+
throw new Error("Futures exact trade placement is not supported on this exchange");
|
|
75733
|
+
}
|
|
75725
75734
|
async placeSpotLimitOrders(_payload) {}
|
|
75726
75735
|
async buildCumulative(payload) {
|
|
75727
75736
|
const {
|
|
@@ -76130,19 +76139,198 @@ class BaseExchange {
|
|
|
76130
76139
|
// src/exchanges/binance/index.ts
|
|
76131
76140
|
var import_p_limit = __toESM(require_p_limit(), 1);
|
|
76132
76141
|
|
|
76133
|
-
// src/exchanges/binance/
|
|
76142
|
+
// src/exchanges/binance/futures-replay.ts
|
|
76134
76143
|
function roundNumber(value2, digits = 8) {
|
|
76135
76144
|
return Number(value2.toFixed(digits));
|
|
76136
76145
|
}
|
|
76137
|
-
|
|
76146
|
+
function parseNumber2(value2) {
|
|
76147
|
+
if (value2 === undefined || value2 === null || value2 === "")
|
|
76148
|
+
return;
|
|
76149
|
+
const parsed = Number(value2);
|
|
76150
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
76151
|
+
return;
|
|
76152
|
+
return roundNumber(parsed);
|
|
76153
|
+
}
|
|
76138
76154
|
function normalizeOrderInput(order) {
|
|
76155
|
+
const stop = parseNumber2(order.stop) ?? parseNumber2(order.stopPrice) ?? parseNumber2(order.triggerPrice);
|
|
76156
|
+
const type = order.type ? order.type.toUpperCase() : undefined;
|
|
76157
|
+
const quantity = order.quantity ?? order.qty ?? 0;
|
|
76158
|
+
return {
|
|
76159
|
+
price: roundNumber(Number(order.price)),
|
|
76160
|
+
quantity: roundNumber(Number(quantity)),
|
|
76161
|
+
...stop ? { stop } : {},
|
|
76162
|
+
...type && type !== "LIMIT" ? { type } : {}
|
|
76163
|
+
};
|
|
76164
|
+
}
|
|
76165
|
+
function sortReplayOrders(orders) {
|
|
76166
|
+
return [...orders].sort((left, right) => {
|
|
76167
|
+
const leftTrigger = left.stop ?? left.price;
|
|
76168
|
+
const rightTrigger = right.stop ?? right.price;
|
|
76169
|
+
if (leftTrigger !== rightTrigger)
|
|
76170
|
+
return leftTrigger - rightTrigger;
|
|
76171
|
+
if (left.price !== right.price)
|
|
76172
|
+
return left.price - right.price;
|
|
76173
|
+
return left.quantity - right.quantity;
|
|
76174
|
+
});
|
|
76175
|
+
}
|
|
76176
|
+
function buildReplayStopLimitPrice(payload) {
|
|
76177
|
+
const spread = payload.stop > 30000 ? 1.00005 : 1.0002;
|
|
76178
|
+
return roundNumber(payload.kind === "long" ? payload.stop * spread ** -1 : payload.stop * spread);
|
|
76179
|
+
}
|
|
76180
|
+
function normalizeRequestedEntryOrders(orders) {
|
|
76181
|
+
return sortReplayOrders(orders.map((order) => ({
|
|
76182
|
+
price: roundNumber(Number(order.price)),
|
|
76183
|
+
quantity: roundNumber(Number(order.quantity))
|
|
76184
|
+
})));
|
|
76185
|
+
}
|
|
76186
|
+
function normalizeRequestedStopOrders(payload) {
|
|
76187
|
+
return sortReplayOrders(payload.orders.map((order) => {
|
|
76188
|
+
const stop = parseNumber2(order.stop) ?? roundNumber(Number(order.price));
|
|
76189
|
+
return {
|
|
76190
|
+
price: order.price !== undefined ? roundNumber(Number(order.price)) : buildReplayStopLimitPrice({
|
|
76191
|
+
kind: payload.kind,
|
|
76192
|
+
stop
|
|
76193
|
+
}),
|
|
76194
|
+
quantity: roundNumber(Number(order.quantity)),
|
|
76195
|
+
stop,
|
|
76196
|
+
type: (order.type || "STOP").toUpperCase()
|
|
76197
|
+
};
|
|
76198
|
+
}));
|
|
76199
|
+
}
|
|
76200
|
+
function normalizeRequestedTakeProfitOrders(orders) {
|
|
76201
|
+
return sortReplayOrders(orders.map((order) => {
|
|
76202
|
+
const stop = parseNumber2(order.stop);
|
|
76203
|
+
const type = order.type?.toUpperCase();
|
|
76204
|
+
return {
|
|
76205
|
+
price: roundNumber(Number(order.price)),
|
|
76206
|
+
quantity: roundNumber(Number(order.quantity)),
|
|
76207
|
+
...stop ? { stop } : {},
|
|
76208
|
+
...type ? { type } : stop ? { type: "TAKE_PROFIT" } : {}
|
|
76209
|
+
};
|
|
76210
|
+
}));
|
|
76211
|
+
}
|
|
76212
|
+
function buildOrderKey(order) {
|
|
76213
|
+
return [
|
|
76214
|
+
order.type || "LIMIT",
|
|
76215
|
+
order.price,
|
|
76216
|
+
order.quantity,
|
|
76217
|
+
order.stop ?? ""
|
|
76218
|
+
].join(":");
|
|
76219
|
+
}
|
|
76220
|
+
function buildComparisonBucket(options) {
|
|
76221
|
+
const expected = sortReplayOrders(options.expected);
|
|
76222
|
+
const actual = sortReplayOrders(options.actual);
|
|
76223
|
+
const expected_keys = expected.map(buildOrderKey);
|
|
76224
|
+
const actual_keys = actual.map(buildOrderKey);
|
|
76139
76225
|
return {
|
|
76140
|
-
|
|
76141
|
-
|
|
76226
|
+
expected,
|
|
76227
|
+
actual,
|
|
76228
|
+
missing: expected_keys.filter((key) => !actual_keys.includes(key)),
|
|
76229
|
+
extra: actual_keys.filter((key) => !expected_keys.includes(key))
|
|
76230
|
+
};
|
|
76231
|
+
}
|
|
76232
|
+
function buildFuturesReplaySnapshot(payload) {
|
|
76233
|
+
const entry_side = payload.kind === "long" ? "buy" : "sell";
|
|
76234
|
+
const close_side = payload.kind === "long" ? "sell" : "buy";
|
|
76235
|
+
const entry_orders = [];
|
|
76236
|
+
const stop_orders = [];
|
|
76237
|
+
const take_profit_orders = [];
|
|
76238
|
+
for (const order of payload.open_orders) {
|
|
76239
|
+
if (order.kind !== payload.kind)
|
|
76240
|
+
continue;
|
|
76241
|
+
const normalized_order = normalizeOrderInput(order);
|
|
76242
|
+
const type = (normalized_order.type || "LIMIT").toUpperCase();
|
|
76243
|
+
if (order.side === entry_side) {
|
|
76244
|
+
entry_orders.push(normalized_order);
|
|
76245
|
+
continue;
|
|
76246
|
+
}
|
|
76247
|
+
if (order.side !== close_side)
|
|
76248
|
+
continue;
|
|
76249
|
+
if (type.includes("TAKE_PROFIT") || normalized_order.stop === undefined) {
|
|
76250
|
+
take_profit_orders.push(normalized_order);
|
|
76251
|
+
continue;
|
|
76252
|
+
}
|
|
76253
|
+
stop_orders.push(normalized_order);
|
|
76254
|
+
}
|
|
76255
|
+
return {
|
|
76256
|
+
symbol: payload.symbol,
|
|
76257
|
+
kind: payload.kind,
|
|
76258
|
+
current_price: payload.current_price,
|
|
76259
|
+
position: payload.position,
|
|
76260
|
+
open_orders: payload.open_orders.filter((order) => order.kind === payload.kind),
|
|
76261
|
+
entry_orders: sortReplayOrders(entry_orders),
|
|
76262
|
+
stop_orders: sortReplayOrders(stop_orders),
|
|
76263
|
+
take_profit_orders: sortReplayOrders(take_profit_orders)
|
|
76264
|
+
};
|
|
76265
|
+
}
|
|
76266
|
+
function inferFuturesReplayInputFromLiveOrders(payload) {
|
|
76267
|
+
const snapshot = buildFuturesReplaySnapshot(payload);
|
|
76268
|
+
return {
|
|
76269
|
+
symbol: payload.symbol,
|
|
76270
|
+
kind: payload.kind,
|
|
76271
|
+
current_price: payload.current_price,
|
|
76272
|
+
position: payload.position,
|
|
76273
|
+
entry_orders: snapshot.entry_orders,
|
|
76274
|
+
stop_orders: snapshot.stop_orders,
|
|
76275
|
+
take_profit_orders: snapshot.take_profit_orders
|
|
76276
|
+
};
|
|
76277
|
+
}
|
|
76278
|
+
function compareFuturesReplayOrders(payload) {
|
|
76279
|
+
const entry = buildComparisonBucket({
|
|
76280
|
+
expected: payload.entry_orders,
|
|
76281
|
+
actual: payload.snapshot.entry_orders
|
|
76282
|
+
});
|
|
76283
|
+
const stop = buildComparisonBucket({
|
|
76284
|
+
expected: payload.stop_orders,
|
|
76285
|
+
actual: payload.snapshot.stop_orders
|
|
76286
|
+
});
|
|
76287
|
+
const take_profit = buildComparisonBucket({
|
|
76288
|
+
expected: payload.take_profit_orders,
|
|
76289
|
+
actual: payload.snapshot.take_profit_orders
|
|
76290
|
+
});
|
|
76291
|
+
return {
|
|
76292
|
+
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,
|
|
76293
|
+
entry,
|
|
76294
|
+
stop,
|
|
76295
|
+
take_profit
|
|
76296
|
+
};
|
|
76297
|
+
}
|
|
76298
|
+
function buildFuturesReplayPlan(payload) {
|
|
76299
|
+
return {
|
|
76300
|
+
symbol: payload.symbol,
|
|
76301
|
+
kind: payload.kind,
|
|
76302
|
+
orders_to_cancel: payload.snapshot.open_orders,
|
|
76303
|
+
orders_to_create: {
|
|
76304
|
+
entry: sortReplayOrders(payload.entry_orders),
|
|
76305
|
+
stop: sortReplayOrders(payload.stop_orders),
|
|
76306
|
+
take_profit: sortReplayOrders(payload.take_profit_orders)
|
|
76307
|
+
}
|
|
76308
|
+
};
|
|
76309
|
+
}
|
|
76310
|
+
function normalizeFuturesReplayInput(payload) {
|
|
76311
|
+
return {
|
|
76312
|
+
entry_orders: normalizeRequestedEntryOrders(payload.entry_orders),
|
|
76313
|
+
stop_orders: normalizeRequestedStopOrders({
|
|
76314
|
+
kind: payload.kind,
|
|
76315
|
+
orders: payload.stop_orders
|
|
76316
|
+
}),
|
|
76317
|
+
take_profit_orders: normalizeRequestedTakeProfitOrders(payload.take_profit_orders)
|
|
76318
|
+
};
|
|
76319
|
+
}
|
|
76320
|
+
|
|
76321
|
+
// src/exchanges/binance/spot-margin-hedge.ts
|
|
76322
|
+
function roundNumber2(value2, digits = 8) {
|
|
76323
|
+
return Number(value2.toFixed(digits));
|
|
76324
|
+
}
|
|
76325
|
+
var STOP_LIMIT_SPREAD_PERCENT = 0.0005;
|
|
76326
|
+
function normalizeOrderInput2(order) {
|
|
76327
|
+
return {
|
|
76328
|
+
price: roundNumber2(order.price),
|
|
76329
|
+
quantity: roundNumber2(order.quantity)
|
|
76142
76330
|
};
|
|
76143
76331
|
}
|
|
76144
76332
|
function sortOrderInputs(orders) {
|
|
76145
|
-
return [...orders].map(
|
|
76333
|
+
return [...orders].map(normalizeOrderInput2).sort((left, right) => left.price - right.price);
|
|
76146
76334
|
}
|
|
76147
76335
|
function normalizeOrderForComparison(order) {
|
|
76148
76336
|
const type = (order.type || "limit").toLowerCase();
|
|
@@ -76151,9 +76339,9 @@ function normalizeOrderForComparison(order) {
|
|
|
76151
76339
|
return {
|
|
76152
76340
|
side: order.side,
|
|
76153
76341
|
type,
|
|
76154
|
-
price:
|
|
76155
|
-
quantity:
|
|
76156
|
-
stop: parsed_stop !== undefined && Number.isFinite(parsed_stop) && parsed_stop > 0 ?
|
|
76342
|
+
price: roundNumber2(order.price),
|
|
76343
|
+
quantity: roundNumber2(order.quantity),
|
|
76344
|
+
stop: parsed_stop !== undefined && Number.isFinite(parsed_stop) && parsed_stop > 0 ? roundNumber2(parsed_stop) : undefined
|
|
76157
76345
|
};
|
|
76158
76346
|
}
|
|
76159
76347
|
function normalizeOrders(orders) {
|
|
@@ -76176,7 +76364,7 @@ function toPlannedOrders(orders) {
|
|
|
76176
76364
|
stop: order.stop
|
|
76177
76365
|
}));
|
|
76178
76366
|
}
|
|
76179
|
-
function
|
|
76367
|
+
function buildOrderKey2(order) {
|
|
76180
76368
|
return [
|
|
76181
76369
|
order.side,
|
|
76182
76370
|
order.type,
|
|
@@ -76186,8 +76374,8 @@ function buildOrderKey(order) {
|
|
|
76186
76374
|
].join(":");
|
|
76187
76375
|
}
|
|
76188
76376
|
function buildDiff(options) {
|
|
76189
|
-
const expectedKeys = options.expected.map(
|
|
76190
|
-
const actualKeys = options.actual.map(
|
|
76377
|
+
const expectedKeys = options.expected.map(buildOrderKey2);
|
|
76378
|
+
const actualKeys = options.actual.map(buildOrderKey2);
|
|
76191
76379
|
return {
|
|
76192
76380
|
missing: expectedKeys.filter((key) => !actualKeys.includes(key)),
|
|
76193
76381
|
extra: actualKeys.filter((key) => !expectedKeys.includes(key))
|
|
@@ -76199,10 +76387,10 @@ function getQuoteAsset(symbol) {
|
|
|
76199
76387
|
return target || symbol.slice(-4);
|
|
76200
76388
|
}
|
|
76201
76389
|
function sumNotional(orders) {
|
|
76202
|
-
return
|
|
76390
|
+
return roundNumber2(orders.reduce((sum, order) => sum + order.price * order.quantity, 0), 8);
|
|
76203
76391
|
}
|
|
76204
76392
|
function sumQuantity(orders) {
|
|
76205
|
-
return
|
|
76393
|
+
return roundNumber2(orders.reduce((sum, order) => sum + order.quantity, 0), 8);
|
|
76206
76394
|
}
|
|
76207
76395
|
function buildLongOrderPlacement(options) {
|
|
76208
76396
|
const { order, current_price } = options;
|
|
@@ -76211,7 +76399,7 @@ function buildLongOrderPlacement(options) {
|
|
|
76211
76399
|
side: "buy",
|
|
76212
76400
|
type: "stop_loss_limit",
|
|
76213
76401
|
price: order.price,
|
|
76214
|
-
stop:
|
|
76402
|
+
stop: roundNumber2(order.price * (1 - STOP_LIMIT_SPREAD_PERCENT)),
|
|
76215
76403
|
quantity: order.quantity
|
|
76216
76404
|
};
|
|
76217
76405
|
}
|
|
@@ -76279,11 +76467,11 @@ function buildSpotMarginHedgePlan(options) {
|
|
|
76279
76467
|
}));
|
|
76280
76468
|
const spot_orders_to_create = options.placement_overrides?.spot || default_spot_orders_to_create;
|
|
76281
76469
|
const margin_orders_to_create = options.placement_overrides?.margin || default_margin_orders_to_create;
|
|
76282
|
-
const borrow_delta =
|
|
76470
|
+
const borrow_delta = roundNumber2(Math.max(0, options.borrow_amount - options.snapshot.borrowed_quote_amount));
|
|
76283
76471
|
const spot_long_notional = sumNotional(spot_long_orders);
|
|
76284
|
-
const transfer_to_spot_amount =
|
|
76472
|
+
const transfer_to_spot_amount = roundNumber2(Math.max(0, spot_long_notional - options.snapshot.spot_quote_free));
|
|
76285
76473
|
const short_quantity = sumQuantity(short_orders);
|
|
76286
|
-
const transfer_base_to_spot_amount =
|
|
76474
|
+
const transfer_base_to_spot_amount = roundNumber2(Math.max(0, short_quantity - options.snapshot.spot_base_free));
|
|
76287
76475
|
return {
|
|
76288
76476
|
borrow_amount: options.borrow_amount,
|
|
76289
76477
|
borrow_delta,
|
|
@@ -77942,6 +78130,30 @@ class BinanceExchange extends BaseExchange {
|
|
|
77942
78130
|
throw error;
|
|
77943
78131
|
}
|
|
77944
78132
|
}
|
|
78133
|
+
async getFuturesSymbolFormats(symbol) {
|
|
78134
|
+
if (typeof this.client.getExchangeInfo !== "function") {
|
|
78135
|
+
return {
|
|
78136
|
+
price_places: "%.8f",
|
|
78137
|
+
decimal_places: "%.8f"
|
|
78138
|
+
};
|
|
78139
|
+
}
|
|
78140
|
+
try {
|
|
78141
|
+
const exchange_info = await this.client.getExchangeInfo();
|
|
78142
|
+
const symbol_info = exchange_info?.symbols?.find((item) => item.symbol === symbol.toUpperCase());
|
|
78143
|
+
const price_filter = symbol_info?.filters?.find((filter) => filter.filterType === "PRICE_FILTER");
|
|
78144
|
+
const lot_size_filter = symbol_info?.filters?.find((filter) => filter.filterType === "LOT_SIZE");
|
|
78145
|
+
return {
|
|
78146
|
+
price_places: getPrintfFormatFromStepSize(price_filter?.tickSize, "%.8f"),
|
|
78147
|
+
decimal_places: getPrintfFormatFromStepSize(lot_size_filter?.stepSize, "%.8f")
|
|
78148
|
+
};
|
|
78149
|
+
} catch (error) {
|
|
78150
|
+
console.error("Error fetching futures symbol formats:", error);
|
|
78151
|
+
return {
|
|
78152
|
+
price_places: "%.8f",
|
|
78153
|
+
decimal_places: "%.8f"
|
|
78154
|
+
};
|
|
78155
|
+
}
|
|
78156
|
+
}
|
|
77945
78157
|
async getSpotSymbolFormats(symbol) {
|
|
77946
78158
|
if (!this.main_client || typeof this.main_client.getExchangeInfo !== "function") {
|
|
77947
78159
|
return {
|
|
@@ -77996,6 +78208,123 @@ class BinanceExchange extends BaseExchange {
|
|
|
77996
78208
|
}
|
|
77997
78209
|
return await getMarginOpenOrders(this.main_client, symbol, isIsolated);
|
|
77998
78210
|
}
|
|
78211
|
+
async getFuturesReplaySnapshot(payload) {
|
|
78212
|
+
const symbol = payload.symbol.toUpperCase();
|
|
78213
|
+
const [open_orders, position_info, current_price] = await Promise.all([
|
|
78214
|
+
this.getOpenOrders({ symbol }),
|
|
78215
|
+
this.getPositionInfo(symbol),
|
|
78216
|
+
this.getCurrentPrice(symbol)
|
|
78217
|
+
]);
|
|
78218
|
+
return buildFuturesReplaySnapshot({
|
|
78219
|
+
symbol,
|
|
78220
|
+
kind: payload.kind,
|
|
78221
|
+
current_price,
|
|
78222
|
+
position: {
|
|
78223
|
+
size: position_info[payload.kind]?.size || 0
|
|
78224
|
+
},
|
|
78225
|
+
open_orders
|
|
78226
|
+
});
|
|
78227
|
+
}
|
|
78228
|
+
async previewFuturesReplay(payload) {
|
|
78229
|
+
const snapshot = payload.snapshot ? {
|
|
78230
|
+
...payload.snapshot,
|
|
78231
|
+
current_price: payload.snapshot.current_price ?? await this.getCurrentPrice(payload.symbol)
|
|
78232
|
+
} : await this.getFuturesReplaySnapshot({
|
|
78233
|
+
symbol: payload.symbol,
|
|
78234
|
+
kind: payload.kind
|
|
78235
|
+
});
|
|
78236
|
+
const shouldInferEntryOrders = !payload.entry_orders || payload.entry_orders.length === 0;
|
|
78237
|
+
const shouldInferStopOrders = !payload.stop_orders || payload.stop_orders.length === 0;
|
|
78238
|
+
const shouldInferTakeProfitOrders = !payload.take_profit_orders || payload.take_profit_orders.length === 0;
|
|
78239
|
+
const inferred_input = shouldInferEntryOrders || shouldInferStopOrders || shouldInferTakeProfitOrders ? inferFuturesReplayInputFromLiveOrders({
|
|
78240
|
+
symbol: payload.symbol,
|
|
78241
|
+
kind: payload.kind,
|
|
78242
|
+
current_price: snapshot.current_price,
|
|
78243
|
+
position: snapshot.position,
|
|
78244
|
+
open_orders: snapshot.open_orders
|
|
78245
|
+
}) : undefined;
|
|
78246
|
+
const explicit_input = normalizeFuturesReplayInput({
|
|
78247
|
+
kind: payload.kind,
|
|
78248
|
+
entry_orders: payload.entry_orders || [],
|
|
78249
|
+
stop_orders: payload.stop_orders || [],
|
|
78250
|
+
take_profit_orders: payload.take_profit_orders || []
|
|
78251
|
+
});
|
|
78252
|
+
const entry_orders = shouldInferEntryOrders ? inferred_input?.entry_orders || [] : explicit_input.entry_orders;
|
|
78253
|
+
const stop_orders = shouldInferStopOrders ? inferred_input?.stop_orders || [] : explicit_input.stop_orders;
|
|
78254
|
+
const take_profit_orders = shouldInferTakeProfitOrders ? inferred_input?.take_profit_orders || [] : explicit_input.take_profit_orders;
|
|
78255
|
+
const requested_input = {
|
|
78256
|
+
symbol: payload.symbol,
|
|
78257
|
+
kind: payload.kind,
|
|
78258
|
+
entry_orders,
|
|
78259
|
+
stop_orders,
|
|
78260
|
+
take_profit_orders
|
|
78261
|
+
};
|
|
78262
|
+
const plan = buildFuturesReplayPlan({
|
|
78263
|
+
...requested_input,
|
|
78264
|
+
snapshot
|
|
78265
|
+
});
|
|
78266
|
+
const comparison = compareFuturesReplayOrders({
|
|
78267
|
+
...requested_input,
|
|
78268
|
+
snapshot
|
|
78269
|
+
});
|
|
78270
|
+
return {
|
|
78271
|
+
snapshot,
|
|
78272
|
+
inferred_input,
|
|
78273
|
+
requested_input,
|
|
78274
|
+
plan,
|
|
78275
|
+
comparison
|
|
78276
|
+
};
|
|
78277
|
+
}
|
|
78278
|
+
async placeFuturesReplay(payload) {
|
|
78279
|
+
const preview = await this.previewFuturesReplay(payload);
|
|
78280
|
+
if (!payload.place) {
|
|
78281
|
+
return preview;
|
|
78282
|
+
}
|
|
78283
|
+
const symbol = payload.symbol.toUpperCase();
|
|
78284
|
+
await cancelAllOrders(this.client, symbol, {
|
|
78285
|
+
kind: payload.kind
|
|
78286
|
+
});
|
|
78287
|
+
const refreshed_snapshot = await this.getFuturesReplaySnapshot({
|
|
78288
|
+
symbol,
|
|
78289
|
+
kind: payload.kind
|
|
78290
|
+
});
|
|
78291
|
+
const execution_plan = buildFuturesReplayPlan({
|
|
78292
|
+
symbol,
|
|
78293
|
+
kind: payload.kind,
|
|
78294
|
+
entry_orders: preview.requested_input.entry_orders,
|
|
78295
|
+
stop_orders: preview.requested_input.stop_orders,
|
|
78296
|
+
take_profit_orders: preview.requested_input.take_profit_orders,
|
|
78297
|
+
snapshot: refreshed_snapshot
|
|
78298
|
+
});
|
|
78299
|
+
const { price_places, decimal_places } = await this.getFuturesSymbolFormats(symbol);
|
|
78300
|
+
const entry_orders = execution_plan.orders_to_create.entry.map((order) => ({
|
|
78301
|
+
...order,
|
|
78302
|
+
side: payload.kind === "long" ? "buy" : "sell",
|
|
78303
|
+
kind: payload.kind
|
|
78304
|
+
}));
|
|
78305
|
+
const stop_orders = execution_plan.orders_to_create.stop.map((order) => ({
|
|
78306
|
+
...order,
|
|
78307
|
+
side: payload.kind === "long" ? "sell" : "buy",
|
|
78308
|
+
kind: payload.kind,
|
|
78309
|
+
type: order.type || "STOP"
|
|
78310
|
+
}));
|
|
78311
|
+
const take_profit_orders = execution_plan.orders_to_create.take_profit.map((order) => ({
|
|
78312
|
+
...order,
|
|
78313
|
+
side: payload.kind === "long" ? "sell" : "buy",
|
|
78314
|
+
kind: payload.kind,
|
|
78315
|
+
...order.stop ? { type: order.type || "TAKE_PROFIT" } : {}
|
|
78316
|
+
}));
|
|
78317
|
+
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]) : [];
|
|
78318
|
+
return {
|
|
78319
|
+
...preview,
|
|
78320
|
+
execution_plan,
|
|
78321
|
+
refreshed_snapshot,
|
|
78322
|
+
execution
|
|
78323
|
+
};
|
|
78324
|
+
}
|
|
78325
|
+
async placeFuturesExactTrade(payload) {
|
|
78326
|
+
return await this.placeFuturesReplay(payload);
|
|
78327
|
+
}
|
|
77999
78328
|
async getSpotMarginHedgeSnapshot(payload) {
|
|
78000
78329
|
if (!this.main_client) {
|
|
78001
78330
|
throw new Error("Main client not available for spot and margin trading");
|