@gbozee/ultimate 0.0.2-116 → 0.0.2-117
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 +92 -100
- package/dist/index.d.ts +3 -73
- package/dist/index.js +92 -100
- package/dist/mcp-server.cjs +90 -100
- package/dist/mcp-server.js +90 -100
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -50323,6 +50323,8 @@ function configure(options) {
|
|
|
50323
50323
|
var exports_database = {};
|
|
50324
50324
|
__export(exports_database, {
|
|
50325
50325
|
initPocketBaseClient: () => initPocketBaseClient,
|
|
50326
|
+
encryptObject: () => encryptObject,
|
|
50327
|
+
decryptObject: () => decryptObject,
|
|
50326
50328
|
AppDatabase: () => AppDatabase
|
|
50327
50329
|
});
|
|
50328
50330
|
var import_crypto = require("crypto");
|
|
@@ -56061,6 +56063,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
56061
56063
|
async getOpenOrders(payload) {
|
|
56062
56064
|
return await getOpenOrders(this.client, payload.symbol);
|
|
56063
56065
|
}
|
|
56066
|
+
async forceClosePosition(symbol, options) {
|
|
56067
|
+
return await forceClosePosition(this.client, symbol, options);
|
|
56068
|
+
}
|
|
56064
56069
|
}
|
|
56065
56070
|
function getPricePlaces(target) {
|
|
56066
56071
|
const numStr = target.toString();
|
|
@@ -56070,6 +56075,90 @@ function getPricePlaces(target) {
|
|
|
56070
56075
|
return 0;
|
|
56071
56076
|
}
|
|
56072
56077
|
}
|
|
56078
|
+
async function forceClosePosition(client, symbol, options) {
|
|
56079
|
+
const {
|
|
56080
|
+
kind = "both",
|
|
56081
|
+
price_places = "%.1f",
|
|
56082
|
+
decimal_places = "%.3f"
|
|
56083
|
+
} = options || {};
|
|
56084
|
+
const result = {
|
|
56085
|
+
success: true,
|
|
56086
|
+
closedPositions: [],
|
|
56087
|
+
errors: []
|
|
56088
|
+
};
|
|
56089
|
+
try {
|
|
56090
|
+
const positionInfo = await getPositionInfo(client, symbol);
|
|
56091
|
+
try {
|
|
56092
|
+
await cancelAllOrders(client, symbol, {});
|
|
56093
|
+
console.log(`Cancelled all orders for ${symbol}`);
|
|
56094
|
+
} catch (error) {
|
|
56095
|
+
console.warn(`Warning: Could not cancel orders for ${symbol}:`, error);
|
|
56096
|
+
}
|
|
56097
|
+
const positionsToClose = [];
|
|
56098
|
+
if ((kind === "long" || kind === "both") && positionInfo.long.size > 0) {
|
|
56099
|
+
positionsToClose.push({
|
|
56100
|
+
kind: "long",
|
|
56101
|
+
size: positionInfo.long.size,
|
|
56102
|
+
side: "sell"
|
|
56103
|
+
});
|
|
56104
|
+
}
|
|
56105
|
+
if ((kind === "short" || kind === "both") && positionInfo.short.size > 0) {
|
|
56106
|
+
positionsToClose.push({
|
|
56107
|
+
kind: "short",
|
|
56108
|
+
size: positionInfo.short.size,
|
|
56109
|
+
side: "buy"
|
|
56110
|
+
});
|
|
56111
|
+
}
|
|
56112
|
+
if (positionsToClose.length === 0) {
|
|
56113
|
+
console.log(`No active positions found for ${symbol} (kind: ${kind})`);
|
|
56114
|
+
return result;
|
|
56115
|
+
}
|
|
56116
|
+
for (const position2 of positionsToClose) {
|
|
56117
|
+
try {
|
|
56118
|
+
const order = {
|
|
56119
|
+
kind: position2.kind,
|
|
56120
|
+
side: position2.side,
|
|
56121
|
+
quantity: position2.size,
|
|
56122
|
+
force_market: true
|
|
56123
|
+
};
|
|
56124
|
+
console.log(`Closing ${position2.kind} position for ${symbol}: ${position2.size} units`);
|
|
56125
|
+
const orderResult = await createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
56126
|
+
result.closedPositions.push({
|
|
56127
|
+
kind: position2.kind,
|
|
56128
|
+
quantity: position2.size,
|
|
56129
|
+
orderResult
|
|
56130
|
+
});
|
|
56131
|
+
console.log(`Successfully closed ${position2.kind} position for ${symbol}`);
|
|
56132
|
+
} catch (error) {
|
|
56133
|
+
const errorMsg = `Failed to close ${position2.kind} position for ${symbol}: ${error}`;
|
|
56134
|
+
console.error(errorMsg);
|
|
56135
|
+
result.errors.push(errorMsg);
|
|
56136
|
+
result.success = false;
|
|
56137
|
+
}
|
|
56138
|
+
}
|
|
56139
|
+
if (result.success && result.closedPositions.length > 0) {
|
|
56140
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
56141
|
+
try {
|
|
56142
|
+
const updatedPositions = await getPositionInfo(client, symbol);
|
|
56143
|
+
const remainingLong = kind === "long" || kind === "both" ? updatedPositions.long.size : 0;
|
|
56144
|
+
const remainingShort = kind === "short" || kind === "both" ? updatedPositions.short.size : 0;
|
|
56145
|
+
if (remainingLong > 0 || remainingShort > 0) {
|
|
56146
|
+
const warningMsg = `Warning: Some positions may still be open after force close for ${symbol}. Long: ${remainingLong}, Short: ${remainingShort}`;
|
|
56147
|
+
console.warn(warningMsg);
|
|
56148
|
+
result.errors.push(warningMsg);
|
|
56149
|
+
}
|
|
56150
|
+
} catch (error) {
|
|
56151
|
+
console.warn(`Could not validate position closure for ${symbol}:`, error);
|
|
56152
|
+
}
|
|
56153
|
+
}
|
|
56154
|
+
} catch (error) {
|
|
56155
|
+
const errorMsg = `Critical error in forceClosePosition for ${symbol}: ${error}`;
|
|
56156
|
+
console.error(errorMsg);
|
|
56157
|
+
result.errors.push(errorMsg);
|
|
56158
|
+
result.success = false;
|
|
56159
|
+
}
|
|
56160
|
+
return result;
|
|
56161
|
+
}
|
|
56073
56162
|
|
|
56074
56163
|
// src/exchanges/bybit.ts
|
|
56075
56164
|
var import_bybit_api = __toESM(require_lib3());
|
|
@@ -56182,11 +56271,11 @@ async function getPositionInfo2(client, symbol) {
|
|
|
56182
56271
|
async function cancelOrders2(payload) {
|
|
56183
56272
|
const client = payload.custom_client;
|
|
56184
56273
|
const results = [];
|
|
56185
|
-
for (let i2 = 0;i2 < payload.orders.length; i2 +=
|
|
56186
|
-
const batch2 = payload.orders.slice(i2, i2 +
|
|
56274
|
+
for (let i2 = 0;i2 < payload.orders.length; i2 += 15) {
|
|
56275
|
+
const batch2 = payload.orders.slice(i2, i2 + 15);
|
|
56187
56276
|
let rr = await client.batchCancelOrders("linear", batch2.map((x) => ({ orderId: x.orderId, symbol: payload.symbol })));
|
|
56188
56277
|
results.push(rr);
|
|
56189
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
56278
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
56190
56279
|
}
|
|
56191
56280
|
return results;
|
|
56192
56281
|
}
|
|
@@ -59563,7 +59652,6 @@ class ExchangeAccount {
|
|
|
59563
59652
|
const long_position = positions.find((k) => k.kind === "long");
|
|
59564
59653
|
const short_position = positions.find((k) => k.kind === "short");
|
|
59565
59654
|
console.log("Getting focus position for ", symbol, kind);
|
|
59566
|
-
const reverse_position = kind === "long" ? short_position : long_position;
|
|
59567
59655
|
if (strategy2.max_reward_factor === 0) {
|
|
59568
59656
|
reward_factor = strategy2.reward_factor;
|
|
59569
59657
|
}
|
|
@@ -59620,13 +59708,6 @@ class ExchangeAccount {
|
|
|
59620
59708
|
params: config2
|
|
59621
59709
|
});
|
|
59622
59710
|
console.log("Checking orders to place for ", symbol, kind);
|
|
59623
|
-
const orders_to_place = await this.placeTrade({
|
|
59624
|
-
symbol,
|
|
59625
|
-
raw: true,
|
|
59626
|
-
kind,
|
|
59627
|
-
place: false,
|
|
59628
|
-
ignore_config: true
|
|
59629
|
-
});
|
|
59630
59711
|
await this.placeTrade({
|
|
59631
59712
|
symbol,
|
|
59632
59713
|
kind,
|
|
@@ -59638,9 +59719,6 @@ class ExchangeAccount {
|
|
|
59638
59719
|
...config2,
|
|
59639
59720
|
...data
|
|
59640
59721
|
};
|
|
59641
|
-
let reverse_action = null;
|
|
59642
|
-
let reverse_orders_to_buy = [];
|
|
59643
|
-
let reverse_config = null;
|
|
59644
59722
|
if (focus_position.avg_qty < last_value.avg_size) {
|
|
59645
59723
|
console.log("Placing trade for ", symbol, kind);
|
|
59646
59724
|
await this.placeTrade({
|
|
@@ -59651,97 +59729,11 @@ class ExchangeAccount {
|
|
|
59651
59729
|
});
|
|
59652
59730
|
}
|
|
59653
59731
|
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
59654
|
-
if (focus_position.quantity > 0) {
|
|
59655
|
-
console.log("Getting details for ", reverse_position.kind);
|
|
59656
|
-
reverse_action = await this.buildOppositeTrades({
|
|
59657
|
-
symbol,
|
|
59658
|
-
kind
|
|
59659
|
-
});
|
|
59660
|
-
if (!reverse_action) {
|
|
59661
|
-
return;
|
|
59662
|
-
}
|
|
59663
|
-
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
59664
|
-
await this.getPositionConfig({
|
|
59665
|
-
symbol,
|
|
59666
|
-
kind: reverse_action.kind,
|
|
59667
|
-
params: {
|
|
59668
|
-
entry: reverse_action.entry,
|
|
59669
|
-
stop: reverse_action.stop,
|
|
59670
|
-
risk: reverse_action.risk_per_trade,
|
|
59671
|
-
profit_percent: reverse_action.profit_percent,
|
|
59672
|
-
risk_reward: reverse_action.risk_reward
|
|
59673
|
-
}
|
|
59674
|
-
});
|
|
59675
|
-
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
59676
|
-
const reverse_app_config = await this.buildAppConfig({
|
|
59677
|
-
entry: reverse_action.entry,
|
|
59678
|
-
stop: reverse_action.stop,
|
|
59679
|
-
risk_reward: reverse_action.risk_reward,
|
|
59680
|
-
risk: reverse_action.risk_per_trade,
|
|
59681
|
-
symbol
|
|
59682
|
-
});
|
|
59683
|
-
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
59684
|
-
reverse_orders_to_buy = await this.placeTrade({
|
|
59685
|
-
symbol,
|
|
59686
|
-
raw: true,
|
|
59687
|
-
kind: reverse_action.kind,
|
|
59688
|
-
ignore_config: true,
|
|
59689
|
-
place: false
|
|
59690
|
-
});
|
|
59691
|
-
let _reverse_config = {
|
|
59692
|
-
avg: reverse_action.avg,
|
|
59693
|
-
entry: reverse_action.entry,
|
|
59694
|
-
stop: reverse_action.stop,
|
|
59695
|
-
risk_per_trade: reverse_action.risk_per_trade,
|
|
59696
|
-
profit_percent: reverse_action.profit_percent,
|
|
59697
|
-
risk_reward: reverse_action.risk_reward
|
|
59698
|
-
};
|
|
59699
|
-
if (reverse_orders_to_buy.length > 0) {
|
|
59700
|
-
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
59701
|
-
let existing = await this.placeOppositeTradeAction({
|
|
59702
|
-
symbol,
|
|
59703
|
-
kind: reverse_action.kind,
|
|
59704
|
-
data: _reverse_config
|
|
59705
|
-
});
|
|
59706
|
-
_reverse_config = {
|
|
59707
|
-
...existing,
|
|
59708
|
-
..._reverse_config
|
|
59709
|
-
};
|
|
59710
|
-
}
|
|
59711
|
-
reverse_config = _reverse_config;
|
|
59712
|
-
}
|
|
59713
|
-
if (!reverse_config?.id) {
|
|
59714
|
-
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
59715
|
-
reverse_config = await this.getPositionConfig({
|
|
59716
|
-
symbol,
|
|
59717
|
-
kind: reverse_action.kind
|
|
59718
|
-
});
|
|
59719
|
-
}
|
|
59720
|
-
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
59721
|
-
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
59722
|
-
const max_size = app_config.max_size * 0.98;
|
|
59723
|
-
if (reverse_config.threshold_qty !== max_size) {
|
|
59724
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59725
|
-
follow: strategy2.follow,
|
|
59726
|
-
threshold_qty: max_size
|
|
59727
|
-
});
|
|
59728
|
-
}
|
|
59729
|
-
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
59730
|
-
} else {
|
|
59731
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59732
|
-
follow: false
|
|
59733
|
-
});
|
|
59734
|
-
}
|
|
59735
|
-
}
|
|
59736
59732
|
return {
|
|
59737
|
-
reverse_config,
|
|
59738
|
-
reverse_action,
|
|
59739
|
-
reverse_orders_to_buy,
|
|
59740
59733
|
positions: {
|
|
59741
59734
|
long: long_position,
|
|
59742
59735
|
short: short_position
|
|
59743
59736
|
},
|
|
59744
|
-
orders_to_place,
|
|
59745
59737
|
config_details: {
|
|
59746
59738
|
app_config,
|
|
59747
59739
|
last_value,
|
package/dist/index.d.ts
CHANGED
|
@@ -520,6 +520,8 @@ declare abstract class BaseExchange {
|
|
|
520
520
|
proxyAgent?: any;
|
|
521
521
|
}): void;
|
|
522
522
|
}
|
|
523
|
+
declare function encryptObject(obj: any, password: string): string;
|
|
524
|
+
declare function decryptObject(encryptedString: string, password: string): any;
|
|
523
525
|
declare function initPocketBaseClient(proxy_credentials: {
|
|
524
526
|
host: string;
|
|
525
527
|
email: string;
|
|
@@ -2184,41 +2186,6 @@ declare class ExchangeAccount$1 {
|
|
|
2184
2186
|
profitWithinGapStrategy(payload: {
|
|
2185
2187
|
symbol: string;
|
|
2186
2188
|
}): Promise<{
|
|
2187
|
-
reverse_config: any;
|
|
2188
|
-
reverse_action: {
|
|
2189
|
-
avg: {
|
|
2190
|
-
entry: number;
|
|
2191
|
-
price: number;
|
|
2192
|
-
quantity: number;
|
|
2193
|
-
};
|
|
2194
|
-
loss: number;
|
|
2195
|
-
profit_percent: number;
|
|
2196
|
-
fee: number;
|
|
2197
|
-
risk_per_trade: number;
|
|
2198
|
-
risk_reward: number;
|
|
2199
|
-
symbol?: string;
|
|
2200
|
-
focus: number;
|
|
2201
|
-
budget: number;
|
|
2202
|
-
support: number;
|
|
2203
|
-
resistance: number;
|
|
2204
|
-
percent_change: number;
|
|
2205
|
-
tradeSplit?: number;
|
|
2206
|
-
take_profit?: number;
|
|
2207
|
-
kind: "long" | "short";
|
|
2208
|
-
entry: number;
|
|
2209
|
-
stop: number;
|
|
2210
|
-
min_size: number;
|
|
2211
|
-
price_places?: string;
|
|
2212
|
-
strategy?: "quantity" | "entry";
|
|
2213
|
-
as_array?: boolean;
|
|
2214
|
-
decimal_places?: string;
|
|
2215
|
-
min_profit?: number;
|
|
2216
|
-
raw?: boolean;
|
|
2217
|
-
gap?: number;
|
|
2218
|
-
rr?: number;
|
|
2219
|
-
max_size?: number;
|
|
2220
|
-
};
|
|
2221
|
-
reverse_orders_to_buy: any;
|
|
2222
2189
|
positions: {
|
|
2223
2190
|
long: PositionsView & {
|
|
2224
2191
|
expand?: {
|
|
@@ -2231,7 +2198,6 @@ declare class ExchangeAccount$1 {
|
|
|
2231
2198
|
};
|
|
2232
2199
|
};
|
|
2233
2200
|
};
|
|
2234
|
-
orders_to_place: any;
|
|
2235
2201
|
config_details: {
|
|
2236
2202
|
app_config: {
|
|
2237
2203
|
fee: number;
|
|
@@ -2460,41 +2426,6 @@ declare class App {
|
|
|
2460
2426
|
account: ExchangeType;
|
|
2461
2427
|
symbol: string;
|
|
2462
2428
|
}): Promise<{
|
|
2463
|
-
reverse_config: any;
|
|
2464
|
-
reverse_action: {
|
|
2465
|
-
avg: {
|
|
2466
|
-
entry: number;
|
|
2467
|
-
price: number;
|
|
2468
|
-
quantity: number;
|
|
2469
|
-
};
|
|
2470
|
-
loss: number;
|
|
2471
|
-
profit_percent: number;
|
|
2472
|
-
fee: number;
|
|
2473
|
-
risk_per_trade: number;
|
|
2474
|
-
risk_reward: number;
|
|
2475
|
-
symbol?: string;
|
|
2476
|
-
focus: number;
|
|
2477
|
-
budget: number;
|
|
2478
|
-
support: number;
|
|
2479
|
-
resistance: number;
|
|
2480
|
-
percent_change: number;
|
|
2481
|
-
tradeSplit?: number;
|
|
2482
|
-
take_profit?: number;
|
|
2483
|
-
kind: "long" | "short";
|
|
2484
|
-
entry: number;
|
|
2485
|
-
stop: number;
|
|
2486
|
-
min_size: number;
|
|
2487
|
-
price_places?: string;
|
|
2488
|
-
strategy?: "quantity" | "entry";
|
|
2489
|
-
as_array?: boolean;
|
|
2490
|
-
decimal_places?: string;
|
|
2491
|
-
min_profit?: number;
|
|
2492
|
-
raw?: boolean;
|
|
2493
|
-
gap?: number;
|
|
2494
|
-
rr?: number;
|
|
2495
|
-
max_size?: number;
|
|
2496
|
-
};
|
|
2497
|
-
reverse_orders_to_buy: any;
|
|
2498
2429
|
positions: {
|
|
2499
2430
|
long: PositionsView & {
|
|
2500
2431
|
expand?: {
|
|
@@ -2507,7 +2438,6 @@ declare class App {
|
|
|
2507
2438
|
};
|
|
2508
2439
|
};
|
|
2509
2440
|
};
|
|
2510
|
-
orders_to_place: any;
|
|
2511
2441
|
config_details: {
|
|
2512
2442
|
app_config: {
|
|
2513
2443
|
fee: number;
|
|
@@ -2604,7 +2534,7 @@ export declare function initialize(payload: {
|
|
|
2604
2534
|
}): Promise<App>;
|
|
2605
2535
|
|
|
2606
2536
|
declare namespace database {
|
|
2607
|
-
export { AppDatabase, ExchangeType, initPocketBaseClient };
|
|
2537
|
+
export { AppDatabase, ExchangeType, decryptObject, encryptObject, initPocketBaseClient };
|
|
2608
2538
|
}
|
|
2609
2539
|
declare namespace exchange_account {
|
|
2610
2540
|
export { ExchangeAccount$1 as ExchangeAccount, getExchangeAccount };
|
package/dist/index.js
CHANGED
|
@@ -50268,6 +50268,8 @@ function configure(options) {
|
|
|
50268
50268
|
var exports_database = {};
|
|
50269
50269
|
__export(exports_database, {
|
|
50270
50270
|
initPocketBaseClient: () => initPocketBaseClient,
|
|
50271
|
+
encryptObject: () => encryptObject,
|
|
50272
|
+
decryptObject: () => decryptObject,
|
|
50271
50273
|
AppDatabase: () => AppDatabase
|
|
50272
50274
|
});
|
|
50273
50275
|
var import_https_proxy_agent = __toESM(require_dist2(), 1);
|
|
@@ -56011,6 +56013,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
56011
56013
|
async getOpenOrders(payload) {
|
|
56012
56014
|
return await getOpenOrders(this.client, payload.symbol);
|
|
56013
56015
|
}
|
|
56016
|
+
async forceClosePosition(symbol, options) {
|
|
56017
|
+
return await forceClosePosition(this.client, symbol, options);
|
|
56018
|
+
}
|
|
56014
56019
|
}
|
|
56015
56020
|
function getPricePlaces(target) {
|
|
56016
56021
|
const numStr = target.toString();
|
|
@@ -56020,6 +56025,90 @@ function getPricePlaces(target) {
|
|
|
56020
56025
|
return 0;
|
|
56021
56026
|
}
|
|
56022
56027
|
}
|
|
56028
|
+
async function forceClosePosition(client, symbol, options) {
|
|
56029
|
+
const {
|
|
56030
|
+
kind = "both",
|
|
56031
|
+
price_places = "%.1f",
|
|
56032
|
+
decimal_places = "%.3f"
|
|
56033
|
+
} = options || {};
|
|
56034
|
+
const result = {
|
|
56035
|
+
success: true,
|
|
56036
|
+
closedPositions: [],
|
|
56037
|
+
errors: []
|
|
56038
|
+
};
|
|
56039
|
+
try {
|
|
56040
|
+
const positionInfo = await getPositionInfo(client, symbol);
|
|
56041
|
+
try {
|
|
56042
|
+
await cancelAllOrders(client, symbol, {});
|
|
56043
|
+
console.log(`Cancelled all orders for ${symbol}`);
|
|
56044
|
+
} catch (error) {
|
|
56045
|
+
console.warn(`Warning: Could not cancel orders for ${symbol}:`, error);
|
|
56046
|
+
}
|
|
56047
|
+
const positionsToClose = [];
|
|
56048
|
+
if ((kind === "long" || kind === "both") && positionInfo.long.size > 0) {
|
|
56049
|
+
positionsToClose.push({
|
|
56050
|
+
kind: "long",
|
|
56051
|
+
size: positionInfo.long.size,
|
|
56052
|
+
side: "sell"
|
|
56053
|
+
});
|
|
56054
|
+
}
|
|
56055
|
+
if ((kind === "short" || kind === "both") && positionInfo.short.size > 0) {
|
|
56056
|
+
positionsToClose.push({
|
|
56057
|
+
kind: "short",
|
|
56058
|
+
size: positionInfo.short.size,
|
|
56059
|
+
side: "buy"
|
|
56060
|
+
});
|
|
56061
|
+
}
|
|
56062
|
+
if (positionsToClose.length === 0) {
|
|
56063
|
+
console.log(`No active positions found for ${symbol} (kind: ${kind})`);
|
|
56064
|
+
return result;
|
|
56065
|
+
}
|
|
56066
|
+
for (const position2 of positionsToClose) {
|
|
56067
|
+
try {
|
|
56068
|
+
const order = {
|
|
56069
|
+
kind: position2.kind,
|
|
56070
|
+
side: position2.side,
|
|
56071
|
+
quantity: position2.size,
|
|
56072
|
+
force_market: true
|
|
56073
|
+
};
|
|
56074
|
+
console.log(`Closing ${position2.kind} position for ${symbol}: ${position2.size} units`);
|
|
56075
|
+
const orderResult = await createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
56076
|
+
result.closedPositions.push({
|
|
56077
|
+
kind: position2.kind,
|
|
56078
|
+
quantity: position2.size,
|
|
56079
|
+
orderResult
|
|
56080
|
+
});
|
|
56081
|
+
console.log(`Successfully closed ${position2.kind} position for ${symbol}`);
|
|
56082
|
+
} catch (error) {
|
|
56083
|
+
const errorMsg = `Failed to close ${position2.kind} position for ${symbol}: ${error}`;
|
|
56084
|
+
console.error(errorMsg);
|
|
56085
|
+
result.errors.push(errorMsg);
|
|
56086
|
+
result.success = false;
|
|
56087
|
+
}
|
|
56088
|
+
}
|
|
56089
|
+
if (result.success && result.closedPositions.length > 0) {
|
|
56090
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
56091
|
+
try {
|
|
56092
|
+
const updatedPositions = await getPositionInfo(client, symbol);
|
|
56093
|
+
const remainingLong = kind === "long" || kind === "both" ? updatedPositions.long.size : 0;
|
|
56094
|
+
const remainingShort = kind === "short" || kind === "both" ? updatedPositions.short.size : 0;
|
|
56095
|
+
if (remainingLong > 0 || remainingShort > 0) {
|
|
56096
|
+
const warningMsg = `Warning: Some positions may still be open after force close for ${symbol}. Long: ${remainingLong}, Short: ${remainingShort}`;
|
|
56097
|
+
console.warn(warningMsg);
|
|
56098
|
+
result.errors.push(warningMsg);
|
|
56099
|
+
}
|
|
56100
|
+
} catch (error) {
|
|
56101
|
+
console.warn(`Could not validate position closure for ${symbol}:`, error);
|
|
56102
|
+
}
|
|
56103
|
+
}
|
|
56104
|
+
} catch (error) {
|
|
56105
|
+
const errorMsg = `Critical error in forceClosePosition for ${symbol}: ${error}`;
|
|
56106
|
+
console.error(errorMsg);
|
|
56107
|
+
result.errors.push(errorMsg);
|
|
56108
|
+
result.success = false;
|
|
56109
|
+
}
|
|
56110
|
+
return result;
|
|
56111
|
+
}
|
|
56023
56112
|
|
|
56024
56113
|
// src/exchanges/bybit.ts
|
|
56025
56114
|
var import_bybit_api = __toESM(require_lib3(), 1);
|
|
@@ -56132,11 +56221,11 @@ async function getPositionInfo2(client, symbol) {
|
|
|
56132
56221
|
async function cancelOrders2(payload) {
|
|
56133
56222
|
const client = payload.custom_client;
|
|
56134
56223
|
const results = [];
|
|
56135
|
-
for (let i2 = 0;i2 < payload.orders.length; i2 +=
|
|
56136
|
-
const batch2 = payload.orders.slice(i2, i2 +
|
|
56224
|
+
for (let i2 = 0;i2 < payload.orders.length; i2 += 15) {
|
|
56225
|
+
const batch2 = payload.orders.slice(i2, i2 + 15);
|
|
56137
56226
|
let rr = await client.batchCancelOrders("linear", batch2.map((x) => ({ orderId: x.orderId, symbol: payload.symbol })));
|
|
56138
56227
|
results.push(rr);
|
|
56139
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
56228
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
56140
56229
|
}
|
|
56141
56230
|
return results;
|
|
56142
56231
|
}
|
|
@@ -59513,7 +59602,6 @@ class ExchangeAccount {
|
|
|
59513
59602
|
const long_position = positions.find((k) => k.kind === "long");
|
|
59514
59603
|
const short_position = positions.find((k) => k.kind === "short");
|
|
59515
59604
|
console.log("Getting focus position for ", symbol, kind);
|
|
59516
|
-
const reverse_position = kind === "long" ? short_position : long_position;
|
|
59517
59605
|
if (strategy2.max_reward_factor === 0) {
|
|
59518
59606
|
reward_factor = strategy2.reward_factor;
|
|
59519
59607
|
}
|
|
@@ -59570,13 +59658,6 @@ class ExchangeAccount {
|
|
|
59570
59658
|
params: config2
|
|
59571
59659
|
});
|
|
59572
59660
|
console.log("Checking orders to place for ", symbol, kind);
|
|
59573
|
-
const orders_to_place = await this.placeTrade({
|
|
59574
|
-
symbol,
|
|
59575
|
-
raw: true,
|
|
59576
|
-
kind,
|
|
59577
|
-
place: false,
|
|
59578
|
-
ignore_config: true
|
|
59579
|
-
});
|
|
59580
59661
|
await this.placeTrade({
|
|
59581
59662
|
symbol,
|
|
59582
59663
|
kind,
|
|
@@ -59588,9 +59669,6 @@ class ExchangeAccount {
|
|
|
59588
59669
|
...config2,
|
|
59589
59670
|
...data
|
|
59590
59671
|
};
|
|
59591
|
-
let reverse_action = null;
|
|
59592
|
-
let reverse_orders_to_buy = [];
|
|
59593
|
-
let reverse_config = null;
|
|
59594
59672
|
if (focus_position.avg_qty < last_value.avg_size) {
|
|
59595
59673
|
console.log("Placing trade for ", symbol, kind);
|
|
59596
59674
|
await this.placeTrade({
|
|
@@ -59601,97 +59679,11 @@ class ExchangeAccount {
|
|
|
59601
59679
|
});
|
|
59602
59680
|
}
|
|
59603
59681
|
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
59604
|
-
if (focus_position.quantity > 0) {
|
|
59605
|
-
console.log("Getting details for ", reverse_position.kind);
|
|
59606
|
-
reverse_action = await this.buildOppositeTrades({
|
|
59607
|
-
symbol,
|
|
59608
|
-
kind
|
|
59609
|
-
});
|
|
59610
|
-
if (!reverse_action) {
|
|
59611
|
-
return;
|
|
59612
|
-
}
|
|
59613
|
-
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
59614
|
-
await this.getPositionConfig({
|
|
59615
|
-
symbol,
|
|
59616
|
-
kind: reverse_action.kind,
|
|
59617
|
-
params: {
|
|
59618
|
-
entry: reverse_action.entry,
|
|
59619
|
-
stop: reverse_action.stop,
|
|
59620
|
-
risk: reverse_action.risk_per_trade,
|
|
59621
|
-
profit_percent: reverse_action.profit_percent,
|
|
59622
|
-
risk_reward: reverse_action.risk_reward
|
|
59623
|
-
}
|
|
59624
|
-
});
|
|
59625
|
-
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
59626
|
-
const reverse_app_config = await this.buildAppConfig({
|
|
59627
|
-
entry: reverse_action.entry,
|
|
59628
|
-
stop: reverse_action.stop,
|
|
59629
|
-
risk_reward: reverse_action.risk_reward,
|
|
59630
|
-
risk: reverse_action.risk_per_trade,
|
|
59631
|
-
symbol
|
|
59632
|
-
});
|
|
59633
|
-
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
59634
|
-
reverse_orders_to_buy = await this.placeTrade({
|
|
59635
|
-
symbol,
|
|
59636
|
-
raw: true,
|
|
59637
|
-
kind: reverse_action.kind,
|
|
59638
|
-
ignore_config: true,
|
|
59639
|
-
place: false
|
|
59640
|
-
});
|
|
59641
|
-
let _reverse_config = {
|
|
59642
|
-
avg: reverse_action.avg,
|
|
59643
|
-
entry: reverse_action.entry,
|
|
59644
|
-
stop: reverse_action.stop,
|
|
59645
|
-
risk_per_trade: reverse_action.risk_per_trade,
|
|
59646
|
-
profit_percent: reverse_action.profit_percent,
|
|
59647
|
-
risk_reward: reverse_action.risk_reward
|
|
59648
|
-
};
|
|
59649
|
-
if (reverse_orders_to_buy.length > 0) {
|
|
59650
|
-
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
59651
|
-
let existing = await this.placeOppositeTradeAction({
|
|
59652
|
-
symbol,
|
|
59653
|
-
kind: reverse_action.kind,
|
|
59654
|
-
data: _reverse_config
|
|
59655
|
-
});
|
|
59656
|
-
_reverse_config = {
|
|
59657
|
-
...existing,
|
|
59658
|
-
..._reverse_config
|
|
59659
|
-
};
|
|
59660
|
-
}
|
|
59661
|
-
reverse_config = _reverse_config;
|
|
59662
|
-
}
|
|
59663
|
-
if (!reverse_config?.id) {
|
|
59664
|
-
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
59665
|
-
reverse_config = await this.getPositionConfig({
|
|
59666
|
-
symbol,
|
|
59667
|
-
kind: reverse_action.kind
|
|
59668
|
-
});
|
|
59669
|
-
}
|
|
59670
|
-
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
59671
|
-
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
59672
|
-
const max_size = app_config.max_size * 0.98;
|
|
59673
|
-
if (reverse_config.threshold_qty !== max_size) {
|
|
59674
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59675
|
-
follow: strategy2.follow,
|
|
59676
|
-
threshold_qty: max_size
|
|
59677
|
-
});
|
|
59678
|
-
}
|
|
59679
|
-
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
59680
|
-
} else {
|
|
59681
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59682
|
-
follow: false
|
|
59683
|
-
});
|
|
59684
|
-
}
|
|
59685
|
-
}
|
|
59686
59682
|
return {
|
|
59687
|
-
reverse_config,
|
|
59688
|
-
reverse_action,
|
|
59689
|
-
reverse_orders_to_buy,
|
|
59690
59683
|
positions: {
|
|
59691
59684
|
long: long_position,
|
|
59692
59685
|
short: short_position
|
|
59693
59686
|
},
|
|
59694
|
-
orders_to_place,
|
|
59695
59687
|
config_details: {
|
|
59696
59688
|
app_config,
|
|
59697
59689
|
last_value,
|
package/dist/mcp-server.cjs
CHANGED
|
@@ -62741,6 +62741,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
62741
62741
|
async getOpenOrders(payload) {
|
|
62742
62742
|
return await getOpenOrders(this.client, payload.symbol);
|
|
62743
62743
|
}
|
|
62744
|
+
async forceClosePosition(symbol, options) {
|
|
62745
|
+
return await forceClosePosition(this.client, symbol, options);
|
|
62746
|
+
}
|
|
62744
62747
|
}
|
|
62745
62748
|
function getPricePlaces(target) {
|
|
62746
62749
|
const numStr = target.toString();
|
|
@@ -62750,6 +62753,90 @@ function getPricePlaces(target) {
|
|
|
62750
62753
|
return 0;
|
|
62751
62754
|
}
|
|
62752
62755
|
}
|
|
62756
|
+
async function forceClosePosition(client, symbol, options) {
|
|
62757
|
+
const {
|
|
62758
|
+
kind = "both",
|
|
62759
|
+
price_places = "%.1f",
|
|
62760
|
+
decimal_places = "%.3f"
|
|
62761
|
+
} = options || {};
|
|
62762
|
+
const result = {
|
|
62763
|
+
success: true,
|
|
62764
|
+
closedPositions: [],
|
|
62765
|
+
errors: []
|
|
62766
|
+
};
|
|
62767
|
+
try {
|
|
62768
|
+
const positionInfo = await getPositionInfo(client, symbol);
|
|
62769
|
+
try {
|
|
62770
|
+
await cancelAllOrders(client, symbol, {});
|
|
62771
|
+
console.log(`Cancelled all orders for ${symbol}`);
|
|
62772
|
+
} catch (error) {
|
|
62773
|
+
console.warn(`Warning: Could not cancel orders for ${symbol}:`, error);
|
|
62774
|
+
}
|
|
62775
|
+
const positionsToClose = [];
|
|
62776
|
+
if ((kind === "long" || kind === "both") && positionInfo.long.size > 0) {
|
|
62777
|
+
positionsToClose.push({
|
|
62778
|
+
kind: "long",
|
|
62779
|
+
size: positionInfo.long.size,
|
|
62780
|
+
side: "sell"
|
|
62781
|
+
});
|
|
62782
|
+
}
|
|
62783
|
+
if ((kind === "short" || kind === "both") && positionInfo.short.size > 0) {
|
|
62784
|
+
positionsToClose.push({
|
|
62785
|
+
kind: "short",
|
|
62786
|
+
size: positionInfo.short.size,
|
|
62787
|
+
side: "buy"
|
|
62788
|
+
});
|
|
62789
|
+
}
|
|
62790
|
+
if (positionsToClose.length === 0) {
|
|
62791
|
+
console.log(`No active positions found for ${symbol} (kind: ${kind})`);
|
|
62792
|
+
return result;
|
|
62793
|
+
}
|
|
62794
|
+
for (const position2 of positionsToClose) {
|
|
62795
|
+
try {
|
|
62796
|
+
const order = {
|
|
62797
|
+
kind: position2.kind,
|
|
62798
|
+
side: position2.side,
|
|
62799
|
+
quantity: position2.size,
|
|
62800
|
+
force_market: true
|
|
62801
|
+
};
|
|
62802
|
+
console.log(`Closing ${position2.kind} position for ${symbol}: ${position2.size} units`);
|
|
62803
|
+
const orderResult = await createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
62804
|
+
result.closedPositions.push({
|
|
62805
|
+
kind: position2.kind,
|
|
62806
|
+
quantity: position2.size,
|
|
62807
|
+
orderResult
|
|
62808
|
+
});
|
|
62809
|
+
console.log(`Successfully closed ${position2.kind} position for ${symbol}`);
|
|
62810
|
+
} catch (error) {
|
|
62811
|
+
const errorMsg = `Failed to close ${position2.kind} position for ${symbol}: ${error}`;
|
|
62812
|
+
console.error(errorMsg);
|
|
62813
|
+
result.errors.push(errorMsg);
|
|
62814
|
+
result.success = false;
|
|
62815
|
+
}
|
|
62816
|
+
}
|
|
62817
|
+
if (result.success && result.closedPositions.length > 0) {
|
|
62818
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
62819
|
+
try {
|
|
62820
|
+
const updatedPositions = await getPositionInfo(client, symbol);
|
|
62821
|
+
const remainingLong = kind === "long" || kind === "both" ? updatedPositions.long.size : 0;
|
|
62822
|
+
const remainingShort = kind === "short" || kind === "both" ? updatedPositions.short.size : 0;
|
|
62823
|
+
if (remainingLong > 0 || remainingShort > 0) {
|
|
62824
|
+
const warningMsg = `Warning: Some positions may still be open after force close for ${symbol}. Long: ${remainingLong}, Short: ${remainingShort}`;
|
|
62825
|
+
console.warn(warningMsg);
|
|
62826
|
+
result.errors.push(warningMsg);
|
|
62827
|
+
}
|
|
62828
|
+
} catch (error) {
|
|
62829
|
+
console.warn(`Could not validate position closure for ${symbol}:`, error);
|
|
62830
|
+
}
|
|
62831
|
+
}
|
|
62832
|
+
} catch (error) {
|
|
62833
|
+
const errorMsg = `Critical error in forceClosePosition for ${symbol}: ${error}`;
|
|
62834
|
+
console.error(errorMsg);
|
|
62835
|
+
result.errors.push(errorMsg);
|
|
62836
|
+
result.success = false;
|
|
62837
|
+
}
|
|
62838
|
+
return result;
|
|
62839
|
+
}
|
|
62753
62840
|
|
|
62754
62841
|
// src/exchanges/bybit.ts
|
|
62755
62842
|
var import_bybit_api = __toESM(require_lib3());
|
|
@@ -62862,11 +62949,11 @@ async function getPositionInfo2(client, symbol) {
|
|
|
62862
62949
|
async function cancelOrders2(payload) {
|
|
62863
62950
|
const client = payload.custom_client;
|
|
62864
62951
|
const results = [];
|
|
62865
|
-
for (let i2 = 0;i2 < payload.orders.length; i2 +=
|
|
62866
|
-
const batch2 = payload.orders.slice(i2, i2 +
|
|
62952
|
+
for (let i2 = 0;i2 < payload.orders.length; i2 += 15) {
|
|
62953
|
+
const batch2 = payload.orders.slice(i2, i2 + 15);
|
|
62867
62954
|
let rr = await client.batchCancelOrders("linear", batch2.map((x) => ({ orderId: x.orderId, symbol: payload.symbol })));
|
|
62868
62955
|
results.push(rr);
|
|
62869
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
62956
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
62870
62957
|
}
|
|
62871
62958
|
return results;
|
|
62872
62959
|
}
|
|
@@ -66243,7 +66330,6 @@ class ExchangeAccount {
|
|
|
66243
66330
|
const long_position = positions.find((k) => k.kind === "long");
|
|
66244
66331
|
const short_position = positions.find((k) => k.kind === "short");
|
|
66245
66332
|
console.log("Getting focus position for ", symbol, kind);
|
|
66246
|
-
const reverse_position = kind === "long" ? short_position : long_position;
|
|
66247
66333
|
if (strategy2.max_reward_factor === 0) {
|
|
66248
66334
|
reward_factor = strategy2.reward_factor;
|
|
66249
66335
|
}
|
|
@@ -66300,13 +66386,6 @@ class ExchangeAccount {
|
|
|
66300
66386
|
params: config2
|
|
66301
66387
|
});
|
|
66302
66388
|
console.log("Checking orders to place for ", symbol, kind);
|
|
66303
|
-
const orders_to_place = await this.placeTrade({
|
|
66304
|
-
symbol,
|
|
66305
|
-
raw: true,
|
|
66306
|
-
kind,
|
|
66307
|
-
place: false,
|
|
66308
|
-
ignore_config: true
|
|
66309
|
-
});
|
|
66310
66389
|
await this.placeTrade({
|
|
66311
66390
|
symbol,
|
|
66312
66391
|
kind,
|
|
@@ -66318,9 +66397,6 @@ class ExchangeAccount {
|
|
|
66318
66397
|
...config2,
|
|
66319
66398
|
...data
|
|
66320
66399
|
};
|
|
66321
|
-
let reverse_action = null;
|
|
66322
|
-
let reverse_orders_to_buy = [];
|
|
66323
|
-
let reverse_config = null;
|
|
66324
66400
|
if (focus_position.avg_qty < last_value.avg_size) {
|
|
66325
66401
|
console.log("Placing trade for ", symbol, kind);
|
|
66326
66402
|
await this.placeTrade({
|
|
@@ -66331,97 +66407,11 @@ class ExchangeAccount {
|
|
|
66331
66407
|
});
|
|
66332
66408
|
}
|
|
66333
66409
|
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
66334
|
-
if (focus_position.quantity > 0) {
|
|
66335
|
-
console.log("Getting details for ", reverse_position.kind);
|
|
66336
|
-
reverse_action = await this.buildOppositeTrades({
|
|
66337
|
-
symbol,
|
|
66338
|
-
kind
|
|
66339
|
-
});
|
|
66340
|
-
if (!reverse_action) {
|
|
66341
|
-
return;
|
|
66342
|
-
}
|
|
66343
|
-
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
66344
|
-
await this.getPositionConfig({
|
|
66345
|
-
symbol,
|
|
66346
|
-
kind: reverse_action.kind,
|
|
66347
|
-
params: {
|
|
66348
|
-
entry: reverse_action.entry,
|
|
66349
|
-
stop: reverse_action.stop,
|
|
66350
|
-
risk: reverse_action.risk_per_trade,
|
|
66351
|
-
profit_percent: reverse_action.profit_percent,
|
|
66352
|
-
risk_reward: reverse_action.risk_reward
|
|
66353
|
-
}
|
|
66354
|
-
});
|
|
66355
|
-
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
66356
|
-
const reverse_app_config = await this.buildAppConfig({
|
|
66357
|
-
entry: reverse_action.entry,
|
|
66358
|
-
stop: reverse_action.stop,
|
|
66359
|
-
risk_reward: reverse_action.risk_reward,
|
|
66360
|
-
risk: reverse_action.risk_per_trade,
|
|
66361
|
-
symbol
|
|
66362
|
-
});
|
|
66363
|
-
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
66364
|
-
reverse_orders_to_buy = await this.placeTrade({
|
|
66365
|
-
symbol,
|
|
66366
|
-
raw: true,
|
|
66367
|
-
kind: reverse_action.kind,
|
|
66368
|
-
ignore_config: true,
|
|
66369
|
-
place: false
|
|
66370
|
-
});
|
|
66371
|
-
let _reverse_config = {
|
|
66372
|
-
avg: reverse_action.avg,
|
|
66373
|
-
entry: reverse_action.entry,
|
|
66374
|
-
stop: reverse_action.stop,
|
|
66375
|
-
risk_per_trade: reverse_action.risk_per_trade,
|
|
66376
|
-
profit_percent: reverse_action.profit_percent,
|
|
66377
|
-
risk_reward: reverse_action.risk_reward
|
|
66378
|
-
};
|
|
66379
|
-
if (reverse_orders_to_buy.length > 0) {
|
|
66380
|
-
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
66381
|
-
let existing = await this.placeOppositeTradeAction({
|
|
66382
|
-
symbol,
|
|
66383
|
-
kind: reverse_action.kind,
|
|
66384
|
-
data: _reverse_config
|
|
66385
|
-
});
|
|
66386
|
-
_reverse_config = {
|
|
66387
|
-
...existing,
|
|
66388
|
-
..._reverse_config
|
|
66389
|
-
};
|
|
66390
|
-
}
|
|
66391
|
-
reverse_config = _reverse_config;
|
|
66392
|
-
}
|
|
66393
|
-
if (!reverse_config?.id) {
|
|
66394
|
-
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
66395
|
-
reverse_config = await this.getPositionConfig({
|
|
66396
|
-
symbol,
|
|
66397
|
-
kind: reverse_action.kind
|
|
66398
|
-
});
|
|
66399
|
-
}
|
|
66400
|
-
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
66401
|
-
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
66402
|
-
const max_size = app_config.max_size * 0.98;
|
|
66403
|
-
if (reverse_config.threshold_qty !== max_size) {
|
|
66404
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
66405
|
-
follow: strategy2.follow,
|
|
66406
|
-
threshold_qty: max_size
|
|
66407
|
-
});
|
|
66408
|
-
}
|
|
66409
|
-
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
66410
|
-
} else {
|
|
66411
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
66412
|
-
follow: false
|
|
66413
|
-
});
|
|
66414
|
-
}
|
|
66415
|
-
}
|
|
66416
66410
|
return {
|
|
66417
|
-
reverse_config,
|
|
66418
|
-
reverse_action,
|
|
66419
|
-
reverse_orders_to_buy,
|
|
66420
66411
|
positions: {
|
|
66421
66412
|
long: long_position,
|
|
66422
66413
|
short: short_position
|
|
66423
66414
|
},
|
|
66424
|
-
orders_to_place,
|
|
66425
66415
|
config_details: {
|
|
66426
66416
|
app_config,
|
|
66427
66417
|
last_value,
|
package/dist/mcp-server.js
CHANGED
|
@@ -62718,6 +62718,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
62718
62718
|
async getOpenOrders(payload) {
|
|
62719
62719
|
return await getOpenOrders(this.client, payload.symbol);
|
|
62720
62720
|
}
|
|
62721
|
+
async forceClosePosition(symbol, options) {
|
|
62722
|
+
return await forceClosePosition(this.client, symbol, options);
|
|
62723
|
+
}
|
|
62721
62724
|
}
|
|
62722
62725
|
function getPricePlaces(target) {
|
|
62723
62726
|
const numStr = target.toString();
|
|
@@ -62727,6 +62730,90 @@ function getPricePlaces(target) {
|
|
|
62727
62730
|
return 0;
|
|
62728
62731
|
}
|
|
62729
62732
|
}
|
|
62733
|
+
async function forceClosePosition(client, symbol, options) {
|
|
62734
|
+
const {
|
|
62735
|
+
kind = "both",
|
|
62736
|
+
price_places = "%.1f",
|
|
62737
|
+
decimal_places = "%.3f"
|
|
62738
|
+
} = options || {};
|
|
62739
|
+
const result = {
|
|
62740
|
+
success: true,
|
|
62741
|
+
closedPositions: [],
|
|
62742
|
+
errors: []
|
|
62743
|
+
};
|
|
62744
|
+
try {
|
|
62745
|
+
const positionInfo = await getPositionInfo(client, symbol);
|
|
62746
|
+
try {
|
|
62747
|
+
await cancelAllOrders(client, symbol, {});
|
|
62748
|
+
console.log(`Cancelled all orders for ${symbol}`);
|
|
62749
|
+
} catch (error) {
|
|
62750
|
+
console.warn(`Warning: Could not cancel orders for ${symbol}:`, error);
|
|
62751
|
+
}
|
|
62752
|
+
const positionsToClose = [];
|
|
62753
|
+
if ((kind === "long" || kind === "both") && positionInfo.long.size > 0) {
|
|
62754
|
+
positionsToClose.push({
|
|
62755
|
+
kind: "long",
|
|
62756
|
+
size: positionInfo.long.size,
|
|
62757
|
+
side: "sell"
|
|
62758
|
+
});
|
|
62759
|
+
}
|
|
62760
|
+
if ((kind === "short" || kind === "both") && positionInfo.short.size > 0) {
|
|
62761
|
+
positionsToClose.push({
|
|
62762
|
+
kind: "short",
|
|
62763
|
+
size: positionInfo.short.size,
|
|
62764
|
+
side: "buy"
|
|
62765
|
+
});
|
|
62766
|
+
}
|
|
62767
|
+
if (positionsToClose.length === 0) {
|
|
62768
|
+
console.log(`No active positions found for ${symbol} (kind: ${kind})`);
|
|
62769
|
+
return result;
|
|
62770
|
+
}
|
|
62771
|
+
for (const position2 of positionsToClose) {
|
|
62772
|
+
try {
|
|
62773
|
+
const order = {
|
|
62774
|
+
kind: position2.kind,
|
|
62775
|
+
side: position2.side,
|
|
62776
|
+
quantity: position2.size,
|
|
62777
|
+
force_market: true
|
|
62778
|
+
};
|
|
62779
|
+
console.log(`Closing ${position2.kind} position for ${symbol}: ${position2.size} units`);
|
|
62780
|
+
const orderResult = await createLimitPurchaseOrders(client, symbol, price_places, decimal_places, [order]);
|
|
62781
|
+
result.closedPositions.push({
|
|
62782
|
+
kind: position2.kind,
|
|
62783
|
+
quantity: position2.size,
|
|
62784
|
+
orderResult
|
|
62785
|
+
});
|
|
62786
|
+
console.log(`Successfully closed ${position2.kind} position for ${symbol}`);
|
|
62787
|
+
} catch (error) {
|
|
62788
|
+
const errorMsg = `Failed to close ${position2.kind} position for ${symbol}: ${error}`;
|
|
62789
|
+
console.error(errorMsg);
|
|
62790
|
+
result.errors.push(errorMsg);
|
|
62791
|
+
result.success = false;
|
|
62792
|
+
}
|
|
62793
|
+
}
|
|
62794
|
+
if (result.success && result.closedPositions.length > 0) {
|
|
62795
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
62796
|
+
try {
|
|
62797
|
+
const updatedPositions = await getPositionInfo(client, symbol);
|
|
62798
|
+
const remainingLong = kind === "long" || kind === "both" ? updatedPositions.long.size : 0;
|
|
62799
|
+
const remainingShort = kind === "short" || kind === "both" ? updatedPositions.short.size : 0;
|
|
62800
|
+
if (remainingLong > 0 || remainingShort > 0) {
|
|
62801
|
+
const warningMsg = `Warning: Some positions may still be open after force close for ${symbol}. Long: ${remainingLong}, Short: ${remainingShort}`;
|
|
62802
|
+
console.warn(warningMsg);
|
|
62803
|
+
result.errors.push(warningMsg);
|
|
62804
|
+
}
|
|
62805
|
+
} catch (error) {
|
|
62806
|
+
console.warn(`Could not validate position closure for ${symbol}:`, error);
|
|
62807
|
+
}
|
|
62808
|
+
}
|
|
62809
|
+
} catch (error) {
|
|
62810
|
+
const errorMsg = `Critical error in forceClosePosition for ${symbol}: ${error}`;
|
|
62811
|
+
console.error(errorMsg);
|
|
62812
|
+
result.errors.push(errorMsg);
|
|
62813
|
+
result.success = false;
|
|
62814
|
+
}
|
|
62815
|
+
return result;
|
|
62816
|
+
}
|
|
62730
62817
|
|
|
62731
62818
|
// src/exchanges/bybit.ts
|
|
62732
62819
|
var import_bybit_api = __toESM(require_lib3(), 1);
|
|
@@ -62839,11 +62926,11 @@ async function getPositionInfo2(client, symbol) {
|
|
|
62839
62926
|
async function cancelOrders2(payload) {
|
|
62840
62927
|
const client = payload.custom_client;
|
|
62841
62928
|
const results = [];
|
|
62842
|
-
for (let i2 = 0;i2 < payload.orders.length; i2 +=
|
|
62843
|
-
const batch2 = payload.orders.slice(i2, i2 +
|
|
62929
|
+
for (let i2 = 0;i2 < payload.orders.length; i2 += 15) {
|
|
62930
|
+
const batch2 = payload.orders.slice(i2, i2 + 15);
|
|
62844
62931
|
let rr = await client.batchCancelOrders("linear", batch2.map((x) => ({ orderId: x.orderId, symbol: payload.symbol })));
|
|
62845
62932
|
results.push(rr);
|
|
62846
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
62933
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
62847
62934
|
}
|
|
62848
62935
|
return results;
|
|
62849
62936
|
}
|
|
@@ -66220,7 +66307,6 @@ class ExchangeAccount {
|
|
|
66220
66307
|
const long_position = positions.find((k) => k.kind === "long");
|
|
66221
66308
|
const short_position = positions.find((k) => k.kind === "short");
|
|
66222
66309
|
console.log("Getting focus position for ", symbol, kind);
|
|
66223
|
-
const reverse_position = kind === "long" ? short_position : long_position;
|
|
66224
66310
|
if (strategy2.max_reward_factor === 0) {
|
|
66225
66311
|
reward_factor = strategy2.reward_factor;
|
|
66226
66312
|
}
|
|
@@ -66277,13 +66363,6 @@ class ExchangeAccount {
|
|
|
66277
66363
|
params: config2
|
|
66278
66364
|
});
|
|
66279
66365
|
console.log("Checking orders to place for ", symbol, kind);
|
|
66280
|
-
const orders_to_place = await this.placeTrade({
|
|
66281
|
-
symbol,
|
|
66282
|
-
raw: true,
|
|
66283
|
-
kind,
|
|
66284
|
-
place: false,
|
|
66285
|
-
ignore_config: true
|
|
66286
|
-
});
|
|
66287
66366
|
await this.placeTrade({
|
|
66288
66367
|
symbol,
|
|
66289
66368
|
kind,
|
|
@@ -66295,9 +66374,6 @@ class ExchangeAccount {
|
|
|
66295
66374
|
...config2,
|
|
66296
66375
|
...data
|
|
66297
66376
|
};
|
|
66298
|
-
let reverse_action = null;
|
|
66299
|
-
let reverse_orders_to_buy = [];
|
|
66300
|
-
let reverse_config = null;
|
|
66301
66377
|
if (focus_position.avg_qty < last_value.avg_size) {
|
|
66302
66378
|
console.log("Placing trade for ", symbol, kind);
|
|
66303
66379
|
await this.placeTrade({
|
|
@@ -66308,97 +66384,11 @@ class ExchangeAccount {
|
|
|
66308
66384
|
});
|
|
66309
66385
|
}
|
|
66310
66386
|
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
66311
|
-
if (focus_position.quantity > 0) {
|
|
66312
|
-
console.log("Getting details for ", reverse_position.kind);
|
|
66313
|
-
reverse_action = await this.buildOppositeTrades({
|
|
66314
|
-
symbol,
|
|
66315
|
-
kind
|
|
66316
|
-
});
|
|
66317
|
-
if (!reverse_action) {
|
|
66318
|
-
return;
|
|
66319
|
-
}
|
|
66320
|
-
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
66321
|
-
await this.getPositionConfig({
|
|
66322
|
-
symbol,
|
|
66323
|
-
kind: reverse_action.kind,
|
|
66324
|
-
params: {
|
|
66325
|
-
entry: reverse_action.entry,
|
|
66326
|
-
stop: reverse_action.stop,
|
|
66327
|
-
risk: reverse_action.risk_per_trade,
|
|
66328
|
-
profit_percent: reverse_action.profit_percent,
|
|
66329
|
-
risk_reward: reverse_action.risk_reward
|
|
66330
|
-
}
|
|
66331
|
-
});
|
|
66332
|
-
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
66333
|
-
const reverse_app_config = await this.buildAppConfig({
|
|
66334
|
-
entry: reverse_action.entry,
|
|
66335
|
-
stop: reverse_action.stop,
|
|
66336
|
-
risk_reward: reverse_action.risk_reward,
|
|
66337
|
-
risk: reverse_action.risk_per_trade,
|
|
66338
|
-
symbol
|
|
66339
|
-
});
|
|
66340
|
-
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
66341
|
-
reverse_orders_to_buy = await this.placeTrade({
|
|
66342
|
-
symbol,
|
|
66343
|
-
raw: true,
|
|
66344
|
-
kind: reverse_action.kind,
|
|
66345
|
-
ignore_config: true,
|
|
66346
|
-
place: false
|
|
66347
|
-
});
|
|
66348
|
-
let _reverse_config = {
|
|
66349
|
-
avg: reverse_action.avg,
|
|
66350
|
-
entry: reverse_action.entry,
|
|
66351
|
-
stop: reverse_action.stop,
|
|
66352
|
-
risk_per_trade: reverse_action.risk_per_trade,
|
|
66353
|
-
profit_percent: reverse_action.profit_percent,
|
|
66354
|
-
risk_reward: reverse_action.risk_reward
|
|
66355
|
-
};
|
|
66356
|
-
if (reverse_orders_to_buy.length > 0) {
|
|
66357
|
-
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
66358
|
-
let existing = await this.placeOppositeTradeAction({
|
|
66359
|
-
symbol,
|
|
66360
|
-
kind: reverse_action.kind,
|
|
66361
|
-
data: _reverse_config
|
|
66362
|
-
});
|
|
66363
|
-
_reverse_config = {
|
|
66364
|
-
...existing,
|
|
66365
|
-
..._reverse_config
|
|
66366
|
-
};
|
|
66367
|
-
}
|
|
66368
|
-
reverse_config = _reverse_config;
|
|
66369
|
-
}
|
|
66370
|
-
if (!reverse_config?.id) {
|
|
66371
|
-
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
66372
|
-
reverse_config = await this.getPositionConfig({
|
|
66373
|
-
symbol,
|
|
66374
|
-
kind: reverse_action.kind
|
|
66375
|
-
});
|
|
66376
|
-
}
|
|
66377
|
-
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
66378
|
-
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
66379
|
-
const max_size = app_config.max_size * 0.98;
|
|
66380
|
-
if (reverse_config.threshold_qty !== max_size) {
|
|
66381
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
66382
|
-
follow: strategy2.follow,
|
|
66383
|
-
threshold_qty: max_size
|
|
66384
|
-
});
|
|
66385
|
-
}
|
|
66386
|
-
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
66387
|
-
} else {
|
|
66388
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
66389
|
-
follow: false
|
|
66390
|
-
});
|
|
66391
|
-
}
|
|
66392
|
-
}
|
|
66393
66387
|
return {
|
|
66394
|
-
reverse_config,
|
|
66395
|
-
reverse_action,
|
|
66396
|
-
reverse_orders_to_buy,
|
|
66397
66388
|
positions: {
|
|
66398
66389
|
long: long_position,
|
|
66399
66390
|
short: short_position
|
|
66400
66391
|
},
|
|
66401
|
-
orders_to_place,
|
|
66402
66392
|
config_details: {
|
|
66403
66393
|
app_config,
|
|
66404
66394
|
last_value,
|