@gbozee/ultimate 0.0.2-115 → 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 +96 -101
- package/dist/index.d.ts +11 -77
- package/dist/index.js +96 -101
- package/dist/mcp-server.cjs +94 -101
- package/dist/mcp-server.js +94 -101
- 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");
|
|
@@ -55124,7 +55126,10 @@ class AccountService {
|
|
|
55124
55126
|
this.proxyAgent = payload.proxyAgent;
|
|
55125
55127
|
}
|
|
55126
55128
|
async getAccount(owner) {
|
|
55127
|
-
const credentials = this.getCredentials(
|
|
55129
|
+
const credentials = await this.getCredentials({
|
|
55130
|
+
account: owner,
|
|
55131
|
+
exchange: "binance"
|
|
55132
|
+
});
|
|
55128
55133
|
const email = credentials.email;
|
|
55129
55134
|
const is_sub_account = owner !== "main_account";
|
|
55130
55135
|
return {
|
|
@@ -56058,6 +56063,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
56058
56063
|
async getOpenOrders(payload) {
|
|
56059
56064
|
return await getOpenOrders(this.client, payload.symbol);
|
|
56060
56065
|
}
|
|
56066
|
+
async forceClosePosition(symbol, options) {
|
|
56067
|
+
return await forceClosePosition(this.client, symbol, options);
|
|
56068
|
+
}
|
|
56061
56069
|
}
|
|
56062
56070
|
function getPricePlaces(target) {
|
|
56063
56071
|
const numStr = target.toString();
|
|
@@ -56067,6 +56075,90 @@ function getPricePlaces(target) {
|
|
|
56067
56075
|
return 0;
|
|
56068
56076
|
}
|
|
56069
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
|
+
}
|
|
56070
56162
|
|
|
56071
56163
|
// src/exchanges/bybit.ts
|
|
56072
56164
|
var import_bybit_api = __toESM(require_lib3());
|
|
@@ -56179,11 +56271,11 @@ async function getPositionInfo2(client, symbol) {
|
|
|
56179
56271
|
async function cancelOrders2(payload) {
|
|
56180
56272
|
const client = payload.custom_client;
|
|
56181
56273
|
const results = [];
|
|
56182
|
-
for (let i2 = 0;i2 < payload.orders.length; i2 +=
|
|
56183
|
-
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);
|
|
56184
56276
|
let rr = await client.batchCancelOrders("linear", batch2.map((x) => ({ orderId: x.orderId, symbol: payload.symbol })));
|
|
56185
56277
|
results.push(rr);
|
|
56186
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
56278
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
56187
56279
|
}
|
|
56188
56280
|
return results;
|
|
56189
56281
|
}
|
|
@@ -59560,7 +59652,6 @@ class ExchangeAccount {
|
|
|
59560
59652
|
const long_position = positions.find((k) => k.kind === "long");
|
|
59561
59653
|
const short_position = positions.find((k) => k.kind === "short");
|
|
59562
59654
|
console.log("Getting focus position for ", symbol, kind);
|
|
59563
|
-
const reverse_position = kind === "long" ? short_position : long_position;
|
|
59564
59655
|
if (strategy2.max_reward_factor === 0) {
|
|
59565
59656
|
reward_factor = strategy2.reward_factor;
|
|
59566
59657
|
}
|
|
@@ -59617,13 +59708,6 @@ class ExchangeAccount {
|
|
|
59617
59708
|
params: config2
|
|
59618
59709
|
});
|
|
59619
59710
|
console.log("Checking orders to place for ", symbol, kind);
|
|
59620
|
-
const orders_to_place = await this.placeTrade({
|
|
59621
|
-
symbol,
|
|
59622
|
-
raw: true,
|
|
59623
|
-
kind,
|
|
59624
|
-
place: false,
|
|
59625
|
-
ignore_config: true
|
|
59626
|
-
});
|
|
59627
59711
|
await this.placeTrade({
|
|
59628
59712
|
symbol,
|
|
59629
59713
|
kind,
|
|
@@ -59635,9 +59719,6 @@ class ExchangeAccount {
|
|
|
59635
59719
|
...config2,
|
|
59636
59720
|
...data
|
|
59637
59721
|
};
|
|
59638
|
-
let reverse_action = null;
|
|
59639
|
-
let reverse_orders_to_buy = [];
|
|
59640
|
-
let reverse_config = null;
|
|
59641
59722
|
if (focus_position.avg_qty < last_value.avg_size) {
|
|
59642
59723
|
console.log("Placing trade for ", symbol, kind);
|
|
59643
59724
|
await this.placeTrade({
|
|
@@ -59648,97 +59729,11 @@ class ExchangeAccount {
|
|
|
59648
59729
|
});
|
|
59649
59730
|
}
|
|
59650
59731
|
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
59651
|
-
if (focus_position.quantity > 0) {
|
|
59652
|
-
console.log("Getting details for ", reverse_position.kind);
|
|
59653
|
-
reverse_action = await this.buildOppositeTrades({
|
|
59654
|
-
symbol,
|
|
59655
|
-
kind
|
|
59656
|
-
});
|
|
59657
|
-
if (!reverse_action) {
|
|
59658
|
-
return;
|
|
59659
|
-
}
|
|
59660
|
-
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
59661
|
-
await this.getPositionConfig({
|
|
59662
|
-
symbol,
|
|
59663
|
-
kind: reverse_action.kind,
|
|
59664
|
-
params: {
|
|
59665
|
-
entry: reverse_action.entry,
|
|
59666
|
-
stop: reverse_action.stop,
|
|
59667
|
-
risk: reverse_action.risk_per_trade,
|
|
59668
|
-
profit_percent: reverse_action.profit_percent,
|
|
59669
|
-
risk_reward: reverse_action.risk_reward
|
|
59670
|
-
}
|
|
59671
|
-
});
|
|
59672
|
-
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
59673
|
-
const reverse_app_config = await this.buildAppConfig({
|
|
59674
|
-
entry: reverse_action.entry,
|
|
59675
|
-
stop: reverse_action.stop,
|
|
59676
|
-
risk_reward: reverse_action.risk_reward,
|
|
59677
|
-
risk: reverse_action.risk_per_trade,
|
|
59678
|
-
symbol
|
|
59679
|
-
});
|
|
59680
|
-
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
59681
|
-
reverse_orders_to_buy = await this.placeTrade({
|
|
59682
|
-
symbol,
|
|
59683
|
-
raw: true,
|
|
59684
|
-
kind: reverse_action.kind,
|
|
59685
|
-
ignore_config: true,
|
|
59686
|
-
place: false
|
|
59687
|
-
});
|
|
59688
|
-
let _reverse_config = {
|
|
59689
|
-
avg: reverse_action.avg,
|
|
59690
|
-
entry: reverse_action.entry,
|
|
59691
|
-
stop: reverse_action.stop,
|
|
59692
|
-
risk_per_trade: reverse_action.risk_per_trade,
|
|
59693
|
-
profit_percent: reverse_action.profit_percent,
|
|
59694
|
-
risk_reward: reverse_action.risk_reward
|
|
59695
|
-
};
|
|
59696
|
-
if (reverse_orders_to_buy.length > 0) {
|
|
59697
|
-
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
59698
|
-
let existing = await this.placeOppositeTradeAction({
|
|
59699
|
-
symbol,
|
|
59700
|
-
kind: reverse_action.kind,
|
|
59701
|
-
data: _reverse_config
|
|
59702
|
-
});
|
|
59703
|
-
_reverse_config = {
|
|
59704
|
-
...existing,
|
|
59705
|
-
..._reverse_config
|
|
59706
|
-
};
|
|
59707
|
-
}
|
|
59708
|
-
reverse_config = _reverse_config;
|
|
59709
|
-
}
|
|
59710
|
-
if (!reverse_config?.id) {
|
|
59711
|
-
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
59712
|
-
reverse_config = await this.getPositionConfig({
|
|
59713
|
-
symbol,
|
|
59714
|
-
kind: reverse_action.kind
|
|
59715
|
-
});
|
|
59716
|
-
}
|
|
59717
|
-
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
59718
|
-
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
59719
|
-
const max_size = app_config.max_size * 0.98;
|
|
59720
|
-
if (reverse_config.threshold_qty !== max_size) {
|
|
59721
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59722
|
-
follow: strategy2.follow,
|
|
59723
|
-
threshold_qty: max_size
|
|
59724
|
-
});
|
|
59725
|
-
}
|
|
59726
|
-
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
59727
|
-
} else {
|
|
59728
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59729
|
-
follow: false
|
|
59730
|
-
});
|
|
59731
|
-
}
|
|
59732
|
-
}
|
|
59733
59732
|
return {
|
|
59734
|
-
reverse_config,
|
|
59735
|
-
reverse_action,
|
|
59736
|
-
reverse_orders_to_buy,
|
|
59737
59733
|
positions: {
|
|
59738
59734
|
long: long_position,
|
|
59739
59735
|
short: short_position
|
|
59740
59736
|
},
|
|
59741
|
-
orders_to_place,
|
|
59742
59737
|
config_details: {
|
|
59743
59738
|
app_config,
|
|
59744
59739
|
last_value,
|
package/dist/index.d.ts
CHANGED
|
@@ -302,11 +302,13 @@ export interface CandlestickAnalysisResult {
|
|
|
302
302
|
}
|
|
303
303
|
declare abstract class BaseExchange {
|
|
304
304
|
client: any;
|
|
305
|
-
getCredentials: (
|
|
305
|
+
getCredentials: (payload: {
|
|
306
|
+
account: string;
|
|
307
|
+
}) => Promise<{
|
|
306
308
|
api_key: string;
|
|
307
309
|
api_secret: string;
|
|
308
310
|
email: string;
|
|
309
|
-
}
|
|
311
|
+
}>;
|
|
310
312
|
proxyAgent?: any;
|
|
311
313
|
constructor(client: any);
|
|
312
314
|
protected abstract getPositionInfo(symbol: string): Promise<any>;
|
|
@@ -508,14 +510,18 @@ declare abstract class BaseExchange {
|
|
|
508
510
|
symbol: string;
|
|
509
511
|
}): Promise<CandlestickAnalysisResult>;
|
|
510
512
|
setAccountDetails(payload: {
|
|
511
|
-
getCredentials: (
|
|
513
|
+
getCredentials: (payload: {
|
|
514
|
+
account: string;
|
|
515
|
+
}) => Promise<{
|
|
512
516
|
api_key: string;
|
|
513
517
|
api_secret: string;
|
|
514
518
|
email: string;
|
|
515
|
-
}
|
|
519
|
+
}>;
|
|
516
520
|
proxyAgent?: any;
|
|
517
521
|
}): void;
|
|
518
522
|
}
|
|
523
|
+
declare function encryptObject(obj: any, password: string): string;
|
|
524
|
+
declare function decryptObject(encryptedString: string, password: string): any;
|
|
519
525
|
declare function initPocketBaseClient(proxy_credentials: {
|
|
520
526
|
host: string;
|
|
521
527
|
email: string;
|
|
@@ -2180,41 +2186,6 @@ declare class ExchangeAccount$1 {
|
|
|
2180
2186
|
profitWithinGapStrategy(payload: {
|
|
2181
2187
|
symbol: string;
|
|
2182
2188
|
}): Promise<{
|
|
2183
|
-
reverse_config: any;
|
|
2184
|
-
reverse_action: {
|
|
2185
|
-
avg: {
|
|
2186
|
-
entry: number;
|
|
2187
|
-
price: number;
|
|
2188
|
-
quantity: number;
|
|
2189
|
-
};
|
|
2190
|
-
loss: number;
|
|
2191
|
-
profit_percent: number;
|
|
2192
|
-
fee: number;
|
|
2193
|
-
risk_per_trade: number;
|
|
2194
|
-
risk_reward: number;
|
|
2195
|
-
symbol?: string;
|
|
2196
|
-
focus: number;
|
|
2197
|
-
budget: number;
|
|
2198
|
-
support: number;
|
|
2199
|
-
resistance: number;
|
|
2200
|
-
percent_change: number;
|
|
2201
|
-
tradeSplit?: number;
|
|
2202
|
-
take_profit?: number;
|
|
2203
|
-
kind: "long" | "short";
|
|
2204
|
-
entry: number;
|
|
2205
|
-
stop: number;
|
|
2206
|
-
min_size: number;
|
|
2207
|
-
price_places?: string;
|
|
2208
|
-
strategy?: "quantity" | "entry";
|
|
2209
|
-
as_array?: boolean;
|
|
2210
|
-
decimal_places?: string;
|
|
2211
|
-
min_profit?: number;
|
|
2212
|
-
raw?: boolean;
|
|
2213
|
-
gap?: number;
|
|
2214
|
-
rr?: number;
|
|
2215
|
-
max_size?: number;
|
|
2216
|
-
};
|
|
2217
|
-
reverse_orders_to_buy: any;
|
|
2218
2189
|
positions: {
|
|
2219
2190
|
long: PositionsView & {
|
|
2220
2191
|
expand?: {
|
|
@@ -2227,7 +2198,6 @@ declare class ExchangeAccount$1 {
|
|
|
2227
2198
|
};
|
|
2228
2199
|
};
|
|
2229
2200
|
};
|
|
2230
|
-
orders_to_place: any;
|
|
2231
2201
|
config_details: {
|
|
2232
2202
|
app_config: {
|
|
2233
2203
|
fee: number;
|
|
@@ -2456,41 +2426,6 @@ declare class App {
|
|
|
2456
2426
|
account: ExchangeType;
|
|
2457
2427
|
symbol: string;
|
|
2458
2428
|
}): Promise<{
|
|
2459
|
-
reverse_config: any;
|
|
2460
|
-
reverse_action: {
|
|
2461
|
-
avg: {
|
|
2462
|
-
entry: number;
|
|
2463
|
-
price: number;
|
|
2464
|
-
quantity: number;
|
|
2465
|
-
};
|
|
2466
|
-
loss: number;
|
|
2467
|
-
profit_percent: number;
|
|
2468
|
-
fee: number;
|
|
2469
|
-
risk_per_trade: number;
|
|
2470
|
-
risk_reward: number;
|
|
2471
|
-
symbol?: string;
|
|
2472
|
-
focus: number;
|
|
2473
|
-
budget: number;
|
|
2474
|
-
support: number;
|
|
2475
|
-
resistance: number;
|
|
2476
|
-
percent_change: number;
|
|
2477
|
-
tradeSplit?: number;
|
|
2478
|
-
take_profit?: number;
|
|
2479
|
-
kind: "long" | "short";
|
|
2480
|
-
entry: number;
|
|
2481
|
-
stop: number;
|
|
2482
|
-
min_size: number;
|
|
2483
|
-
price_places?: string;
|
|
2484
|
-
strategy?: "quantity" | "entry";
|
|
2485
|
-
as_array?: boolean;
|
|
2486
|
-
decimal_places?: string;
|
|
2487
|
-
min_profit?: number;
|
|
2488
|
-
raw?: boolean;
|
|
2489
|
-
gap?: number;
|
|
2490
|
-
rr?: number;
|
|
2491
|
-
max_size?: number;
|
|
2492
|
-
};
|
|
2493
|
-
reverse_orders_to_buy: any;
|
|
2494
2429
|
positions: {
|
|
2495
2430
|
long: PositionsView & {
|
|
2496
2431
|
expand?: {
|
|
@@ -2503,7 +2438,6 @@ declare class App {
|
|
|
2503
2438
|
};
|
|
2504
2439
|
};
|
|
2505
2440
|
};
|
|
2506
|
-
orders_to_place: any;
|
|
2507
2441
|
config_details: {
|
|
2508
2442
|
app_config: {
|
|
2509
2443
|
fee: number;
|
|
@@ -2600,7 +2534,7 @@ export declare function initialize(payload: {
|
|
|
2600
2534
|
}): Promise<App>;
|
|
2601
2535
|
|
|
2602
2536
|
declare namespace database {
|
|
2603
|
-
export { AppDatabase, ExchangeType, initPocketBaseClient };
|
|
2537
|
+
export { AppDatabase, ExchangeType, decryptObject, encryptObject, initPocketBaseClient };
|
|
2604
2538
|
}
|
|
2605
2539
|
declare namespace exchange_account {
|
|
2606
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);
|
|
@@ -55074,7 +55076,10 @@ class AccountService {
|
|
|
55074
55076
|
this.proxyAgent = payload.proxyAgent;
|
|
55075
55077
|
}
|
|
55076
55078
|
async getAccount(owner) {
|
|
55077
|
-
const credentials = this.getCredentials(
|
|
55079
|
+
const credentials = await this.getCredentials({
|
|
55080
|
+
account: owner,
|
|
55081
|
+
exchange: "binance"
|
|
55082
|
+
});
|
|
55078
55083
|
const email = credentials.email;
|
|
55079
55084
|
const is_sub_account = owner !== "main_account";
|
|
55080
55085
|
return {
|
|
@@ -56008,6 +56013,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
56008
56013
|
async getOpenOrders(payload) {
|
|
56009
56014
|
return await getOpenOrders(this.client, payload.symbol);
|
|
56010
56015
|
}
|
|
56016
|
+
async forceClosePosition(symbol, options) {
|
|
56017
|
+
return await forceClosePosition(this.client, symbol, options);
|
|
56018
|
+
}
|
|
56011
56019
|
}
|
|
56012
56020
|
function getPricePlaces(target) {
|
|
56013
56021
|
const numStr = target.toString();
|
|
@@ -56017,6 +56025,90 @@ function getPricePlaces(target) {
|
|
|
56017
56025
|
return 0;
|
|
56018
56026
|
}
|
|
56019
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
|
+
}
|
|
56020
56112
|
|
|
56021
56113
|
// src/exchanges/bybit.ts
|
|
56022
56114
|
var import_bybit_api = __toESM(require_lib3(), 1);
|
|
@@ -56129,11 +56221,11 @@ async function getPositionInfo2(client, symbol) {
|
|
|
56129
56221
|
async function cancelOrders2(payload) {
|
|
56130
56222
|
const client = payload.custom_client;
|
|
56131
56223
|
const results = [];
|
|
56132
|
-
for (let i2 = 0;i2 < payload.orders.length; i2 +=
|
|
56133
|
-
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);
|
|
56134
56226
|
let rr = await client.batchCancelOrders("linear", batch2.map((x) => ({ orderId: x.orderId, symbol: payload.symbol })));
|
|
56135
56227
|
results.push(rr);
|
|
56136
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
56228
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
56137
56229
|
}
|
|
56138
56230
|
return results;
|
|
56139
56231
|
}
|
|
@@ -59510,7 +59602,6 @@ class ExchangeAccount {
|
|
|
59510
59602
|
const long_position = positions.find((k) => k.kind === "long");
|
|
59511
59603
|
const short_position = positions.find((k) => k.kind === "short");
|
|
59512
59604
|
console.log("Getting focus position for ", symbol, kind);
|
|
59513
|
-
const reverse_position = kind === "long" ? short_position : long_position;
|
|
59514
59605
|
if (strategy2.max_reward_factor === 0) {
|
|
59515
59606
|
reward_factor = strategy2.reward_factor;
|
|
59516
59607
|
}
|
|
@@ -59567,13 +59658,6 @@ class ExchangeAccount {
|
|
|
59567
59658
|
params: config2
|
|
59568
59659
|
});
|
|
59569
59660
|
console.log("Checking orders to place for ", symbol, kind);
|
|
59570
|
-
const orders_to_place = await this.placeTrade({
|
|
59571
|
-
symbol,
|
|
59572
|
-
raw: true,
|
|
59573
|
-
kind,
|
|
59574
|
-
place: false,
|
|
59575
|
-
ignore_config: true
|
|
59576
|
-
});
|
|
59577
59661
|
await this.placeTrade({
|
|
59578
59662
|
symbol,
|
|
59579
59663
|
kind,
|
|
@@ -59585,9 +59669,6 @@ class ExchangeAccount {
|
|
|
59585
59669
|
...config2,
|
|
59586
59670
|
...data
|
|
59587
59671
|
};
|
|
59588
|
-
let reverse_action = null;
|
|
59589
|
-
let reverse_orders_to_buy = [];
|
|
59590
|
-
let reverse_config = null;
|
|
59591
59672
|
if (focus_position.avg_qty < last_value.avg_size) {
|
|
59592
59673
|
console.log("Placing trade for ", symbol, kind);
|
|
59593
59674
|
await this.placeTrade({
|
|
@@ -59598,97 +59679,11 @@ class ExchangeAccount {
|
|
|
59598
59679
|
});
|
|
59599
59680
|
}
|
|
59600
59681
|
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
59601
|
-
if (focus_position.quantity > 0) {
|
|
59602
|
-
console.log("Getting details for ", reverse_position.kind);
|
|
59603
|
-
reverse_action = await this.buildOppositeTrades({
|
|
59604
|
-
symbol,
|
|
59605
|
-
kind
|
|
59606
|
-
});
|
|
59607
|
-
if (!reverse_action) {
|
|
59608
|
-
return;
|
|
59609
|
-
}
|
|
59610
|
-
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
59611
|
-
await this.getPositionConfig({
|
|
59612
|
-
symbol,
|
|
59613
|
-
kind: reverse_action.kind,
|
|
59614
|
-
params: {
|
|
59615
|
-
entry: reverse_action.entry,
|
|
59616
|
-
stop: reverse_action.stop,
|
|
59617
|
-
risk: reverse_action.risk_per_trade,
|
|
59618
|
-
profit_percent: reverse_action.profit_percent,
|
|
59619
|
-
risk_reward: reverse_action.risk_reward
|
|
59620
|
-
}
|
|
59621
|
-
});
|
|
59622
|
-
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
59623
|
-
const reverse_app_config = await this.buildAppConfig({
|
|
59624
|
-
entry: reverse_action.entry,
|
|
59625
|
-
stop: reverse_action.stop,
|
|
59626
|
-
risk_reward: reverse_action.risk_reward,
|
|
59627
|
-
risk: reverse_action.risk_per_trade,
|
|
59628
|
-
symbol
|
|
59629
|
-
});
|
|
59630
|
-
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
59631
|
-
reverse_orders_to_buy = await this.placeTrade({
|
|
59632
|
-
symbol,
|
|
59633
|
-
raw: true,
|
|
59634
|
-
kind: reverse_action.kind,
|
|
59635
|
-
ignore_config: true,
|
|
59636
|
-
place: false
|
|
59637
|
-
});
|
|
59638
|
-
let _reverse_config = {
|
|
59639
|
-
avg: reverse_action.avg,
|
|
59640
|
-
entry: reverse_action.entry,
|
|
59641
|
-
stop: reverse_action.stop,
|
|
59642
|
-
risk_per_trade: reverse_action.risk_per_trade,
|
|
59643
|
-
profit_percent: reverse_action.profit_percent,
|
|
59644
|
-
risk_reward: reverse_action.risk_reward
|
|
59645
|
-
};
|
|
59646
|
-
if (reverse_orders_to_buy.length > 0) {
|
|
59647
|
-
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
59648
|
-
let existing = await this.placeOppositeTradeAction({
|
|
59649
|
-
symbol,
|
|
59650
|
-
kind: reverse_action.kind,
|
|
59651
|
-
data: _reverse_config
|
|
59652
|
-
});
|
|
59653
|
-
_reverse_config = {
|
|
59654
|
-
...existing,
|
|
59655
|
-
..._reverse_config
|
|
59656
|
-
};
|
|
59657
|
-
}
|
|
59658
|
-
reverse_config = _reverse_config;
|
|
59659
|
-
}
|
|
59660
|
-
if (!reverse_config?.id) {
|
|
59661
|
-
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
59662
|
-
reverse_config = await this.getPositionConfig({
|
|
59663
|
-
symbol,
|
|
59664
|
-
kind: reverse_action.kind
|
|
59665
|
-
});
|
|
59666
|
-
}
|
|
59667
|
-
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
59668
|
-
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
59669
|
-
const max_size = app_config.max_size * 0.98;
|
|
59670
|
-
if (reverse_config.threshold_qty !== max_size) {
|
|
59671
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59672
|
-
follow: strategy2.follow,
|
|
59673
|
-
threshold_qty: max_size
|
|
59674
|
-
});
|
|
59675
|
-
}
|
|
59676
|
-
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
59677
|
-
} else {
|
|
59678
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
59679
|
-
follow: false
|
|
59680
|
-
});
|
|
59681
|
-
}
|
|
59682
|
-
}
|
|
59683
59682
|
return {
|
|
59684
|
-
reverse_config,
|
|
59685
|
-
reverse_action,
|
|
59686
|
-
reverse_orders_to_buy,
|
|
59687
59683
|
positions: {
|
|
59688
59684
|
long: long_position,
|
|
59689
59685
|
short: short_position
|
|
59690
59686
|
},
|
|
59691
|
-
orders_to_place,
|
|
59692
59687
|
config_details: {
|
|
59693
59688
|
app_config,
|
|
59694
59689
|
last_value,
|
package/dist/mcp-server.cjs
CHANGED
|
@@ -61804,7 +61804,10 @@ class AccountService {
|
|
|
61804
61804
|
this.proxyAgent = payload.proxyAgent;
|
|
61805
61805
|
}
|
|
61806
61806
|
async getAccount(owner) {
|
|
61807
|
-
const credentials = this.getCredentials(
|
|
61807
|
+
const credentials = await this.getCredentials({
|
|
61808
|
+
account: owner,
|
|
61809
|
+
exchange: "binance"
|
|
61810
|
+
});
|
|
61808
61811
|
const email = credentials.email;
|
|
61809
61812
|
const is_sub_account = owner !== "main_account";
|
|
61810
61813
|
return {
|
|
@@ -62738,6 +62741,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
62738
62741
|
async getOpenOrders(payload) {
|
|
62739
62742
|
return await getOpenOrders(this.client, payload.symbol);
|
|
62740
62743
|
}
|
|
62744
|
+
async forceClosePosition(symbol, options) {
|
|
62745
|
+
return await forceClosePosition(this.client, symbol, options);
|
|
62746
|
+
}
|
|
62741
62747
|
}
|
|
62742
62748
|
function getPricePlaces(target) {
|
|
62743
62749
|
const numStr = target.toString();
|
|
@@ -62747,6 +62753,90 @@ function getPricePlaces(target) {
|
|
|
62747
62753
|
return 0;
|
|
62748
62754
|
}
|
|
62749
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
|
+
}
|
|
62750
62840
|
|
|
62751
62841
|
// src/exchanges/bybit.ts
|
|
62752
62842
|
var import_bybit_api = __toESM(require_lib3());
|
|
@@ -62859,11 +62949,11 @@ async function getPositionInfo2(client, symbol) {
|
|
|
62859
62949
|
async function cancelOrders2(payload) {
|
|
62860
62950
|
const client = payload.custom_client;
|
|
62861
62951
|
const results = [];
|
|
62862
|
-
for (let i2 = 0;i2 < payload.orders.length; i2 +=
|
|
62863
|
-
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);
|
|
62864
62954
|
let rr = await client.batchCancelOrders("linear", batch2.map((x) => ({ orderId: x.orderId, symbol: payload.symbol })));
|
|
62865
62955
|
results.push(rr);
|
|
62866
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
62956
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
62867
62957
|
}
|
|
62868
62958
|
return results;
|
|
62869
62959
|
}
|
|
@@ -66240,7 +66330,6 @@ class ExchangeAccount {
|
|
|
66240
66330
|
const long_position = positions.find((k) => k.kind === "long");
|
|
66241
66331
|
const short_position = positions.find((k) => k.kind === "short");
|
|
66242
66332
|
console.log("Getting focus position for ", symbol, kind);
|
|
66243
|
-
const reverse_position = kind === "long" ? short_position : long_position;
|
|
66244
66333
|
if (strategy2.max_reward_factor === 0) {
|
|
66245
66334
|
reward_factor = strategy2.reward_factor;
|
|
66246
66335
|
}
|
|
@@ -66297,13 +66386,6 @@ class ExchangeAccount {
|
|
|
66297
66386
|
params: config2
|
|
66298
66387
|
});
|
|
66299
66388
|
console.log("Checking orders to place for ", symbol, kind);
|
|
66300
|
-
const orders_to_place = await this.placeTrade({
|
|
66301
|
-
symbol,
|
|
66302
|
-
raw: true,
|
|
66303
|
-
kind,
|
|
66304
|
-
place: false,
|
|
66305
|
-
ignore_config: true
|
|
66306
|
-
});
|
|
66307
66389
|
await this.placeTrade({
|
|
66308
66390
|
symbol,
|
|
66309
66391
|
kind,
|
|
@@ -66315,9 +66397,6 @@ class ExchangeAccount {
|
|
|
66315
66397
|
...config2,
|
|
66316
66398
|
...data
|
|
66317
66399
|
};
|
|
66318
|
-
let reverse_action = null;
|
|
66319
|
-
let reverse_orders_to_buy = [];
|
|
66320
|
-
let reverse_config = null;
|
|
66321
66400
|
if (focus_position.avg_qty < last_value.avg_size) {
|
|
66322
66401
|
console.log("Placing trade for ", symbol, kind);
|
|
66323
66402
|
await this.placeTrade({
|
|
@@ -66328,97 +66407,11 @@ class ExchangeAccount {
|
|
|
66328
66407
|
});
|
|
66329
66408
|
}
|
|
66330
66409
|
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
66331
|
-
if (focus_position.quantity > 0) {
|
|
66332
|
-
console.log("Getting details for ", reverse_position.kind);
|
|
66333
|
-
reverse_action = await this.buildOppositeTrades({
|
|
66334
|
-
symbol,
|
|
66335
|
-
kind
|
|
66336
|
-
});
|
|
66337
|
-
if (!reverse_action) {
|
|
66338
|
-
return;
|
|
66339
|
-
}
|
|
66340
|
-
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
66341
|
-
await this.getPositionConfig({
|
|
66342
|
-
symbol,
|
|
66343
|
-
kind: reverse_action.kind,
|
|
66344
|
-
params: {
|
|
66345
|
-
entry: reverse_action.entry,
|
|
66346
|
-
stop: reverse_action.stop,
|
|
66347
|
-
risk: reverse_action.risk_per_trade,
|
|
66348
|
-
profit_percent: reverse_action.profit_percent,
|
|
66349
|
-
risk_reward: reverse_action.risk_reward
|
|
66350
|
-
}
|
|
66351
|
-
});
|
|
66352
|
-
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
66353
|
-
const reverse_app_config = await this.buildAppConfig({
|
|
66354
|
-
entry: reverse_action.entry,
|
|
66355
|
-
stop: reverse_action.stop,
|
|
66356
|
-
risk_reward: reverse_action.risk_reward,
|
|
66357
|
-
risk: reverse_action.risk_per_trade,
|
|
66358
|
-
symbol
|
|
66359
|
-
});
|
|
66360
|
-
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
66361
|
-
reverse_orders_to_buy = await this.placeTrade({
|
|
66362
|
-
symbol,
|
|
66363
|
-
raw: true,
|
|
66364
|
-
kind: reverse_action.kind,
|
|
66365
|
-
ignore_config: true,
|
|
66366
|
-
place: false
|
|
66367
|
-
});
|
|
66368
|
-
let _reverse_config = {
|
|
66369
|
-
avg: reverse_action.avg,
|
|
66370
|
-
entry: reverse_action.entry,
|
|
66371
|
-
stop: reverse_action.stop,
|
|
66372
|
-
risk_per_trade: reverse_action.risk_per_trade,
|
|
66373
|
-
profit_percent: reverse_action.profit_percent,
|
|
66374
|
-
risk_reward: reverse_action.risk_reward
|
|
66375
|
-
};
|
|
66376
|
-
if (reverse_orders_to_buy.length > 0) {
|
|
66377
|
-
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
66378
|
-
let existing = await this.placeOppositeTradeAction({
|
|
66379
|
-
symbol,
|
|
66380
|
-
kind: reverse_action.kind,
|
|
66381
|
-
data: _reverse_config
|
|
66382
|
-
});
|
|
66383
|
-
_reverse_config = {
|
|
66384
|
-
...existing,
|
|
66385
|
-
..._reverse_config
|
|
66386
|
-
};
|
|
66387
|
-
}
|
|
66388
|
-
reverse_config = _reverse_config;
|
|
66389
|
-
}
|
|
66390
|
-
if (!reverse_config?.id) {
|
|
66391
|
-
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
66392
|
-
reverse_config = await this.getPositionConfig({
|
|
66393
|
-
symbol,
|
|
66394
|
-
kind: reverse_action.kind
|
|
66395
|
-
});
|
|
66396
|
-
}
|
|
66397
|
-
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
66398
|
-
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
66399
|
-
const max_size = app_config.max_size * 0.98;
|
|
66400
|
-
if (reverse_config.threshold_qty !== max_size) {
|
|
66401
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
66402
|
-
follow: strategy2.follow,
|
|
66403
|
-
threshold_qty: max_size
|
|
66404
|
-
});
|
|
66405
|
-
}
|
|
66406
|
-
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
66407
|
-
} else {
|
|
66408
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
66409
|
-
follow: false
|
|
66410
|
-
});
|
|
66411
|
-
}
|
|
66412
|
-
}
|
|
66413
66410
|
return {
|
|
66414
|
-
reverse_config,
|
|
66415
|
-
reverse_action,
|
|
66416
|
-
reverse_orders_to_buy,
|
|
66417
66411
|
positions: {
|
|
66418
66412
|
long: long_position,
|
|
66419
66413
|
short: short_position
|
|
66420
66414
|
},
|
|
66421
|
-
orders_to_place,
|
|
66422
66415
|
config_details: {
|
|
66423
66416
|
app_config,
|
|
66424
66417
|
last_value,
|
package/dist/mcp-server.js
CHANGED
|
@@ -61781,7 +61781,10 @@ class AccountService {
|
|
|
61781
61781
|
this.proxyAgent = payload.proxyAgent;
|
|
61782
61782
|
}
|
|
61783
61783
|
async getAccount(owner) {
|
|
61784
|
-
const credentials = this.getCredentials(
|
|
61784
|
+
const credentials = await this.getCredentials({
|
|
61785
|
+
account: owner,
|
|
61786
|
+
exchange: "binance"
|
|
61787
|
+
});
|
|
61785
61788
|
const email = credentials.email;
|
|
61786
61789
|
const is_sub_account = owner !== "main_account";
|
|
61787
61790
|
return {
|
|
@@ -62715,6 +62718,9 @@ class BinanceExchange extends BaseExchange {
|
|
|
62715
62718
|
async getOpenOrders(payload) {
|
|
62716
62719
|
return await getOpenOrders(this.client, payload.symbol);
|
|
62717
62720
|
}
|
|
62721
|
+
async forceClosePosition(symbol, options) {
|
|
62722
|
+
return await forceClosePosition(this.client, symbol, options);
|
|
62723
|
+
}
|
|
62718
62724
|
}
|
|
62719
62725
|
function getPricePlaces(target) {
|
|
62720
62726
|
const numStr = target.toString();
|
|
@@ -62724,6 +62730,90 @@ function getPricePlaces(target) {
|
|
|
62724
62730
|
return 0;
|
|
62725
62731
|
}
|
|
62726
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
|
+
}
|
|
62727
62817
|
|
|
62728
62818
|
// src/exchanges/bybit.ts
|
|
62729
62819
|
var import_bybit_api = __toESM(require_lib3(), 1);
|
|
@@ -62836,11 +62926,11 @@ async function getPositionInfo2(client, symbol) {
|
|
|
62836
62926
|
async function cancelOrders2(payload) {
|
|
62837
62927
|
const client = payload.custom_client;
|
|
62838
62928
|
const results = [];
|
|
62839
|
-
for (let i2 = 0;i2 < payload.orders.length; i2 +=
|
|
62840
|
-
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);
|
|
62841
62931
|
let rr = await client.batchCancelOrders("linear", batch2.map((x) => ({ orderId: x.orderId, symbol: payload.symbol })));
|
|
62842
62932
|
results.push(rr);
|
|
62843
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
62933
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
62844
62934
|
}
|
|
62845
62935
|
return results;
|
|
62846
62936
|
}
|
|
@@ -66217,7 +66307,6 @@ class ExchangeAccount {
|
|
|
66217
66307
|
const long_position = positions.find((k) => k.kind === "long");
|
|
66218
66308
|
const short_position = positions.find((k) => k.kind === "short");
|
|
66219
66309
|
console.log("Getting focus position for ", symbol, kind);
|
|
66220
|
-
const reverse_position = kind === "long" ? short_position : long_position;
|
|
66221
66310
|
if (strategy2.max_reward_factor === 0) {
|
|
66222
66311
|
reward_factor = strategy2.reward_factor;
|
|
66223
66312
|
}
|
|
@@ -66274,13 +66363,6 @@ class ExchangeAccount {
|
|
|
66274
66363
|
params: config2
|
|
66275
66364
|
});
|
|
66276
66365
|
console.log("Checking orders to place for ", symbol, kind);
|
|
66277
|
-
const orders_to_place = await this.placeTrade({
|
|
66278
|
-
symbol,
|
|
66279
|
-
raw: true,
|
|
66280
|
-
kind,
|
|
66281
|
-
place: false,
|
|
66282
|
-
ignore_config: true
|
|
66283
|
-
});
|
|
66284
66366
|
await this.placeTrade({
|
|
66285
66367
|
symbol,
|
|
66286
66368
|
kind,
|
|
@@ -66292,9 +66374,6 @@ class ExchangeAccount {
|
|
|
66292
66374
|
...config2,
|
|
66293
66375
|
...data
|
|
66294
66376
|
};
|
|
66295
|
-
let reverse_action = null;
|
|
66296
|
-
let reverse_orders_to_buy = [];
|
|
66297
|
-
let reverse_config = null;
|
|
66298
66377
|
if (focus_position.avg_qty < last_value.avg_size) {
|
|
66299
66378
|
console.log("Placing trade for ", symbol, kind);
|
|
66300
66379
|
await this.placeTrade({
|
|
@@ -66305,97 +66384,11 @@ class ExchangeAccount {
|
|
|
66305
66384
|
});
|
|
66306
66385
|
}
|
|
66307
66386
|
console.log("Checking if focus position has quantity for ", symbol, kind);
|
|
66308
|
-
if (focus_position.quantity > 0) {
|
|
66309
|
-
console.log("Getting details for ", reverse_position.kind);
|
|
66310
|
-
reverse_action = await this.buildOppositeTrades({
|
|
66311
|
-
symbol,
|
|
66312
|
-
kind
|
|
66313
|
-
});
|
|
66314
|
-
if (!reverse_action) {
|
|
66315
|
-
return;
|
|
66316
|
-
}
|
|
66317
|
-
console.log("Updating config for ", symbol, reverse_action.kind);
|
|
66318
|
-
await this.getPositionConfig({
|
|
66319
|
-
symbol,
|
|
66320
|
-
kind: reverse_action.kind,
|
|
66321
|
-
params: {
|
|
66322
|
-
entry: reverse_action.entry,
|
|
66323
|
-
stop: reverse_action.stop,
|
|
66324
|
-
risk: reverse_action.risk_per_trade,
|
|
66325
|
-
profit_percent: reverse_action.profit_percent,
|
|
66326
|
-
risk_reward: reverse_action.risk_reward
|
|
66327
|
-
}
|
|
66328
|
-
});
|
|
66329
|
-
console.log("Checking reverse orders to buy for ", symbol, reverse_action.kind);
|
|
66330
|
-
const reverse_app_config = await this.buildAppConfig({
|
|
66331
|
-
entry: reverse_action.entry,
|
|
66332
|
-
stop: reverse_action.stop,
|
|
66333
|
-
risk_reward: reverse_action.risk_reward,
|
|
66334
|
-
risk: reverse_action.risk_per_trade,
|
|
66335
|
-
symbol
|
|
66336
|
-
});
|
|
66337
|
-
if (reverse_app_config.max_size != reverse_position.avg_qty) {
|
|
66338
|
-
reverse_orders_to_buy = await this.placeTrade({
|
|
66339
|
-
symbol,
|
|
66340
|
-
raw: true,
|
|
66341
|
-
kind: reverse_action.kind,
|
|
66342
|
-
ignore_config: true,
|
|
66343
|
-
place: false
|
|
66344
|
-
});
|
|
66345
|
-
let _reverse_config = {
|
|
66346
|
-
avg: reverse_action.avg,
|
|
66347
|
-
entry: reverse_action.entry,
|
|
66348
|
-
stop: reverse_action.stop,
|
|
66349
|
-
risk_per_trade: reverse_action.risk_per_trade,
|
|
66350
|
-
profit_percent: reverse_action.profit_percent,
|
|
66351
|
-
risk_reward: reverse_action.risk_reward
|
|
66352
|
-
};
|
|
66353
|
-
if (reverse_orders_to_buy.length > 0) {
|
|
66354
|
-
console.log("Placing opposite trade action for ", symbol, reverse_action.kind);
|
|
66355
|
-
let existing = await this.placeOppositeTradeAction({
|
|
66356
|
-
symbol,
|
|
66357
|
-
kind: reverse_action.kind,
|
|
66358
|
-
data: _reverse_config
|
|
66359
|
-
});
|
|
66360
|
-
_reverse_config = {
|
|
66361
|
-
...existing,
|
|
66362
|
-
..._reverse_config
|
|
66363
|
-
};
|
|
66364
|
-
}
|
|
66365
|
-
reverse_config = _reverse_config;
|
|
66366
|
-
}
|
|
66367
|
-
if (!reverse_config?.id) {
|
|
66368
|
-
console.log("fetching reverse config for ", symbol, reverse_action.kind);
|
|
66369
|
-
reverse_config = await this.getPositionConfig({
|
|
66370
|
-
symbol,
|
|
66371
|
-
kind: reverse_action.kind
|
|
66372
|
-
});
|
|
66373
|
-
}
|
|
66374
|
-
if (reverse_position.quantity > 0 && reverse_config?.id) {
|
|
66375
|
-
console.log("Checking if reverse position has quantity for ", symbol, reverse_action.kind);
|
|
66376
|
-
const max_size = app_config.max_size * 0.98;
|
|
66377
|
-
if (reverse_config.threshold_qty !== max_size) {
|
|
66378
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
66379
|
-
follow: strategy2.follow,
|
|
66380
|
-
threshold_qty: max_size
|
|
66381
|
-
});
|
|
66382
|
-
}
|
|
66383
|
-
console.log("Updating follow and threshold for ", symbol, reverse_action.kind);
|
|
66384
|
-
} else {
|
|
66385
|
-
await this.app_db.updateScheduledTrade(reverse_config.id, {
|
|
66386
|
-
follow: false
|
|
66387
|
-
});
|
|
66388
|
-
}
|
|
66389
|
-
}
|
|
66390
66387
|
return {
|
|
66391
|
-
reverse_config,
|
|
66392
|
-
reverse_action,
|
|
66393
|
-
reverse_orders_to_buy,
|
|
66394
66388
|
positions: {
|
|
66395
66389
|
long: long_position,
|
|
66396
66390
|
short: short_position
|
|
66397
66391
|
},
|
|
66398
|
-
orders_to_place,
|
|
66399
66392
|
config_details: {
|
|
66400
66393
|
app_config,
|
|
66401
66394
|
last_value,
|